api

package
v2.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2022 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// EventKind represents the canonical Event kind string
	EventKind = "Event"

	// CloneLabelKey is the label key used for tracing the original event
	// on any cloned event
	CloneLabelKey = "brigade.sh/cloneOf"

	// RetryLabelKey is the label key used for tracing the original event
	// on any retried event
	RetryLabelKey = "brigade.sh/retryOf"
)
View Source
const (
	// ProjectRoleAssignmentKind represents the canonical ProjectRoleAssignment
	// kind string
	ProjectRoleAssignmentKind = "ProjectRoleAssignment"

	// ProjectRoleAssignmentListKind represents the canonical
	// ProjectRoleAssignmentList kind string
	ProjectRoleAssignmentListKind = "ProjectRoleAssignmentList"
)
View Source
const (
	// RoleAssignmentKind represents the canonical RoleAssignment kind string
	RoleAssignmentKind = "RoleAssignment"

	// RoleAssignmentListKind represents the canonical RoleAssignmentList kind
	// string
	RoleAssignmentListKind = "RoleAssignmentList"
)
View Source
const JobKind = "Job"

JobKind represents the canonical Job kind string

View Source
const PrincipalReferenceKind = "PrincipalReference"

PrincipalReferenceKind represents the canonical PrincipalReference kind string

View Source
const ProjectKind = "Project"

ProjectKind represents the canonical Project kind string

View Source
const ProjectRoleScopeGlobal = "*"

ProjectRoleScopeGlobal represents an unbounded project scope.

View Source
const RoleScopeGlobal = "*"

RoleScopeGlobal represents an unbounded scope.

View Source
const ServiceAccountKind = "ServiceAccount"

ServiceAccountKind represents the canonical Service Account kind string

View Source
const SessionKind = "Session"

SessionKind represents the canonical Session kind string

View Source
const UserKind = "User"

UserKind represents the canonical User kind string

Variables

This section is empty.

Functions

func ContextWithPrincipal

func ContextWithPrincipal(
	ctx context.Context,
	principal interface{},
) context.Context

ContextWithPrincipal returns a context.Context that has been augmented with the provided principal.

func ContextWithSessionID

func ContextWithSessionID(
	ctx context.Context,
	sessionID string,
) context.Context

ContextWithSessionID returns a context.Context that has been augmented with the provided Session identifier.

func PrincipalFromContext

func PrincipalFromContext(ctx context.Context) interface{}

PrincipalFromContext extracts a principal from the provided context.Context and returns it.

func SessionIDFromContext

func SessionIDFromContext(ctx context.Context) string

SessionIDFromContext extracts a Session identifier from the provided context.Context and returns it.

Types

type AuthorizeFn

type AuthorizeFn func(ctx context.Context, role Role, scope string) error

AuthorizeFn is the signature for any function that can, presumably, retrieve a principal from the provided Context and make an access control decision based on the principal having (or not having) the specified Role with the specified scope. Implementations MUST return a *meta.ErrAuthorization error if the principal is not authorized.

type Authorizer

type Authorizer interface {
	// Authorize retrieves a principal from the provided Context and asserts that
	// it has the specified Role with the specified scope. If it does not,
	// implementations MUST return a *meta.ErrAuthorization error.
	Authorize(ctx context.Context, roles Role, scope string) error
}

Authorizer is the public interface for the component returned by the NewAuthorizer function.

func NewAuthorizer

func NewAuthorizer(roleAssignmentsStore RoleAssignmentsStore) Authorizer

NewAuthorizer returns a component that can authorize a request.

type CancelManyEventsResult

type CancelManyEventsResult struct {
	// Count represents the number of Events canceled.
	Count int64 `json:"count"`
}

CancelManyEventsResult represents a summary of a mass Event cancellation operation.

func (CancelManyEventsResult) MarshalJSON

func (c CancelManyEventsResult) MarshalJSON() ([]byte, error)

MarshalJSON amends CancelManyEventsResult instances with type metadata.

type ContainerSpec

type ContainerSpec struct {
	// Image specifies the OCI image on which the container should be based.
	Image string `json:"image,omitempty" bson:"image,omitempty"`
	// ImagePullPolicy specifies whether a container host already having the
	// specified OCI image should attempt to re-pull that image prior to launching
	// a new container.
	ImagePullPolicy ImagePullPolicy `json:"imagePullPolicy,omitempty" bson:"imagePullPolicy,omitempty"` // nolint: lll
	// Command specifies the command to be executed by the OCI container. This
	// can be used to optionally override the default command specified by the OCI
	// image itself.
	Command []string `json:"command,omitempty" bson:"command,omitempty"`
	// Arguments specifies arguments to the command executed by the OCI container.
	Arguments []string `json:"arguments,omitempty" bson:"arguments,omitempty"`
	// Environment is a map of key/value pairs that specify environment variables
	// to be set within the OCI container.
	Environment map[string]string `json:"environment,omitempty" bson:"environment,omitempty"` // nolint: lll
}

ContainerSpec represents the technical details of an OCI container.

func (ContainerSpec) EqualTo

func (cs ContainerSpec) EqualTo(cs2 ContainerSpec) bool

type CoolLogsStore

type CoolLogsStore interface {
	LogsStore

	// DeleteEventLogs deletes all logs associated with the provided event.
	DeleteEventLogs(ctx context.Context, id string) error

	// DeleteProjectLogs deletes all logs associated with the provided project.
	DeleteProjectLogs(ctx context.Context, id string) error
}

CoolLogsStore is an interface for components that implement "cool" Log persistence concerns. These log store types are intended to act as longterm storehouses for worker and job logs after they have reached a terminal state. Thus, log deletion methods are prudent for managing the size of the underlying store.

type DeleteManyEventsResult

type DeleteManyEventsResult struct {
	// Count represents the number of Events deleted.
	Count int64 `json:"count"`
}

DeleteManyEventsResult represents a summary of a mass Event deletion operation.

func (DeleteManyEventsResult) MarshalJSON

func (d DeleteManyEventsResult) MarshalJSON() ([]byte, error)

MarshalJSON amends DeleteManyEventsResult instances with type metadata.

type Event

type Event struct {
	// ObjectMeta contains Event metadata.
	meta.ObjectMeta `json:"metadata" bson:",inline"`
	// ProjectID specifies the Project this Event is for. Often, this field will
	// be left blank, in which case the Event is matched against subscribed
	// Projects on the basis of the Source, Type, Qualifiers, and Labels fields,
	// then used as a template to create a discrete Event for each subscribed
	// Project.
	ProjectID string `json:"projectID,omitempty" bson:"projectID,omitempty"`
	// Source specifies the source of the Event, e.g. what gateway created it.
	// Gateways should populate this field with a unique string that clearly
	// identifies themself as the source of the event. The ServiceAccount used by
	// each gateway can be authorized (by a admin) to only create events having a
	// specified value in the Source field, thereby eliminating the possibility of
	// gateways maliciously creating events that spoof events from another
	// gateway.
	Source string `json:"source,omitempty" bson:"source,omitempty"`
	// SourceState encapsulates opaque, source-specific (e.g. gateway-specific)
	// state.
	SourceState *SourceState `json:"sourceState,omitempty" bson:"sourceState,omitempty"` // nolint: lll
	// Type specifies the exact event that has occurred in the upstream system.
	// Values are opaque and source-specific.
	Type string `json:"type,omitempty" bson:"type,omitempty"`
	// Qualifiers provide critical disambiguation of an Event's type. A Project is
	// considered subscribed to an Event IF AND ONLY IF (in addition to matching
	// the Event's Source and Type) it matches ALL of the Event's qualifiers
	// EXACTLY. To demonstrate the usefulness of this, consider any event from a
	// hypothetical GitHub gateway. If, by design, that gateway does not intend
	// for any Project to subscribe to ALL Events (i.e. regardless of which
	// repository they originated from), then that gateway can QUALIFY Events it
	// emits into Brigade's event bus with repo=<repository name>. Projects
	// wishing to subscribe to Events from the GitHub gateway MUST include that
	// Qualifier in their EventSubscription. Note that the Qualifiers field's
	// "MUST match" subscription semantics differ from the Labels field's "MAY
	// match" subscription semantics.
	Qualifiers Qualifiers `json:"qualifiers,omitempty" bson:"qualifiers,omitempty"` // nolint: lll
	// Labels convey supplementary Event details that Projects may OPTIONALLY use
	// to narrow EventSubscription criteria. A Project is considered subscribed to
	// an Event if (in addition to matching the Event's Source, Type, and
	// Qualifiers) the Event has ALL labels expressed in the Project's
	// EventSubscription. If the Event has ADDITIONAL labels, not mentioned by the
	// EventSubscription, these do not preclude a match. To demonstrate the
	// usefulness of this, consider any event from a hypothetical Slack gateway.
	// If, by design, that gateway intends for Projects to select between
	// subscribing to ALL Events or ONLY events originating from a specific
	// channel, then that gateway can LABEL Events it emits into Brigade's event
	// bus with channel=<channel name>. Projects wishing to subscribe to ALL
	// Events from the Slack gateway MAY omit that Label from their
	// EventSubscription, while Projects wishing to subscribe to only Events
	// originating from a specific channel MAY include that Label in their
	// EventSubscription. Note that the Labels field's "MAY match" subscription
	// semantics differ from the Qualifiers field's "MUST match" subscription
	// semantics.
	Labels map[string]string `json:"labels,omitempty" bson:"labels,omitempty"`
	// ShortTitle is an optional, succinct title for the Event, ideal for use in
	// lists or in scenarios where UI real estate is constrained.
	ShortTitle string `json:"shortTitle,omitempty" bson:"shortTitle,omitempty"`
	// LongTitle is an optional, detailed title for the Event.
	LongTitle string `json:"longTitle,omitempty" bson:"longTitle,omitempty"`
	// Git contains git-specific Event details. These can be used to override
	// similar details defined at the Project level. This is useful for scenarios
	// wherein an Event may need to convey an alternative source, branch, etc.
	Git *GitDetails `json:"git,omitempty" bson:"git,omitempty"`
	// Payload optionally contains Event details provided by the upstream system
	// that was the original source of the event. Payloads MUST NOT contain
	// sensitive information. Since Projects SUBSCRIBE to Events, the potential
	// exists for any Project to express an interest in any or all Events. This
	// being the case, sensitive details must never be present in payloads. The
	// common workaround work this constraint (which is also a sensible practice
	// to begin with) is that event payloads may contain REFERENCES to sensitive
	// details that are useful only to properly configured Workers.
	Payload string `json:"payload,omitempty" bson:"payload,omitempty"`
	// Summary is a counterpart to Payload. If Payload is free-form Worker input,
	// then Summary is free-form Worker output. It can optionally be set by a
	// Worker to provide a summary of the work completed by the Worker and its
	// Jobs.
	Summary string `json:"summary,omitempty" bson:"summary,omitempty"`
	// Worker contains details of the Worker assigned to handle the Event.
	Worker Worker `json:"worker" bson:"worker"`
}

Event represents an occurrence in some upstream system. Once accepted into the system, Brigade amends each Event with a plan for handling it in the form of a Worker. An Event's status is, implicitly, the status of its Worker.

func (Event) MarshalJSON

func (e Event) MarshalJSON() ([]byte, error)

MarshalJSON amends Event instances with type metadata.

type EventSubscription

