runner

package
v0.3.25 Latest Latest
Warning

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

Go to latest
Published: Jun 24, 2025 License: MPL-2.0 Imports: 56 Imported by: 0

Documentation

Overview

Package runner contains the runner, the component responsible for carrying out runs by executing terraform processes, either as part of the server or remotely via agents.

templ: version: v0.3.865

Index

Constants

View Source
const DefaultMaxJobs = 5

Variables

View Source
var (
	ErrInvalidJobStateTransition = errors.New("invalid job state transition")
	ErrMalformedJobSpecString    = errors.New("malformed stringified job spec")
)
View Source
var (
	ErrCannotDeletePoolReferencedByWorkspaces = errors.New("agent pool is still being used by workspaces in your organization. You must switch your workspaces to a different agent pool or execution mode before you can delete this agent pool")
	ErrWorkspaceNotAllowedToUsePool           = errors.New("access to this agent pool is not allowed - you must explictly grant access to the workspace first")
	ErrPoolAssignedWorkspacesNotAllowed       = errors.New("workspaces assigned to the pool have not been granted access to the pool")
)
View Source
var ErrInvalidStateTransition = errors.New("invalid runner state transition")
View Source
var PluginCacheDir = filepath.Join(os.TempDir(), "plugin-cache")

Functions

func NewAgentsCommand

func NewAgentsCommand(apiClient *otfapi.Client) *cobra.Command

Types

type AgentOptions

type AgentOptions struct {
	*Config

	URL   string
	Token string
}

func NewAgentOptionsFromFlags

func NewAgentOptionsFromFlags(flags *pflag.FlagSet) *AgentOptions

type Config

type Config struct {
	Name         string // descriptive name given to runner
	MaxJobs      int    // number of jobs the runner can execute at any one time
	Sandbox      bool   // isolate privileged ops within sandbox
	Debug        bool   // toggle debug mode
	PluginCache  bool   // toggle use of terraform's shared plugin cache
	EngineBinDir string // destination directory for engine binaries
}

func NewConfig added in v0.3.20

func NewConfig() *Config

func NewConfigFromFlags

func NewConfigFromFlags(flags *pflag.FlagSet) *Config

type CreateAgentPoolOptions

type CreateAgentPoolOptions struct {
	Name string `schema:"name,required"`
	// name of org
	Organization organization.Name `schema:"organization_name,required"`
	// defaults to true
	OrganizationScoped *bool
	// IDs of workspaces allowed to access the pool.
	AllowedWorkspaces []resource.TfeID
}

type CreateAgentTokenOptions

type CreateAgentTokenOptions struct {
	Description string `json:"description" schema:"description,required"`
}

type Job

type Job struct {
	ID resource.TfeID `jsonapi:"primary,jobs" db:"job_id"`
	// ID of the run that this job is for.
	RunID resource.TfeID `jsonapi:"attribute" json:"run_id" db:"run_id"`
	// Phase of run that this job is for.
	Phase otfrun.PhaseType `jsonapi:"attribute" json:"phase"`
	// Current status of job.
	Status JobStatus `jsonapi:"attribute" json:"status"`
	// ID of agent pool the job's workspace is assigned to use. If non-nil then
	// the job is allocated to an agent runner belonging to the pool. If nil then
	// the job is allocated to a server runner.
	AgentPoolID *resource.TfeID `jsonapi:"attribute" json:"agent_pool_id" db:"agent_pool_id"`
	// Name of job's organization
	Organization organization.Name `jsonapi:"attribute" json:"organization" db:"organization_name"`
	// ID of job's workspace
	WorkspaceID resource.TfeID `jsonapi:"attribute" json:"workspace_id" db:"workspace_id"`
	// ID of runner that this job is allocated to. Only set once job enters
	// JobAllocated state.
	RunnerID *resource.TfeID `jsonapi:"attribute" json:"runner_id" db:"runner_id"`
	// Signaled is non-nil when a cancelation signal has been sent to the job
	// and it is true when it has been forceably canceled.
	Signaled *bool `jsonapi:"attribute" json:"signaled"`
}

Job is the unit of work corresponding to a run phase. A job is allocated to a runner, which then executes the work through to completion.

func (*Job) CanAccess

func (j *Job) CanAccess(action authz.Action, req authz.Request) bool

func (*Job) LogValue

func (j *Job) LogValue() slog.Value