type EventSubscription struct {
	// Source specifies the origin of an Event (e.g. a gateway). This is a
	// required field.
	Source string `json:"source,omitempty" bson:"source,omitempty"`
	// Types enumerates specific Events of interest from the specified Source.
	// This is useful in narrowing a subscription when a Source also emits many
	// Event types that are NOT of interest. This is a required field. The value
	// "*" may be utilized to denote that ALL events originating from the
	// specified Source are of interest.
	Types []string `json:"types,omitempty" bson:"types,omitempty"`
	// Qualifiers specifies an EXACT set of key/value pairs with which an Event
	// MUST also be qualified for a Project to be considered subscribed. To
	// demonstrate the usefulness of this, consider any event from a hypothetical
	// GitHub gateway. If, by design, that gateway does not intend for any Project
	// to subscribe to ALL Events (i.e. regardless of which repository they
	// originated from), then that gateway can QUALIFY Events it emits into
	// Brigade's event bus with repo=<repository name>. Projects wishing to
	// subscribe to Events from the GitHub gateway MUST include that Qualifier in
	// their EventSubscription. Note that the Qualifiers field's "MUST match"
	// subscription semantics differ from the Labels field's "MAY match"
	// subscription semantics.
	Qualifiers Qualifiers `json:"qualifiers,omitempty" bson:"qualifiers,omitempty"` // nolint: lll
	// Labels optionally specifies filter criteria as key/value pairs with which
	// an Event MUST also be labeled for a Project to be considered subscribed. If
	// the Event has ADDITIONAL labels, not mentioned by this EventSubscription,
	// these do not preclude a match. To demonstrate the usefulness of this,
	// consider any event from a hypothetical Slack gateway. If, by design, that
	// gateway intends for Projects to select between subscribing to ALL Events or
	// ONLY events originating from a specific channel, then that gateway can
	// LABEL Events it emits into Brigade's event bus with channel=<channel name>.
	// Projects wishing to subscribe to ALL Events from the Slack gateway MAY omit
	// that Label from their EventSubscription, while Projects wishing to
	// subscribe to only Events originating from a specific channel MAY include
	// that Label in their EventSubscription. Note that the Labels field's "MAY
	// match" subscription semantics differ from the Qualifiers field's "MUST
	// match" subscription semantics.
	Labels map[string]string `json:"labels,omitempty" bson:"labels,omitempty"`
}

EventSubscription defines a set of Events of interest. ProjectSpecs utilize these in defining the Events that should trigger the execution of a new Worker. An Event matches a subscription if it meets ALL of the specified criteria.

type EventSummary

type EventSummary struct {
	// Text is the Event summary as (optionally) provided by a Worker.
	Text string `json:"text,omitempty"`
}

EventSummary encapsulates an opaque, Worker-specific summary of an Event.

type EventsSelector

type EventsSelector struct {
	// ProjectID specifies that only Events belonging to the indicated Project
	// should be selected.
	ProjectID string
	// Source specifies that only Events from the indicated source should be
	// selected.
	Source string
	// SourceState specifies that only Events having all of the indicated source
	// state key/value pairs should be selected.
	SourceState map[string]string
	// Type specifies that only Events having the indicated type should be
	// selected.
	Type string
	// WorkerPhases specifies that only Events with their Workers in any of the
	// indicated phases should be selected.
	WorkerPhases []WorkerPhase
	// Qualifiers specifies that only Events qualified with these key/value pairs
	// should be selected.
	Qualifiers Qualifiers
	// Labels specifies that only Events labeled with these key/value pairs should
	// be selected.
	Labels map[string]string
}

EventsSelector represents useful filter criteria when selecting multiple Events for API group operations like list, cancel, or delete.

type EventsService

type EventsService interface {
	// Create creates a new Event.
	Create(context.Context, Event) (
		meta.List[Event],
		error,
	)
	// List retrieves an EventList, with its Items (Events) ordered by age, newest
	// first. Criteria for which Events should be retrieved can be specified using
	// the EventListOptions parameter.
	List(
		context.Context,
		EventsSelector,
		meta.ListOptions,
	) (meta.List[Event], error)
	// Get retrieves a single Event specified by its identifier. If no such event
	// is found, implementations MUST return a *meta.ErrNotFound error.
	Get(context.Context, string) (Event, error)
	// GetByWorkerToken retrieves a single Event specified by its Worker's token.
	// If no such event is found, implementations MUST return a *meta.ErrNotFound
	// error.
	GetByWorkerToken(context.Context, string) (Event, error)
	// Clones an Event and creates a new Event after removing the original's
	// metadata and Worker configuration
	Clone(context.Context, string) (Event, error)
	// UpdateSourceState updates source-specific (e.g. gateway-specific) Event
	// state.
	UpdateSourceState(context.Context, string, SourceState) error
	// UpdateSummary updates the opaque, Worker-specific summary of work performed
	// by the Worker and its Jobs.
	UpdateSummary(context.Context, string, EventSummary) error
	// Cancel cancels a single Event specified by its identifier. If no such event
	// is found, implementations MUST return a *meta.ErrNotFound error.
	// Implementations MUST only cancel events whose Workers have not already
	// reached a terminal state. If the specified Event's Worker has already
	// reached a terminal state, implementations MUST return a *meta.ErrConflict.
	Cancel(context.Context, string) error
	// CancelMany cancels multiple Events specified by the EventsSelector
	// parameter. Implementations MUST only cancel events whose Workers have not
	// already reached a terminal state.
	CancelMany(
		context.Context,
		EventsSelector,
	) (CancelManyEventsResult, error)
	// Delete unconditionally deletes a single Event specified by its identifier.
	// If no such event is found, implementations MUST return a *meta.ErrNotFound
	// error.
	Delete(context.Context, string) error
	// DeleteMany unconditionally deletes multiple Events specified by the
	// EventsSelector parameter.
	DeleteMany(
		context.Context,
		EventsSelector,
	) (DeleteManyEventsResult, error)
	// Retry copies an Event, including Worker configuration and Jobs, and
	// creates a new Event from this information.  Where possible, job results
	// are inherited and the job not re-scheduled, for example when a job has
	// succeeded and does not make use of a shared workspace.
	Retry(context.Context, string) (Event, error)
}

EventsService is the specialized interface for managing Events. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewEventsService

func NewEventsService(
	authorizeFn AuthorizeFn,
	projectAuthorize ProjectAuthorizeFn,
	projectsStore ProjectsStore,
	eventsStore EventsStore,
	logsStore CoolLogsStore,
	substrate Substrate,
) EventsService

NewEventsService returns a specialized interface for managing Events.

type EventsStore

type EventsStore interface {
	// Create persists a new Event in the underlying data store. If n Event having
	// the same ID already exists, implementations MUST return a *meta.ErrConflict
	// error.
	Create(context.Context, Event) error
	// List retrieves an EventList from the underlying data store, with its Items
	// (Events) ordered by age, newest first. Criteria for which Events should be
	// retrieved can be specified using the EventListOptions parameter.
	List(
		context.Context,
		EventsSelector,
		meta.ListOptions,
	) (meta.List[Event], error)
	// Get retrieves a single Event from the underlying data store. If the
	// specified Event does not exist, implementations MUST return a
	// *meta.ErrNotFound error.
	Get(context.Context, string) (Event, error)
	// GetByHashedWorkerToken retrieves a single Event from the underlying data
	// store by the provided hashed Worker token. If no such Event exists,
	// implementations MUST return a *meta.ErrNotFound error.
	GetByHashedWorkerToken(context.Context, string) (Event, error)
	// UpdateSourceState updates source-specific (e.g. gateway-specific) Event
	// state. Implementations MAY assume the Event's existence has been
	// pre-confirmed by the caller.
	UpdateSourceState(context.Context, string, SourceState) error
	// UpdateSummary updates the opaque, Worker-specific Event summary.
	UpdateSummary(context.Context, string, EventSummary) error
	// Cancel updates the specified Event in the underlying data store to reflect
	// that it has been canceled. Implementations MAY assume the Event's existence
	// has been pre-confirmed by the caller. Implementations MUST only cancel
	// events whose Workers have not already reached a terminal state. If the
	// specified Event's Worker has already reached a terminal state,
	// implementations MUST return a *meta.ErrConflict.
	Cancel(context.Context, string) error
	// CancelMany updates multiple Events specified by the EventsSelector
	// parameter in the underlying data store to reflect that they have been
	// canceled. Implementations MUST only cancel events whose Workers have not
	// already reached a terminal state and MUST return the total number of
	// canceled events.
	CancelMany(context.Context, EventsSelector) (<-chan Event, int64, error)
	// Delete unconditionally deletes the specified Event from the underlying data
	// store. If the specified Event does not exist, implementations MUST
	// return a *meta.ErrNotFound error.
	Delete(context.Context, string) error
	// DeleteMany unconditionally deletes multiple Events specified by the
	// EventsSelector parameter from the underlying data store. Implementations
	// MUST return the total number of deleted events.
	DeleteMany(context.Context, EventsSelector) (<-chan Event, int64, error)
	// DeleteByProjectID unconditionally deletes all Events associated with the
	// specified project.
	DeleteByProjectID(context.Context, string) error
}

EventsStore is an interface for components that implement Event persistence concerns.

type GitConfig

type GitConfig struct {
	// CloneURL specifies the location from where a source code repository may
	// be cloned.
	CloneURL string `json:"cloneURL,omitempty" bson:"cloneURL,omitempty"`
	// Commit specifies a revision (by SHA) to be checked out. If non-empty, this
	// field takes precedence over any value in the Ref field.
	Commit string `json:"commit,omitempty" bson:"commit,omitempty"`
	// Ref is a symbolic reference to a revision to be checked out. If non-empty,
	// the value of the Commit field supercedes any value in this field. Example
	// uses of this field include referencing a branch (refs/heads/<branch name>)
	// or a tag (refs/tags/<tag name>). If left blank, this field is interpreted
	// as a reference to the repository's default branch.
	Ref string `json:"ref,omitempty" bson:"ref,omitempty"`
	// InitSubmodules indicates whether to clone the repository's submodules.
	InitSubmodules bool `json:"initSubmodules" bson:"initSubmodules"`
}

GitConfig represents git-specific Worker details.

type GitDetails

type GitDetails struct {
	// CloneURL specifies the location from where a source code repository may
	// be cloned.
	CloneURL string `json:"cloneURL,omitempty" bson:"cloneURL,omitempty"`
	// Commit specifies a revision (by SHA) to be checked out. If non-empty, this
	// field takes precedence over any value in the Ref field.
	Commit string `json:"commit,omitempty" bson:"commit,omitempty"`
	// Ref is a symbolic reference to a revision to be checked out. If non-empty,
	// the value of the Commit field supercedes any value in this field. Example
	// uses of this field include referencing a branch (refs/heads/<branch name>)
	// or a tag (refs/tags/<tag name>). If left blank, this field is interpreted
	// as a reference to the repository's default branch.
	Ref string `json:"ref,omitempty" bson:"ref,omitempty"`
}

GitDetails represents git-specific Event details. These may override Project-level GitConfig.

type ImagePullPolicy

type ImagePullPolicy string

ImagePullPolicy represents a policy for whether container hosts already having a certain OCI image should attempt to re-pull that image prior to launching a new container based on that image.

type Job

type Job struct {
	// Name is the Job's name. It should be unique among a given Worker's Jobs.
	Name string `json:"name" bson:"name"`
	// Created indicates the time at which a Job was created.
	Created *time.Time `json:"created,omitempty"`
	// Spec is the technical blueprint for the Job.
	Spec JobSpec `json:"spec" bson:"spec"`
	// Status contains details of the Job's current state.
	Status *JobStatus `json:"status" bson:"status"`
}

Job represents a component spawned by a Worker to complete a single task in the course of handling an Event.

func (Job) UsesWorkspace

func (j Job) UsesWorkspace() bool

UsesWorkspace returns a boolean value indicating whether or not the job uses a shared workspace.

type JobContainerSpec

type JobContainerSpec struct {
	// ContainerSpec encapsulates generic specifications for an OCI container.
	ContainerSpec `json:",inline" bson:",inline"`
	// WorkingDirectory specifies the OCI container's working directory.
	WorkingDirectory string `json:"workingDirectory,omitempty" bson:"workingDirectory,omitempty"` // nolint: lll
	// WorkspaceMountPath specifies the path in the OCI container's file system
	// where, if applicable, the Worker's shared workspace should be mounted. If
	// left blank, the Job implicitly does not use the Worker's shared workspace.
	WorkspaceMountPath string `json:"workspaceMountPath,omitempty" bson:"workspaceMountPath,omitempty"` // nolint: lll
	// SourceMountPath specifies the path in the OCI container's file system
	// where, if applicable, source code retrieved from a VCS repository should be
	// mounted. If left blank, the Job implicitly does not use source code
	// retrieved from a VCS repository.
	SourceMountPath string `json:"sourceMountPath,omitempty" bson:"sourceMountPath,omitempty"` // nolint: lll
	// Privileged indicates whether the OCI container should operate in a
	// "privileged" (relaxed permissions) mode. This is commonly used to effect
	// "Docker-in-Docker" ("DinD") scenarios wherein one of a Job's OCI containers
	// must run its own Docker daemon. Note this field REQUESTS privileged status
	// for the container, but that may be disallowed by Project-level
	// configuration.
	Privileged bool `json:"privileged" bson:"privileged"`
}

JobContainerSpec amends the ContainerSpec type with additional Job-specific fields.

func (JobContainerSpec) EqualTo

func (jcs JobContainerSpec) EqualTo(jcs2 JobContainerSpec) bool

type JobHost

type JobHost struct {
	// OS specifies which "family" of operating system is required on a substrate
	// node to host a Job. Valid values are "linux" and "windows". When empty,
	// Brigade assumes "linux".
	OS OSFamily `json:"os,omitempty" bson:"os,omitempty"`
	// NodeSelector specifies labels that must be present on the substrate node to
	// host a Job. This provides an opaque mechanism for communicating Job needs
	// such as specific hardware like an SSD or GPU.
	NodeSelector map[string]string `json:"nodeSelector,omitempty" bson:"nodeSelector,omitempty"` // nolint: lll
}

JobHost represents criteria for selecting a suitable host (substrate node) for a Job.

func (*JobHost) EqualTo

func (jh *JobHost) EqualTo(jh2 *JobHost) bool

type JobPhase

type JobPhase string

JobPhase represents where a Job is within its lifecycle.

const (
	// JobPhaseAborted represents the state wherein a Job was forcefully
	// stopped during execution.
	JobPhaseAborted JobPhase = "ABORTED"
	// JobPhaseCanceled represents the state wherein a pending Job was
	// canceled prior to execution.
	JobPhaseCanceled JobPhase = "CANCELED"
	// JobPhaseFailed represents the state wherein a Job has run to
	// completion but experienced errors.
	JobPhaseFailed JobPhase = "FAILED"
	// JobPhasePending represents the state wherein a Job is awaiting
	// execution.
	JobPhasePending JobPhase = "PENDING"
	// JobPhaseRunning represents the state wherein a Job is currently
	// being executed.
	JobPhaseRunning JobPhase = "RUNNING"
	// JobPhaseSchedulingFailed represents the state wherein a Job was not
	// scheduled due to some unexpected and unrecoverable error encountered by the
	// scheduler.
	JobPhaseSchedulingFailed JobPhase = "SCHEDULING_FAILED"
	// JobPhaseStarting represents the state wherein a Job is starting on the
	// substrate but isn't running yet.
	JobPhaseStarting JobPhase = "STARTING"
	// JobPhaseSucceeded represents the state where a Job has run to
	// completion without error.
	JobPhaseSucceeded JobPhase = "SUCCEEDED"
	// JobPhaseTimedOut represents the state wherein a Job has has not completed
	// within a designated timeframe.
	JobPhaseTimedOut JobPhase = "TIMED_OUT"
	// JobPhaseUnknown represents the state wherein a Job's state is unknown. Note
	// that this is possible if and only if the underlying Job execution substrate
	// (Kubernetes), for some unanticipated, reason does not know the Job's
	// (Pod's) state.
	JobPhaseUnknown JobPhase = "UNKNOWN"
)

func (JobPhase) IsTerminal

func (j JobPhase) IsTerminal() bool

IsTerminal returns a bool indicating whether the JobPhase is terminal.

type JobPolicies

type JobPolicies struct {
	// AllowPrivileged specifies whether the Worker is permitted to launch Jobs
	// that utilize privileged containers.
	AllowPrivileged bool `json:"allowPrivileged" bson:"allowPrivileged"`
}

JobPolicies represents policies for any Jobs spawned by a Worker.

type JobSpec

type JobSpec struct {
	// PrimaryContainer specifies the details of an OCI container that forms the
	// cornerstone of the Job. Job success or failure is tied to completion and
	// exit code of this container.
	PrimaryContainer JobContainerSpec `json:"primaryContainer" bson:"primaryContainer"` // nolint: lll
	// SidecarContainers specifies the details of supplemental, "sidecar"
	// containers. Their completion and exit code do not directly impact Job
	// status. Brigade does not understand dependencies between a Job's multiple
	// containers and cannot enforce any specific startup or shutdown order. When
	// such dependencies exist (for instance, a primary container than cannot
	// proceed with a suite of tests until a database is launched and READY in a
	// sidecar container), then logic within those containers must account for
	// these constraints.
	SidecarContainers map[string]JobContainerSpec `json:"sidecarContainers,omitempty" bson:"sidecarContainers,omitempty"` // nolint: lll
	// TimeoutDuration specifies the time duration that must elapse before a
	// running Job should be considered to have timed out. This duration string
	// is a sequence of decimal numbers, each with optional fraction and a unit
	// suffix, such as "300ms", "3.14s" or "2h45m".
	// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
	TimeoutDuration string `json:"timeoutDuration,omitempty" bson:"timeoutDuration,omitempty"` // nolint: lll
	// Host specifies criteria for selecting a suitable host (substrate node) for
	// the Job. This is useful in cases where a Job requires a specific,
	// non-default operating system (i.e. Windows) or specific hardware (e.g. a
	// GPU.)
	Host *JobHost `json:"host,omitempty" bson:"host,omitempty"`
	// Fallible specifies whether the job is permitted to fail WITHOUT causing the
	// worker process to fail. The API server does not use this field directly,
	// but it is information that may be valuable to gateways that report job
	// success/failure upstream to original event sources.
	Fallible bool `json:"fallible" bson:"fallible"`
}

JobSpec is the technical blueprint for a Job.

func (JobSpec) EqualTo

func (js JobSpec) EqualTo(js2 JobSpec) bool

type JobStatus

type JobStatus struct {
	// Started indicates the time the Job began execution.
	Started *time.Time `json:"started,omitempty" bson:"started,omitempty"`
	// Ended indicates the time the Job concluded execution. It will be nil
	// for a Job that is not done executing.
	Ended *time.Time `json:"ended,omitempty" bson:"ended,omitempty"`
	// Phase indicates where the Job is in its lifecycle.
	Phase JobPhase `json:"phase,omitempty" bson:"phase,omitempty"`
	// LogsEventID indicates which event ID the job logs are associated with.
	// This is useful for looking up logs for an inherited job associated with
	// retry events.
	LogsEventID string `json:"logsEventID,omitempty" bson:"logsEventID,omitempty"`
}

JobStatus represents the status of a Job.

type JobsService

type JobsService interface {
	// Create, given an Event identifier and Job, creates a new Job and schedules
	// it on Brigade's workload execution substrate. If the specified Event does
	// not exist, implementations MUST return a *meta.ErrNotFound error. If the
	// specified Event already has a Job with the specified name, implementations
	// MUST return a *meta.ErrConflict error.
	Create(ctx context.Context, eventID string, job Job) error
	// Start, given an Event identifier and Job name, starts that Job on
	// Brigade's workload execution substrate. If the specified Event or specified
	// Job thereof does not exist, implementations MUST return a *meta.ErrNotFound
	// error.
	Start(ctx context.Context, eventID string, jobName string) error
	// GetStatus, given an Event identifier and Job name, returns the Job's
	// status. If the specified Event or specified Job thereof does not exist,
	// implementations MUST return a *meta.ErrNotFound error.
	GetStatus(
		ctx context.Context,
		eventID string,
		jobName string,
	) (JobStatus, error)
	// WatchStatus, given an Event identifier and Job name, returns a channel over
	// which the Job's status is streamed. The channel receives a new JobStatus
	// every time there is any change in that status. If the specified Event or
	// specified Job thereof does not exist, implementations MUST return a
	// *meta.ErrNotFound error.
	WatchStatus(
		ctx context.Context,
		eventID string,
		jobName string,
	) (<-chan JobStatus, error)
	// UpdateStatus, given an Event identifier and Job name, updates the status of
	// that Job. If the specified Event or specified Job thereof does not exist,
	// implementations MUST return a *meta.ErrNotFound error.
	UpdateStatus(
		ctx context.Context,
		eventID string,
		jobName string,
		status JobStatus,
	) error
	// Cleanup removes Job-related resources from the substrate, presumably
	// upon completion, without deleting the Job from the data store.
	Cleanup(ctx context.Context, eventID, jobName string) error
	// Timeout updates a Job's status to indicate it has timed out and proceeds
	// to cleanup Job-related resources from the substrate.
	Timeout(ctx context.Context, eventID, jobName string) error
}

JobsService is the specialized interface for managing Jobs. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewJobsService

func NewJobsService(
	authorizeFn AuthorizeFn,
	projectsStore ProjectsStore,
	eventsStore EventsStore,
	jobsStore JobsStore,
	substrate Substrate,
) JobsService

NewJobsService returns a specialized interface for managing Jobs.

type JobsStore

type JobsStore interface {
	// Create persists a new Job for the specified Event in the underlying data
	// store.
	Create(ctx context.Context, eventID string, job Job) error
	// UpdateStatus updates the status of the specified Job in the underlying data
	// store. If the specified job is not found, implementations MUST return a
	// *meta.ErrNotFound error.
	UpdateStatus(
		ctx context.Context,
		eventID string,
		jobName string,
		status JobStatus,
	) error
}

JobsStore is an interface for components that implement Job persistence concerns.

type KubernetesConfig

type KubernetesConfig struct {
	// ImagePullSecrets enumerates any image pull secrets that Kubernetes may use
	// when pulling the OCI image on which a Worker's or Job's container is based.
	// This field only needs to be utilized in the case of private, custom Worker
	// or Job images. The image pull secrets in question must be created
	// out-of-band by a sufficiently authorized user of the Kubernetes cluster.
	ImagePullSecrets []string `json:"imagePullSecrets,omitempty" bson:"imagePullSecrets,omitempty"` // nolint: lll
}

KubernetesConfig represents Kubernetes-specific Worker or Job configuration.

type KubernetesDetails

type KubernetesDetails struct {
	// Namespace is the dedicated Kubernetes namespace for the Project. This is
	// NOT specified by clients when creating a new Project. The namespace is
	// created by / assigned by the system. This detail is a necessity to prevent
	// clients from naming existing namespaces in an attempt to hijack them.
	Namespace string `json:"namespace,omitempty" bson:"namespace,omitempty"`
}

KubernetesDetails represents Kubernetes-specific configuration.

type LogEntry