func (*Job) String

func (j *Job) String() string

type JobEvent added in v0.3.23

type JobEvent struct {
	ID resource.TfeID `json:"job_id"`
	// ID of the run that this job is for.
	RunID resource.TfeID `jsonapi:"attribute" json:"run_id" db:"run_id"`
	// Current status of job.
	Status JobStatus `json:"status"`
	// ID of runner that this job is allocated to. Only set once job enters
	// JobAllocated state.
	RunnerID *resource.TfeID `json:"runner_id"`
	// Signaled is non-nil when a cancelation signal has been sent to the job
	// and it is true when it has been forceably canceled.
	Signaled *bool `json:"signaled"`
}

type JobStatus

type JobStatus string
const (
	JobUnallocated JobStatus = "unallocated"
	JobAllocated   JobStatus = "allocated"
	JobRunning     JobStatus = "running"
	JobFinished    JobStatus = "finished"
	JobErrored     JobStatus = "errored"
	JobCanceled    JobStatus = "canceled"
)

type ListOptions added in v0.3.17

type ListOptions struct {
	resource.PageOptions
	// Organization filters runners by the organization of their agent pool.
	//
	// NOTE: setting this does not exclude server runners (which do not belong
	// to an organization). To exclude servers runners as well set Server below to
	// false.
	Organization *organization.Name `schema:"organization_name"`
	// PoolID filters runners by agent pool ID
	PoolID *resource.TfeID `schema:"pool_id"`
	// HideServerRunners if true filters out server runners
	HideServerRunners bool `schema:"hide_server_runners"`
}

type Pool

type Pool struct {
	ID        resource.TfeID `json:"agent_pool_id" db:"agent_pool_id"`
	Name      string
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	// Pool belongs to an organization with this name.
	Organization organization.Name `json:"organization_name" db:"organization_name"`
	// Whether pool of agents is accessible to all workspaces in organization
	// (true) or only those specified in AllowedWorkspaces (false).
	OrganizationScoped bool `json:"organization_scoped" db:"organization_scoped"`
	// IDs of workspaces allowed to access pool. Ignored if OrganizationScoped
	// is true.
	AllowedWorkspaces []resource.TfeID `json:"allowed_workspace_ids" db:"allowed_workspace_ids"`
	// IDs of workspaces assigned to the pool. Note: this is a subset of
	// AllowedWorkspaces.
	AssignedWorkspaces []resource.TfeID `json:"workspace_ids" db:"workspace_ids"`
}

Pool is a group of remote runners sharing one or more tokens, assigned to an organization or particular workspaces within the organization.

func (*Pool) LogValue

func (p *Pool) LogValue() slog.Value

type Runner

type Runner struct {
	*RunnerMeta

	Sandbox         bool   // isolate privileged ops within sandbox
	Debug           bool   // toggle debug mode
	PluginCache     bool   // toggle use of terraform's shared plugin cache
	TerraformBinDir string // destination directory for terraform binaries
	// contains filtered or unexported fields
}

func NewAgent

func NewAgent(logger logr.Logger, opts AgentOptions) (*Runner, error)

func NewServerRunner

func NewServerRunner(opts ServerRunnerOptions) (*Runner, error)

NewServerRunner constructs a server runner.

func (*Runner) Start

func (r *Runner) Start(ctx context.Context) error

Start the runner daemon.

func (*Runner) Started added in v0.3.23

func (r *Runner) Started() <-chan struct{}

type RunnerEvent added in v0.3.23

type RunnerEvent struct {
	ID     resource.TfeID `json:"runner_id"`
	Status RunnerStatus   `json:"status"`
}

type RunnerMeta

type RunnerMeta struct {
	ID resource.TfeID `jsonapi:"primary,runners" db:"runner_id"`
	// Optional name
	Name string `jsonapi:"attribute" json:"name"`
	// Version of runner
	Version string `jsonapi:"attribute" json:"version"`
	// Current status of runner
	Status RunnerStatus `jsonapi:"attribute" json:"status"`
	// Max number of jobs runner can execute
	MaxJobs int `jsonapi:"attribute" json:"max_jobs" db:"max_jobs"`
	// Current number of jobs allocated to runner.
	CurrentJobs int `jsonapi:"attribute" json:"current_jobs" db:"current_jobs"`
	// Last time a ping was received from the runner.
	LastPingAt time.Time `jsonapi:"attribute" json:"last-ping-at" db:"last_ping_at"`
	// Last time the status was updated
	LastStatusAt time.Time `jsonapi:"attribute" json:"last-status-at" db:"last_status_at"`
	// IP address of runner.
	IPAddress netip.Addr `jsonapi:"attribute" json:"ip-address" db:"ip_address"`
	// Info about the runner's agent pool. Non-nil if agent runner; nil if server
	// runner.
	AgentPool *Pool `jsonapi:"attribute" json:"agent-pool" db:"agent_pool"`
}