type LogEntry struct {
	// Time is the time the line was written.
	Time *time.Time `json:"time,omitempty" bson:"time,omitempty"`
	// Message is a single line of log output from an OCI container.
	Message string `json:"message,omitempty" bson:"log,omitempty"`
}

LogEntry represents one line of output from an OCI container.

func (LogEntry) MarshalJSON

func (l LogEntry) MarshalJSON() ([]byte, error)

MarshalJSON amends LogEntry instances with type metadata so that clients do not need to be concerned with the tedium of doing so.

type LogLevel

type LogLevel string

LogLevel represents the desired granularity of Worker log output.

const LogLevelInfo LogLevel = "INFO"

LogLevelInfo represents INFO level granularity in Worker log output.

type LogStreamOptions

type LogStreamOptions struct {
	// Follow indicates whether the stream should conclude after the last
	// available line of logs has been sent to the client (false) or remain open
	// until closed by the client (true), continuing to send new lines as they
	// become available.
	Follow bool `json:"follow"`
}

LogStreamOptions represents useful options for streaming logs from some container of a Worker or Job.

type LogsSelector

type LogsSelector struct {
	// Job specifies, by name, a Job spawned by some Worker. If not specified, log
	// streaming operations presume logs are desired for the Worker itself.
	Job string
	// Container specifies, by name, a container belonging to some Worker or, if
	// Job is specified, that Job. If not specified, log streaming operations
	// presume logs are desired from a container having the same name as the
	// selected Worker or Job.
	Container string
}

LogsSelector represents useful criteria for selecting logs to be streamed from any container belonging to some Worker OR any container belonging to Jobs spawned by that Worker.

type LogsService

type LogsService interface {
	// Stream returns a channel over which logs for an Event's Worker, or using
	// the LogsSelector parameter, a Job spawned by that Worker (or specific
	// container thereof), are streamed. If the specified Event, Job, or Container
	// thereof does not exist, implementations MUST return a *meta.ErrNotFound
	// error.
	Stream(
		ctx context.Context,
		eventID string,
		selector LogsSelector,
		opts LogStreamOptions,
	) (<-chan LogEntry, error)
}

LogsService is the specialized interface for accessing logs. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewLogsService

func NewLogsService(
	authorize AuthorizeFn,
	projectAuthorize ProjectAuthorizeFn,
	projectsStore ProjectsStore,
	eventsStore EventsStore,
	warmLogsStore LogsStore,
	coolLogsStore LogsStore,
) LogsService

NewLogsService returns a specialized interface for accessing logs.

type LogsStore

type LogsStore interface {
	// Stream returns a channel over which logs for an Event's Worker, or using
	// the LogsSelector parameter, a Job spawned by that Worker (or specific
	// container thereof), are streamed. If the specified Event, Job, or Container
	// thereof does not exist, implementations MUST return a *meta.ErrNotFound
	// error.
	StreamLogs(
		ctx context.Context,
		project Project,
		event Event,
		selector LogsSelector,
		opts LogStreamOptions,
	) (<-chan LogEntry, error)
}

LogsStore is an interface for components that implement Log persistence concerns.

type OSFamily

type OSFamily string

OSFamily represents a type of operating system.

const (
	// OSFamilyLinux represents a Linux-based OS.
	OSFamilyLinux OSFamily = "linux"
	// OSFamilyWindows represents a Windows-based OS.
	OSFamilyWindows OSFamily = "windows"
)

type ObserverPrincipal added in v2.3.0

type ObserverPrincipal struct{}

ObserverPrincipal is an implementation of the Principal interface that represents the observer component, which is a special class of user because, although it cannot do much, it has the UNIQUE ability to update Worker and Job statuses.

func (*ObserverPrincipal) RoleAssignments added in v2.3.0

func (o *ObserverPrincipal) RoleAssignments() []RoleAssignment

type PrincipalReference

type PrincipalReference struct {
	// Type qualifies what kind of principal is referenced by the ID field-- for
	// instance, a User or a ServiceAccount.
	Type PrincipalType `json:"type,omitempty"`
	// ID references a principal. The Type qualifies what type of principal that
	// is-- for instance, a User or a ServiceAccount.
	ID string `json:"id,omitempty"`
}

PrincipalReference is a reference to any sort of security principal (human user, service account, etc.)

func (PrincipalReference) MarshalJSON added in v2.3.0

func (p PrincipalReference) MarshalJSON() ([]byte, error)

MarshalJSON amends PrincipalReference instances with type metadata.

type PrincipalType

type PrincipalType string

PrincipalType is a type whose values can be used to disambiguate one type of principal from another. For instance, when assigning a Role to a principal via a RoleAssignment, a PrincipalType field is used to indicate whether the value of the PrincipalID field reflects a User ID or a ServiceAccount ID.

const (
	// PrincipalTypeServiceAccount represents a principal that is authenticated as
	// the root user.
	PrincipalTypeRoot PrincipalType = "ROOT"
	// PrincipalTypeServiceAccount represents a principal that is a
	// ServiceAccount.
	PrincipalTypeServiceAccount PrincipalType = "SERVICE_ACCOUNT"
	// PrincipalTypeUser represents a principal that is a User.
	PrincipalTypeUser PrincipalType = "USER"
)

type PrincipalsService added in v2.3.0

type PrincipalsService interface {
	// WhoAmI returns a reference to the current authenticated principal.
	WhoAmI(context.Context) (PrincipalReference, error)
}

PrincipalsService is a generalized interface for retrieving information about a User or Service account when it is not known which of the two one is dealing with. It's decoupled from underlying technology choices (e.g. data store) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewPrincipalsService added in v2.3.0

func NewPrincipalsService(authorizeFn AuthorizeFn) PrincipalsService

NewUsersService returns a generalized interface for retrieving principal information.

type Project

type Project struct {
	// ObjectMeta contains Project metadata.
	meta.ObjectMeta `json:"metadata" bson:",inline"`
	// Description is a natural language description of the Project.
	Description string `json:"description,omitempty" bson:"description,omitempty"`
	// Spec is an instance of a ProjectSpec that pairs EventSubscriptions with
	// a WorkerTemplate.
	Spec ProjectSpec `json:"spec" bson:"spec"`
	// Kubernetes contains Kubernetes-specific details of the Project's
	// environment. These details are populated by Brigade so that sufficiently
	// authorized Kubernetes users may obtain the information needed to directly
	// modify a Project's environment to facilitate certain advanced use cases.
	Kubernetes *KubernetesDetails `json:"kubernetes,omitempty" bson:"kubernetes,omitempty"` // nolint: lll
}

Project is Brigade's fundamental configuration, management, and isolation construct.

  • Configuration: Users define Projects to pair EventSubscriptions with template WorkerSpecs.
  • Management: Project administrators govern Project access by granting and revoking project-level Roles to/from principals (such as Users or ServiceAccounts)
  • Isolation: All workloads (Workers and Jobs) spawned to handle a given Project's Events are isolated from other Projects' workloads in the underlying workload execution substrate.

func (Project) MarshalJSON

func (p Project) MarshalJSON() ([]byte, error)

MarshalJSON amends Project instances with type metadata.

type ProjectAuthorizeFn

type ProjectAuthorizeFn func(
	ctx context.Context,
	projectID string,
	role Role,
) error

ProjectAuthorizeFn is the signature for any function that can, presumably, retrieve a principal from the provided Context and make an access control decision based on the principal having (or not having) the specified Role for the specified Project. Implementations MUST return a *meta.ErrAuthorization error if the principal is not authorized.

type ProjectAuthorizer

type ProjectAuthorizer interface {
	// Authorize retrieves a principal from the provided Context and asserts that
	// it has the specified Role for the specified Project. If it does not,
	// implementations MUST return a *meta.ErrAuthorization error.
	Authorize(ctx context.Context, projectID string, role Role) error
}

ProjectAuthorizer is the public interface for the component returned by the NewProjectAuthorizer function.

func NewProjectAuthorizer

func NewProjectAuthorizer(
	projectRoleAssignmentsStore ProjectRoleAssignmentsStore,
) ProjectAuthorizer

NewProjectAuthorizer returns a component that can authorize a request.

type ProjectRoleAssignment

type ProjectRoleAssignment struct {
	// ProjectID qualifies the scope of the Role.
	ProjectID string `json:"projectID" bson:"projectID,omitempty"`
	// Role assigns a Role to the specified principal.
	Role Role `json:"role" bson:"role"`
	// Principal specifies the principal to whom the Role is assigned.
	Principal PrincipalReference `json:"principal" bson:"principal"`
}

ProjectRoleAssignment represents the assignment of a project-level Role to a principal such as a User or ServiceAccount.

func (ProjectRoleAssignment) MarshalJSON

func (p ProjectRoleAssignment) MarshalJSON() ([]byte, error)

MarshalJSON amends ProjectRoleAssignment instances with type metadata.

func (ProjectRoleAssignment) Matches

func (p ProjectRoleAssignment) Matches(
	projectID string,
	role Role,
) bool

Matches determines if this ProjectRoleAssignment matches the projectID and role arguments.

type ProjectRoleAssignmentsSelector

type ProjectRoleAssignmentsSelector struct {
	// Principal specifies that only ProjectRoleAssignments for the specified
	// principal should be selected.
	Principal *PrincipalReference
	// ProjectID specifies that only ProjectRoleAssignments for the specified
	// Project should be selected.
	ProjectID string
	// Role specifies that only ProjectRoleAssignments for the specified
	// Role should be selected.
	Role Role
}

ProjectRoleAssignmentsSelector represents useful filter criteria when selecting multiple ProjectRoleAssignments for API group operations like list.

type ProjectRoleAssignmentsService

type ProjectRoleAssignmentsService interface {
	// Grant grants the project-level Role specified by the ProjectRoleAssignment
	// to the principal also specified by the ProjectRoleAssignment. If the
	// specified Project or principal does not exist, implementations must return
	// a *meta.ErrNotFound error.
	Grant(context.Context, ProjectRoleAssignment) error

	// List returns a ProjectRoleAssignmentList, with its Items
	// (ProjectRoleAssignments) ordered by projectID, principal type, principalID,
	// and role. Criteria for which ProjectRoleAssignments should be retrieved can
	// be specified using the ProjectRoleAssignmentsSelector parameter.
	List(
		context.Context,
		ProjectRoleAssignmentsSelector,
		meta.ListOptions,
	) (meta.List[ProjectRoleAssignment], error)

	// Revoke revokes the project-level Role specified by the
	// ProjectRoleAssignment for the principal also specified by the
	// ProjectRoleAssignment. If the specified principal does not exist,
	// implementations must return a *meta.ErrNotFound error.
	Revoke(context.Context, ProjectRoleAssignment) error
}

ProjectRoleAssignmentsService is the specialized interface for managing ProjectRoleAssignments. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewProjectRoleAssignmentsService

func NewProjectRoleAssignmentsService(
	authorize AuthorizeFn,
	projectAuthorize ProjectAuthorizeFn,
	projectsStore ProjectsStore,
	usersStore UsersStore,
	serviceAccountsStore ServiceAccountsStore,
	projectRoleAssignmentsStore ProjectRoleAssignmentsStore,
) ProjectRoleAssignmentsService

NewProjectRoleAssignmentsService returns a specialized interface for managing project-level RoleAssignments.

type ProjectRoleAssignmentsStore

type ProjectRoleAssignmentsStore interface {
	// Grant the project-level Role specified by the ProjectRoleAssignment to the
	// principal specified by the ProjectRoleAssignment.
	Grant(context.Context, ProjectRoleAssignment) error
	// List returns a ProjectRoleAssignmentsList, with its Items
	// (ProjectRoleAssignments) ordered by projectID, principal type, principalID,
	// and role. Criteria for which RoleAssignments should be retrieved can be
	// specified using the RoleAssignmentsSelector parameter.
	List(
		context.Context,
		ProjectRoleAssignmentsSelector,
		meta.ListOptions,
	) (meta.List[ProjectRoleAssignment], error)
	// Revoke the Project specified by the ProjectRoleAssignment for the principal
	// specified by the ProjectRoleAssignment.
	Revoke(context.Context, ProjectRoleAssignment) error
	// RevokeByProjectID revokes all ProjectRoleAssignments for the specified
	// Project.
	RevokeByProjectID(ctx context.Context, projectID string) error
	// RevokeByPrincipal revokes all project roles for the principal specified by
	// the PrincipalReference.
	RevokeByPrincipal(context.Context, PrincipalReference) error
	// Exists returns a bool indicating whether the specified
	// ProjectRoleAssignment exists within the store. Implementations MUST also
	// return true if a ProjectRoleAssignment exists in the store that logically
	// "overlaps" the specified ProjectRoleAssignment. For instance, when seeking
	// to determine whether a ProjectRoleAssignment exists that endows some
	// principal P with Role X for Project Y, and such a ProjectRoleAssignment
	// does not exist, but one does that endows that principal P with Role X
	// having GLOBAL PROJECT SCOPE (*), then true MUST be returned.
	// Implementations MUST also return an error if and only if anything goes
	// wrong. i.e. Errors are never used to communicate that the specified
	// ProjectRoleAssignment does not exist in the store. They are only used to
	// convey an actual failure.
	Exists(context.Context, ProjectRoleAssignment) (bool, error)
}

ProjectRoleAssignmentsStore is an interface for components that implement ProjectRoleAssignment persistence concerns.

type ProjectSpec

type ProjectSpec struct {
	// EventSubscription defines a set of trigger conditions under which a new
	// Worker should be created.
	EventSubscriptions []EventSubscription `json:"eventSubscriptions,omitempty" bson:"eventSubscriptions,omitempty"` // nolint: lll
	// WorkerTemplate is a prototypical WorkerSpec.
	WorkerTemplate WorkerSpec `json:"workerTemplate" bson:"workerTemplate"`
}

ProjectSpec is the technical component of a Project. It pairs EventSubscriptions with a prototypical WorkerSpec that is used as a template for creating new Workers.

type ProjectUpdateOptions added in v2.3.0

type ProjectUpdateOptions struct {
	// CreateIfNotFound when set to true will cause a non-existing Project to be
	// created instead of updated.
	CreateIfNotFound bool
}

ProjectUpdateOptions represents useful, optional settings for updating a Project. It currently has no fields, but exists to preserve the possibility of future expansion without having to change client function signatures.

type ProjectsService

type ProjectsService interface {
	// Create creates a new Project. If a Project with the specified identifier
	// already exists, implementations MUST return a *meta.ErrConflict error.
	// Implementations may assume the Project passed to this function has been
	// pre-validated.
	Create(context.Context, Project) (Project, error)
	// List returns a ProjectList, with its Items (Projects) ordered
	// alphabetically by Project ID.
	List(context.Context, meta.ListOptions) (meta.List[Project], error)
	// Get retrieves a single Project specified by its identifier. If the
	// specified Project does not exist, implementations MUST return a
	// *meta.ErrNotFound error.
	Get(context.Context, string) (Project, error)
	// Update updates an existing Project. If the specified Project does not
	// exist, implementations MUST return a *meta.ErrNotFound error.
	// Implementations may assume the Project passed to this function has been
	// pre-validated.
	Update(context.Context, Project, ProjectUpdateOptions) error
	// Delete deletes a single Project specified by its identifier. If the
	// specified Project does not exist, implementations MUST return a
	// *meta.ErrNotFound error.
	Delete(context.Context, string) error
}

ProjectsService is the specialized interface for managing Projects. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewProjectsService

func NewProjectsService(
	authorizeFn AuthorizeFn,
	projectAuthorize ProjectAuthorizeFn,
	projectsStore ProjectsStore,
	eventsStore EventsStore,
	logsStore CoolLogsStore,
	projectRoleAssignmentsStore ProjectRoleAssignmentsStore,
	substrate Substrate,
) ProjectsService

NewProjectsService returns a specialized interface for managing Projects.

type ProjectsStore

type ProjectsStore interface {
	// Create stores the provided Project. Implementations MUST return a
	// *meta.ErrConflict error if a Project having the indicated identifier
	// already exists.
	Create(context.Context, Project) error
	// List returns a ProjectList, with its Items (Projects) ordered
	// alphabetically by Project ID.
	List(
		context.Context,
		meta.ListOptions,
	) (meta.List[Project], error)
	ListSubscribers(
		ctx context.Context,
		event Event,
	) (meta.List[Project], error)
	// Get returns a Project having the indicated ID. If no such Project exists,
	// implementations MUST return a *meta.ErrNotFound error.
	Get(context.Context, string) (Project, error)
	// Update updates the provided Project in storage, presuming that Project
	// already exists in storage. If no Project having the indicated ID already
	// exists, implementations MUST return a *meta.ErrNotFound error.
	// Implementations MUST apply updates ONLY to the Description and Spec fields,
	// as only these fields are intended to be mutable. Implementations MUST
	// ignore changes to all other fields when updating.
	Update(context.Context, Project) error
	// Delete deletes the specified Project. If no Project having the given
	// identifier is found, implementations MUST return a *meta.ErrNotFound error.
	Delete(context.Context, string) error
}

ProjectsStore is an interface for components that implement Project persistence concerns.

type Qualifiers

type Qualifiers map[string]string

func (Qualifiers) MarshalBSONValue

func (q Qualifiers) MarshalBSONValue() (bsontype.Type, []byte, error)

type Role

type Role string

Role is a type whose value maps to a well-defined Brigade Role.

const (
	// RoleProjectAdmin represents a project-level Role that enables a principal
	// to manage a Project.
	RoleProjectAdmin Role = "PROJECT_ADMIN"

	// RoleProjectDeveloper represents a project-level Role that enables a
	// principal to update a Project.
	RoleProjectDeveloper Role = "PROJECT_DEVELOPER"

	// RoleProjectUser represents a project-level Role that enables a principal to
	// create and manage Events for a Project.
	RoleProjectUser Role = "PROJECT_USER"
)
const (
	// RoleAdmin represents a system-level Role that enables principals to manage
	// Users, ServiceAccounts, and system-level permissions for Users and
	// ServiceAccounts.
	RoleAdmin Role = "ADMIN"

	// RoleEventCreator represents a system-level Role that enables principals to
	// create Events for all Projects.
	RoleEventCreator Role = "EVENT_CREATOR"

	// RoleProjectCreator represents a system-level Role that enables principals
	// to create new Projects.
	RoleProjectCreator Role = "PROJECT_CREATOR"

	// RoleReader represents a system-level Role that enables global read access.
	RoleReader Role = "READER"
)
const (

	// RoleObserver represents a system-level Role that enables principals to
	// update Worker and Job status based on observation of the underlying
	// workload execution substrate. This Role exists exclusively for use by
	// Brigade's Observer component.
	RoleObserver Role = "OBSERVER"

	// RoleScheduler represents a system-level Role that enables principals to
	// initiate execution of a Worker or Job on the underlying workload execution
	// substrate. This Role exists exclusively for use by Brigade's Scheduler
	// component.
	RoleScheduler Role = "SCHEDULER"

	// RoleWorker represents an event-level Role that enables principals to create
	// new Jobs, monitor the status of those Jobs, and access their logs. This
	// Role is exclusively for the use of Brigade Workers.
	RoleWorker Role = "WORKER"
)

type RoleAssignment

type RoleAssignment struct {
	// Role assigns a Role to the specified principal.
	Role Role `json:"role" bson:"role"`
	// Principal specifies the principal to whom the Role is assigned.
	Principal PrincipalReference `json:"principal" bson:"principal"`
	// Scope qualifies the scope of the Role. The value is opaque and has meaning
	// only in relation to a specific Role.
	Scope string `json:"scope,omitempty" bson:"scope,omitempty"`
}

RoleAssignment represents the assignment of a Role to a principal such as a User or ServiceAccount.

func (RoleAssignment) MarshalJSON

func (r RoleAssignment) MarshalJSON() ([]byte, error)

MarshalJSON amends RoleAssignment instances with type metadata.

func (RoleAssignment) Matches

func (r RoleAssignment) Matches(role Role, scope string) bool

Matches determines if this RoleAssignment matches the role and scope arguments.

type RoleAssignmentsSelector

type RoleAssignmentsSelector struct {
	// Principal specifies that only RoleAssignments for the specified principal
	// should be selected.
	Principal *PrincipalReference
	// Role specifies that only RoleAssignments for the specified Role should be
	// selected.
	Role Role
}

RoleAssignmentsSelector represents useful filter criteria when selecting multiple RoleAssignments for API group operations like list.

type RoleAssignmentsService

type RoleAssignmentsService interface {
	// Grant grants the Role specified by the RoleAssignment to the principal also
	// specified by the RoleAssignment. If the specified principal does not exist,
	// implementations must return a *meta.ErrNotFound error.
	Grant(ctx context.Context, roleAssignment RoleAssignment) error

	// List returns a RoleAssignmentsList, with its Items (RoleAssignments)
	// ordered by principal type, principalID, role, and scope. Criteria for which
	// RoleAssignments should be retrieved can be specified using the
	// RoleAssignmentsSelector parameter.
	List(
		context.Context,
		RoleAssignmentsSelector,
		meta.ListOptions,
	) (meta.List[RoleAssignment], error)

	// Revoke revokes the Role specified by the RoleAssignment for the principal
	// also specified by the RoleAssignment. If the specified principal does not
	// exist, implementations must return a *meta.ErrNotFound error.
	Revoke(ctx context.Context, roleAssignment RoleAssignment) error
}

RoleAssignmentsService is the specialized interface for managing RoleAssignments. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewRoleAssignmentsService

func NewRoleAssignmentsService(
	authorizeFn AuthorizeFn,
	usersStore UsersStore,
	serviceAccountsStore ServiceAccountsStore,
	roleAssignmentsStore RoleAssignmentsStore,
) RoleAssignmentsService

NewRoleAssignmentsService returns a specialized interface for managing RoleAssignments.

type RoleAssignmentsStore

type RoleAssignmentsStore interface {
	// Grant the role specified by the RoleAssignment to the principal specified
	// by the RoleAssignment.
	Grant(context.Context, RoleAssignment) error
	// List returns a RoleAssignmentsList, with its Items (system-level
	// RoleAssignments) ordered by principal type, principalID, role name, and
	// scope. Criteria for which RoleAssignments should be retrieved can be
	// specified using the RoleAssignmentsSelector parameter.
	List(
		context.Context,
		RoleAssignmentsSelector,
		meta.ListOptions,
	) (meta.List[RoleAssignment], error)
	// Revoke the role specified by the RoleAssignment for the principal specified
	// by the RoleAssignment.
	Revoke(context.Context, RoleAssignment) error
	// RevokeByPrincipal revokes all roles for the principal specified by the
	// PrincipalReference.
	RevokeByPrincipal(context.Context, PrincipalReference) error
	// Exists returns a bool indicating whether the specified RoleAssignment
	// exists within the store. Implementations MUST also return true if a
	// RoleAssignment exists in the store that logically "overlaps" the specified
	// RoleAssignment. For instance, when seeking to determine whether a
	// RoleAssignment exists that endows some principal P with Role X having scope
	// Y, and such a RoleAssignment does not exist, but one does that endows that
	// principal P with Role X having GLOBAL SCOPE (*), then true MUST be
	// returned. Implementations MUST also return an error if and only if anything
	// goes wrong. i.e. Errors are never used to communicate that the specified
	// RoleAssignment does not exist in the store. They are only used to convey an
	// actual failure.
	Exists(context.Context, RoleAssignment) (bool, error)
}