RunnerMeta is information about a runner.

func (*RunnerMeta) CanAccess

func (m *RunnerMeta) CanAccess(action authz.Action, req authz.Request) bool

func (*RunnerMeta) IsAgent

func (m *RunnerMeta) IsAgent() bool

func (*RunnerMeta) LogValue

func (m *RunnerMeta) LogValue() slog.Value

func (*RunnerMeta) String

func (m *RunnerMeta) String() string

type RunnerStatus

type RunnerStatus string
const (
	RunnerIdle    RunnerStatus = "idle"
	RunnerBusy    RunnerStatus = "busy"
	RunnerExited  RunnerStatus = "exited"
	RunnerErrored RunnerStatus = "errored"
	RunnerUnknown RunnerStatus = "unknown"
)

type ServerRunnerOptions

type ServerRunnerOptions struct {
	*Config

	Logger     logr.Logger
	Runners    *Service
	Runs       runClient
	Workspaces workspaceClient
	Variables  variablesClient
	State      stateClient
	Configs    configClient
	Server     hostnameClient
	Jobs       operationJobsClient
}

ServerRunnerOptions are options for constructing a server runner.

type Service

type Service struct {
	logr.Logger
	*authz.Authorizer
	// contains filtered or unexported fields
}

func NewService

func NewService(opts ServiceOptions) *Service

func (*Service) AddHandlers

func (s *Service) AddHandlers(r *mux.Router)

func (*Service) CreateAgentPool

func (s *Service) CreateAgentPool(ctx context.Context, opts CreateAgentPoolOptions) (*Pool, error)

func (*Service) CreateAgentToken

func (s *Service) CreateAgentToken(ctx context.Context, poolID resource.TfeID, opts CreateAgentTokenOptions) (*agentToken, []byte, error)

func (*Service) DeleteAgentToken

func (s *Service) DeleteAgentToken(ctx context.Context, tokenID resource.TfeID) (*agentToken, error)

func (*Service) GetAgentPool

func (s *Service) GetAgentPool(ctx context.Context, poolID resource.TfeID) (*Pool, error)

func (*Service) GetAgentToken

func (s *Service) GetAgentToken(ctx context.Context, tokenID resource.TfeID) (*agentToken, error)

func (*Service) List added in v0.3.17

func (s *Service) List(ctx context.Context, opts ListOptions) (*resource.Page[*RunnerMeta], error)

func (*Service) ListAgentTokens

func (s *Service) ListAgentTokens(ctx context.Context, poolID resource.TfeID) ([]*agentToken, error)

func (Service) NewAgentToken

func (f Service) NewAgentToken(poolID resource.TfeID, opts CreateAgentTokenOptions) (*agentToken, []byte, error)

NewAgentToken constructs a token for an agent, returning both the representation of the token, and the cryptographic token itself.

func (*Service) NewAllocator

func (s *Service) NewAllocator(logger logr.Logger) *allocator

func (*Service) NewManager

func (s *Service) NewManager() *manager

func (*Service) Watch added in v0.3.17

func (s *Service) Watch(ctx context.Context) (<-chan pubsub.Event[*RunnerEvent], func())

func (*Service) WatchAgentPools

func (s *Service) WatchAgentPools(ctx context.Context) (<-chan pubsub.Event[*Pool], func())

func (*Service) WatchJobs

func (s *Service) WatchJobs(ctx context.Context) (<-chan pubsub.Event[*JobEvent], func())

func (*Service) WatchRunners

func (s *Service) WatchRunners(ctx context.Context) (<-chan pubsub.Event[*RunnerEvent], func())

type ServiceOptions

type ServiceOptions struct {
	logr.Logger
	*sql.DB
	*sql.Listener
	*tfeapi.Responder

	RunService       *otfrun.Service
	WorkspaceService *workspace.Service
	TokensService    *tokens.Service
	Authorizer       *authz.Authorizer
}