RoleAssignmentsStore is an interface for components that implement RoleAssignment persistence concerns.

type RootPrincipal added in v2.3.0

type RootPrincipal struct{}

RootPrincipal is an implementation of the Principal interface for the "root" user.

func (*RootPrincipal) ProjectRoleAssignments added in v2.3.0

func (r *RootPrincipal) ProjectRoleAssignments() []ProjectRoleAssignment

func (*RootPrincipal) RoleAssignments added in v2.3.0

func (r *RootPrincipal) RoleAssignments() []RoleAssignment

type SchedulerPrincipal added in v2.3.0

type SchedulerPrincipal struct{}

SchedulerPrincipal is an implementation of the Principal interface that represents the scheduler component, which is a special class of user because, although it cannot do much, it has the UNIQUE ability to launch Workers and Jobs.

func (*SchedulerPrincipal) RoleAssignments added in v2.3.0

func (s *SchedulerPrincipal) RoleAssignments() []RoleAssignment

type Secret

type Secret struct {
	// Key is a key by which the secret can referred.
	Key string `json:"key,omitempty"`
	// Value is the sensitive information. This is a write-only field.
	Value string `json:"value,omitempty"`
}

Secret represents Project-level sensitive information.

func (Secret) MarshalJSON

func (s Secret) MarshalJSON() ([]byte, error)

MarshalJSON amends Secret instances with type metadata.

type SecretsService

type SecretsService interface {
	// List returns a SecretList whose Items (Secrets) contain Keys only and
	// not Values (all Value fields are empty). i.e. Once a secret is set, end
	// clients are unable to retrieve values.
	List(
		ctx context.Context,
		projectID string,
		opts meta.ListOptions,
	) (meta.List[Secret], error)
	// Set sets the value of a new Secret or updates the value of an existing
	// Secret. If the specified Project does not exist, implementations MUST
	// return a *meta.ErrNotFound error. If the specified Key does not exist, it
	// is created. If the specified Key does exist, its corresponding Value is
	// overwritten.
	Set(
		ctx context.Context,
		projectID string,
		secret Secret,
	) error
	// Unset clears the value of an existing Secret. If the specified Project does
	// not exist, implementations MUST return a *meta.ErrNotFound error. If the
	// specified Key does not exist, no error is returned.
	Unset(ctx context.Context, projectID string, key string) error
}

SecretsService is the specialized interface for managing Secrets. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewSecretsService

func NewSecretsService(
	authorizeFn AuthorizeFn,
	projectAuthorize ProjectAuthorizeFn,
	projectsStore ProjectsStore,
	secretsStore SecretsStore,
) SecretsService

NewSecretsService returns a specialized interface for managing Secrets.

type SecretsStore

type SecretsStore interface {
	// List returns a SecretList, with its Items (Secrets) ordered lexically by
	// Key.
	List(ctx context.Context,
		project Project,
		opts meta.ListOptions,
	) (meta.List[Secret], error)
	// Set adds or updates the provided Secret associated with the specified
	// Project.
	Set(ctx context.Context, project Project, secret Secret) error
	// Unset clears (deletes) the Secret (identified by its Key) associated with
	// the specified Project.
	Unset(ctx context.Context, project Project, key string) error
}

SecretsStore is an interface for components that implement Secret persistence concerns.

type ServiceAccount

type ServiceAccount struct {
	// ObjectMeta encapsulates ServiceAccount metadata.
	meta.ObjectMeta `json:"metadata" bson:",inline"`
	// Description is a natural language description of the ServiceAccount's
	// purpose.
	Description string `json:"description" bson:"description"`
	// HashedToken is a secure, one-way hash of the ServiceAccount's token.
	HashedToken string `json:"-" bson:"hashedToken"`
	// Locked indicates when the ServiceAccount has been locked out of the system
	// by an administrator. If this field's value is nil, the ServiceAccount is
	// not locked.
	Locked *time.Time `json:"locked,omitempty" bson:"locked"`
}

ServiceAccount represents a non-human Brigade user, such as an Event gateway.

func (ServiceAccount) MarshalJSON

func (s ServiceAccount) MarshalJSON() ([]byte, error)

MarshalJSON amends ServiceAccount instances with type metadata.

type ServiceAccountsService

type ServiceAccountsService interface {
	// Create creates a new ServiceAccount. If a ServiceAccount having the same ID
	// already exists, implementations MUST return a *meta.ErrConflict error.
	Create(context.Context, ServiceAccount) (Token, error)
	// List retrieves a ServiceAccountList.
	List(context.Context, meta.ListOptions) (meta.List[ServiceAccount], error)
	// Get retrieves a single ServiceAccount specified by its identifier. If the
	// specified ServiceAccount does not exist, implementations MUST return a
	// *meta.ErrNotFound error.
	Get(context.Context, string) (ServiceAccount, error)
	// GetByToken retrieves a single ServiceAccount specified by token. If no
	// such ServiceAccount exists, implementations MUST return a *meta.ErrNotFound
	// error.
	GetByToken(context.Context, string) (ServiceAccount, error)

	// Lock revokes system access for a single ServiceAccount specified by its
	// identifier. If the specified ServiceAccount does not exist, implementations
	// MUST return a *meta.ErrNotFound error.
	Lock(context.Context, string) error
	// Unlock restores system access for a single ServiceAccount (after presumably
	// having been revoked) specified by its identifier. It returns a new Token.
	// If the specified ServiceAccount does not exist, implementations MUST return
	// a *meta.ErrNotFound error.
	Unlock(context.Context, string) (Token, error)

	// Delete removes a single ServiceAccount specified by its identifier.
	Delete(context.Context, string) error
}

ServiceAccountsService is the specialized interface for managing ServiceAccounts. It's decoupled from underlying technology choices (e.g. data store) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewServiceAccountsService

func NewServiceAccountsService(
	authorizeFn AuthorizeFn,
	store ServiceAccountsStore,
	roleAssignmentsStore RoleAssignmentsStore,
	projectRoleAssignmentsStore ProjectRoleAssignmentsStore,
) ServiceAccountsService

NewServiceAccountsService returns a specialized interface for managing ServiceAccounts.

type ServiceAccountsStore

type ServiceAccountsStore interface {
	// Create persists a new ServiceAccount in the underlying data store. If a
	// ServiceAccount having the same ID already exists, implementations MUST
	// return a *meta.ErrConflict error.
	Create(context.Context, ServiceAccount) error
	// List retrieves a ServiceAccountList from the underlying data store, with
	// its Items (ServiceAccounts) ordered by ID.
	List(context.Context, meta.ListOptions) (meta.List[ServiceAccount], error)
	// Get retrieves a single ServiceAccount from the underlying data store. If
	// the specified ServiceAccount does not exist, implementations MUST return
	// a *meta.ErrNotFound error.
	Get(context.Context, string) (ServiceAccount, error)
	// GetByHashedToken retrieves a single ServiceAccount having the provided
	// hashed token from the underlying data store. If no such ServiceAccount
	// exists, implementations MUST return a *meta.ErrNotFound error.
	GetByHashedToken(context.Context, string) (ServiceAccount, error)

	// Lock updates the specified ServiceAccount in the underlying data store to
	// reflect that it has been locked out of the system. If the specified
	// ServiceAccount does not exist, implementations MUST return a
	// *meta.ErrNotFound error.
	Lock(context.Context, string) error
	// Unlock updates the specified ServiceAccount in the underlying data store to
	// reflect that it's system access (after presumably having been revoked) has
	// been restored. A hashed token must be provided as a replacement for the
	// existing token. If the specified ServiceAccount does not exist,
	// implementations MUST return a *meta.ErrNotFound error.
	Unlock(ctx context.Context, id string, newHashedToken string) error

	// Delete deletes the specified ServiceAccount. If no ServiceAccount having
	// the given identifier is found, implementations MUST return a
	// *meta.ErrNotFound error.
	Delete(context.Context, string) error
}

ServiceAccountsStore is an interface for components that implement ServiceAccount persistence concerns.

type Session

type Session struct {
	// ObjectMeta encapsulates Session metadata.
	meta.ObjectMeta `json:"metadata" bson:",inline"`
	// Root indicates whether the Session belongs to the root user (true) or a
	// some discrete User.
	Root bool `json:"root" bson:"root"`
	// UserID, if set, identifies the discrete User to whom this Session belongs.
	UserID string `json:"userID" bson:"userID"`
	// HashedOAuth2State, if set, is a secure hash of the OAuth 2 "state" code
	// used in completing authentication via a third-party identity provider.
	HashedOAuth2State string `json:"-" bson:"hashedOAuth2State"`
	// HashedToken is a secure hash of the opaque bearer token associated with
	// this Session.
	HashedToken string `json:"-" bson:"hashedToken"`
	// Authenticated indicates the date/time at which authentication was completed
	// successfully. If the value of this field is nil, the Session is NOT
	// authenticated.
	Authenticated *time.Time `json:"authenticated" bson:"authenticated"`
	// Expires, if set, specified an expiry date/time for the Session and its
	// associated token.
	Expires *time.Time `json:"expires" bson:"expires"`
	// AuthSuccessURL indicates a URL to redirect the User to after successful
	// completion of a third-party authentication workflow. If not specified, a
	// default URL is used.
	AuthSuccessURL string `json:"authSuccessURL" bson:"authSuccessURL"`
}

Session encapsulates details of a session belonging either to the root user or a discrete User that has authenticated (or is in the process of authenticating) via OpenID Connect or GitHub.

type SessionsService

type SessionsService interface {
	// CreateRootSession creates a Session for the root user (if enabled by the
	// system administrator) and returns a Token with a short expiry period
	// (determined by a system administrator). If authentication as the root user
	// is not enabled, implementations MUST return a *meta.ErrNotSupported error.
	// If the specified username is not "root" or the specified password is
	// incorrect, implementations MUST return a *meta.ErrAuthentication error.
	CreateRootSession(
		ctx context.Context,
		username string,
		password string,
	) (Token, error)
	// CreateUserSession creates a new User Session and initiates a third-party
	// authentication workflow (if enabled by the system administrator). It
	// returns ThirdPartyAuthDetails containing all information required to
	// continue the authentication process with the third-party identity provider.
	// If authentication using a third-party is not enabled, implementations MUST
	// return a *meta.ErrNotSupported error.
	CreateUserSession(
		context.Context,
		*ThirdPartyAuthOptions,
	) (ThirdPartyAuthDetails, error)
	// Authenticate completes the final steps of the third-party authentication
	// workflow (if enabled by the system administrator) and returns a URL to
	// which the user may be redirected. It uses the provided state to identify an
	// as-yet anonymous Session (with an as-yet unactivated token). It
	// communicates with the third-party identity provider, exchanging the
	// provided code for user information. This information can be used to
	// correlate the as-yet anonymous Session to an existing User. If the User is
	// previously unknown to Brigade, implementations MUST seamlessly create one
	// (with no initial permissions) based on information provided by the identity
	// provider. Finally, the Session's token is activated. If authentication
	// using a third-party is not enabled, implementations MUST return a
	// *meta.ErrNotSupported error.
	Authenticate(ctx context.Context, state string, code string) (string, error)
	// GetByToken retrieves the Session having the provided token. If no such
	// Session is found or is found but is expired, implementations MUST return a
	// *meta.ErrAuthentication error.
	GetByToken(ctx context.Context, token string) (Session, error)
	// Delete deletes the specified Session.
	Delete(ctx context.Context, id string) error
}

SessionsService is the specialized interface for managing Sessions. It's decoupled from underlying technology choices (e.g. data store) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewSessionsService

func NewSessionsService(
	sessionsStore SessionsStore,
	usersStore UsersStore,
	roleAssignmentsStore RoleAssignmentsStore,
	thirdPartyAuthHelper ThirdPartyAuthHelper,
	config *SessionsServiceConfig,
) SessionsService

NewSessionsService returns a specialized interface for managing Sessions.

type SessionsServiceConfig

type SessionsServiceConfig struct {
	// RootUserEnabled indicates whether the Session service should permit the
	// "root" user to authenticate using a password.
	RootUserEnabled bool
	// RootUserSessionTTL specifies the TTL for the root user session. This value
	// will be used to set the Expires field on the Session record for the root
	// user.
	RootUserSessionTTL time.Duration
	// RootUserPassword specifies the password that must be supplied by users
	// attempting to authenticate as the "root" user. This field is applicable
	// only when value of the RootUserEnabled field is true.
	RootUserPassword string
	// ThirdPartyAuthEnabled indicates whether authentication using a third-party
	// identity provider is supported by the Sessions service.
	ThirdPartyAuthEnabled bool
	// UserSessionTTL specifies the TTL for user sessions. This value will be
	// used to set the Expires field on the Session record for each user.
	UserSessionTTL time.Duration
	// AdminUserIDs enumerates users who should be granted system admin privileges
	// the first time they log in.
	AdminUserIDs []string
	// GrantReadOnInitialLogin indicates whether all users should automatically
	// be granted read-only permissions the first time they log in.
	GrantReadOnInitialLogin bool
}

SessionsServiceConfig encapsulates several configuration options for the Sessions service.

type SessionsStore

type SessionsStore interface {
	// Create stores the provided Session. Implementations MUST return an error if
	// a Session having the indicated identifier already exists.
	Create(context.Context, Session) error
	// GetByHashedOAuth2State returns a Session having the indicated secure hash
	// of the OAuth 2 "state" code. This is used in completing both OpenID Connect
	// and GitHub authentication workflows. If no such Session exists,
	// implementations MUST return a *meta.ErrNotFound error.
	GetByHashedOAuth2State(context.Context, string) (Session, error)
	// GetByHashedToken returns a Session having the indicated secure hash of the
	// opaque bearer token. If no such Session exists, implementations MUST
	// return a *meta.ErrNotFound error.
	GetByHashedToken(context.Context, string) (Session, error)
	// Authenticate updates the specified, as-yet-anonymous Session (with an
	// as-yet unactivated token) to denote ownership by the indicated User and to
	// assign the specified expiry date/time. This is used in completing
	// third-party authentication workflows.
	Authenticate(
		ctx context.Context,
		sessionID string,
		userID string,
		expires time.Time,
	) error
	// Delete deletes the specified Session. If no Session having the given
	// identifier is found, implementations MUST return a *meta.ErrNotFound error.
	Delete(context.Context, string) error
	// DeleteByUser deletes all sessions belonging to the specified User.
	DeleteByUser(ctx context.Context, userID string) error
}

SessionsStore is an interface for Session persistence operations.

type SourceState

type SourceState struct {
	// State is a map of arbitrary and opaque key/value pairs that the source of
	// an Event (e.g. the gateway that created it) can use to store
	// source-specific state.
	State map[string]string `json:"state,omitempty" bson:"state,omitempty"`
}

SourceState encapsulates opaque, source-specific (e.g. gateway-specific) state.

type Substrate

type Substrate interface {
	// CountRunningWorkers returns a count of Workers currently executing on the
	// substrate.
	CountRunningWorkers(context.Context) (SubstrateWorkerCount, error)
	// CountRunningJobs returns a count of Jobs currently executing on the
	// substrate.
	CountRunningJobs(context.Context) (SubstrateJobCount, error)

	// CreateProject prepares the substrate to host Project workloads. The
	// provided Project argument may be amended with substrate-specific details
	// and returned, so this function should be called prior to a Project being
	// initially persisted so that substrate-specific details will be included.
	CreateProject(context.Context, Project) (Project, error)
	// DeleteProject removes all Project-related resources from the substrate.
	DeleteProject(context.Context, Project) error

	// ScheduleWorker prepares the substrate for the Event's worker and schedules
	// the Worker for async / eventual execution.
	ScheduleWorker(context.Context, Event) error
	// StartWorker starts an Event's Worker on the substrate.
	StartWorker(
		ctx context.Context,
		project Project,
		event Event,
		token string,
	) error

	// StoreJobEnvironment securely stores Job environment variables where they
	// are accessible to other substrate operations. This obviates the need to
	// store these potential secrets in the database.
	StoreJobEnvironment(
		ctx context.Context,
		project Project,
		eventID string,
		jobName string,
		jobSpec JobSpec,
	) error
	// ScheduleJob prepares the substrate for a Job and schedules the Job for
	// async / eventual execution.
	ScheduleJob(
		ctx context.Context,
		project Project,
		event Event,
		jobName string,
	) error
	// StartJob starts a Job on the substrate.
	StartJob(
		ctx context.Context,
		project Project,
		event Event,
		jobName string,
	) error

	// DeleteJob deletes all substrate resources pertaining to the specified Job.
	DeleteJob(
		ctx context.Context,
		project Project,
		event Event,
		jobName string,
	) error

	// DeleteWorkerAndJobs deletes all substrate resources pertaining to the
	// specified Event's Worker and Jobs.
	DeleteWorkerAndJobs(context.Context, Project, Event) error
}

Substrate is an interface for components that permit services to coordinate with Brigade's underlying workload execution substrate, i.e. Kubernetes.

type SubstrateJobCount

type SubstrateJobCount struct {
	// Count is the cardinality of Jobs currently executing on the substrate.
	Count int `json:"count"`
}

SubstrateJobCount represents a count of Workers currently executing on the substrate.

func (SubstrateJobCount) MarshalJSON

func (s SubstrateJobCount) MarshalJSON() ([]byte, error)

MarshalJSON amends SubstrateJobCount instances with type metadata.

type SubstrateService

type SubstrateService interface {
	// CountRunningWorkers returns a count of Workers currently executing on the
	// substrate.
	CountRunningWorkers(context.Context) (SubstrateWorkerCount, error)
	// CountRunningJobs returns a count of Jobs currently executing on the
	// substrate.
	CountRunningJobs(context.Context) (SubstrateJobCount, error)
}

SubstrateService is the specialized interface for monitoring the state of the substrate.

func NewSubstrateService

func NewSubstrateService(
	authorizeFn AuthorizeFn,
	substrate Substrate,
) SubstrateService

NewSubstrateService returns a specialized interface for managing Projects.

type SubstrateWorkerCount

type SubstrateWorkerCount struct {
	// Count is the cardinality of Workers currently executing on the substrate.
	Count int `json:"count"`
}

SubstrateWorkerCount represents a count of Workers currently executing on the substrate.

func (SubstrateWorkerCount) MarshalJSON

func (s SubstrateWorkerCount) MarshalJSON() ([]byte, error)

MarshalJSON amends SubstrateWorkerCount instances with type metadata.

type ThirdPartyAuthDetails

type ThirdPartyAuthDetails struct {
	// AuthURL is a URL that can be requested in a user's web browser to complete
	// authentication via a third-party identity provider.
	AuthURL string `json:"authURL"`
	// Token is an opaque bearer token issued by Brigade to correlate a User with
	// a Session. It remains unactivated (useless) until the authentication
	// workflow is successfully completed. Clients may expect that that the token
	// expires (at an interval determined by a system administrator) and, for
	// simplicity, is NOT refreshable. When the token has expired,
	// re-authentication is required.
	Token string `json:"token"`
}

ThirdPartyAuthDetails encapsulates all information required for a client authenticating by means of a third-party identity provider to complete the authentication workflow.

func (ThirdPartyAuthDetails) MarshalJSON

func (t ThirdPartyAuthDetails) MarshalJSON() ([]byte, error)

MarshalJSON amends ThirdPartyAuthDetails instances with type metadata.

type ThirdPartyAuthHelper

type ThirdPartyAuthHelper interface {
	// AuthURL returns a URL to which a User may be redirected for purposes of
	// completing authentication using a third-party identity provider.
	AuthURL(oauth2State string) string
	// Exchange exchanges a code issued by a third-party identity provider for
	// User identity information.
	Exchange(
		ctx context.Context,
		oauth2State string,
		oauth2Code string,
	) (ThirdPartyIdentity, error)
}