type TFEAgentPool added in v0.3.17

type TFEAgentPool struct {
	ID                 resource.TfeID `jsonapi:"primary,agent-pools"`
	Name               string         `jsonapi:"attribute" json:"name"`
	AgentCount         int            `jsonapi:"attribute" json:"agent-count"`
	OrganizationScoped bool           `jsonapi:"attribute" json:"organization-scoped"`

	// Relations
	Organization      *organization.TFEOrganization `jsonapi:"relationship" json:"organization"`
	Workspaces        []*workspace.TFEWorkspace     `jsonapi:"relationship" json:"workspaces"`
	AllowedWorkspaces []*workspace.TFEWorkspace     `jsonapi:"relationship" json:"allowed-workspaces"`
}

TFEAgentPool represents a Terraform Cloud agent pool.

type TFEAgentPoolCreateOptions added in v0.3.17

type TFEAgentPoolCreateOptions struct {
	// Type is a public field utilized by JSON:API to
	// set the resource type via the field tag.
	// It is not a user-defined value and does not need to be set.
	// https://jsonapi.org/format/#crud-creating
	Type string `jsonapi:"primary,agent-pools"`

	// Required: A name to identify the agent pool.
	Name *string `jsonapi:"attribute" json:"name"`

	// True if the agent pool is organization scoped, false otherwise.
	OrganizationScoped *bool `jsonapi:"attribute" json:"organization-scoped,omitempty"`

	// List of workspaces that are associated with an agent pool.
	AllowedWorkspaces []*workspace.TFEWorkspace `jsonapi:"relationship" json:"allowed-workspaces,omitempty"`
}

TFEAgentPoolCreateOptions represents the options for creating an agent pool.

type TFEAgentPoolListOptions added in v0.3.17

type TFEAgentPoolListOptions struct {
	types.ListOptions

	// Optional: A search query string used to filter agent pool. Agent pools are searchable by name
	Query *string `schema:"q,omitempty"`

	// Optional: String (workspace name) used to filter the results.
	AllowedWorkspacesName *string `schema:"filter[allowed_workspaces][name],omitempty"`
}

TFEAgentPoolListOptions represents the options for listing agent pools.

type TFEAgentPoolUpdateOptions added in v0.3.17

type TFEAgentPoolUpdateOptions struct {
	// Type is a public field utilized by JSON:API to
	// set the resource type via the field tag.
	// It is not a user-defined value and does not need to be set.
	// https://jsonapi.org/format/#crud-creating
	Type string `jsonapi:"primary,agent-pools"`

	// A new name to identify the agent pool.
	Name *string `jsonapi:"attribute" json:"name,omitempty"`

	// True if the agent pool is organization scoped, false otherwise.
	OrganizationScoped *bool `jsonapi:"attribute" json:"organization-scoped,omitempty"`

	// A new list of workspaces that are associated with an agent pool.
	AllowedWorkspaces []*workspace.TFEWorkspace `jsonapi:"relationship" json:"allowed-workspaces,omitempty"`
}

TFEAgentPoolUpdateOptions represents the options for updating an agent pool.

type TFEAgentToken added in v0.3.17

type TFEAgentToken struct {
	ID          resource.TfeID `jsonapi:"primary,authentication-tokens"`
	CreatedAt   time.Time      `jsonapi:"attribute" json:"created-at"`
	Description string         `jsonapi:"attribute" json:"description"`
	LastUsedAt  time.Time      `jsonapi:"attribute" json:"last-used-at"`
	Token       string         `jsonapi:"attribute" json:"token"`
}

TFEAgentToken represents a TFE agent token.

type TFEAgentTokenCreateOptions added in v0.3.17

type TFEAgentTokenCreateOptions struct {
	// Type is a public field utilized by JSON:API to set the resource type via
	// the field tag.  It is not a user-defined value and does not need to be
	// set.  https://jsonapi.org/format/#crud-creating
	Type string `jsonapi:"primary,agent-tokens"`

	// Description is a meaningful description of the purpose of the agent
	// token.
	Description string `jsonapi:"attribute" json:"description"`
}

TFEAgentTokenCreateOptions represents the options for creating a new otf agent token.

Jump to

Keyboard shortcuts

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