ThirdPartyAuthHelper is an interface for components that implement pluggable portions of third party authentication schemes based on OAuth2. OpenID Connect (used by certain identity providers like Azure Active Directory or Google Cloud Identity Platform) is built on top of OAuth2 (strictly speaking OAuth2 is for authorization; not authentication, but OpenID Connect extends OAuth2 with an authentication standard), but other authentication schemes (like GitHub's) are ALSO based on OAuth2, but DON'T implement OpenID Connect. This interface allows universal parts of authentication based on OAuth2 to be common for all third-party identity providers while utilizing standard-specific or provider-specific functionality for the portions of those authentication schemes that vary.

type ThirdPartyAuthOptions

type ThirdPartyAuthOptions struct {
	// SuccessURL indicates where users should be redirected to after successful
	// completion of a third-party authentication workflow. If this is left
	// unspecified, users will be redirected to a default success page.
	SuccessURL string
}

ThirdPartyAuthOptions encapsulates user-specified options when creating a new Session that will authenticate using a third-party identity provider.

type ThirdPartyAuthStrategy

type ThirdPartyAuthStrategy string

type ThirdPartyIdentity

type ThirdPartyIdentity struct {
	// ID is a handle or email address for the User.
	ID string
	// Name is the User's given name + surname.
	Name string
}

ThirdPartyIdentity encapsulates ID (handle or email address) and name information for a User obtained from a third-party identity provider.

type Token

type Token struct {
	Value string `json:"value" bson:"value"`
}

Token represents an opaque bearer token used to authenticate to the Brigade API.

func (Token) MarshalJSON

func (t Token) MarshalJSON() ([]byte, error)

MarshalJSON amends Token instances with type metadata.

type User

type User struct {
	// ObjectMeta encapsulates User metadata.
	meta.ObjectMeta `json:"metadata" bson:",inline"`
	// Name is the given name and surname of the User.
	Name string `json:"name" bson:"name"`
	// Locked indicates when the User has been locked out of the system by an
	// administrator. If this field's value is nil, the User is not locked.
	Locked *time.Time `json:"locked" bson:"locked"`
}

User represents a (human) Brigade user.

func (User) MarshalJSON

func (u User) MarshalJSON() ([]byte, error)

MarshalJSON amends User instances with type metadata.

type UsersService

type UsersService interface {
	// List returns a UserList.
	List(context.Context, meta.ListOptions) (meta.List[User], error)
	// Get retrieves a single User specified by their identifier.
	Get(context.Context, string) (User, error)

	// Lock removes access to the API for a single User specified by their
	// identifier.
	Lock(context.Context, string) error
	// Unlock restores access to the API for a single User specified by their
	// identifier.
	Unlock(context.Context, string) error

	// Delete removes a single User specified by their identifier.
	Delete(context.Context, string) error
}

UsersService is the specialized interface for managing Users. It's decoupled from underlying technology choices (e.g. data store) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewUsersService

func NewUsersService(
	authorizeFn AuthorizeFn,
	usersStore UsersStore,
	sessionsStore SessionsStore,
	roleAssignmentsStore RoleAssignmentsStore,
	projectRoleAssignmentsStore ProjectRoleAssignmentsStore,
	config UsersServiceConfig,
) UsersService

NewUsersService returns a specialized interface for managing Users.

type UsersServiceConfig

type UsersServiceConfig struct {
	// ThirdPartyAuthEnabled indicates whether authentication using a third-party
	// identity provider is supported by the Sessions service.
	ThirdPartyAuthEnabled bool
}

UsersServiceConfig encapsulates several configuration options for the UsersService.

type UsersStore

type UsersStore interface {
	// Create persists a new User in the underlying data store. If a User having
	// the same ID already exists, implementations MUST return a *meta.ErrConflict
	// error.
	Create(context.Context, User) error
	// List retrieves a UserList from the underlying data store, with its Items
	// (Users) ordered by ID.
	List(context.Context, meta.ListOptions) (meta.List[User], error)
	// Get retrieves a single User from the underlying data store. Implementations
	// MUST use a case insensitive query for this operation. If the specified User
	// does not exist, implementations MUST return a *meta.ErrNotFound error.
	Get(context.Context, string) (User, error)

	// Lock updates the specified User in the underlying data store to reflect
	// that it has been locked out of the system. Implementations MUST use a case
	// insensitive update statement for this operation. If the specified User does
	// not exist, implementations MUST return a *meta.ErrNotFound error.
	Lock(context.Context, string) error
	// Unlock updates the specified User in the underlying data store to reflect
	// that its system access (after presumably having been revoked) has been
	// restored. Implementations MUST use a case insensitive update statement for
	// this operation. If the specified User does not exist, implementations MUST
	// return a *meta.ErrNotFound error.
	Unlock(ctx context.Context, id string) error

	// Delete deletes the specified User. If no User having the given identifier
	// is found, implementations MUST return a *meta.ErrNotFound error.
	Delete(context.Context, string) error
}

UsersStore is an interface for User persistence operations.

type Worker

type Worker struct {
	// Spec is the technical blueprint for the Worker.
	Spec WorkerSpec `json:"spec" bson:"spec"`
	// Status contains details of the Worker's current state.
	Status WorkerStatus `json:"status" bson:"status"`
	// Jobs contains details of all Jobs spawned by the Worker during handling of
	// the Event.
	Jobs []Job `json:"jobs,omitempty" bson:"jobs"`
}

Worker represents a component that orchestrates handling of a single Event.

func (*Worker) Job

func (w *Worker) Job(jobName string) (Job, bool)

Job retrieves a Job by name. It returns a boolean indicating whether the returned Job is the one requested (true) or a zero value (false) because no Job with the specified name belongs to this Worker.

type WorkerPhase

type WorkerPhase string

WorkerPhase represents where a Worker is within its lifecycle.

const (
	// WorkerPhaseAborted represents the state wherein a Worker was forcefully
	// stopped during execution.
	WorkerPhaseAborted WorkerPhase = "ABORTED"
	// WorkerPhaseCanceled represents the state wherein a pending Worker was
	// canceled prior to execution.
	WorkerPhaseCanceled WorkerPhase = "CANCELED"
	// WorkerPhaseFailed represents the state wherein a Worker has run to
	// completion but experienced errors.
	WorkerPhaseFailed WorkerPhase = "FAILED"
	// WorkerPhasePending represents the state wherein a Worker is awaiting
	// execution.
	WorkerPhasePending WorkerPhase = "PENDING"
	// WorkerPhaseRunning represents the state wherein a Worker is currently
	// being executed.
	WorkerPhaseRunning WorkerPhase = "RUNNING"
	// WorkerPhaseSchedulingFailed represents the state wherein a Worker was not
	// scheduled due to some unexpected and unrecoverable error encountered by the
	// scheduler.
	WorkerPhaseSchedulingFailed WorkerPhase = "SCHEDULING_FAILED"
	// WorkerPhaseStarting represents the state wherein a Worker is starting on
	// the substrate but isn't running yet.
	WorkerPhaseStarting WorkerPhase = "STARTING"
	// WorkerPhaseSucceeded represents the state where a Worker has run to
	// completion without error.
	WorkerPhaseSucceeded WorkerPhase = "SUCCEEDED"
	// WorkerPhaseTimedOut represents the state wherein a Worker has has not
	// completed within a designated timeframe.
	WorkerPhaseTimedOut WorkerPhase = "TIMED_OUT"
	// WorkerPhaseUnknown represents the state wherein a Worker's state is
	// unknown. Note that this is possible if and only if the underlying Worker
	// execution substrate (Kubernetes), for some unanticipated, reason does not
	// know the Worker's (Pod's) state.
	WorkerPhaseUnknown WorkerPhase = "UNKNOWN"
)

func WorkerPhasesAll

func WorkerPhasesAll() []WorkerPhase

WorkerPhasesAll returns a slice of WorkerPhases containing ALL possible phases. Note that instead of utilizing a package-level slice, this a function returns ad-hoc copies of the slice in order to preclude the possibility of this important collection being modified at runtime.

func (WorkerPhase) IsTerminal

func (w WorkerPhase) IsTerminal() bool

IsTerminal returns a bool indicating whether the WorkerPhase is terminal.

type WorkerPrincipal added in v2.3.0

type WorkerPrincipal struct {
	// contains filtered or unexported fields
}

WorkerPrincipal is an implementation of the Principal interface that represents an Event's Worker, which is a special class of user because, although it cannot do much, it has the UNIQUE ability to create new Jobs.

func GetWorkerPrincipal added in v2.3.0

func GetWorkerPrincipal(eventID string) *WorkerPrincipal

GetWorkerPrincipal returns an Principal that represents the specified Event's Worker.

func (*WorkerPrincipal) RoleAssignments added in v2.3.0

func (w *WorkerPrincipal) RoleAssignments() []RoleAssignment

type WorkerSpec

type WorkerSpec struct {
	// Container specifies the details of an OCI container that forms the
	// cornerstone of the Worker.
	Container *ContainerSpec `json:"container,omitempty" bson:"container,omitempty"` // nolint: lll
	// UseWorkspace indicates whether the Worker and/or any Jobs it may spawn
	// requires access to a shared workspace. When false, no such workspace is
	// provisioned prior to Worker creation. This is a generally useful feature,
	// but by opting out of it (or rather, not opting-in), Job results can be made
	// cacheable and Jobs resumable/retriable-- something which cannot be done
	// otherwise since managing the state of the shared volume would require a
	// layered file system that we currently do not have.
	UseWorkspace bool `json:"useWorkspace" bson:"useWorkspace"`
	// WorkspaceSize specifies the size of a volume that will be provisioned as
	// a shared workspace for the Worker and any Jobs it spawns.
	// The value can be expressed in bytes (as a plain integer) or as a
	// fixed-point integer using one of these suffixes: E, P, T, G, M, K.
	// Power-of-two equivalents may also be used: Ei, Pi, Ti, Gi, Mi, Ki.
	WorkspaceSize string `json:"workspaceSize,omitempty" bson:"workspaceSize,omitempty"` // nolint: lll
	// Git contains git-specific Worker details.
	Git *GitConfig `json:"git,omitempty"`
	// Kubernetes contains Kubernetes-specific Worker details.
	Kubernetes *KubernetesConfig `json:"kubernetes,omitempty" bson:"kubernetes,omitempty"` // nolint: lll
	// JobPolicies specifies policies for any Jobs spawned by the Worker.
	JobPolicies *JobPolicies `json:"jobPolicies,omitempty" bson:"jobPolicies,omitempty"` // nolint: lll
	// LogLevel specifies the desired granularity of Worker log output.
	LogLevel LogLevel `json:"logLevel,omitempty" bson:"logLevel,omitempty"`
	// ConfigFilesDirectory specifies a directory within the Worker's workspace
	// where any relevant configuration files (e.g. brigade.js, package.json,
	// etc.) can be located.
	ConfigFilesDirectory string `json:"configFilesDirectory,omitempty" bson:"configFilesDirectory,omitempty"` // nolint: lll
	// DefaultConfigFiles is a map of configuration file names to configuration
	// file content. This is useful for Workers that do not integrate with any
	// source control system and would like to embed configuration (e.g.
	// package.json) or scripts (e.g. brigade.js) directly within the WorkerSpec.
	DefaultConfigFiles map[string]string `json:"defaultConfigFiles,omitempty" bson:"defaultConfigFiles,omitempty"` // nolint: lll
	// TimeoutDuration specifies the time duration that must elapse before a
	// running Job should be considered to have timed out. This duration string
	// is a possibly signed sequence of decimal numbers, each with optional
	// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
	// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
	TimeoutDuration string `json:"timeoutDuration,omitempty" bson:"timeoutDuration,omitempty"` // nolint: lll
}

WorkerSpec is the technical blueprint for a Worker.

type WorkerStatus

type WorkerStatus struct {
	// Started indicates the time the Worker began execution. It will be nil for
	// a Worker that is not yet executing.
	Started *time.Time `json:"started,omitempty" bson:"started,omitempty"`
	// Ended indicates the time the Worker concluded execution. It will be nil
	// for a Worker that is not done executing (or hasn't started).
	Ended *time.Time `json:"ended,omitempty" bson:"ended,omitempty"`
	// Phase indicates where the Worker is in its lifecycle.
	Phase WorkerPhase `json:"phase,omitempty" bson:"phase,omitempty"`
}

WorkerStatus represents the status of a Worker.

type WorkersService

type WorkersService interface {
	// Start starts the indicated Event's Worker on Brigade's workload
	// execution substrate. If the specified Event does not exist, implementations
	// MUST return a *meta.ErrNotFound.
	Start(ctx context.Context, eventID string) error
	// GetStatus returns an Event's Worker's status. If the specified Event does
	// not exist, implementations MUST return a *meta.ErrNotFound.
	GetStatus(
		ctx context.Context,
		eventID string,
	) (WorkerStatus, error)
	// WatchStatus returns a channel over which an Event's Worker's status is
	// streamed. The channel receives a new WorkerStatus every time there is any
	// change in that status. If the specified Event does not exist,
	// implementations MUST return a *meta.ErrNotFound.
	WatchStatus(
		ctx context.Context,
		eventID string,
	) (<-chan WorkerStatus, error)
	// UpdateStatus updates the status of an Event's Worker. If the specified
	// Event does not exist, implementations MUST return a *meta.ErrNotFound.
	UpdateStatus(
		ctx context.Context,
		eventID string,
		status WorkerStatus,
	) error
	// Cleanup removes Worker-related resources from the substrate, presumably
	// upon completion, without deleting the Worker from the data store.
	Cleanup(ctx context.Context, eventID string) error
	// Timeout updates the status of an Event's Worker that has timed out and
	// then proceeds to remove Worker-related resources from the substrate.
	Timeout(ctx context.Context, eventID string) error
}

WorkersService is the specialized interface for managing Workers. It's decoupled from underlying technology choices (e.g. data store, message bus, etc.) to keep business logic reusable and consistent while the underlying tech stack remains free to change.

func NewWorkersService

func NewWorkersService(
	authorizeFn AuthorizeFn,
	projectsStore ProjectsStore,
	eventsStore EventsStore,
	workersStore WorkersStore,
	substrate Substrate,
) WorkersService

NewWorkersService returns a specialized interface for managing Workers.

type WorkersStore

type WorkersStore interface {
	UpdateStatus(
		ctx context.Context,
		eventID string,
		status WorkerStatus,
	) error

	UpdateHashedToken(
		ctx context.Context,
		eventID string,
		hashedToken string,
	) error

	Timeout(ctx context.Context, eventID string) error
}

WorkersStore is an interface for components that implement Worker persistence concerns.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL