Documentation
¶
Overview ¶
Package controller is the wiring between everything else: it owns the reconcile loop, the GitHub client cache, webhook ingest, the agent task queue, the log relay and the background housekeeping.
Nothing in here decides how many runners a pool should have -- that is internal/scheduler, and it is a pure function -- and nothing in here writes SQL, which is internal/store. What this package does is turn a decision into GitHub calls, database rows and tasks for an agent, in an order that leaves the fleet in a defensible state when any single step fails.
The controller never dials an agent. Agents connect outbound, long-poll for tasks and POST their results, which is why the task queue and the log relay are shaped the way they are.
Index ¶
- Constants
- Variables
- func AnalysePRDelayEvidence(in PRDelayInput) (analysis.MergeDelayResult, error)
- func AssistantOutputLimit(row *store.AssistantProvider) int
- func CertificateProblem(text string) string
- func DecimalID(n int64) string
- func DemoRequested() bool
- func EffectiveMinimum(r store.Resources, fleet config.Runners) (cpus float64, memoryMB int64)
- func HostRefusal(h *store.Host, p *store.Pool) (code, reason string)
- func IsDemoID(id string) bool
- func JobEventFor(e store.JobEvent, visitor bool) store.JobEvent
- func OptimisationHistoryReview(headSHA, sourceSHA256 string) optimisation.HistoryReview
- func PoolEffectiveDockerWait(p *store.Pool, cfg *config.Config) time.Duration
- func PoolSizing(p *store.Pool) string
- func PublicSentence(code string) string
- func RemedyBase(v any) string
- func SpanRefusal(span, limit time.Duration, what string) string
- func UsableBy(row *store.AssistantProvider, userID string) bool
- func ValidateAssistantChat(in []AssistantChatMessage) ([]assistant.Message, error)
- type AIContextDiscovery
- type AIContextDraftRequest
- type AIContextMaintenanceRequest
- type AIContextRefusal
- type AIContextSetupApproval
- type AIContextSetupPreview
- type AcceptInput
- type AdviceOptions
- type AdviceWindow
- type AnalysisWindow
- type ArchiveSecrets
- type AssistantChat
- type AssistantChatEvent
- type AssistantChatInvalid
- type AssistantChatMessage
- type AssistantChatRequest
- type AssistantProviderCheck
- type AssistantProviderView
- type AssistantStyle
- type AssistantToolUse
- type AssistantToolbox
- type Audience
- type AutoPoolPending
- type AutoPoolSkip
- type AutoPoolStatus
- type AutoPoolSummary
- type AutoPoolsView
- type BackendInfoView
- type BackupPruning
- type BackupStatus
- type Band
- type CPUResourceView
- type CapacityDemandEvent
- type CheckoutInspection
- type CompareRequest
- type Controller
- func (c *Controller) AIContextDiagnosis(r *store.AIContextRepository) *aicontext.Diagnosis
- func (c *Controller) AcceptHostCheck(ctx context.Context, hostID string, in AcceptInput, by HostActor) (HostView, *store.HostCheckAcceptance, error)
- func (c *Controller) AcceptLogStream(hostID, streamID string, r io.Reader) error
- func (c *Controller) AcknowledgeJob(ctx context.Context, jobID, by string) (*store.Job, bool, error)
- func (c *Controller) ActEliOpportunity(ctx context.Context, user, id, action string, admin bool) (*store.EliRepair, error)
- func (c *Controller) AdmitJoinToken(ctx context.Context) error
- func (c *Controller) AdmitPool(ctx context.Context) error
- func (c *Controller) AdmitPools(ctx context.Context, n int) error
- func (c *Controller) AllowAgentCall(hostID string) (bool, time.Duration)
- func (c *Controller) AnalyseCompare(ctx context.Context, req CompareRequest) (analysis.CompareFinding, error)
- func (c *Controller) AnalyseHostPressure(ctx context.Context, w AnalysisWindow, hostID string) (analysis.HostPressureFinding, error)
- func (c *Controller) AnalyseQueueWait(ctx context.Context, w AnalysisWindow, poolID string) (analysis.QueueWaitFinding, error)
- func (c *Controller) AnalyseStartupFailures(ctx context.Context, w AnalysisWindow, poolID, hostID string) (analysis.StartupFailuresFinding, error)
- func (c *Controller) ApplyAIContextMaintenance(ctx context.Context, id string, req AIContextMaintenanceRequest) (*AIContextSetupPreview, error)
- func (c *Controller) ApplyMigration(ctx context.Context, req MigrationApplyRequest) (*MigrationOutcome, error)
- func (c *Controller) AssistantProviderView(p *store.AssistantProvider) AssistantProviderView
- func (c *Controller) AssistantProviderViewFor(ctx context.Context, p *store.AssistantProvider, userID string) AssistantProviderView
- func (c *Controller) Auth() *auth.Service
- func (c *Controller) AutoAdjustEffective(h *store.Host) bool
- func (c *Controller) AutoPoolKept(p *store.Pool) bool
- func (c *Controller) AutoPoolStatus() AutoPoolStatus
- func (c *Controller) AutoPools() AutoPoolsView
- func (c *Controller) AutoPoolsMode() string
- func (c *Controller) Backends() *backend.Registry
- func (c *Controller) BackupDir() string
- func (c *Controller) BackupRemotes(ctx context.Context) []RemoteBackupStatus
- func (c *Controller) BackupStatus() BackupStatus
- func (c *Controller) BootstrapFromEnvironment(ctx context.Context) error
- func (c *Controller) CancelJobWorkflow(ctx context.Context, jobID string, force bool) (*store.Job, error)
- func (c *Controller) CancelRollout(ctx context.Context, by UpdateActor) (*UpdatesView, RolloutChange, error)
- func (c *Controller) CancelTransfer(ctx context.Context) error
- func (c *Controller) CancelWorkflowRun(ctx context.Context, repo string, runID int64, force bool) ([]*store.Job, error)
- func (c *Controller) CaptureExperimentComparison(ctx context.Context, actor *store.AuditEvent, ...) (*RetainedExperimentComparison, error)
- func (c *Controller) CaptureOptimisationPreview(ctx context.Context, actor *store.AuditEvent, installation, repo string, ...) (*RetainedOptimisationPreview, error)
- func (c *Controller) CheckAIContextUploadToken(ctx context.Context, rawToken, audience string) error
- func (c *Controller) CheckAssistantDraft(ctx context.Context, draft *store.AssistantProvider, apiKey string) AssistantProviderCheck
- func (c *Controller) CheckAssistantProvider(ctx context.Context, row *store.AssistantProvider) AssistantProviderCheck
- func (c *Controller) CheckBackupRemote(ctx context.Context, cfg config.BackupRemote) error
- func (c *Controller) CheckForReleases(ctx context.Context) error
- func (c *Controller) CheckProvider(ctx context.Context, row *store.Provider) (ProviderCheckView, error)
- func (c *Controller) ClearHostThrottle(ctx context.Context, id string) (*store.Host, error)
- func (c *Controller) ClientFor(ctx context.Context, installationID string) (github.Client, error)
- func (c *Controller) ClientForRepo(ctx context.Context, repoFullName string) (github.Client, error)
- func (c *Controller) CollectExperimentAttempts(ctx context.Context, installation, repo string, ...) (*ExperimentRetainedEvidence, error)
- func (c *Controller) CollectExperimentEvidence(ctx context.Context, installation, repo string, ...) (*ExperimentJoinedEvidence, error)
- func (c *Controller) Config() *config.Config
- func (c *Controller) ControlProvisioning(ctx context.Context, ids []string, action string) ([]store.ProvisioningResult, error)
- func (c *Controller) ControlWorkflowRunProvisioning(ctx context.Context, repo string, runID int64, action string) ([]store.ProvisioningResult, error)
- func (c *Controller) CreateAIContextDraft(ctx context.Context, req AIContextDraftRequest) (*store.AIContextRepository, error)
- func (c *Controller) CreateAIContextSetupPR(ctx context.Context, id string, approval AIContextSetupApproval) (*AIContextSetupPreview, error)
- func (c *Controller) CreateKennelGuidancePR(ctx context.Context, id string, approval KennelGuidanceApproval) (*KennelGuidancePreview, error)
- func (c *Controller) DatabasePath() string
- func (c *Controller) DeleteHost(ctx context.Context, id string) error
- func (c *Controller) DeleteHostForgettingMachine(ctx context.Context, id, machineID string) error
- func (c *Controller) DeleteInstallation(ctx context.Context, id string) error
- func (c *Controller) DeletePool(ctx context.Context, id string) error
- func (c *Controller) DiscoverAIContext(ctx context.Context, installationID string) (*AIContextDiscovery, error)
- func (c *Controller) DiscoverDraft(ctx context.Context, row *store.Provider, credential, address string) (ProviderDiscoveryView, error)
- func (c *Controller) DiscoverProvider(ctx context.Context, row *store.Provider) (ProviderDiscoveryView, error)
- func (c *Controller) DrainRunner(ctx context.Context, runnerID, reason string, confirmed bool) (*store.Runner, error)
- func (c *Controller) EliAutomaticRepairs(ctx context.Context) ([]EliAutomaticRepository, error)
- func (c *Controller) EliErrorOutput(ctx context.Context, user, repo string, jobID int64) (EliErrorOutput, error)
- func (c *Controller) EliOpportunities(ctx context.Context, user string) ([]store.EliRepairOpportunity, error)
- func (c *Controller) EliReadiness(ctx context.Context, user, repo string, pull int, run int64) (out EliReadiness)
- func (c *Controller) EmbeddedAgent() *agent.Agent
- func (c *Controller) EmbeddedTransport() agent.Transport
- func (c *Controller) Events() *events.Bus
- func (c *Controller) ExplainJob(ctx context.Context, jobID string, logs int) (*JobExplanation, error)
- func (c *Controller) ExportInstallation(ctx context.Context, id, passphrase string) (*InstallationArchive, error)
- func (c *Controller) Fenced() store.RecoveryFence
- func (c *Controller) FindAIContextDraft(ctx context.Context, installationID string, repositoryID int64) (*store.AIContextRepository, error)
- func (c *Controller) Forget(installationID string)
- func (c *Controller) HandleWebhook(w http.ResponseWriter, r *http.Request)
- func (c *Controller) Heartbeat(ctx context.Context, hostID string, req agent.HeartbeatRequest) (*agent.HeartbeatResponse, error)
- func (c *Controller) HostFit(ctx context.Context, p *store.Pool) (HostFit, error)
- func (c *Controller) HostRecommendation(ctx context.Context, h *store.Host) (scheduler.HostRecommendation, bool)
- func (c *Controller) HostSamples(ctx context.Context, since time.Time, hostID string) ([]store.HostSample, error)
- func (c *Controller) HostStrandings(ctx context.Context, proposed *store.Host) ([]Stranding, error)
- func (c *Controller) HostView(h *store.Host) HostView
- func (c *Controller) ImportInstallation(ctx context.Context, a *InstallationArchive, passphrase string) (*store.Installation, *store.ImportedInstallation, error)
- func (c *Controller) IngestAIContextUpload(ctx context.Context, rawToken, audience string, body []byte) (*store.AIContextRepository, error)
- func (c *Controller) InspectCheckoutEvidence(ctx context.Context, installation, repo string, ...) (*CheckoutInspection, error)
- func (c *Controller) JobEvents(ctx context.Context, jobID string) ([]*store.JobEvent, error)
- func (c *Controller) JobRenderer(ctx context.Context) (*JobRenderer, error)
- func (c *Controller) Join(ctx context.Context, req agent.JoinRequest, ip string) (*agent.JoinResponse, error)
- func (c *Controller) KennelChecks() []KennelCheckInfo
- func (c *Controller) KennelOverview(ctx context.Context) (*KennelOverviewView, error)
- func (c *Controller) KennelPass(ctx context.Context)
- func (c *Controller) KennelRepositories(ctx context.Context, f KennelListFilter, page store.Page) ([]KennelRepositoryView, int, error)
- func (c *Controller) KennelRepository(ctx context.Context, id string) (*KennelRepositoryView, error)
- func (c *Controller) KickAutoPools()
- func (c *Controller) KickKennel()
- func (c *Controller) KickUpdates()
- func (c *Controller) LabelAdvice(ctx context.Context, opts AdviceOptions) ([]*scheduler.Advice, AdviceWindow, error)
- func (c *Controller) LastPollAt() time.Time
- func (c *Controller) ListAssistantModels(ctx context.Context, draft *store.AssistantProvider, apiKey string) ([]string, error)
- func (c *Controller) LoadFence(ctx context.Context) error
- func (c *Controller) LoopPanics() map[string]loopPanic
- func (c *Controller) MachineRenderer(ctx context.Context) (*MachineRenderer, error)
- func (c *Controller) NoteAgentSession(ctx context.Context, hostID, sessionID string)
- func (c *Controller) NoteManualBackup()
- func (c *Controller) NoteRemoteListing(name string, copies int, bytes int64)
- func (c *Controller) Now() time.Time
- func (c *Controller) Nudge()
- func (c *Controller) NudgeBackupRemotes()
- func (c *Controller) NudgeMachines()
- func (c *Controller) OpenAssistantProvider(row *store.AssistantProvider, apiKey string) (assistant.Provider, error)
- func (c *Controller) OpenLogStream(ctx context.Context, runnerID string, opts backend.LogOptions) (<-chan []byte, func(), error)
- func (c *Controller) OptimisationPolicy(context.Context) (optimisation.Policy, error)
- func (c *Controller) OrphanReport(ctx context.Context, row *store.Provider) (OrphanReportView, error)
- func (c *Controller) PRDelayForJob(ctx context.Context, jobID string, pull int) (*PRDelayReport, error)
- func (c *Controller) PlanMigration(ctx context.Context, req MigrationPlanRequest) (*MigrationPlan, error)
- func (c *Controller) PollTasks(ctx context.Context, hostID string, wait time.Duration) (*agent.TaskBatch, error)
- func (c *Controller) PollerEnabled() bool
- func (c *Controller) PollingOnly() bool
- func (c *Controller) PoolCapacityProblems() []Problem
- func (c *Controller) PoolCountsByInstallation(ctx context.Context) (map[string]int, error)
- func (c *Controller) PoolRenderer(ctx context.Context) (*PoolRenderer, error)
- func (c *Controller) PoolRoom(ctx context.Context, p *store.Pool) (PoolRoom, error)
- func (c *Controller) PoolRunnerGroupProblems() []Problem
- func (c *Controller) PoolStranding(ctx context.Context, current, proposed *store.Pool) ([]Stranding, error)
- func (c *Controller) PrepareTransfer(ctx context.Context) (TransferProgress, error)
- func (c *Controller) PreviewAIContextMaintenance(ctx context.Context, id string, req AIContextMaintenanceRequest) (*AIContextSetupPreview, error)
- func (c *Controller) PreviewAIContextSetup(ctx context.Context, id string) (*AIContextSetupPreview, error)
- func (c *Controller) PreviewKennelGuidance(ctx context.Context, id string) (*KennelGuidancePreview, error)
- func (c *Controller) PrewarmPool(ctx context.Context, p *store.Pool) (int, error)
- func (c *Controller) PrivateConnectionFault() *PrivateConnectionFault
- func (c *Controller) ProbeInstallation(ctx context.Context, installationID string) (*github.AppInfo, error)
- func (c *Controller) Problems(ctx context.Context) ([]Problem, error)
- func (c *Controller) ProviderKinds() []ProviderKindView
- func (c *Controller) ProviderOrphans() map[string][]string
- func (c *Controller) ProviderPairings(ctx context.Context) ([]PairingView, error)
- func (c *Controller) ProviderView(p *store.Provider, machines []*store.Machine) ProviderView
- func (c *Controller) ProvidersAvailable() bool
- func (c *Controller) PruneBackups(ctx context.Context) (BackupPruning, error)
- func (c *Controller) PublishHost(h *store.Host)
- func (c *Controller) PublishHostDeleted(id string)
- func (c *Controller) PublishInstallation(ctx context.Context, inst *store.Installation)
- func (c *Controller) PublishInstallationDeleted(id string)
- func (c *Controller) PublishKennelRepository(ctx context.Context, id string)
- func (c *Controller) PublishMachine(ctx context.Context, m *store.Machine)
- func (c *Controller) PublishMachineDeleted(id string)
- func (c *Controller) PublishPool(ctx context.Context, kind events.Kind, p *store.Pool)
- func (c *Controller) PublishPoolDeleted(id string)
- func (c *Controller) PublishProvider(ctx context.Context, p *store.Provider)
- func (c *Controller) PublishProviderDeleted(id string)
- func (c *Controller) PurgeInstallation(ctx context.Context, id string) error
- func (c *Controller) RecheckHostPriority(ctx context.Context, hostID string) (store.Host, error)
- func (c *Controller) RecheckKennelRepository(ctx context.Context, id string) (*KennelRepositoryView, error)
- func (c *Controller) ReclassifyQueuedJobs(ctx context.Context, repo, workflow, jobName string) (int, error)
- func (c *Controller) ReclassifyWaitingJobs(ctx context.Context) (int, error)
- func (c *Controller) Reconcile(ctx context.Context) error
- func (c *Controller) ReconcileAutoPools(ctx context.Context) error
- func (c *Controller) ReconcileMachines(ctx context.Context) error
- func (c *Controller) ReconcileUpdates(ctx context.Context) error
- func (c *Controller) RecordAssistantProviderCheck(ctx context.Context, id string, check AssistantProviderCheck) error
- func (c *Controller) RefreshAIContext(ctx context.Context, id string) error
- func (c *Controller) RegenerateAIContext(ctx context.Context, id string) error
- func (c *Controller) Registry() *prometheus.Registry
- func (c *Controller) RemoteBackup(ctx context.Context, name string) (*backup.Remote, error)
- func (c *Controller) RemoveRunner(ctx context.Context, runnerID, reason string, force, confirmed bool) (*store.Runner, error)
- func (c *Controller) Renting(ctx context.Context) (RentingView, error)
- func (c *Controller) ReopenJobAttention(ctx context.Context, jobID, by string) (*store.Job, bool, error)
- func (c *Controller) ReplayExperimentComparison(ctx context.Context, installation, repo, id string) (*RetainedExperimentComparison, error)
- func (c *Controller) ReplayOptimisationPreview(ctx context.Context, installation, repo, id string) (*RetainedOptimisationPreview, error)
- func (c *Controller) ReportResult(ctx context.Context, hostID string, res agent.TaskResult) (resultErr error)
- func (c *Controller) ReportRunners(ctx context.Context, hostID string, reports []agent.RunnerReport) error
- func (c *Controller) RequestControllerUpdate(ctx context.Context, by UpdateActor, tag string) (*UpdatesView, error)
- func (c *Controller) RequestControllerUpdateAttempt(ctx context.Context, by UpdateActor, tag string) (*UpdatesView, string, error)
- func (c *Controller) RequestEliRepair(ctx context.Context, userID, repo string, pull int, instruction string, ...) (*store.EliRepair, error)
- func (c *Controller) RequestHostCheck(ctx context.Context, hostID string) (h store.Host, queued bool, err error)
- func (c *Controller) RequestHostUpdate(ctx context.Context, by UpdateActor, hostID string) (*HostView, error)
- func (c *Controller) RequestPinnedEliRepair(ctx context.Context, userID, repo string, pull int, ...) (*store.EliRepair, error)
- func (c *Controller) RequestRestart(reason string)
- func (c *Controller) RerunJobWorkflow(ctx context.Context, jobID string) (*store.Job, error)
- func (c *Controller) RestartRequested() <-chan struct{}
- func (c *Controller) Restarting() (bool, string)
- func (c *Controller) ResumeRollout(ctx context.Context, by UpdateActor) (*UpdatesView, RolloutChange, error)
- func (c *Controller) RetainExperimentComparison(ctx context.Context, actor *store.AuditEvent, ...) (*RetainedExperimentComparison, error)
- func (c *Controller) RetainOptimisationPreview(ctx context.Context, actor *store.AuditEvent, installation, repo string, ...) (*RetainedOptimisationPreview, error)
- func (c *Controller) RetireRecoveryHost(ctx context.Context, id, confirm, actor string) error
- func (c *Controller) RevokeHostCheck(ctx context.Context, hostID, checkID string) (HostView, *store.HostCheckAcceptance, error)
- func (c *Controller) RunnerImage(p *store.Pool) string
- func (c *Controller) RunnerRenderer(ctx context.Context, runners []*store.Runner) (*RunnerRenderer, error)
- func (c *Controller) Samples(ctx context.Context, since time.Time) ([]store.FleetSample, error)
- func (c *Controller) SeedDemo(ctx context.Context) error
- func (c *Controller) SeedStuck(ctx context.Context) error
- func (c *Controller) SetActionsIssuer(issuer string)
- func (c *Controller) SetActionsIssuerFor(issuerFor func(host string) string)
- func (c *Controller) SetKennelTracking(ctx context.Context, repositoryID string, in KennelTrackingInput, ...) (*KennelRepositoryView, *store.KennelUntracked, bool, error)
- func (c *Controller) SetPrivateConnectionFault(f *PrivateConnectionFault)
- func (c *Controller) SetSSOTrouble(t *SSOTrouble)
- func (c *Controller) SharedProblems(ctx context.Context) ([]Problem, error)
- func (c *Controller) ShipBackups(ctx context.Context) ([]backup.Copy, error)
- func (c *Controller) Start(ctx context.Context) error
- func (c *Controller) StartAssistantChat(ctx context.Context, in AssistantChatRequest) (*AssistantChat, error)
- func (c *Controller) StartEmbeddedAgent(ctx context.Context, cfg *config.Config) error
- func (c *Controller) StartHostRollout(ctx context.Context, by UpdateActor, hostIDs []string) (*UpdatesView, RolloutChange, error)
- func (c *Controller) StartTestMachine(ctx context.Context, row *store.Provider) (*store.Machine, error)
- func (c *Controller) StartToolchainScan(ctx context.Context) error
- func (c *Controller) Stats(ctx context.Context, window time.Duration) (*Stats, error)
- func (c *Controller) Status(ctx context.Context) (*FleetStatus, error)
- func (c *Controller) Stop(ctx context.Context) error
- func (c *Controller) StopEliAutomatic(ctx context.Context, repos []string, then string) ([]EliAutomaticStop, error)
- func (c *Controller) Store() *store.Store
- func (c *Controller) SyncAIContext(ctx context.Context, id string, grace time.Duration) error
- func (c *Controller) TakeBackup(ctx context.Context, source, by string) (*backup.Entry, error)
- func (c *Controller) ToolchainScanResult() ToolchainScan
- func (c *Controller) TracksClasses() bool
- func (c *Controller) TransferProgress(ctx context.Context) (TransferProgress, error)
- func (c *Controller) Unfence(ctx context.Context) error
- func (c *Controller) UnwaiveKennelFinding(ctx context.Context, repositoryID, waiverID string) (*KennelRepositoryView, *store.KennelWaiver, error)
- func (c *Controller) UpdateConfig(fn func(*config.Config)) *config.Config
- func (c *Controller) UpdatesView(ctx context.Context) (*UpdatesView, error)
- func (c *Controller) ValidateProviderSettings(kind store.ProviderKind, settings map[string]string) ([]config.Finding, error)
- func (c *Controller) VerifiedAIContextSnapshot(ctx context.Context, id string) (*aicontext.Snapshot, *store.AIContextFreshness, error)
- func (c *Controller) WaiveKennelFinding(ctx context.Context, repositoryID string, in KennelWaiverInput, by KennelActor) (*KennelRepositoryView, *store.KennelWaiver, error)
- type DaemonShareChange
- type DoctorView
- type EffectiveProfileView
- type EffectiveSizeView
- type EffectiveStandardView
- type EliAutomaticRepository
- type EliAutomaticStop
- type EliBlocker
- type EliCheck
- type EliErrorOutput
- type EliReadiness
- type EliReadinessPull
- type Evidence
- type ExperimentAdmissionError
- type ExperimentAttemptSelection
- type ExperimentComparisonRecord
- type ExperimentComparisonReport
- type ExperimentJoinedAttempt
- type ExperimentJoinedEvidence
- type ExperimentMatchedJob
- type ExperimentRecordedGrant
- type ExperimentRecordedGrantView
- type ExperimentRetainedAttempt
- type ExperimentRetainedEvidence
- type ExperimentRetainedJob
- type ExperimentRootSourceView
- type ExperimentRunnerEvidence
- type ExperimentRunnerEvidenceArm
- type ExperimentRunnerEvidenceJob
- type ExperimentRunnerObservationView
- type ExperimentRunnerRequestView
- type ExperimentWorkflowEvidence
- type ExperimentWorkflowEvidenceArm
- type ExperimentWorkflowEvidenceAttempt
- type Fence
- type FleetState
- type FleetStatus
- type HostAcceptInvalidError
- type HostActor
- type HostAutoPoolView
- type HostCheckChangedError
- type HostCheckCooldownError
- type HostCheckError
- type HostCheckView
- type HostExclusion
- type HostFit
- type HostSizeClassView
- type HostStats
- type HostUpdateView
- type HostView
- type InstallationArchive
- type InstallationView
- type JobExplanation
- type JobRenderer
- type JobSummaryView
- type JobView
- type KennelActor
- type KennelAttentionView
- type KennelCheckInfo
- type KennelCheckView
- type KennelCooldownError
- type KennelCoverageSummary
- type KennelCoverageView
- type KennelFieldError
- type KennelFileView
- type KennelFindingView
- type KennelGuidanceApproval
- type KennelGuidancePreview
- type KennelInstallationNote
- type KennelInvalidError
- type KennelListFilter
- type KennelNeed
- type KennelNeedsAdminError
- type KennelOverviewView
- type KennelRepositoryView
- type KennelSkippedView
- type KennelStateCounts
- type KennelTrackingInput
- type KennelTrackingView
- type KennelWaiverInput
- type LimitError
- type LogExcerpt
- type LogLine
- type MachineLimits
- type MachinePlan
- type MachineRenderer
- type MachineSnapshot
- type MachineTimelineEntry
- type MachineView
- type MemoryPoolView
- type MemoryResourceView
- type MigrationApplyRequest
- type MigrationOutcome
- type MigrationPlan
- type MigrationPlanRequest
- type MigrationPoolOption
- type MigrationResult
- type NextStep
- type NotFoundError
- type OptimisationCheckoutProvenance
- type OptimisationPolicyCheck
- type Options
- type OrphanReportView
- type OrphanView
- type PRDelayAdmissionError
- type PRDelayInput
- type PRDelayJobEvidence
- type PRDelayReport
- type PairingView
- type PoolAutoView
- type PoolCountsView
- type PoolHostRoom
- type PoolHostSizing
- type PoolMinimumView
- type PoolRenderer
- type PoolRenting
- type PoolRoom
- type PoolStats
- type PoolView
- type PrivateConnectionFault
- type Problem
- type ProblemsView
- type ProviderCheckView
- type ProviderChoiceView
- type ProviderDiscoveryView
- type ProviderGuideStepView
- type ProviderKindView
- type ProviderPlan
- type ProviderSettingView
- type ProviderView
- type Remedy
- type RemedyKind
- type RemoteBackupStatus
- type RemotePruning
- type RentingState
- type RentingView
- type RetainedExperimentComparison
- type RetainedOptimisationPreview
- type RolloutChange
- type RunnerRenderer
- type RunnerSizeView
- type RunnerStats
- type RunnerView
- type SSOTrouble
- type ScopedJobStats
- type ScratchFolderView
- type ScratchPeakView
- type ScratchView
- type SizeClassLimits
- type SplitOption
- type SplitPlan
- type Stats
- type StatusReason
- type Stranding
- type TmpfsFolderPlan
- type TmpfsHostPlan
- type TmpfsPlan
- type TmpfsShareOption
- type TmpfsSizeOption
- type ToolCacheFill
- type ToolchainDemand
- type ToolchainScan
- type ToolchainScanInstallation
- type TransferProgress
- type UnservedPool
- type UpdateActor
- type UpdatesAttempt
- type UpdatesDevelopment
- type UpdatesHelper
- type UpdatesRelease
- type UpdatesRollout
- type UpdatesRunning
- type UpdatesSigning
- type UpdatesTarget
- type UpdatesView
- type WhyClass
- type WhyConfidence
- type WorkflowRunView
Constants ¶
const ( // AssistantOutputTokensMin and Max bound what a provider row may ask for // in one round: below the floor a thinking model cannot answer at all, and // the ceiling is a cost a person should raise on purpose, not by a typo. AssistantOutputTokensMin = 1024 AssistantOutputTokensMax = 65536 )
What one chat may carry. They are blunt on purpose: there are no per-person limits yet (the rest of slice 7c), so the ceiling on what a single request can send, and on what comes back, is the only ceiling a person meets. Redaction and the tool loop have their own, in assistant_tools.go.
const ( RemoteSourceFile = backup.OriginFile RemoteSourceDatabase = backup.OriginDatabase )
The two places a destination is described, named here as the API serves them. They are internal/backup's, aliased so a handler reading this file does not have to go looking for where the merge lives.
const ( EliStopAskFirst = "ask_first" EliStopOff = "off" )
What a repository does once its automatic repairs are stopped. Ask me first hands the decision back to a person, with the repository's provider, allowance and workflow setting kept; off clears the policy's switch and nothing else, so the same switch in setup turns Automatic back on as it was.
const ( EliCheckOK = "ok" EliCheckBlocked = "blocked" EliCheckUnchecked = "unchecked" )
const ( // Bounds on an acceptance's reason, in characters, are the Kennel waiver's: // ten is a sentence's worth, so "ok" is not a reason, and five hundred is a // paragraph, which is what an audit row should carry and a row can render. HostAcceptMinReason = KennelMinReason HostAcceptMaxReason = KennelMaxReason )
const ( HostCheckNotConnected = "not_connected" HostCheckIncompatible = "incompatible" HostCheckUnsupported = "unsupported" HostCheckFenced = "fenced" HostCheckBusy = "busy" )
Reasons a request is refused, as the stable codes HostCheckError carries.
const ( ExcludedSelector = "selector" ExcludedBackend = "backend" ExcludedPlatform = "platform" ExcludedSize = "size" // ExcludedProfile is a host whose runner profile and the pool's size // disagree: its minimum is above a size the pool states, or its standard is // below the floor of a pool that takes its size from the host. ExcludedProfile = "profile" // ReducedSize is not an exclusion: it marks a host in HostFit.Reduced. ReducedSize = "reduced" )
The reasons a host cannot run the pool. HostFit never returns the first of them -- a host the selector does not reach is not counted as excluded there, because the pool never asked for it -- but an edit that takes a label off a host is exactly that rule being failed, and it needs a name for the same reasons the others have one.
const ( // KennelRecheckCooldown is the least time between two requests to read one // repository again. A read costs GitHub requests the scheduler shares, and a // person pressing the button every few seconds is not asking a different // question each time. KennelRecheckCooldown = 5 * time.Minute // KennelMaxWaiverDays is the longest a waiver may last. A waiver that never // ends is a decision nobody is asked to make again. KennelMaxWaiverDays = 365 // KennelMaxWaivers is how many a repository may carry: a waiver is made for a // finding that exists, and a repository with fifty of them has a different // problem from one more of them. KennelMaxWaivers = 50 // Bounds on a waiver's reason, in characters. Ten is a sentence's worth, so // "ok" and "fine" are not reasons; five hundred is a paragraph, which is what // an audit row should carry and the page should render. KennelMinReason = 10 KennelMaxReason = 500 )
const ( // MemoryWatching: the valve is on and has done nothing for this runner. MemoryWatching = "watching" // MemoryObserving: observe mode, which decides and records and changes // nothing. The runner would have been lent memory, or came near a limit. MemoryObserving = "observing" // MemoryLent: the runner holds memory beyond what it was created with. MemoryLent = "lent" // MemorySpilled: it may use swap beyond its limit, which is the last resort. MemorySpilled = "spilled" )
Memory states a runner's memory_resource can be in. They are stable names for clients and alerts; Reason is the sentence for a person.
const ( // MaxPlanRepos is the most repositories one plan will read workflows from. // The wizard scans in pages; an operator with more repositories than this // migrates them in batches, which is how anyone would want to review them // anyway. MaxPlanRepos = 50 // MaxApplyRepos is the most pull requests one call will open. It is lower // than the plan's limit on purpose: fifty pull requests landing at once in // somebody's review queue is not a migration, it is an incident. MaxApplyRepos = 25 )
Both halves fan out into GitHub's API on a quota the scheduler shares, so each bounds what one request will do.
const ( BadgeAdded = "added" BadgePresent = "present" BadgeNoReadme = "no_readme" BadgeUnread = "unread" BadgeOff = "off" )
The values MigrationResult.Badge takes.
const ( EnvCargoBuildJobs = "CARGO_BUILD_JOBS" EnvDotnetProcessors = "DOTNET_PROCESSOR_COUNT" EnvJavaToolOptions = "JAVA_TOOL_OPTIONS" )
The variables that tell a toolchain how many CPUs to size its workers for. Each of these reads the container's CPU quota once, at start, and never again, so a job started at its guarantee has workers for its guarantee and no worker to use a loan that arrives a minute later.
const ( AdviceBoundAsked = "asked" AdviceBoundRetention = "retention" )
What bounded the window the figures were read over.
const ( HelperReady = "ready" HelperMissing = "missing" // HelperUnsupported is a controller the helper can never be installed // beside, where the install command would only refuse. HelperUnsupported = "unsupported" )
The helper's states as the status names them.
const ( HostUpdateNone = "none" // HostUpdateUnsupported is a host behind the controller that the update // helper can never be installed on, so the command on its card is the way. HostUpdateUnsupported = "unsupported" )
The states of a host with no attempt worth showing.
const ( // SizingAutomatic is one slot's guaranteed share of whichever host the runner lands // on: charged by scheduler.Reserve and applied as a real cgroup limit by // scheduler.Allocation, so the books and the cgroups say the same thing. // It is what a pool means by naming no size, and it keeps fitting when a // bigger machine joins the fleet -- which a figure typed once does not. SizingAutomatic = "automatic" // SizingElastic is the same guaranteed host share, with unused CPU lent // to busy runners while fresh host measurements say it is safe. SizingElastic = "elastic" // SizingFixed is the figures on the pool, the same on every host. SizingFixed = "fixed" // SizingProfile is the size each host's runner profile names: one pool whose // runners are as big as the machine they land on was said to be, and the // fleet's default where a host says nothing. It is automatic sizing with the // host's own answer in place of a slot's share. SizingProfile = "profile" )
PoolWarnings renders a pool's dangerous settings as problems.
They are the same sentences the UI's problems drawer shows, because an operator should not have to learn that "host-socket" on the pool page and "any job on this pool can become root on the host" on the Overview are the same fact.
The installation is there for the one risk a pool cannot see in itself, the repository cache below. Nil when it is unknown, which validation reports on its own. The two ways a pool decides how much machine one of its runners gets.
const AssistantMaxWait = 10 * time.Second
AssistantMaxWait is the longest one of Eli's waits for a change may hold. Calls in a round run one after another and the limit is on calls, not time, so at the tools' own 25 seconds a model that queued its twelve calls as waits would spend the whole of the answer's deadline on them and lose it.
const AssistantWindowBlock = assistantToolResultBytes * 3 / 4
AssistantWindowBlock is what Eli's toolbox asks the fleet window tools to hold each block of an answer to. Under assistantToolResultBytes, the tools cut a large window on whole rows, with a cursor naming the last row kept, before the ceiling here would cut by bytes from the front: that keeps the end, which starts inside a row and, for the events, sits under a cursor that has moved past the rows it dropped. The quarter left over is room for hiding, which writes "[redacted email]" over an address shorter than it.
const EnvDockerWait = "ZOOMIES_DOCKER_WAIT"
EnvDockerWait is the variable the runner image reads for how long to wait for its pool's Docker daemon, in whole seconds. The fleet's runners.docker_wait is rendered into it; a pool's own env may name it to say otherwise.
const ( // HostCheckCooldown is how soon after a request the same host may be asked // again. It runs from the request, lives in controller memory, and is not // cleared by a failure: clearing on failure would let a token in a loop hammer // an agent that fails fast. It is a judgement value, not a measurement. HostCheckCooldown = 15 * time.Second )
const InstallationArchiveKind = "zoomies-installation"
InstallationArchiveKind names the document, so an import can tell an installation archive from a settings export or anything else somebody points it at before it reads a single row.
const ( // LeaseTTL is how long a controller's claim on the database stands without // being renewed. It is comfortably longer than the renewal interval, so a // slow disk or a paused process does not lose a lease it still holds, and // short enough that a controller killed rather than stopped does not keep // a fleet waiting for long. LeaseTTL = 90 * time.Second )
const ManagedRunnerGroupName = "zoomies"
ManagedRunnerGroupName is the organisation runner group Zoomies provisions and uses for pools that do not explicitly choose another one.
const SeedEnvVar = "ZOOMIES_SEED_DEMO"
SeedEnvVar names the environment variable that turns demo seeding on. The Playwright suite sets it (see web/tests/support/serve.mjs) so the UI has a fixture fleet to render.
const StuckSeedEnvVar = "ZOOMIES_SEED_STUCK"
StuckSeedEnvVar names the environment variable that adds the diagnostics fixture on top of the demo fleet.
It is separate from ZOOMIES_SEED_DEMO on purpose, and it is the opposite of what a demo wants. The demo deliberately keeps its two starting runners young (see freshenDemoRunners) so an instance left open never reports a fault in a fleet that has no agent to have one. Every diagnostic this project has for a fleet in trouble -- the problems drawer, the stuck-runner shapes, the blocked pool, the held job -- is therefore unreachable from the demo, which is why they went untested until this existed.
Nothing here is for an operator. It exists so a test can open the pages an operator opens on their worst day.
const ( // StuckThrottledHostName is the fixture's throttled host, named here so // a browser test can find its card. StuckThrottledHostName = "demo-throttled-1" )
The diagnostics fixture's own identifiers. They begin "demo" after the prefix, so IsDemoID covers them and every guard that keeps a fixture out of a real fleet applies to them unchanged.
const UnmatchedPool = "unmatched"
UnmatchedPool is the `pool` label for work no pool here claims.
A literal rather than an empty string, because Prometheus has no notion of an absent label value and a blank one is indistinguishable from a bug. A real pool named `unmatched` would merge with it; that is a price worth naming in the docs rather than designing around.
const UpdatesSeedEnvVar = "ZOOMIES_SEED_UPDATES"
UpdatesSeedEnvVar names the environment variable that gives a controller a release list of its own to be behind, for the browser suite's Updates project.
The binary that suite drives is a dev build, which no release comparison accepts, so without this the Updates page could only ever say that the build is left alone. The value is not a flag: it is the folder the controller will do its updating through, which the suite makes and names, and unset or empty switches the fixture off. Like the other seeds it is not a setting, and nothing in a real deployment's configuration reads it.
Variables ¶
var ( AssistantLengths = []string{"short", "medium", "long"} AssistantTones = []string{"plain", "balanced", "technical"} )
AssistantLengths and AssistantTones are the choices a style may name, in the order the UI offers them.
var ( ErrWorkflowCancellationDisabled = errors.New("workflow cancellation is disabled") ErrJobAlreadyCompleted = errors.New("the job has already completed") // ErrJobNotFinished and ErrJobDidNotFail are the two ways a re-run is // refused for the job's own sake rather than for a missing permission, and // they are separate because the advice differs: one is "wait", the other is // "you are looking at the wrong job". ErrJobNotFinished = errors.New("the job has not finished") ErrJobDidNotFail = errors.New("the job did not fail") )
var ( // ErrKennelOff is the answer to anything that needs Kennel Club's rows while // it is off. The API turns it into a 409 that says where to turn it on. ErrKennelOff = errors.New("kennel club is off") // ErrKennelWaiverLimit means a repository already has as many waivers as it // may. ErrKennelWaiverLimit = errors.New("kennel club: this repository has as many waivers as it may") // ErrKennelNotTracked is the answer to anything that needs Kennel Club's // findings for a repository it has been told not to look at: it has none, and // reading or deciding about findings that are not there would be guessing. ErrKennelNotTracked = errors.New("kennel club: this repository is not tracked") // ErrKennelUntrackNeedsAdmin is a request to stop Kennel Club looking at a // repository by somebody who may only start it again. ErrKennelUntrackNeedsAdmin = errors.New("kennel club: stopping tracking a repository takes the administrator role") )
var ( // ErrNoMigrationPool means the installation has no enabled pool, so there // is nowhere to send a job and nothing to plan. ErrNoMigrationPool = errors.New("there is nowhere to migrate to: this installation has no enabled pool") // ErrNothingMapped means the apply request maps no hosted label to a pool // and points no single job at one either, so no workflow would change. ErrNothingMapped = errors.New("nothing would change: no hosted label is mapped to a pool, and no job is pointed at one by name") // ErrNotAWorkflow means the apply request named a file GitHub would never // run, which would be a pull request that quietly changed nothing. ErrNotAWorkflow = errors.New("only files directly under .github/workflows can be migrated") // ErrBadOverride means an override named something other than one job in // one workflow file in one repository, so there is no single place for it // to apply to. ErrBadOverride = errors.New("an override names one job in one workflow file in one repository") )
var ( // ErrUpdateModeOff refuses every update while updates.mode is off, which is // the promise that mode makes: Zoomies says a release exists and does nothing // about it. ErrUpdateModeOff = errors.New("updates.mode is off, so this controller updates nothing; set updates.mode to manual on the Settings page to update from here") // ErrUpdateHelperMissing refuses an update nothing on the host could carry // out. Only the helper, installed by the host's owner, may replace a binary. ErrUpdateHelperMissing = errors.New("the update helper is not ready on this host") // ErrUpdateInProgress refuses a second update while one is open for the same // target, so that two people, or a person and the planner, never send two // requests. ErrUpdateInProgress = errors.New("an update is already in flight for this target; wait for it to finish, or for it to time out after 90 minutes, before asking again") // ErrUpdateNotARelease refuses to update a build that did not come from a // release. A build from main is usually ahead of every release, and taking one // would be a downgrade. ErrUpdateNotARelease = errors.New("this controller is not running a release, so no release can be compared with it: a build from main is usually ahead of every release; install a release with zoomies upgrade to update from here") // ErrUpdateNothingNewer refuses an update that would change nothing, or would // go backwards. ErrUpdateNothingNewer = errors.New("there is no newer release to take") // ErrUpdateHostCannotUpdate refuses to update a host whose agent cannot // update itself, because no helper has been installed on it. ErrUpdateHostCannotUpdate = errors.New("this host cannot update itself: its agent does not offer it, which it does only once the update helper is installed on the host; run \"sudo zoomies updates helper install\" there, or update it by hand") // ErrUpdateRolloutHalted refuses to start an update while a rollout is halted // after a failure, which is waiting for a person to look. ErrUpdateRolloutHalted = errors.New("the rollout is halted after a failed update; resume it or cancel it before starting another") // ErrUpdateFenced refuses an update while this controller may not act: the // fleet is fenced for recovery, or another controller holds the database's // lease. A restored copy must not replace the binary of a live deployment. ErrUpdateFenced = errors.New("this controller may not act right now, so it starts no update") )
The refusals of an update. Each is a sentinel so that the API can give it a stable code, and each is written for the person who pressed the button: what stopped it, and what to change. A refusal that needs a detail (which folder, which release) wraps its sentinel, so the code survives the detail.
var AssistantFleetTools = []string{
"fleet_status", "list_problems", "list_jobs", "get_job", "job_stats",
"list_runners", "list_pools", "list_hosts", "host_health", "label_advice",
"get_runner_log", "kennel_overview", "kennel_repository", "kennel_findings",
"list_providers", "provider_pairings", "list_machines", "get_catalog", "get_usage", "get_pr_delay", "get_retained_comparison",
"recent_events", "wait_for_change", "scaling_decisions", "fleet_samples",
"host_samples", "runner_timeline", "list_workflow_runs",
"queue_wait_breakdown", "compare_periods", "host_pressure", "startup_failures",
"list_elis_repairs", "get_eli_repair",
}
AssistantFleetTools is every tool Eli may be offered, and nothing else is. It is a list of names and not "whatever the MCP server has" because what Eli is offered can leave the machine, to a hosted model, and a tool added to the MCP server for an agent a person runs is not a decision anyone took about that. The api package's tests hold this list against the server's own: a new read tool has to be named here or named as left out, which is the decision.
Left out on purpose: the context_* tools, which read a repository's source and are the most that could leave the building; the configuration and note tools; the webhook deliveries, the audit log and the support bundle, which are GitHub's whole payloads, who did what by name, and the whole instance at once; and every tool that changes the fleet. That last half is why a repair write (a request, an accept, a clear, a policy) can never reach the list: a repair spends an attempt and pushes to a pull request, so the press is a person's at the repairs page. The history itself is the feature's read, added so a question about why a repair is stuck is answered by looking, the way the other resources are.
var AssistantWithheldKinds = []string{"audit", "webhook.delivery"}
AssistantWithheldKinds are the event kinds Eli's toolbox never asks for. The audit log and the webhook deliveries are left off Eli's list by the owner's choice, and their frames are the same rows one at a time, so the event tools leave them out too rather than hand a hosted model what the list keeps from it.
var ErrAIContextUploadRefused = errors.New("this upload is not from the repository's managed workflow on its trusted branch")
ErrAIContextUploadRefused is a valid Actions token that does not entitle this upload: the wrong workflow, branch, event or commit. The wrapped text says which, for the workflow log; it never carries source.
var ErrAIContextUploadSuperseded = errors.New("this upload has been superseded")
ErrAIContextUploadSuperseded is an upload for a commit that is no longer the head of the trusted branch, or a token that has already been used. Either way a later run is the one that counts.
var ErrArchive = errors.New("installation archive")
ErrArchive is an archive or passphrase the operator can do something about: the wrong file, a missing or wrong passphrase, or no instance key to seal the secrets under once they are open.
var ErrAssistantCannotList = errors.New("this provider cannot list its models; type the model's name")
ErrAssistantCannotList is a provider that has no list of models to give.
var ErrAssistantNoModel = errors.New("no assistant model is set up")
var ErrAssistantNotYours = errors.New("that provider is another person's own subscription, and only they may use it")
ErrAssistantNotYours is a chat asked through somebody else's own subscription.
var ErrAssistantSubscriptionRestricted = errors.New("subscription tools on the controller require administrator permission")
ErrAssistantNoModel is a chat asked of an instance with no enabled provider to answer it, or of a provider that is not one.
var ErrBackupRunning = errors.New("controller: a backup is already being taken; wait for it to finish")
ErrBackupRunning is a second backup asked for while one is being taken.
var ErrConfirmationRequired = errors.New("this runner is running a job, and draining it will end that job")
ErrConfirmationRequired is an operator asking to drain a runner that is running a job, without having said they accept losing it.
A drain is not the gentle option it reads as. The stop task carries agent.DefaultStopTimeout, so the runner gets five minutes and is then killed; a twenty-minute job drained at minute one dies at minute six and GitHub marks it failed. That is the behaviour -- an operator draining a host for maintenance needs the machine to actually empty -- but it must not be something they get by accident, so the paths an operator reaches ask first.
The scheduler is deliberately not subject to this. It reaches a drain through the unexported drainRunnerID, and never proposes one for a busy runner in the first place; automatic scale-down must not be waiting on anybody to confirm.
var ErrDemoFixture = errors.New("this is a seeded demo installation with no GitHub App behind it")
ErrDemoFixture is returned by the demo installation for anything that would have to reach GitHub to be true.
var ErrDiscoveryUnsupported = errors.New("this provider cannot list what its credential can see")
ErrDiscoveryUnsupported is a provider whose driver cannot list what a credential can see. The guided form asks the operator to type identifiers instead, so this is reported rather than hidden.
var ErrEliErrorOutputDenied = errors.New("controller: error output is only for people who can write to the repository")
ErrEliErrorOutputDenied is a caller who may not read a job's error output: no confirmed GitHub account, no write access to the repository through it, or a repository no installation serves. They are one error on purpose; which of them it was is not something to tell a person who may not know the repository.
var ErrExperimentAdmission = errors.New("workflow comparison diagnostic reads are temporarily limited")
var ErrExperimentEvidence = errors.New("comparison evidence is incomplete or inconsistent")
var ErrExperimentUnsupported = errors.New("this installation cannot read workflow-attempt comparison evidence")
var ErrHostAcceptLimit = errors.New("this host already has as many accepted checks as it may; revoke one that is no longer needed first")
ErrHostAcceptLimit is a host that already holds as many acceptances as it may.
var ErrLimitReached = errors.New("limit reached")
ErrLimitReached marks a refusal because one of the limits.* ceilings has been reached. The API answers it with a 409 and the stable code limit_reached, since the request is well formed and would succeed on an instance with room: it is the state of the fleet that refuses it, not the request.
var ErrOptimisationPolicy = errors.New("optimisation previews are not enabled: turn on optimisation.source_reads and optimisation.workflow_edits")
ErrOptimisationPolicy means the server's own settings do not permit reading workflow source or previewing a workflow edit. It is separate from ErrOptimisationPreview so a transport can name the setting to change.
var ErrOptimisationPreview = errors.New("optimisation preview evidence is unavailable, inconsistent or unsupported")
var ErrPRDelayAdmission = errors.New("PR delay diagnostic reads are temporarily limited")
var ErrPRDelayClosed = errors.New("the PR is closed; its checks are not a current PR gate")
var ErrPRDelayEvidence = errors.New("PR delay evidence is incomplete or inconsistent")
var ErrPRDelayJobHeadChanged = errors.New("the selected job is not on the current PR head; select a job from that head")
var ErrPRDelayTargetChanged = errors.New("the PR target branch changed; refresh its delay evidence")
var ErrPRDelayUnsupported = errors.New("this installation cannot read PR delay evidence")
var ErrPrewarmUnsupported = errors.New("the process backend does not support image prewarming; its runners install the runner archive themselves")
PrewarmPool queues one idempotent image preparation task on every matching healthy host. A failure is recorded per host and never affects scheduling. ErrPrewarmUnsupported is returned for a pool whose backend has no image to pull ahead of time. It is a refusal the caller can act on, kept apart from a failure to list hosts so the API can answer the two differently.
var ErrProviderKindUnknown = errors.New("this build has no driver for that provider kind")
ErrProviderKindUnknown is a provider row, or a draft, naming a kind this build has no driver for. It is a conflict rather than a validation failure for a stored row -- the row was legal when it was written -- and the message names the kind so an operator knows which build they need.
var ErrReportTooLarge = fmt.Errorf("controller: a report carried more than %d runners", agent.MaxRunnersPerReport)
ErrReportTooLarge is a heartbeat or runner report carrying more runners than agent.MaxRunnersPerReport. The API answers it with a 413.
var ErrRunHasNoQueuedJobs = errors.New("no job of this workflow run is queued for this fleet")
ErrRunHasNoQueuedJobs is a run-level provisioning action on a run none of whose jobs is waiting for a runner here: every job has started or finished, or the ones still queued were removed from the queue and are restored from the Queue page rather than swept back in with their siblings.
var ErrSameRelease = errors.New("a and b name the same release, so there is nothing to compare; name two different releases, or leave a out to compare with the release before b")
ErrSameRelease is a release comparison asked to compare a release with itself, which would read as a release that held still.
var ErrShippingRunning = errors.New("controller: the backups are already being copied offsite; wait for that to finish")
ErrShippingRunning is a second offsite pass asked for while one is running.
var ErrSinceNotPast = errors.New("since is not before now, and an analysis reads only what has already happened; choose a since in the past")
ErrSinceNotPast is a period that begins at or after now. Nothing in it has happened, so any answer would be about an empty period read as a quiet one.
var ErrStreamUnknown = errors.New("controller: no log stream is open with that ID")
ErrStreamUnknown is returned when an agent posts a log stream nobody is waiting for, which happens whenever the last viewer closed the tab between the task being issued and the agent acting on it.
var ErrTestMachineRefused = errors.New("a test machine cannot be started")
ErrTestMachineRefused is a test that cannot be started, with the sentence that says why and what to change. The API answers it with a 409.
var ErrTooFewReleases = errors.New("fewer than two releases completed a job in this period, so there is no pair to compare; name the releases with a and b, widen the period, or compare by period")
ErrTooFewReleases is a release comparison asked to choose its releases when fewer than two completed a job in the period. Pairing the one there is with the jobs no release stamped, or with nothing, would read as a verdict on it.
var ErrToolchainScanRunning = errors.New("a toolchain scan is already running")
ErrToolchainScanRunning is returned when a scan is asked for while one is already under way; the running one's result is the answer.
var ErrUnknownHost = errors.New("no host has that id")
ErrUnknownHost refuses a rollout of a host id that names no host. It is not store.ErrNotFound, which the API answers as the route's own 404: an id the caller sent is the body to fix.
var ErrUpdateCheckDisabled = errors.New("the release check is switched off, so this controller does not ask github.com which release is current; set updates.check_interval to a duration such as 24h to turn it on")
ErrUpdateCheckDisabled is the answer to asking for a release check while updates.check_interval is 0. That setting is the air-gap switch: it keeps the one request Zoomies makes to github.com that is not about the fleet from ever being made, and a button must not make it either.
var ErrUpdateCheckFailed = errors.New("the release check could not be completed")
ErrUpdateCheckFailed is the answer to a release check that GitHub, or the network to it, did not allow to finish. It is not a refusal of the person's request: the request was fine, and what failed is outside this controller. The error that carries it keeps its own sentence, which says what failed and what to try, because that is what the person who pressed the button can act on.
var ErrWholeDaysOnly = errors.New("a period older than retention.jobs can only be read in whole UTC days")
ErrWholeDaysOnly is a by-period comparison one of whose sides is older than retention.jobs and has no midnight inside it to end on. The roll-up keeps whole UTC days, so such a side would read the other side's hours as its own, or nothing at all. The error a caller sees is a wholeDaysError, which says which side and what to change.
var KennelSources = []kennel.Source{kennel.SourceFleet, kennel.SourceMetadata, kennel.SourceRuns, kennel.SourceSetup, kennel.SourceWorkflows, kennel.SourceGuidance, kennel.SourceSettings, kennel.SourceProtection}
KennelSources is the order a repository's sources are listed in.
Functions ¶
func AnalysePRDelayEvidence ¶ added in v1.3.8
func AnalysePRDelayEvidence(in PRDelayInput) (analysis.MergeDelayResult, error)
AnalysePRDelayEvidence joins transient GitHub check names to required checks and verifies job-link hints against fleet records before calling the pure core. It reads no source, executes nothing and returns no repository names chosen for checks, workflows or jobs.
func AssistantOutputLimit ¶ added in v1.3.8
func AssistantOutputLimit(row *store.AssistantProvider) int
AssistantOutputLimit is how much a provider's model may write in one round: what its row asks for, or the controller's default when the row says nothing. It is said on the done frame, so a cut answer can tell the person what to raise and on which provider.
func CertificateProblem ¶ added in v1.3.8
CertificateProblem says what is wrong with text that is meant to be one or more PEM certificates, or returns "" when there is nothing wrong. Nothing at all is fine: an empty box means the system's trust store.
It is written for a person looking at the box the text is in. A private key is named as one, because that is the mistake a cluster invites (its authority keeps the private half beside the public one), and the text itself is never repeated, so a key pasted by mistake is not echoed into a response or a log.
func DemoRequested ¶ added in v1.3.8
func DemoRequested() bool
DemoRequested reports whether the demo fixtures were asked for, for the one API decision that follows from it: the fake assistant provider may be edited where the demo seeded it and created nowhere else.
func EffectiveMinimum ¶ added in v1.3.8
EffectiveMinimum is the minimum size a pool's runners are actually held to: the pool's own figure on a field where it set one, and otherwise the fleet's runners.minimum_cpus / runners.minimum_memory_mb.
The fleet figure is read live rather than copied into the pool when it is created, so changing it moves every pool that never said otherwise on the next pass -- and saving a pool never freezes today's value into it. A fleet minimum at or above a pool's typed standard size means nothing for that pool (the same rule the wizard's opening value follows), and is ignored there. On an automatic field it applies as-is: below a host's slot share it is how far a runner may be reduced, and above it the scheduler gives each runner the minimum (scheduler.MinimumSlot).
func HostRefusal ¶ added in v1.3.8
HostRefusal says which of the rules that are configuration -- rather than weather -- this host fails for this pool, and why, in the operator's terms. It is empty when the host could run the pool.
The order is the scheduler's own, so the reason given is the first rule the host actually failed, and the sentences are written about "it" with the host's name left out, so a caller can put the name where its layout wants it. HostFit renders its exclusions from here, and so does every refusal an edit produces: the count before a pool exists and the refusal that stops one being stranded are the same fact, and they are said in the same words.
func IsDemoID ¶
IsDemoID reports whether an identifier belongs to the seeded demo fixtures.
The fixtures have no GitHub behind them, so the two places that would otherwise reach out on their behalf -- the credential prober and the registration reaper -- check this and skip. Without it a demo or a UI test run fills the problems drawer with "this installation is not usable" and the log with parse failures, none of which says anything about the fleet.
A fixture's identifier begins "demo" after its prefix and is never the shape store.NewID produces. Both halves matter: the prefix alone also matched a real identifier whose random part happened to start with those four letters, which one row in a million does, and such an installation was then skipped by the prober, the poller and the reap, and such a host was never reclaimed. A test in this package holds every fixture literal to the rule.
func JobEventFor ¶ added in v1.3.8
JobEventFor is a timeline entry as one audience may read it. A visitor to a public view reads that a failure was marked as known, or put back, and when, and not by whom. The sentence is rebuilt from the entry's kind rather than the stored one being trimmed, so no name can survive in what an older version, or a rename, left in the row.
func OptimisationHistoryReview ¶ added in v1.3.8
func OptimisationHistoryReview(headSHA, sourceSHA256 string) optimisation.HistoryReview
OptimisationHistoryReview builds the operator's declaration from what they were shown. The scope is fixed here; a request supplies only the digest and head it reviewed, and the preview refuses any that no longer match.
func PoolEffectiveDockerWait ¶ added in v1.3.8
PoolEffectiveDockerWait is how long this pool's runners actually wait for their daemon: the pool's own override where it has one, the fleet's figure where it does not, and the runner image's own two minutes where neither says. Zero from either means "the image chooses", never "no wait".
func PoolSizing ¶ added in v1.3.8
PoolSizing says which of the ways a pool decides its runners' size it is using.
func PublicSentence ¶ added in v1.3.8
PublicSentence is what the status page says about a code, for a reader who cannot act on the fleet and wants to know whether to wait.
func RemedyBase ¶ added in v1.3.8
RemedyBase is the fingerprint a remedy's Base and the object it will replace are compared by.
func SpanRefusal ¶ added in v1.3.8
SpanRefusal is the sentence that refuses a period longer than limits.job_stats_window, which bounds the job statistics and every analysis alike. what is the reader and its verb, "job statistics cover" or "an analysis covers", so the routes and this package say one sentence and neither borrows the other's noun.
func UsableBy ¶ added in v1.3.8
func UsableBy(row *store.AssistantProvider, userID string) bool
UsableBy is whether an account may use a provider: any administrator may use one that is shared, and only its owner one that is somebody's own subscription.
func ValidateAssistantChat ¶ added in v1.3.8
func ValidateAssistantChat(in []AssistantChatMessage) ([]assistant.Message, error)
ValidateAssistantChat says what is wrong with a conversation, or returns the turns to send. It is separate from StartAssistantChat so the limits can be held by a test that needs no model.
Types ¶
type AIContextDiscovery ¶ added in v1.3.8
type AIContextDiscovery struct {
Repositories []github.Repository `json:"repositories"`
CanReadContents bool `json:"can_read_contents"`
MissingSetupPermissions []string `json:"missing_setup_permissions"`
DefaultExclusions []string `json:"default_exclusions"`
DefaultKeepSnapshots int `json:"default_keep_snapshots"`
Capped bool `json:"capped"`
// ZoomiesUploadAvailable says whether this controller can take
// Zoomies-only uploads at all: GitHub's runners need an https address.
ZoomiesUploadAvailable bool `json:"zoomies_upload_available"`
}
AIContextDiscovery describes candidates only; discovery never grants source access, enables a repository or changes the GitHub App's permissions.
type AIContextDraftRequest ¶ added in v1.3.8
type AIContextDraftRequest struct {
InstallationID string `json:"installation_id"`
RepositoryID int64 `json:"repository_id"`
}
AIContextDraftRequest selects a discovered identity, never a caller-supplied host or name. Those fields must come from the installation's own metadata.
type AIContextMaintenanceRequest ¶ added in v1.3.8
type AIContextRefusal ¶ added in v1.3.8
type AIContextRefusal struct{ Message string }
AIContextRefusal is a regeneration Zoomies declined for a reason the operator can fix. The message is written to be shown as it is.
func (*AIContextRefusal) Error ¶ added in v1.3.8
func (e *AIContextRefusal) Error() string
type AIContextSetupApproval ¶ added in v1.3.8
type AIContextSetupPreview ¶ added in v1.3.8
type AIContextSetupPreview struct {
Mode string `json:"mode,omitempty"`
Config *aicontext.Config `json:"config,omitempty"`
PreviousHash string `json:"previous_hash,omitempty"`
Revision int64 `json:"revision"`
BaseCommit string `json:"base_commit"`
Branch string `json:"branch"`
PlanHash string `json:"plan_hash"`
Files []aicontext.SetupChange `json:"files"`
Setup *store.AIContextSetup `json:"setup,omitempty"`
}
type AcceptInput ¶ added in v1.3.8
type AcceptInput struct {
CheckID string
// SeenCurrent is what the person read when they decided. The acceptance is
// recorded against the stored report's text, never this, and only when the
// two agree.
SeenCurrent string
Reason string
ExpiresAt time.Time
}
AcceptInput is a request to accept one host's check as deliberate.
type AdviceOptions ¶ added in v1.3.8
AdviceOptions narrows a request for label advice: a window the figures behind each row are read over (zero is scheduler.ClassWindow, the span the class itself is decided over) and a repository, compared as GitHub does.
type AdviceWindow ¶ added in v1.3.8
type AdviceWindow struct {
Asked store.Duration `json:"asked"`
Applied store.Duration `json:"applied"`
Bound string `json:"bound"`
}
AdviceWindow is the span the figures behind a page of advice cover: what was asked, what applied, and which of the two bounded it. A window longer than the history the fleet keeps would promise figures over runs that were pruned, so retention is the ceiling and the answer says when it was hit.
type AnalysisWindow ¶ added in v1.3.8
AnalysisWindow is the period an analysis reads: Since inclusive, Until exclusive, as the job routes' are.
type ArchiveSecrets ¶ added in v1.3.8
type ArchiveSecrets struct {
PrivateKey []byte `json:"private_key,omitempty"`
WebhookSecret []byte `json:"webhook_secret,omitempty"`
}
ArchiveSecrets are passphrase-sealed values (cryptox.SealWithPassphrase), base64 in JSON.
type AssistantChat ¶ added in v1.3.8
type AssistantChat struct {
// Provider, ProviderID and Model say who answers, as the row names them.
Provider string
ProviderID string
Model string
// FleetAccess is whether Eli was offered the fleet's tools in this chat.
FleetAccess bool
// OutputLimit is how much the model may write in one round of this chat,
// so a cut answer can say what to raise.
OutputLimit int
// contains filtered or unexported fields
}
AssistantChat is an answer in progress, which may take several questions to the model: each time it asks for tools, they are run and it is asked again with what they showed.
func (*AssistantChat) Close ¶ added in v1.3.8
func (a *AssistantChat) Close()
Close ends the answer and releases the connection to the model.
func (*AssistantChat) Next ¶ added in v1.3.8
func (a *AssistantChat) Next(ctx context.Context) (AssistantChatEvent, bool)
Next is the answer's next event. Tool calls are never passed on: they are run here, and said as tool events before and after, so the caller sees Eli look at something without being in the business of looking.
func (*AssistantChat) Redactions ¶ added in v1.3.8
func (a *AssistantChat) Redactions() redact.Result
Redactions is how many credentials and email addresses were hidden from the model in this chat, in what the person sent and in what the tools returned. Only the counts are kept: what was hidden is not recorded anywhere.
func (*AssistantChat) ToolsUsed ¶ added in v1.3.8
func (a *AssistantChat) ToolsUsed() []string
ToolsUsed are the names of the tools Eli called, in order, with repeats. It is what the page shows under the answer and what the audit row records.
type AssistantChatEvent ¶ added in v1.3.8
type AssistantChatEvent struct {
Delta string
Tool *AssistantToolUse
Usage *assistant.Usage
Done bool
Cut bool
Err error
}
AssistantChatEvent is one thing an answer yields. Cut, on Done, says the provider stopped the answer at its output ceiling, so the page can say so rather than show what arrived as the whole answer.
type AssistantChatInvalid ¶ added in v1.3.8
AssistantChatInvalid is a request that cannot be answered as sent. The field names the part of the body to fix.
func (*AssistantChatInvalid) Error ¶ added in v1.3.8
func (e *AssistantChatInvalid) Error() string
type AssistantChatMessage ¶ added in v1.3.8
AssistantChatMessage is one turn the person's page holds. Only the person's words and the model's earlier answers are accepted: a system or tool message from a client would be a way to speak with the operator's voice.
func ValidateAssistantTranscript ¶ added in v1.3.8
func ValidateAssistantTranscript(in []AssistantChatMessage) ([]AssistantChatMessage, error)
ValidateAssistantTranscript is ValidateAssistantChat for a conversation being kept rather than sent: the same roles and the same limits, since what is kept is what the page would send back, but it may end with the answer, which is how a conversation is when a person stops reading it.
type AssistantChatRequest ¶ added in v1.3.8
type AssistantChatRequest struct {
Personal bool
AllowSubscription bool
// ProviderID names the provider to ask, or is empty for the default.
ProviderID string
OwnerID string
Messages []AssistantChatMessage
// UserID is the account asking. A provider that belongs to somebody is used
// only by them: it is what Anthropic's terms ask of a subscription.
UserID string
// Tools is what the fleet can be read with, as the person asking: nil when
// there is none. Eli is offered it only if the provider is one the
// administrator let read the fleet, and only the part of it that
// AssistantFleetTools names.
Tools AssistantToolbox
// Page is the path of the page the question was asked from, or empty: what
// "here" means in "what is wrong here". Role is the asker's RBAC role, or
// empty when authentication is off.
Page string
Role string
// Style is how the person wants the answer written.
Style AssistantStyle
}
AssistantChatRequest is a conversation so far, ending in a question. The controller keeps nothing between requests; the page holds the history.
type AssistantProviderCheck ¶ added in v1.3.8
type AssistantProviderCheck struct {
OK bool `json:"ok"`
Model string `json:"model,omitempty"`
LatencyMS int64 `json:"latency_ms"`
UsageReported bool `json:"usage_reported"`
Error string `json:"error,omitempty"`
CheckedAt time.Time `json:"checked_at"`
}
AssistantProviderCheck is what a check learned, as the row keeps it and the page shows it. Error is written for a person and never carries the request; the adapters' status errors see to that.
type AssistantProviderView ¶ added in v1.3.8
type AssistantProviderView struct {
OwnerID string `json:"owner_id"`
ID string `json:"id"`
Name string `json:"name"`
Kind string `json:"kind"`
BaseURL string `json:"base_url"`
Model string `json:"model"`
KeyConfigured bool `json:"key_configured"`
Enabled bool `json:"enabled"`
IsDefault bool `json:"is_default"`
Local bool `json:"local"`
FleetAccess bool `json:"fleet_access"`
// ReasoningEffort is how hard the model is told to think, in the provider's
// words, or empty for its default.
ReasoningEffort string `json:"reasoning_effort"`
// MaxOutputTokens is how much the model may write in one round, or zero for
// automatic: a chat starts at a default and a repair raises the limit itself.
MaxOutputTokens int `json:"max_output_tokens"`
// Subscription is a provider that is somebody's own subscription, used through
// the vendor's own tool on this machine. Owner says whose, and OwnedByYou whether
// the person asking is the one who may use it. Usable is the same question for
// every provider: whether the person asking may.
Subscription bool `json:"subscription"`
Owner string `json:"owner,omitempty"`
OwnedByYou bool `json:"owned_by_you"`
Usable bool `json:"usable"`
LastCheck *AssistantProviderCheck `json:"last_check,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AssistantProviderView is one of the assistant's providers as the API renders it. The key has no field it could be in: KeyConfigured says one is sealed on the row, which is all a form needs. Local says the address is on this machine or a private network, which is what the page shows beside the local-only switch.
type AssistantStyle ¶ added in v1.3.8
type AssistantStyle struct {
// Length is short, medium or long, or empty for short.
Length string
// Tone is plain, balanced or technical, or empty for balanced.
Tone string
}
AssistantStyle is how the person wants answers: how long, and for whom. The zero value is the default, short and for an operator. It is the person's choice and not the provider's, because it is about who reads the answer.
type AssistantToolUse ¶ added in v1.3.8
type AssistantToolUse struct {
Name string
// Status is running, done or failed.
Status string
// Reason is why a look failed, in one line, for the page to show beside the
// name: a code that is not in the catalog, a route that refused. It is what
// the model was told, which is Zoomies' own text or the fleet's, after
// hiding.
Reason string
}
AssistantToolUse is Eli looking at something, said as it happens so the page can show it.
type AssistantToolbox ¶ added in v1.3.8
type AssistantToolbox interface {
// Tools lists everything the box has. The controller narrows it.
Tools() []assistant.Tool
// Call runs a tool and returns its answer block by block, as the tool made
// them, so a block a tool set apart as a stranger's words stays apart in
// front of the model. failed is true when the tool answered with a refusal
// or an error, which is text for the model to read; err is for a call that
// could not be made.
Call(ctx context.Context, name string, args json.RawMessage) (blocks []string, failed bool, err error)
}
AssistantToolbox is the fleet's read tools as the person asking may use them. The api package builds it over the same in-process routes, with the same identity, that an MCP client of theirs would reach, so Eli can see nothing the person could not.
type Audience ¶ added in v1.3.8
type Audience string
Audience says which of an instance's two audiences a problem is for.
An instance one team operates while another uses the fleet has two lists, not one. The platform's is what the process is doing wrong -- its lease, its loops, its backups, the release it could be running. The fleet's is what its own runners are doing wrong. Showing either audience the other's is a leak in one direction and noise in the other: a fleet told its controller's backup remote is unreadable can do nothing about it, and learns the instance has a backup remote.
const ( // AudiencePlatform is for whoever runs the process. AudiencePlatform Audience = "platform" // AudienceFleet is for whoever runs the fleet. AudienceFleet Audience = "fleet" // AudienceBoth is for the handful that are genuinely both people's, of // which there is currently one: a list that could not be fully gathered // has to say so to whoever is reading it. AudienceBoth Audience = "both" )
type AutoPoolPending ¶ added in v1.3.8
type AutoPoolPending struct {
Kind string `json:"kind"`
Key string `json:"key"`
Pool string `json:"pool"`
Cause string `json:"cause"`
}
AutoPoolPending is a change the controller would make and has not, because it is being watched rather than trusted.
type AutoPoolSkip ¶ added in v1.3.8
type AutoPoolSkip struct {
Host string `json:"host"`
HostID string `json:"host_id"`
Reason string `json:"reason"`
Message string `json:"message"`
}
AutoPoolSkip is a host that counts towards no automatic pool. Reason is the stable code and Message the sentence that says what it means for the host.
type AutoPoolStatus ¶ added in v1.3.8
type AutoPoolStatus struct {
// Mode is scheduler.auto_pools as it was when the pass ran.
Mode string `json:"mode"`
// At is when the pass ran, zero for a controller that has not run one.
At time.Time `json:"at"`
// Installation is the target of the installation the pools belong to, and
// Problem says why there is none when the mode is not off.
Installation string `json:"installation,omitempty"`
Problem string `json:"problem,omitempty"`
// Findings are what the controller could not do, and what to change.
Findings []scheduler.AutoPoolFinding `json:"findings,omitempty"`
// Pools is every pool the controller keeps, or would, with the hosts that
// count towards it and what they give it between them.
Pools []AutoPoolSummary `json:"pools"`
// Skipped is every host that counted towards no pool, and why.
Skipped []AutoPoolSkip `json:"skipped,omitempty"`
// Pending is, under shadow, what the controller would have done.
Pending []AutoPoolPending `json:"pending,omitempty"`
// contains filtered or unexported fields
}
AutoPoolStatus is what the last pass of the automatic pool reconciler found.
type AutoPoolSummary ¶ added in v1.3.8
type AutoPoolSummary struct {
Key string `json:"key"`
// Name is the pool's, or what it would be called under shadow. PoolID is
// empty until there is a pool.
Name string `json:"name"`
PoolID string `json:"pool_id,omitempty"`
Hosts []string `json:"hosts"`
// Slots is the runners those hosts hold between them, before any cap.
Slots int `json:"slots"`
}
AutoPoolSummary is a pool the controller keeps, or would, with the hosts that count towards it.
type AutoPoolsView ¶ added in v1.3.8
type AutoPoolsView struct {
SizeRouting string `json:"size_routing"`
AutoPools string `json:"auto_pools"`
// Installation is the target the pools belong to, and Problem says why there
// is none. At is when the last pass ran, null before the first.
Installation string `json:"installation,omitempty"`
Problem string `json:"problem,omitempty"`
At *time.Time `json:"at"`
Pools []AutoPoolSummary `json:"pools"`
Findings []scheduler.AutoPoolFinding `json:"findings"`
Skipped []AutoPoolSkip `json:"skipped"`
Pending []AutoPoolPending `json:"pending"`
Classes []SizeClassLimits `json:"classes"`
DefaultClass store.SizeClass `json:"default_class"`
Hold store.Duration `json:"hold"`
FallbackWait store.Duration `json:"fallback_wait"`
HostGrace store.Duration `json:"host_grace"`
}
AutoPoolsView is the state of size routing and of the pools the controller keeps, as GET /auto-pools returns it.
type BackendInfoView ¶
type BackendInfoView struct {
Kind store.BackendKind `json:"kind"`
Available bool `json:"available"`
Version string `json:"version,omitempty"`
Rootless bool `json:"rootless"`
Endpoint string `json:"endpoint,omitempty"`
Detail string `json:"detail,omitempty"`
DinD bool `json:"supports_dind"`
// Limits is what the daemon said it can enforce, which is what the
// controller defaults a runner's limits from and what
// host.limits_unenforceable reasons about; the API carries it so a
// reader of the problem can see the fact behind it.
Limits store.LimitSupport `json:"limits"`
// agent said; see host.shared_folder_unmounted.
SharedFolder string `json:"shared_folder,omitempty"`
}
BackendInfoView describes one backend a host offers.
type BackupPruning ¶ added in v1.3.8
type BackupPruning struct {
// Keep is backup.keep as the pass read it. Zero keeps every copy, and
// nothing is removed from this host at all.
Keep int `json:"keep"`
// Removed is what was deleted from the backup directory. Copies somebody
// uploaded or pulled back out of a bucket are never in it: Prune itself
// guarantees that, because a copy that arrived here is not one this fleet
// took and retention has no claim on it.
Removed []string `json:"removed"`
// Error is why the directory could not be pruned, in the words the
// filesystem used.
Error string `json:"error,omitempty"`
// Remotes is the same pass over each destination.
Remotes []RemotePruning `json:"remotes"`
}
BackupPruning is what applying retention removed, here and in each bucket.
It is reported per destination rather than as a total because the numbers disagree on purpose: this host keeps backup.keep copies and each remote keeps its own, so "three here, thirty offsite" is a correct fleet and a single count would read like a fault.
type BackupStatus ¶ added in v1.3.8
type BackupStatus struct {
// Directory is where backups are kept, resolved.
Directory string `json:"directory"`
// Interval is backup.interval; zero means scheduled backups are off.
Interval time.Duration `json:"-"`
// Keep is backup.keep.
Keep int `json:"keep"`
// Running says a backup is being taken right now.
Running bool `json:"running"`
// LastScheduledAt is when the loop last tried, LastScheduledID what it
// wrote, and LastError why it did not.
LastScheduledAt time.Time `json:"-"`
LastScheduledID string `json:"last_scheduled_id,omitempty"`
LastError string `json:"last_error,omitempty"`
// NextDueAt is when the next scheduled backup is expected, from the
// newest backup in the directory and the interval. Zero when off.
NextDueAt time.Time `json:"-"`
}
BackupStatus is the state of scheduled backups, for the settings page and the problems drawer.
type Band ¶ added in v1.3.8
type Band string
Band is a count said roughly. The status projection is read by people with no account, and "eleven jobs queued" tells them nothing "many" does not while telling a stranger exactly how big the fleet is.
type CPUResourceView ¶ added in v1.3.8
type CPUResourceView struct {
State string `json:"state"`
Label string `json:"label"`
Reason string `json:"reason"`
GuaranteedCPUs float64 `json:"guaranteed_cpus"`
CurrentCPUs float64 `json:"current_cpus"`
CeilingCPUs float64 `json:"ceiling_cpus"`
Factor float64 `json:"factor"`
// SizedForCPUs is the CPU count the runner's toolchains were told to size
// their workers for when it started; zero when they were told nothing.
SizedForCPUs int `json:"sized_for_cpus,omitempty"`
}
CPUResourceView keeps the playful fleet voice beside exact numbers and a stable state. Operators can scan the label; clients and alerts use State.
type CapacityDemandEvent ¶
type CapacityDemandEvent struct {
SchemaVersion int `json:"schema_version"`
EventID string `json:"event_id"`
Type string `json:"type"`
Timestamp time.Time `json:"timestamp"`
PoolID string `json:"pool_id"`
HostSelector store.StringMap `json:"host_selector"`
Backend store.BackendKind `json:"backend"`
RequiredRunnerSlots int `json:"required_runner_slots"`
CurrentCapacity int `json:"current_capacity"`
QueuedJobCount int `json:"queued_job_count"`
OldestQueueAgeSeconds int64 `json:"oldest_queue_age_seconds"`
}
CapacityDemandEvent is the stable wire contract consumed by provisioners. RequiredRunnerSlots is positive for demand and negative for removable idle capacity. It is a reading, not an increment: the pool should have CurrentCapacity+RequiredRunnerSlots slots, and a receiver that adds RequiredRunnerSlots to whatever it already asked for adds the same shortfall again on every re-delivery, because each attempt after the cooldown carries a fresh EventID for what may be the same unmet demand.
type CheckoutInspection ¶ added in v1.3.8
type CheckoutInspection struct {
Repository string
Selection github.CheckoutSelection
HeadSHA string
Path string
Mode string
Content string
SourceSHA256 string
StepNumber int64
CheckoutMS int64
EvidenceID string
Basis string
InspectedAt time.Time
ReviewDeclared string
// JobName and StepName are the literal names the source gives the job and
// the checkout step that was found, so a person sees "Build, Checkout"
// instead of two positions in a file.
JobName string
StepName string
}
CheckoutInspection is what an operator is shown before declaring that the repository and its downstream consumers do not need full history. It is transient: nothing is retained, so a closed page leaves no source behind.
type CompareRequest ¶ added in v1.3.8
type CompareRequest struct {
// By is "version" (the default when empty) or "period".
By string
// A and B name two releases when By is version. Either left empty is
// taken from the releases that ran jobs in the period, the latest first.
A, B string
Since, Until time.Time
}
CompareRequest is what AnalyseCompare compares.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller owns the control plane's moving parts and their lifecycles.
func New ¶
func New(opts Options) (*Controller, error)
New validates the options and builds a controller that is not yet running.
func (*Controller) AIContextDiagnosis ¶ added in v1.3.8
func (c *Controller) AIContextDiagnosis(r *store.AIContextRepository) *aicontext.Diagnosis
AIContextDiagnosis is what the repository's card and the API show about the failed run, with what Zoomies means to do about it. It is nil unless the context is behind and a run for the commit it is waiting for failed.
func (*Controller) AcceptHostCheck ¶ added in v1.3.8
func (c *Controller) AcceptHostCheck(ctx context.Context, hostID string, in AcceptInput, by HostActor) (HostView, *store.HostCheckAcceptance, error)
AcceptHostCheck records that a counted warning on one host is deliberate. It changes nothing on the host -- the controller never runs a command there -- it only stops Zoomies counting the check until the value changes or the term ends.
The value stored is the stored report's, not the request's, so an acceptance cannot be made to cover text the host never reported.
func (*Controller) AcceptLogStream ¶
func (c *Controller) AcceptLogStream(hostID, streamID string, r io.Reader) error
AcceptLogStream consumes the agent's outbound chunked POST and fans it out. It returns when the agent closes the body or the stream is torn down.
hostID is the host the request authenticated as, and it must be the host the stream was opened for: whatever arrives here is shown to operators as that runner's output, so a stream another agent could write into would let one host put words in another's mouth. Every other agent endpoint checks the same thing against the runner's host; this one checks it against the stream's.
func (*Controller) AcknowledgeJob ¶ added in v1.3.8
func (c *Controller) AcknowledgeJob(ctx context.Context, jobID, by string) (*store.Job, bool, error)
AcknowledgeJob records that somebody has read this job's failure and does not need it in the attention list again, and ReopenJobAttention takes that decision back. They are the two halves of triage: the first says "known", the second says "no, this still wants a person".
An acknowledgement is not a resolution and does not pretend to be one. The failure keeps its conclusion on GitHub and its row here; a later attempt that passes is what settles it, and a later attempt that fails is a new failure somebody has to look at on its own. What the acknowledgement buys is that the attention list (the Overview's failures panel and the Jobs page's "Needs attention" view, which share one definition) stops asking about something a person has already read, which is the difference between a list of what is wrong and a list of what is new.
Only a job that failed can be acknowledged: there is nothing to triage about one that is still running, and marking it would take it out of the attention list before it has an outcome to be out of the list for.
Both report whether this call is the one that changed the row. A second press on a failure somebody has already marked changes nothing, and writes no timeline entry; the caller writes its audit row from the same flag, so that the log never credits a person with a decision that was another's.
func (*Controller) ActEliOpportunity ¶ added in v1.3.8
func (*Controller) AdmitJoinToken ¶ added in v1.3.8
func (c *Controller) AdmitJoinToken(ctx context.Context) error
AdmitJoinToken says whether one more outstanding join token fits under limits.join_tokens.
func (*Controller) AdmitPool ¶ added in v1.3.8
func (c *Controller) AdmitPool(ctx context.Context) error
AdmitPool says whether one more pool fits under limits.pools.
func (*Controller) AdmitPools ¶ added in v1.3.8
func (c *Controller) AdmitPools(ctx context.Context, n int) error
AdmitPools says whether n more pools fit under limits.pools together.
func (*Controller) AllowAgentCall ¶ added in v1.3.8
func (c *Controller) AllowAgentCall(hostID string) (bool, time.Duration)
AllowAgentCall spends one call from a host's budget for heartbeats, results and reports. When it is refused, the duration says how long until the next call would be accepted, for a Retry-After header.
func (*Controller) AnalyseCompare ¶ added in v1.3.8
func (c *Controller) AnalyseCompare(ctx context.Context, req CompareRequest) (analysis.CompareFinding, error)
AnalyseCompare says what got worse and what got better between two releases, or between the period and the one before it.
func (*Controller) AnalyseHostPressure ¶ added in v1.3.8
func (c *Controller) AnalyseHostPressure(ctx context.Context, w AnalysisWindow, hostID string) (analysis.HostPressureFinding, error)
AnalyseHostPressure says whether what went wrong on a host came in the minutes it was under pressure.
func (*Controller) AnalyseQueueWait ¶ added in v1.3.8
func (c *Controller) AnalyseQueueWait(ctx context.Context, w AnalysisWindow, poolID string) (analysis.QueueWaitFinding, error)
AnalyseQueueWait puts every second jobs queued in the period waited down to one cause, for the fleet or for one pool.
func (*Controller) AnalyseStartupFailures ¶ added in v1.3.8
func (c *Controller) AnalyseStartupFailures(ctx context.Context, w AnalysisWindow, poolID, hostID string) (analysis.StartupFailuresFinding, error)
AnalyseStartupFailures names the host or pool that keeps failing to start runners in the period, narrowed to a pool or a host when one is given.
func (*Controller) ApplyAIContextMaintenance ¶ added in v1.3.8
func (c *Controller) ApplyAIContextMaintenance(ctx context.Context, id string, req AIContextMaintenanceRequest) (*AIContextSetupPreview, error)
func (*Controller) ApplyMigration ¶
func (c *Controller) ApplyMigration(ctx context.Context, req MigrationApplyRequest) (*MigrationOutcome, error)
ApplyMigration opens the pull requests a plan described, one repository at a time.
It re-reads and re-plans rather than trusting a plan the browser sends back. The workflows may have changed since the review step, and the alternative -- committing content the browser supplied -- would make this a way to write arbitrary files into any repository the App can reach. The caller has already bounded req.Repos to MaxApplyRepos; an empty mapping is ErrNothingMapped.
func (*Controller) AssistantProviderView ¶ added in v1.3.8
func (c *Controller) AssistantProviderView(p *store.AssistantProvider) AssistantProviderView
AssistantProviderView renders one row.
func (*Controller) AssistantProviderViewFor ¶ added in v1.3.8
func (c *Controller) AssistantProviderViewFor(ctx context.Context, p *store.AssistantProvider, userID string) AssistantProviderView
AssistantProviderViewFor renders one row for a person: the same view, and whose it is and whether it is theirs to use.
func (*Controller) Auth ¶
func (c *Controller) Auth() *auth.Service
Auth returns the authentication and audit service.
func (*Controller) AutoAdjustEffective ¶ added in v1.3.8
func (c *Controller) AutoAdjustEffective(h *store.Host) bool
AutoAdjustEffective is whether the controller keeps this host at its recommendation: the host's own answer where it has one, the fleet's otherwise.
func (*Controller) AutoPoolKept ¶ added in v1.3.8
func (c *Controller) AutoPoolKept(p *store.Pool) bool
AutoPoolKept says whether the controller is keeping this pool now, which is what decides whether deleting it would only have it made again.
func (*Controller) AutoPoolStatus ¶ added in v1.3.8
func (c *Controller) AutoPoolStatus() AutoPoolStatus
AutoPoolStatus returns what the last pass found.
func (*Controller) AutoPools ¶ added in v1.3.8
func (c *Controller) AutoPools() AutoPoolsView
AutoPools reports the state of both switches and of the pools the controller keeps. It reads what the last pass found and does not run one.
func (*Controller) AutoPoolsMode ¶ added in v1.3.8
func (c *Controller) AutoPoolsMode() string
AutoPoolsMode is scheduler.auto_pools as the controller reads it, for the handlers that must refuse what the reconciler would only undo.
func (*Controller) Backends ¶
func (c *Controller) Backends() *backend.Registry
Backends returns the backend registry, or nil in a controller that runs no embedded agent.
func (*Controller) BackupDir ¶ added in v1.3.8
func (c *Controller) BackupDir() string
BackupDir is where this controller keeps its backups.
func (*Controller) BackupRemotes ¶ added in v1.3.8
func (c *Controller) BackupRemotes(ctx context.Context) []RemoteBackupStatus
BackupRemotes reports every destination this fleet has and what became of it: the file's first, then the stored ones.
func (*Controller) BackupStatus ¶ added in v1.3.8
func (c *Controller) BackupStatus() BackupStatus
BackupStatus reports the schedule and its last outcome.
func (*Controller) BootstrapFromEnvironment ¶ added in v1.3.8
func (c *Controller) BootstrapFromEnvironment(ctx context.Context) error
BootstrapFromEnvironment creates the first identity ZOOMIES_BOOTSTRAP_* describes, if the database has no accounts yet.
It runs once, at start, beside the setup token. On an empty database it is what makes an instance a compose file or a Terraform module brought up usable with no human step: nobody is there to read the setup token out of the log. Once any account exists the variables are ignored -- they must never be a way to add a platform account to an instance somebody has already claimed -- and bootstrap.ignored names them, because variables that silently do nothing are a credential sitting in a file for no reason.
A malformed request is an error that stops startup: a provisioner waiting on /readyz for bootstrap_required to go false would otherwise wait for ever.
func (*Controller) CancelJobWorkflow ¶
func (c *Controller) CancelJobWorkflow(ctx context.Context, jobID string, force bool) (*store.Job, error)
CancelJobWorkflow asks GitHub to cancel the workflow run containing jobID. GitHub remains authoritative for terminal job states, but once its run-scoped API accepts the request Zoomies immediately suppresses queued demand and tears down runners executing jobs from that run. Waiting for a completed webhook would let an arbitrary current step keep running.
It exists beside CancelWorkflowRun because the Jobs page and JobDrawer already have a job in hand, not a run; it resolves the job to its run and delegates. The job's own already-completed check stays here rather than moving to the run-scoped method, so asking to cancel through a job that has itself finished is still refused even when a sibling job has not.
func (*Controller) CancelRollout ¶ added in v1.3.8
func (c *Controller) CancelRollout(ctx context.Context, by UpdateActor) (*UpdatesView, RolloutChange, error)
CancelRollout ends the open rollout. An update a helper has already been handed finishes by itself and is recorded; nothing new starts for the rollout. Who cancelled is kept, because auto does not start again what a person stopped.
func (*Controller) CancelTransfer ¶ added in v1.3.8
func (c *Controller) CancelTransfer(ctx context.Context) error
func (*Controller) CancelWorkflowRun ¶ added in v1.3.8
func (c *Controller) CancelWorkflowRun(ctx context.Context, repo string, runID int64, force bool) ([]*store.Job, error)
CancelWorkflowRun asks GitHub to cancel repo's workflow run runID, without needing one of its jobs' IDs. It is what the Workflows page's own run rows call directly, since a run there is only ever repo + GitHub's run ID -- see store.WorkflowRun for why it has no ID of its own.
Every job of the run still in hand gets the timeline entry an operator's request produces, not only whichever job happened to be used to reach the run: nothing about the run names one job over another as the one this was "really" about.
func (*Controller) CaptureExperimentComparison ¶ added in v1.3.8
func (c *Controller) CaptureExperimentComparison(ctx context.Context, actor *store.AuditEvent, record ExperimentComparisonRecord, installation string, baseline, candidate []ExperimentAttemptSelection) (*RetainedExperimentComparison, error)
CaptureExperimentComparison admits both arms as one bounded diagnostic. It validates the operator record before spending quota and never loops batches.
func (*Controller) CaptureOptimisationPreview ¶ added in v1.3.8
func (c *Controller) CaptureOptimisationPreview(ctx context.Context, actor *store.AuditEvent, installation, repo string, selection github.CheckoutSelection, review optimisation.HistoryReview, check OptimisationPolicyCheck) (*RetainedOptimisationPreview, error)
func (*Controller) CheckAIContextUploadToken ¶ added in v1.3.8
func (c *Controller) CheckAIContextUploadToken(ctx context.Context, rawToken, audience string) error
CheckAIContextUploadToken verifies an upload's token alone, so the API can refuse a stranger before reading a body of up to 32 MiB. The full check runs again in IngestAIContextUpload; the keys are cached, so that costs nothing.
func (*Controller) CheckAssistantDraft ¶ added in v1.3.8
func (c *Controller) CheckAssistantDraft(ctx context.Context, draft *store.AssistantProvider, apiKey string) AssistantProviderCheck
CheckAssistantDraft checks a provider that is not saved, with the key the form holds, and stores nothing.
func (*Controller) CheckAssistantProvider ¶ added in v1.3.8
func (c *Controller) CheckAssistantProvider(ctx context.Context, row *store.AssistantProvider) AssistantProviderCheck
CheckAssistantProvider runs Check and a one-token completion, which is how the adapters' Check is defined, and reports the result rather than failing: a check that found the key wrong is an answer, not an error, and is what the page and the row keep.
func (*Controller) CheckBackupRemote ¶ added in v1.3.8
func (c *Controller) CheckBackupRemote(ctx context.Context, cfg config.BackupRemote) error
CheckBackupRemote tests a destination that has not been saved yet, which is what makes the page's "test" button worth pressing before the credential is stored rather than after.
func (*Controller) CheckForReleases ¶ added in v1.3.8
func (c *Controller) CheckForReleases(ctx context.Context) error
CheckForReleases asks GitHub now instead of at the next scheduled check, for a person who asked for one.
It refuses while updates.check_interval is 0, because that setting says this controller must never make the request, and it lets one request through a minute. A press inside the minute is not an error: what it would have learnt is what the last one learnt a moment ago, so it returns as though it had asked. The minute is counted from the request and not from its success, because a refusal from GitHub is a reason to ask less often.
func (*Controller) CheckProvider ¶ added in v1.3.8
func (c *Controller) CheckProvider(ctx context.Context, row *store.Provider) (ProviderCheckView, error)
CheckProvider asks a provider what it would refuse, changing nothing.
The result is recorded on the row as well as returned, because the page, the problems drawer and the reconciler's own "this template has not been verified since the configuration changed" warning all read it from there -- a check an operator ran in a terminal should quiet the warning the UI is showing.
func (*Controller) ClearHostThrottle ¶ added in v1.3.8
ClearHostThrottle lifts a host's throttle by hand, whatever rung it is on.
It is the operator's way out once the cause is fixed -- a pool given the limits it lacked, a capacity lowered to what the machine can carry -- without waiting out the recovery the ladder would otherwise ask for. The caller audits, because it knows who asked; this writes nothing to the audit trail itself. It logs the lift, publishes the host and nudges a pass, since the slots it gives back are room a queued job may be waiting on. A host that is not throttled is returned unchanged.
Nothing pins a throttle the other way: if the pressure is still there, the next heartbeat puts the host back on the first rung, which is the honest answer to a clear that was premature.
func (*Controller) ClientFor ¶
ClientFor returns a GitHub client for one installation, identified by its Zoomies installation ID ("ins_...").
func (*Controller) ClientForRepo ¶
ClientForRepo returns the client for whichever installation covers a repository, preferring a repo-scoped installation over the owning org.
func (*Controller) CollectExperimentAttempts ¶ added in v1.3.8
func (c *Controller) CollectExperimentAttempts(ctx context.Context, installation, repo string, selected []ExperimentAttemptSelection) (*ExperimentRetainedEvidence, error)
CollectExperimentAttempts is for a caller already authorised to read jobs. It checks installation/repository joins, not the caller's role. No transport exposes this yet. The report omits names, log tails and workflow output. A later adapter must treat the repository and revision strings as untrusted.
func (*Controller) CollectExperimentEvidence ¶ added in v1.3.8
func (c *Controller) CollectExperimentEvidence(ctx context.Context, installation, repo string, selected []ExperimentAttemptSelection) (*ExperimentJoinedEvidence, error)
CollectExperimentEvidence requires an already authorised job reader. There is no transport here: an installation join cannot authorise a caller. Sharing PR diagnostic admission prevents two kinds of reader racing the same quota.
func (*Controller) Config ¶
func (c *Controller) Config() *config.Config
Config returns the configuration as it currently stands: what the controller was built with, as changed since by UpdateConfig. It is a snapshot and must not be written through; the next UpdateConfig would silently discard the write, and until then every loop would be reading it unsynchronised.
func (*Controller) ControlProvisioning ¶
func (c *Controller) ControlProvisioning(ctx context.Context, ids []string, action string) ([]store.ProvisioningResult, error)
func (*Controller) ControlWorkflowRunProvisioning ¶ added in v1.3.8
func (c *Controller) ControlWorkflowRunProvisioning(ctx context.Context, repo string, runID int64, action string) ([]store.ProvisioningResult, error)
ControlWorkflowRunProvisioning is ControlProvisioning for every queued job of one run: what the Workflows page's run rows call, since a run has no ID of its own to select by, only repo + GitHub's run ID.
store.ErrNotFound for a run this fleet has never heard of, and ErrRunHasNoQueuedJobs when it knows the run but nothing in it is waiting for a runner here -- the two are different answers for an operator, and a 200 with no results would read as a button that did nothing.
func (*Controller) CreateAIContextDraft ¶ added in v1.3.8
func (c *Controller) CreateAIContextDraft(ctx context.Context, req AIContextDraftRequest) (*store.AIContextRepository, error)
func (*Controller) CreateAIContextSetupPR ¶ added in v1.3.8
func (c *Controller) CreateAIContextSetupPR(ctx context.Context, id string, approval AIContextSetupApproval) (*AIContextSetupPreview, error)
func (*Controller) CreateKennelGuidancePR ¶ added in v1.3.8
func (c *Controller) CreateKennelGuidancePR(ctx context.Context, id string, approval KennelGuidanceApproval) (*KennelGuidancePreview, error)
func (*Controller) DatabasePath ¶ added in v1.3.8
func (c *Controller) DatabasePath() string
DatabasePath is the database the staged-restore files sit beside. It is the configured path rather than the store's own, because the store a test opens is in memory and has nowhere for a file to sit; in production the two are the same file.
func (*Controller) DeleteHost ¶
func (c *Controller) DeleteHost(ctx context.Context, id string) error
DeleteHost removes a host and announces its runner rows and then the host.
func (*Controller) DeleteHostForgettingMachine ¶ added in v1.3.8
func (c *Controller) DeleteHostForgettingMachine(ctx context.Context, id, machineID string) error
DeleteHostForgettingMachine deletes a host and, in the same transaction, the machine row behind it, announcing the machine only once both are gone.
func (*Controller) DeleteInstallation ¶
func (c *Controller) DeleteInstallation(ctx context.Context, id string) error
DeleteInstallation removes an installation with its pools and their runner rows, forgets its GitHub client, and announces each thing that went in the order a page wants them: runners, pools, then the installation.
func (*Controller) DeletePool ¶
func (c *Controller) DeletePool(ctx context.Context, id string) error
DeletePool removes a pool and announces everything that went with it: each runner row, then any queued job it took off the queue with it, then the pool. The runners go first so a page that drops them has nothing left to explain when the pool disappears; the jobs are announced as their own updated view -- unmatched and off the queue -- so the Jobs and Queue pages drop them without a refresh.
func (*Controller) DiscoverAIContext ¶ added in v1.3.8
func (c *Controller) DiscoverAIContext(ctx context.Context, installationID string) (*AIContextDiscovery, error)
func (*Controller) DiscoverDraft ¶ added in v1.3.8
func (c *Controller) DiscoverDraft(ctx context.Context, row *store.Provider, credential, address string) (ProviderDiscoveryView, error)
DiscoverDraft asks a provider that has not been saved what its credential can see, so the wizard can offer the nodes, storages, bridges and templates as a menu before there is a row to save them on.
The secrets arrive in plaintext because there is no row to unseal them from, and they go nowhere: the client is built for this one call and dropped, and a private connection opened for it is closed with it. Nothing is cached, because a draft has no identity to cache under and its credential may be about to be corrected.
func (*Controller) DiscoverProvider ¶ added in v1.3.8
func (c *Controller) DiscoverProvider(ctx context.Context, row *store.Provider) (ProviderDiscoveryView, error)
DiscoverProvider asks a provider what this credential can see, so the form offers a menu rather than asking somebody to go and look an identifier up.
func (*Controller) DrainRunner ¶
func (c *Controller) DrainRunner(ctx context.Context, runnerID, reason string, confirmed bool) (*store.Runner, error)
DrainRunner asks a runner to finish its current job and exit.
confirmed is the operator saying they accept that a job in flight will be ended: see ErrConfirmationRequired. It is ignored for a runner that is not busy, because there is nothing to lose.
func (*Controller) EliAutomaticRepairs ¶ added in v1.3.8
func (c *Controller) EliAutomaticRepairs(ctx context.Context) ([]EliAutomaticRepository, error)
EliAutomaticRepairs lists the repositories whose policy is enabled and Automatic, the ones with a problem first and then by name without regard to case. A provider that cannot pay is reported here for the same reasons the worker refuses it, so the administrator reads it before the next failure is spent on it rather than after.
func (*Controller) EliErrorOutput ¶ added in v1.3.8
func (c *Controller) EliErrorOutput(ctx context.Context, user, repo string, jobID int64) (EliErrorOutput, error)
EliErrorOutput reads the error lines of one job for a person who could fix the pull request. It is on demand and it keeps nothing: the lines are never stored and never logged, because a log is where a job's secrets end up and the repair record is read by more people than could read the job. They are passed through the same redaction the model's evidence gets, held in memory for a minute so a second look is not a second download, and handed back.
The access check runs on every call, before the copy in memory is looked at. The copy belongs to a job, not to a person, and the one person who could read it must not be how another one does.
func (*Controller) EliOpportunities ¶ added in v1.3.8
func (c *Controller) EliOpportunities(ctx context.Context, user string) ([]store.EliRepairOpportunity, error)
Offers contain repository data, so even administrators must have current access through their linked GitHub account before seeing personal offers.
func (*Controller) EliReadiness ¶ added in v1.3.8
func (c *Controller) EliReadiness(ctx context.Context, user, repo string, pull int, run int64) (out EliReadiness)
func (*Controller) EmbeddedAgent ¶
func (c *Controller) EmbeddedAgent() *agent.Agent
EmbeddedAgent returns the in-process agent, or nil when this controller runs without one.
func (*Controller) EmbeddedTransport ¶
func (c *Controller) EmbeddedTransport() agent.Transport
EmbeddedTransport returns an agent.Transport that calls this controller directly. It is what makes the single-VM case one process: no listener, no TLS, no token on the wire.
func (*Controller) Events ¶
func (c *Controller) Events() *events.Bus
Events returns the bus the API's SSE endpoint subscribes to.
func (*Controller) ExplainJob ¶
func (c *Controller) ExplainJob(ctx context.Context, jobID string, logs int) (*JobExplanation, error)
ExplainJob works out why a job is where it is.
It reads rather than decides: the scheduler has already said why it could not place a runner, and repeating that decision here would give an operator two answers that drift apart. What this adds is the surrounding facts, which the plan does not carry -- whose runner it is, and whether that runner's host is still alive. logs is how many lines of the runner's kept output to quote around the decisive one; 0 quotes none.
func (*Controller) ExportInstallation ¶ added in v1.3.8
func (c *Controller) ExportInstallation(ctx context.Context, id, passphrase string) (*InstallationArchive, error)
ExportInstallation assembles one installation's archive. With a passphrase its secrets are opened with the instance key and sealed again under the passphrase; without one they are left out.
func (*Controller) Fenced ¶
func (c *Controller) Fenced() store.RecoveryFence
Fenced reports whether this fleet is held for recovery, and why.
func (*Controller) FindAIContextDraft ¶ added in v1.3.8
func (c *Controller) FindAIContextDraft(ctx context.Context, installationID string, repositoryID int64) (*store.AIContextRepository, error)
func (*Controller) Forget ¶
func (c *Controller) Forget(installationID string)
Forget drops the cached client for an installation. The API calls it after deleting or re-keying one, so the next call rebuilds from the stored row.
func (*Controller) HandleWebhook ¶
func (c *Controller) HandleWebhook(w http.ResponseWriter, r *http.Request)
HandleWebhook is the endpoint GitHub delivers to, mounted by the API at config.GitHub.WebhookPath.
It answers quickly on purpose. GitHub gives a webhook ten seconds before it records the delivery as failed, so this verifies, writes one row and returns; the scheduling it triggers happens on the reconcile loop, which nothing here waits for.
func (*Controller) Heartbeat ¶
func (c *Controller) Heartbeat(ctx context.Context, hostID string, req agent.HeartbeatRequest) (*agent.HeartbeatResponse, error)
Heartbeat records that a host is alive, merges anything its agent observed, and tells the agent whether the controller still recognises it.
func (*Controller) HostFit ¶
HostFit counts the hosts that could run a pool, using the scheduler's own placement rule so the wizard can never disagree with the fleet.
func (*Controller) HostRecommendation ¶ added in v1.3.8
func (c *Controller) HostRecommendation(ctx context.Context, h *store.Host) (scheduler.HostRecommendation, bool)
HostRecommendation is what Adjust recommends for a host now, and whether it could be worked out at all. It is the same answer the automatic adjustment applies, so a person looking at the dialog and the controller moving the host are looking at one set of numbers.
func (*Controller) HostSamples ¶ added in v1.3.8
func (c *Controller) HostSamples(ctx context.Context, since time.Time, hostID string) ([]store.HostSample, error)
HostSamples returns every host's minute samples since a cutoff, for the Hosts page's capacity map. An empty hostID means every host.
func (*Controller) HostStrandings ¶ added in v1.3.8
HostStrandings reports the pools that could run somewhere in this fleet today and would have nowhere to run if this host were saved as proposed.
Proposed is the host as it would be after the edit, id and all; every other host is read as it stands. Health is not consulted on either side: a host waiting for its agent to check in is still where a pool lives, and refusing an edit because some other machine happened to be rebooting would be a rule nobody could predict.
func (*Controller) HostView ¶
func (c *Controller) HostView(h *store.Host) HostView
HostView renders a host as the API returns it.
backend_info is the agent's own probe, which includes the backends it could not use and the sentence explaining why: that sentence is the whole answer to "this host is connected, so why is nothing running on it?". A host that joined an older controller has no probe stored, so its available kinds are rendered as the bare list they are, and nothing is invented about the backends it never reported on.
func (*Controller) ImportInstallation ¶ added in v1.3.8
func (c *Controller) ImportInstallation(ctx context.Context, a *InstallationArchive, passphrase string) (*store.Installation, *store.ImportedInstallation, error)
ImportInstallation writes an archive onto this instance. The secrets are opened with the passphrase and sealed under this instance's key before the row is written, so nothing on disk here is readable with the passphrase alone.
func (*Controller) IngestAIContextUpload ¶ added in v1.3.8
func (c *Controller) IngestAIContextUpload(ctx context.Context, rawToken, audience string, body []byte) (*store.AIContextRepository, error)
IngestAIContextUpload admits a Zoomies-only snapshot. The token proves which repository, branch, commit and workflow file ran; everything the Both mode checks on a generated branch is then checked here too, against GitHub. Nothing about the request body is trusted until all of that holds.
func (*Controller) InspectCheckoutEvidence ¶ added in v1.3.8
func (c *Controller) InspectCheckoutEvidence(ctx context.Context, installation, repo string, selection github.CheckoutSelection) (*CheckoutInspection, error)
InspectCheckoutEvidence performs the same admitted read as a capture, under the same quota, flight and policy rules, and returns the source for review.
func (*Controller) JobRenderer ¶
func (c *Controller) JobRenderer(ctx context.Context) (*JobRenderer, error)
JobRenderer builds the index a page of jobs is rendered from.
func (*Controller) Join ¶
func (c *Controller) Join(ctx context.Context, req agent.JoinRequest, ip string) (*agent.JoinResponse, error)
Join enrols an agent: it redeems the single-use join token, creates or updates the host row, and mints the long-lived agent token that every later request carries. The plaintext token is returned exactly once.
func (*Controller) KennelChecks ¶ added in v1.3.8
func (c *Controller) KennelChecks() []KennelCheckInfo
KennelChecks is the catalogue. It is built from the registry the evaluator runs, so the page that says what is checked, the documentation and the checks cannot disagree.
func (*Controller) KennelOverview ¶ added in v1.3.8
func (c *Controller) KennelOverview(ctx context.Context) (*KennelOverviewView, error)
KennelOverview computes the Overview's document. With Kennel Club off it reads nothing from the database, which is the property that lets "off" mean no rows and no work.
func (*Controller) KennelPass ¶ added in v1.3.8
func (c *Controller) KennelPass(ctx context.Context)
KennelPass is one look at every installation. With Kennel Club off it does nothing at all: no query, no request, no row.
It is exported, as Reconcile is, so a test of the API can make a pass and read what the loop itself wrote, not a row it built to agree with the handler.
A fenced controller, or one that has lost its lease, does no GitHub work and writes nothing: mayAct is asked before each installation is touched and before each repository is evaluated, which is where a pass could otherwise carry on for minutes after the answer changed. It is not asked up here as well, because a second copy of a guard that the first already makes is a copy no test can tell from the first.
func (*Controller) KennelRepositories ¶ added in v1.3.8
func (c *Controller) KennelRepositories(ctx context.Context, f KennelListFilter, page store.Page) ([]KennelRepositoryView, int, error)
KennelRepositories lists what Kennel Club has concluded, in the shape of GET /kennel/repositories/{id}.
func (*Controller) KennelRepository ¶ added in v1.3.8
func (c *Controller) KennelRepository(ctx context.Context, id string) (*KennelRepositoryView, error)
KennelRepository is one repository, in the shape the event stream carries.
func (*Controller) KickAutoPools ¶ added in v1.3.8
func (c *Controller) KickAutoPools()
KickAutoPools asks for a pass of the reconciler now. It never blocks and never queues, like Nudge: fifty hosts joining at once cost one pass.
func (*Controller) KickKennel ¶ added in v1.3.8
func (c *Controller) KickKennel()
KickKennel asks the loop to look for work now, which a recheck and a change of setting do. It never blocks and never queues.
func (*Controller) KickUpdates ¶ added in v1.3.8
func (c *Controller) KickUpdates()
KickUpdates asks for a pass of the update loop now. It never blocks and never queues, like Nudge.
func (*Controller) LabelAdvice ¶ added in v1.3.8
func (c *Controller) LabelAdvice(ctx context.Context, opts AdviceOptions) ([]*scheduler.Advice, AdviceWindow, error)
LabelAdvice says what to change in the runs-on of the jobs whose measured runs call for something other than what they ask for, the costliest first, with the figures each row rests on and whether any host carries the class it recommends. There is none while size routing is off, because nothing is classed to compare with.
func (*Controller) LastPollAt ¶
func (c *Controller) LastPollAt() time.Time
LastPollAt is when the fallback poller last completed a sweep, or the zero time if it has not completed one since this controller started.
func (*Controller) ListAssistantModels ¶ added in v1.3.8
func (c *Controller) ListAssistantModels(ctx context.Context, draft *store.AssistantProvider, apiKey string) ([]string, error)
ListAssistantModels asks a provider, as a form has it, which models it serves. Nothing is stored. The key is the form's, or the saved row's when the box is blank, exactly as a draft check chooses it.
func (*Controller) LoadFence ¶
func (c *Controller) LoadFence(ctx context.Context) error
LoadFence reads the recovery fence from the database into this controller.
It is called at start and again whenever the fence is changed, rather than on every pass: the fence changes once in the life of a recovery, and a database read in the hot path of a loop that runs every few seconds would cost more than it could ever save.
func (*Controller) LoopPanics ¶
func (c *Controller) LoopPanics() map[string]loopPanic
LoopPanics returns the crashes recorded against each background loop, and each kind of detached work, since the process started, for the problems drawer.
func (*Controller) MachineRenderer ¶ added in v1.3.8
func (c *Controller) MachineRenderer(ctx context.Context) (*MachineRenderer, error)
MachineRenderer gathers what the machine views need. A list endpoint would otherwise be N+1 in three directions at once.
func (*Controller) NoteAgentSession ¶
func (c *Controller) NoteAgentSession(ctx context.Context, hostID, sessionID string)
NoteAgentSession folds the session an agent identified itself with into its host's record, and warns when the host has seen that session before.
Seeing a session a host has already moved on from is the duplicate-agent signal: an agent mints its session at start-up, so restarting moves the id forward and never back, and only two agents sharing one host's credentials -- a cloned VM, or a copied state directory -- hand the same pair back and forth. Counting plain changes instead would flag every ordinary restart.
Detect only, by decision. Refusing the older session would be a coin toss over which of two live agents keeps the host, and both are running real work; the problems panel names it and an operator decides which machine should not be there.
func (*Controller) NoteManualBackup ¶ added in v1.3.8
func (c *Controller) NoteManualBackup()
NoteManualBackup clears a scheduled failure: what was failing has just worked, and a warning about it would be stale.
func (*Controller) NoteRemoteListing ¶ added in v1.3.8
func (c *Controller) NoteRemoteListing(name string, copies int, bytes int64)
NoteRemoteListing records what a listing found, so that a page which has just read a remote leaves the count behind for the page that has not.
func (*Controller) Now ¶
func (c *Controller) Now() time.Time
Now returns the controller's clock, always in UTC.
func (*Controller) Nudge ¶
func (c *Controller) Nudge()
Nudge wakes the reconcile loop immediately.
It never blocks and never queues: the channel holds a single token, so a burst of webhooks costs one reconcile pass rather than one per delivery.
func (*Controller) NudgeBackupRemotes ¶ added in v1.3.8
func (c *Controller) NudgeBackupRemotes()
NudgeBackupRemotes asks the backup loop to reconcile the destinations now. It is what a destination added or corrected on the page presses: waiting an hour to find out whether it works is the opposite of what an operator who has just typed a credential wants.
func (*Controller) NudgeMachines ¶ added in v1.3.8
func (c *Controller) NudgeMachines()
NudgeMachines wakes the machine loop immediately. Like Nudge it never blocks and never queues: the channel holds one token, so a burst of changes costs one pass.
func (*Controller) OpenAssistantProvider ¶ added in v1.3.8
func (c *Controller) OpenAssistantProvider(row *store.AssistantProvider, apiKey string) (assistant.Provider, error)
OpenAssistantProvider builds the provider for a row, with the key opened here, where the instance key is, and the live local-only switch applied. apiKey, when non-empty, is used instead of the row's: a draft being checked has a key the row does not.
func (*Controller) OpenLogStream ¶
func (c *Controller) OpenLogStream(ctx context.Context, runnerID string, opts backend.LogOptions) (<-chan []byte, func(), error)
OpenLogStream subscribes to a runner's output and returns the channel the API's SSE handler reads, plus the function that unsubscribes.
The channel is closed when the stream ends, so a handler can range over it. Bytes are dropped rather than queued without limit when a reader falls behind: a wedged browser tab must not hold a runner's output in memory.
func (*Controller) OptimisationPolicy ¶ added in v1.3.8
func (c *Controller) OptimisationPolicy(context.Context) (optimisation.Policy, error)
OptimisationPolicy reads the effective settings on every call. Nothing a request carries can stand in for it, and a setting turned off between the inspection and the capture takes effect at once.
func (*Controller) OrphanReport ¶ added in v1.3.8
func (c *Controller) OrphanReport(ctx context.Context, row *store.Provider) (OrphanReportView, error)
OrphanReport gathers a provider's three disagreements. The untracked half comes from the last ownership sweep rather than from a call made now, because the page is read far more often than the hypervisor should be asked -- the sweep's own timestamp is returned so a stale answer says so.
func (*Controller) PRDelayForJob ¶ added in v1.3.8
func (c *Controller) PRDelayForJob(ctx context.Context, jobID string, pull int) (*PRDelayReport, error)
PRDelayForJob is on-demand collection for a job the caller may already read. A transport must authorise job access before calling it. It has no background trigger and cannot fall back to another installation's credentials.
func (*Controller) PlanMigration ¶
func (c *Controller) PlanMigration(ctx context.Context, req MigrationPlanRequest) (*MigrationPlan, error)
PlanMigration works out what a migration would change. It creates nothing.
It answers store.ErrNotFound for an installation that does not exist, ErrNoMigrationPool for one with nowhere to migrate to, and GitHub's own errors when the App cannot see or read the repositories.
func (*Controller) PollTasks ¶
func (c *Controller) PollTasks(ctx context.Context, hostID string, wait time.Duration) (*agent.TaskBatch, error)
PollTasks blocks until this host has work or wait elapses.
It waits on a per-host channel rather than sleeping in a loop, so a task enqueued by a reconcile reaches the agent in the same instant rather than up to a poll interval later.
func (*Controller) PollerEnabled ¶
func (c *Controller) PollerEnabled() bool
PollerEnabled reports whether the fallback poller is running at all. It is off by configuration, never by failure, so a fleet with no safety net is a choice somebody made and the UI should say which.
func (*Controller) PollingOnly ¶
func (c *Controller) PollingOnly() bool
PollingOnly reports whether scaling is running on the fallback poller because no webhook has ever been received.
func (*Controller) PoolCapacityProblems ¶
func (c *Controller) PoolCapacityProblems() []Problem
func (*Controller) PoolCountsByInstallation ¶
PoolCountsByInstallation answers "how much depends on this installation?", which is what makes the delete confirmation honest.
func (*Controller) PoolRenderer ¶
func (c *Controller) PoolRenderer(ctx context.Context) (*PoolRenderer, error)
PoolRenderer gathers the per-pool counts, installation targets and queue depths in three queries rather than three per pool.
func (*Controller) PoolRoom ¶ added in v1.3.8
PoolRoom counts the room a pool has across the hosts that can run it.
Only the hosts that could run it at all are counted: a host turned down for its backend or its platform has no room for this pool whatever its size, and HostFit already says so in its own words. Counting it here would put machine the pool can never reach into the number an operator sets a maximum from.
func (*Controller) PoolRunnerGroupProblems ¶
func (c *Controller) PoolRunnerGroupProblems() []Problem
PoolRunnerGroupProblems reports the pools whose runners went into GitHub's default runner group because the group they asked for could not be resolved.
It is a warning rather than a log line because runner-group policy can make a runner either broader than intended or completely ineligible. A pool put into a named group to fence its runners off and quietly placed in Default is wider than its operator asked for; a group that blocks public repositories leaves their matching jobs queued while its runners look healthy and idle.
func (*Controller) PoolStranding ¶ added in v1.3.8
func (c *Controller) PoolStranding(ctx context.Context, current, proposed *store.Pool) ([]Stranding, error)
PoolStranding is the same question asked from the other side: whether this pool, saved as proposed, would still have a host it could run on.
It returns at most one entry, because there is only one pool in question. The host it names is one that has room for the pool as it stands, which is the machine the new figures should be read against -- an operator who has just typed 16 GB needs to see the 12 GB host it no longer fits, not a count.
func (*Controller) PrepareTransfer ¶ added in v1.3.8
func (c *Controller) PrepareTransfer(ctx context.Context) (TransferProgress, error)
Preparing changes the scheduler's view, never the saved pool configuration. Existing jobs finish naturally; the ordinary idle-runner withdrawal handshake keeps the last job that raced with the button from being killed.
func (*Controller) PreviewAIContextMaintenance ¶ added in v1.3.8
func (c *Controller) PreviewAIContextMaintenance(ctx context.Context, id string, req AIContextMaintenanceRequest) (*AIContextSetupPreview, error)
func (*Controller) PreviewAIContextSetup ¶ added in v1.3.8
func (c *Controller) PreviewAIContextSetup(ctx context.Context, id string) (*AIContextSetupPreview, error)
func (*Controller) PreviewKennelGuidance ¶ added in v1.3.8
func (c *Controller) PreviewKennelGuidance(ctx context.Context, id string) (*KennelGuidancePreview, error)
func (*Controller) PrewarmPool ¶
func (*Controller) PrivateConnectionFault ¶ added in v1.3.8
func (c *Controller) PrivateConnectionFault() *PrivateConnectionFault
PrivateConnectionFault is the listener's current fault, or nil.
func (*Controller) ProbeInstallation ¶
func (c *Controller) ProbeInstallation(ctx context.Context, installationID string) (*github.AppInfo, error)
ProbeInstallation verifies one installation's credentials end to end and records the outcome, publishing it so the UI updates.
It returns the App information on success and the operator-facing error on failure; the error is also stored, because "why is nothing scaling?" is answered on the Installations page.
func (*Controller) ProviderKinds ¶ added in v1.3.8
func (c *Controller) ProviderKinds() []ProviderKindView
ProviderKinds is every driver this build can speak, in the registry's stable order.
func (*Controller) ProviderOrphans ¶ added in v1.3.8
func (c *Controller) ProviderOrphans() map[string][]string
ProviderOrphans is the untracked resources the last sweep found, by provider.
func (*Controller) ProviderPairings ¶ added in v1.3.8
func (c *Controller) ProviderPairings(ctx context.Context) ([]PairingView, error)
ProviderPairings answers, for every provider and pool, whether the provider would rent for the pool and, if not, whose setting says so. It asks the same rules the machine decision does (scheduler.Pair and scheduler.HostCouldRun), so the page that explains a pairing and the pass that acts on it cannot disagree.
func (*Controller) ProviderView ¶ added in v1.3.8
func (c *Controller) ProviderView(p *store.Provider, machines []*store.Machine) ProviderView
ProviderView renders a provider with its machine counts and whatever is currently holding it back.
func (*Controller) ProvidersAvailable ¶ added in v1.3.8
func (c *Controller) ProvidersAvailable() bool
ProvidersAvailable reports whether this deployment can rent machines at all: a driver to rent from, and an operator who has switched provider.enabled on. The page that would otherwise offer to buy machines nothing would ever create asks this first.
func (*Controller) PruneBackups ¶ added in v1.3.8
func (c *Controller) PruneBackups(ctx context.Context) (BackupPruning, error)
PruneBackups applies retention now, to this host's directory and to every destination, and reports what went.
Retention otherwise runs as part of a backup, which is the right moment for it and the wrong one for an operator who has just lowered backup.keep from thirty to seven: nothing at all happens until the next backup, and on a fleet with the schedule off that is never. So this exists, it is deliberate, and it says what it deleted rather than reporting a tidy success.
Whatever cannot be pruned is recorded against the thing that refused and the pass carries on: one bucket with a wrong credential must not leave the others full.
func (*Controller) PublishHost ¶
func (c *Controller) PublishHost(h *store.Host)
PublishHost announces a host an operator changed: its capacity, its labels, or whether it is cordoned.
func (*Controller) PublishHostDeleted ¶
func (c *Controller) PublishHostDeleted(id string)
PublishHostDeleted announces that a host is gone.
func (*Controller) PublishInstallation ¶
func (c *Controller) PublishInstallation(ctx context.Context, inst *store.Installation)
PublishInstallation announces an installation an operator added or edited.
func (*Controller) PublishInstallationDeleted ¶
func (c *Controller) PublishInstallationDeleted(id string)
PublishInstallationDeleted announces that an installation is gone.
func (*Controller) PublishKennelRepository ¶ added in v1.3.8
func (c *Controller) PublishKennelRepository(ctx context.Context, id string)
PublishKennelRepository announces one repository in the shape GET /kennel/repositories/{id} returns. The API calls it after its own write, as it does for a pool, and the loop calls it after an evaluation.
func (*Controller) PublishMachine ¶ added in v1.3.8
func (c *Controller) PublishMachine(ctx context.Context, m *store.Machine)
PublishMachine announces a machine an operator acted on.
func (*Controller) PublishMachineDeleted ¶ added in v1.3.8
func (c *Controller) PublishMachineDeleted(id string)
PublishMachineDeleted announces that a machine row is gone.
The row, not the resource: a machine whose VM was destroyed keeps its row until retention takes it, because the row is the only record of what was rented and what it cost.
func (*Controller) PublishPool ¶
PublishPool announces a pool an operator created or changed, in the shape GET /pools/{id} returns. The API calls it after its own write: the operator who made the change is looking at the response, but every other open dashboard learns about it from here.
func (*Controller) PublishPoolDeleted ¶
func (c *Controller) PublishPoolDeleted(id string)
PublishPoolDeleted announces that a pool is gone.
func (*Controller) PublishProvider ¶ added in v1.3.8
func (c *Controller) PublishProvider(ctx context.Context, p *store.Provider)
PublishProvider announces a provider an operator created or changed.
func (*Controller) PublishProviderDeleted ¶ added in v1.3.8
func (c *Controller) PublishProviderDeleted(id string)
PublishProviderDeleted announces that a provider is gone.
func (*Controller) PurgeInstallation ¶ added in v1.3.8
func (c *Controller) PurgeInstallation(ctx context.Context, id string) error
PurgeInstallation is DeleteInstallation that also takes the history: the installation's jobs, deliveries, scaling events, sessions, usage days and the audit rows that name any of them. It announces what the page shows the same way the delete does; history rows have no live view to retract.
func (*Controller) RecheckHostPriority ¶ added in v1.3.8
RecheckHostPriority recomputes what a host's specs currently rank it at and republishes the card for it.
There is nothing stored to recompute against: the priority is read back out of the reported specs, which every heartbeat re-measures, so the score is always the machine's current one and an upgrade the host ever has is re-placed on its own with the next report after it. What this forces is the frame at once, for the UI's re-check button, and a nudge so the next pass places against the figure now on the card rather than by whatever the last one carried.
func (*Controller) RecheckKennelRepository ¶ added in v1.3.8
func (c *Controller) RecheckKennelRepository(ctx context.Context, id string) (*KennelRepositoryView, error)
RecheckKennelRepository asks for a repository's reads from GitHub to happen again. It makes the repository due and wakes the loop; it reads nothing itself, so a person pressing the button waits on the same budget and the same hold as everything else.
func (*Controller) ReclassifyQueuedJobs ¶ added in v1.3.8
func (c *Controller) ReclassifyQueuedJobs(ctx context.Context, repo, workflow, jobName string) (int, error)
ReclassifyQueuedJobs puts the jobs waiting for a runner back through the classification, for the jobs of one repository, one workflow or one job. It is what makes an operator's pin reach the queue and not only the jobs that arrive afterwards: a pin made to fix a job that is stuck in the wrong class has to fix that one. It returns how many jobs changed class.
func (*Controller) ReclassifyWaitingJobs ¶ added in v1.3.8
func (c *Controller) ReclassifyWaitingJobs(ctx context.Context) (int, error)
ReclassifyWaitingJobs does it for every job waiting for a runner, which is what a change to scheduler.size_routing has to do. The switch is read as each job arrives, so without this a job that was already waiting when routing was turned on would have no route for as long as it waited and be placed as it always was, and one that was waiting when routing was turned off would go on saying it had been sent to a class. It returns how many jobs changed.
func (*Controller) Reconcile ¶
func (c *Controller) Reconcile(ctx context.Context) error
Reconcile runs exactly one scheduling pass: snapshot the fleet, decide, and apply. It is exported so that tests and the API can force a pass and know it has finished, which Nudge deliberately cannot promise.
func (*Controller) ReconcileAutoPools ¶ added in v1.3.8
func (c *Controller) ReconcileAutoPools(ctx context.Context) error
ReconcileAutoPools runs one pass: give every host its class, work out the pools the hosts call for, and make them so. It is exported so that tests and the API can force a pass and know it has finished.
It holds no lock the scheduling pass takes. Everything it writes is a narrow statement on columns the scheduler only reads -- a pool's derived figures, a host's class -- so a pass that is placing runners while this one lowers a maximum sees the old figure or the new one, and either is a state the next pass puts right; and every figure here is recomputed from the hosts as they are, so there is nothing to lose by being run twice or late.
func (*Controller) ReconcileMachines ¶ added in v1.3.8
func (c *Controller) ReconcileMachines(ctx context.Context) error
ReconcileMachines runs exactly one machine pass. It is exported so that tests and the API can force a pass and know it has finished, which a nudge deliberately cannot promise.
The order is the design. Recovery runs before demand on every pass that may act, so a restart is simply the pass where nothing was in memory and there is no separate startup path to get wrong. Ownership is swept before anything is decided, so a resource that vanished under us is known about before the fleet works out whether to buy another. And nothing is created until every machine already on the way has been counted.
func (*Controller) ReconcileUpdates ¶ added in v1.3.8
func (c *Controller) ReconcileUpdates(ctx context.Context) error
ReconcileUpdates runs one pass: read the release list if updating has just been turned on, then close every open attempt that has ended. It is exported so that tests can force a pass and know it has finished.
Every attempt is judged on what can be seen now, so a pass missed, run twice, or run by the next process after a restart comes to the same answer, and the store keeps the first ending if two passes race.
func (*Controller) RecordAssistantProviderCheck ¶ added in v1.3.8
func (c *Controller) RecordAssistantProviderCheck(ctx context.Context, id string, check AssistantProviderCheck) error
RecordAssistantProviderCheck keeps a check on its row, so the page shows the last result after a reload and not only in the tab that pressed Test.
func (*Controller) RefreshAIContext ¶ added in v1.3.8
func (c *Controller) RefreshAIContext(ctx context.Context, id string) error
func (*Controller) RegenerateAIContext ¶ added in v1.3.8
func (c *Controller) RegenerateAIContext(ctx context.Context, id string) error
RegenerateAIContext runs the managed workflow on the trusted branch, for the repository whose context has gone stale and will not catch up on its own -- the push that should have started it was missed, or the run failed. It asks GitHub to start the workflow and nothing else: the result arrives the way any other generation does, through verification, so a regeneration can neither open the source gate nor write a snapshot itself.
trustedAIContext runs first because dispatching runs the workflow file as it is on the branch today; that is only safe while it is still the reviewed one.
func (*Controller) Registry ¶
func (c *Controller) Registry() *prometheus.Registry
Registry returns the Prometheus registry the API serves at the configured metrics path.
func (*Controller) RemoteBackup ¶ added in v1.3.8
RemoteBackup resolves one destination by name, for the handlers that list, fetch from or delete a copy in it.
func (*Controller) RemoveRunner ¶
func (c *Controller) RemoveRunner(ctx context.Context, runnerID, reason string, force, confirmed bool) (*store.Runner, error)
RemoveRunner tears a runner down now and deletes its GitHub registration. Without force it drains instead, which still ends a running job after the stop timeout -- so the unforced path asks for the same acknowledgement a direct drain does.
func (*Controller) Renting ¶ added in v1.3.8
func (c *Controller) Renting(ctx context.Context) (RentingView, error)
Renting is the fleet's renting view as it stands: the switches now, laid over the last machine pass's verdicts. It reads the database only when there is no report to read, for the providers that say whether there is anything to rent from at all.
func (*Controller) ReopenJobAttention ¶ added in v1.3.8
func (c *Controller) ReopenJobAttention(ctx context.Context, jobID, by string) (*store.Job, bool, error)
ReopenJobAttention puts an acknowledged failure back in front of whoever looks next. It is the undo for a row put away by mistake, and it is deliberately as easy as the acknowledgement: a triage decision nobody can take back is one people learn not to make.
func (*Controller) ReplayExperimentComparison ¶ added in v1.3.8
func (c *Controller) ReplayExperimentComparison(ctx context.Context, installation, repo, id string) (*RetainedExperimentComparison, error)
ReplayExperimentComparison reads only retained evidence. Its digest checks stored bytes; recomputation also checks the report against its recorded input. The transport must authorise the repository read before invoking this method.
func (*Controller) ReplayOptimisationPreview ¶ added in v1.3.8
func (c *Controller) ReplayOptimisationPreview(ctx context.Context, installation, repo, id string) (*RetainedOptimisationPreview, error)
ReplayOptimisationPreview validates historical calculation, not current head or current publication policy. It never reads replacement source. Its private source-bearing result requires separate authorisation before any future route.
func (*Controller) ReportResult ¶
func (c *Controller) ReportResult(ctx context.Context, hostID string, res agent.TaskResult) (resultErr error)
ReportResult applies the outcome of one task and clears its lease.
func (*Controller) ReportRunners ¶
func (c *Controller) ReportRunners(ctx context.Context, hostID string, reports []agent.RunnerReport) error
ReportRunners merges an agent's observations outside the heartbeat cycle, so a runner coming up is visible immediately rather than up to a beat later.
func (*Controller) RequestControllerUpdate ¶ added in v1.3.8
func (c *Controller) RequestControllerUpdate(ctx context.Context, by UpdateActor, tag string) (*UpdatesView, error)
RequestControllerUpdate is RequestControllerUpdateAttempt for a caller that wants only the status.
func (*Controller) RequestControllerUpdateAttempt ¶ added in v1.3.8
func (c *Controller) RequestControllerUpdateAttempt(ctx context.Context, by UpdateActor, tag string) (*UpdatesView, string, error)
RequestControllerUpdateAttempt asks the helper beside this controller to take it to tag, or to the newest release that can be installed here when tag is empty, and returns the status with the attempt in it.
The order is the design. Everything that can refuse does so before anything is written. The attempt is recorded before the request, because the store's rule of one open attempt per target is what stops two callers each writing one. And a request that cannot be written closes the attempt it opened, so a failed button leaves nothing in flight.
The helper's unit stops after five starts in ten minutes. One open attempt at a time, each closed by an answer or after 90 minutes, keeps requests well below it.
The attempt's id comes back beside the status so that a caller that audits the press does not have to find it in the status, where it is only the latest.
func (*Controller) RequestEliRepair ¶ added in v1.3.8
func (c *Controller) RequestEliRepair(ctx context.Context, userID, repo string, pull int, instruction string, requesterAdmin bool) (*store.EliRepair, error)
RequestEliRepair is the same owner-scoped operation as a GitHub mention, reachable from the UI.
func (*Controller) RequestHostCheck ¶ added in v1.3.8
func (c *Controller) RequestHostCheck(ctx context.Context, hostID string) (h store.Host, queued bool, err error)
RequestHostCheck asks a host's agent to run its OS checks once. queued is true only when a task was actually put on the host's queue, which is what the caller audits: a repeat press and every refusal queue nothing.
Nothing is dialled. The task goes out on the agent's own poll.
func (*Controller) RequestHostUpdate ¶ added in v1.3.8
func (c *Controller) RequestHostUpdate(ctx context.Context, by UpdateActor, hostID string) (*HostView, error)
RequestHostUpdate asks a host's agent to have its helper take it to this controller's release, and returns the host with the attempt on it.
The order is RequestControllerUpdateAttempt's: everything that can refuse does so before anything is written, and the attempt is recorded before the task is queued, because the store's one open attempt per host is what stops two callers each sending one. Nothing is dialled: the task goes out on the agent's own poll, and success is the host heartbeating the release, not the task's answer.
The helper's path unit stops after five starts in ten minutes. One open attempt per host, and the planner's 30-minute wait after a failure, keep a host far below it.
func (*Controller) RequestPinnedEliRepair ¶ added in v1.3.8
func (c *Controller) RequestPinnedEliRepair(ctx context.Context, userID, repo string, pull int, instruction, expectedHead string, runID int64, requesterAdmin bool) (*store.EliRepair, error)
RequestPinnedEliRepair is the request the repair page makes. runID is the run whose failure the person was looking at, or 0 when they came from the pull request alone; it is what the attempt later says the repair was started for.
func (*Controller) RequestRestart ¶ added in v1.3.8
func (c *Controller) RequestRestart(reason string)
RequestRestart asks the process to stop so that its service manager starts it again. It is how a staged restore is applied from the settings page: the restore has to happen with the database closed, and the only process that can close this controller's database is this controller, by exiting.
It is a request, not a promise: whether the process comes back is up to whatever started it, which is why the page that presses it says what to do if nothing does.
func (*Controller) RerunJobWorkflow ¶ added in v1.3.8
RerunJobWorkflow asks GitHub to run the failed jobs of this job's run again.
This is what Zoomies can actually do about a failure it caused. A job the fleet broke did not fail on its merits -- nothing about the workflow has changed, and the ordinary remedy is to run it again -- but until now an operator had to notice the fault, work out that it was the fleet's, find the run on GitHub and press the button there.
Three things it deliberately does not do:
It does not re-run by itself. GitHub minutes are the operator's to spend, a fleet that re-runs its own failures can loop on a fault it is causing every time, and a job that failed may have had side effects the person who wrote it knows about and this does not.
It does not restrict itself to fleet faults. The check is that the job failed, not whose fault it was: an operator who has looked at a failure and decided to run it again is entitled to, and a button that refused on a judgement Zoomies made about blame would be a button people learn to route around. What the fault category does is decide where the button is offered.
And it does not touch the local row. The re-run arrives as new deliveries with a higher run attempt, through the same webhook path as everything else; writing an outcome here would be the fleet inventing one.
func (*Controller) RestartRequested ¶ added in v1.3.8
func (c *Controller) RestartRequested() <-chan struct{}
RestartRequested is closed once RequestRestart has been called.
func (*Controller) Restarting ¶ added in v1.3.8
func (c *Controller) Restarting() (bool, string)
Restarting reports whether a restart has been asked for, and why.
func (*Controller) ResumeRollout ¶ added in v1.3.8
func (c *Controller) ResumeRollout(ctx context.Context, by UpdateActor) (*UpdatesView, RolloutChange, error)
ResumeRollout lets a halted rollout carry on. The failure it halted on stays on the host's attempt, and the planner reads only failures after the resume, so the host that failed waits out its retry and the rollout goes on. A rollout already running is left as it is, and the change says nothing moved.
func (*Controller) RetainExperimentComparison ¶ added in v1.3.8
func (c *Controller) RetainExperimentComparison(ctx context.Context, actor *store.AuditEvent, record ExperimentComparisonRecord, a, b *ExperimentJoinedEvidence) (*RetainedExperimentComparison, error)
RetainExperimentComparison requires an authenticated, authorised actor from the transport. Actor and evidence identity are never accepted from a record. Nothing succeeds until the complete envelope and audit are durably committed.
func (*Controller) RetainOptimisationPreview ¶ added in v1.3.8
func (c *Controller) RetainOptimisationPreview(ctx context.Context, actor *store.AuditEvent, installation, repo string, source optimisation.Source, timing optimisation.Timing, history optimisation.HistoryReview, policy optimisation.Policy) (*RetainedOptimisationPreview, error)
RetainOptimisationPreview is an internal adapter for already admitted source, timing and policy. It is not a collector and has no route. A future transport must independently authorise source-bearing history and obtain evidence; request booleans or client-submitted timing must never stand in for server admission.
func (*Controller) RetireRecoveryHost ¶ added in v1.3.8
func (c *Controller) RetireRecoveryHost(ctx context.Context, id, confirm, actor string) error
RetireRecoveryHost fences even a queue held by a request authenticated before retirement. Unfence cannot resume delivery until this queue has been sealed.
func (*Controller) RevokeHostCheck ¶ added in v1.3.8
func (c *Controller) RevokeHostCheck(ctx context.Context, hostID, checkID string) (HostView, *store.HostCheckAcceptance, error)
RevokeHostCheck ends an acceptance and returns the one it ended, which is what the audit row records as what was. Revoking one that is not there is not an error: two operators pressing the button agree on the outcome, and the second is told the host as it stands. The returned acceptance is nil then.
func (*Controller) RunnerImage ¶
func (c *Controller) RunnerImage(p *store.Pool) string
RunnerImage returns the image a pool's runners use.
Three answers in order. A pool that names an image gets it, unchanged: an operator who has built their own is not second-guessed. Otherwise the pool's platform picks the variant, so a pool called zoomies-4vcpu-debian-12 boots the Debian 12 image without anyone keeping the two in step by hand. A pool that names neither falls back to the instance default.
Whichever it lands on, a pool that gives its jobs a daemon then runs that image's Docker variant. The API already writes the swap into the pool when it is saved; it is made again here because this is the one place that sees the other two answers, and because what runs should be decided where the runner is made rather than trusted to every path that ever wrote a pool row.
func (*Controller) RunnerRenderer ¶
func (c *Controller) RunnerRenderer(ctx context.Context, runners []*store.Runner) (*RunnerRenderer, error)
RunnerRenderer builds the index a page of runners is rendered from.
func (*Controller) Samples ¶
func (c *Controller) Samples(ctx context.Context, since time.Time) ([]store.FleetSample, error)
Samples returns the Overview's sparkline points since a cutoff.
func (*Controller) SeedDemo ¶
func (c *Controller) SeedDemo(ctx context.Context) error
SeedDemo writes a deterministic fixture fleet: one installation, two pools, a dozen runners spread across the state machine, fifty jobs with plausible queue waits and outcomes, three hosts, one provider with the two machines it has rented, some scaling history and an audit trail. It is what ZOOMIES_SEED_DEMO turns on for the Playwright suite and for a demo instance.
It is idempotent -- a second call does nothing -- and it refuses to run at all if this instance has any pool that is not one of its own, because a fixture fleet appearing in a real deployment would be indistinguishable from a compromise.
The installation it creates carries a dummy private key. Nothing ever calls GitHub with it: the fixtures are written straight to the database.
func (*Controller) SeedStuck ¶
func (c *Controller) SeedStuck(ctx context.Context) error
SeedStuck ages the demo's starting runners into the two stuck shapes and adds the two fixtures the demo has no room for: a pool nothing can place, and a job GitHub is holding.
It runs after SeedDemo and depends on it, because a fleet in trouble is only legible against one that is working: the point of the problems drawer is that it names the three things wrong among the twenty that are right.
func (*Controller) SetActionsIssuer ¶ added in v1.3.8
func (c *Controller) SetActionsIssuer(issuer string)
SetActionsIssuer points GitHub.com upload verification at another OIDC issuer. Tests use it with github.NewFakeActionsIssuer; production keeps GitHub's.
func (*Controller) SetActionsIssuerFor ¶ added in v1.3.8
func (c *Controller) SetActionsIssuerFor(issuerFor func(host string) string)
SetActionsIssuerFor replaces how a host's Actions issuer is found, for tests that stand in for an Enterprise Server's.
func (*Controller) SetKennelTracking ¶ added in v1.3.8
func (c *Controller) SetKennelTracking(ctx context.Context, repositoryID string, in KennelTrackingInput, by KennelActor) (*KennelRepositoryView, *store.KennelUntracked, bool, error)
SetKennelTracking stops Kennel Club looking at a repository, or starts it again. It returns the repository as it now stands, the decision it replaced (nil if the repository was tracked), and whether anything changed: asking for the state a repository is already in is answered and is not a second decision, so the caller has no audit row to write for it.
Stopping silences the repository's errors, so it takes the administrator role and a reason in the words a waiver's is held to, and it is checked before the reason is: a person who may not do it is told so and not told how to ask better. Starting again takes an operator, because the only thing it can do is make Kennel Club stricter, and it makes the repository due at once so the next pass reads it.
func (*Controller) SetPrivateConnectionFault ¶ added in v1.3.8
func (c *Controller) SetPrivateConnectionFault(f *PrivateConnectionFault)
SetPrivateConnectionFault records the private-connection listener's state: a fault while no relay answers, nil once one does. It is safe to call from any goroutine.
func (*Controller) SetSSOTrouble ¶ added in v1.3.8
func (c *Controller) SetSSOTrouble(t *SSOTrouble)
SetSSOTrouble records that single sign-on is not working, or with nil that it is again. The problem it raises clears on the next pass after a nil.
func (*Controller) SharedProblems ¶ added in v1.3.8
func (c *Controller) SharedProblems(ctx context.Context) ([]Problem, error)
SharedProblems is Problems for callers that may overlap: the API handler and the event stream. Callers that arrive while a computation is running wait for it rather than starting another, and each gets its own copy of the list.
func (*Controller) ShipBackups ¶ added in v1.3.8
ShipBackups makes every enabled remote hold what the backup directory holds, and returns what it sent.
It is safe to call from anywhere: one pass at a time across the whole controller, so the loop's catch-up and an operator pressing "copy offsite now" cannot upload the same archive twice.
func (*Controller) Start ¶
func (c *Controller) Start(ctx context.Context) error
Start launches the background loops and returns as soon as they are running. It does not block until they finish; Stop does that.
func (*Controller) StartAssistantChat ¶ added in v1.3.8
func (c *Controller) StartAssistantChat(ctx context.Context, in AssistantChatRequest) (*AssistantChat, error)
StartAssistantChat opens the answer to a conversation. Everything that can be refused is refused here, before any stream exists, so the caller can answer with a status and not with a stream that opens and fails.
The error from the provider is passed on: the adapters write theirs for a person and never carry the request or the key.
func (*Controller) StartEmbeddedAgent ¶
StartEmbeddedAgent runs an agent inside the controller process, so a single VM needs exactly one process and one systemd unit.
It joins itself with a short-lived token it mints on the spot: the embedded agent is not a remote party, and requiring an operator to paste a token into their own controller would be ceremony without a threat model behind it.
func (*Controller) StartHostRollout ¶ added in v1.3.8
func (c *Controller) StartHostRollout(ctx context.Context, by UpdateActor, hostIDs []string) (*UpdatesView, RolloutChange, error)
StartHostRollout starts a rollout of every host behind this controller's release, or of hostIDs, and returns the status with it. The planner moves it on from the next pass, one host at a time; nothing is asked of a host here.
by is only written down, as the rollout's started_by. The handler that took the request audits it with the caller's identity. Once the rollout is written the change names it even when the status after it cannot be worked out, so that the handler can audit a rollout that exists before it reports the failure.
func (*Controller) StartTestMachine ¶ added in v1.3.8
func (c *Controller) StartTestMachine(ctx context.Context, row *store.Provider) (*store.Machine, error)
StartTestMachine reserves one test machine on a provider and wakes the machine loop to build it.
Only one runs at a time per provider: two would race for the same ceiling and each would leave the operator unsure which machine the answer was about. The checks read what exists and the reservation writes after, so a second request arriving between them would see nothing on the way; one lock holds them together, and a request that waits for it is answered by what the first made.
func (*Controller) StartToolchainScan ¶ added in v1.3.8
func (c *Controller) StartToolchainScan(ctx context.Context) error
StartToolchainScan begins a scan in the background and returns at once. A scan reads every workflow file in every repository, which on a large organisation is minutes of GitHub calls: far longer than a request should hold a connection open, so the scan is detached from the request.
func (*Controller) Status ¶ added in v1.3.8
func (c *Controller) Status(ctx context.Context) (*FleetStatus, error)
Status is the projection for the running fleet, with Since kept across calls so it means "since the state last changed" rather than "since you asked".
func (*Controller) Stop ¶
func (c *Controller) Stop(ctx context.Context) error
Stop shuts the loops down gracefully and flushes what is worth keeping.
It deliberately does not tear down runners. Restarting a controller must not kill jobs: the runners keep working, their agents keep reporting, and the next reconcile picks up where this one left off.
func (*Controller) StopEliAutomatic ¶ added in v1.3.8
func (c *Controller) StopEliAutomatic(ctx context.Context, repos []string, then string) ([]EliAutomaticStop, error)
StopEliAutomatic stops automatic repairs on the named repositories, once each, in the order given. It only relaxes a policy: it never enables a repository, raises a limit or changes a provider, and it does not look the provider up, because the day an administrator needs this is the day the provider is the problem. A repair already queued is blocked by the worker when it reaches it, and one that has not yet pushed stops before it does (see runEliRepair), so the stop needs no second write.
One repository failing to save is that repository's result and does not stop the rest. An unknown choice is an error, so the API validates first.
func (*Controller) Store ¶
func (c *Controller) Store() *store.Store
Store returns the database handle the API reads through.
func (*Controller) SyncAIContext ¶ added in v1.3.8
SyncAIContext verifies a repository and, when the only thing wrong is that the published context is behind the trusted branch, starts the managed workflow itself once the push-triggered run has had grace to finish. The workflow already runs on every push, so this is the safety net under it: a push GitHub did not deliver, a run that was cancelled by a later one, or a run that failed all leave the same stale card, and this is what clears it without anybody pressing a button.
It never acts on a verification that failed for any other reason, and it starts a given commit's workflow at most aiContextRunAttempts times.
func (*Controller) TakeBackup ¶ added in v1.3.8
TakeBackup takes a backup now, on behalf of whoever asked, and applies retention afterwards.
One at a time. The store serialises the copy itself, but two callers racing for the same second would race for the same directory name too, and a backup and a prune interleaved could delete the copy being taken.
func (*Controller) ToolchainScanResult ¶ added in v1.3.8
func (c *Controller) ToolchainScanResult() ToolchainScan
ToolchainScanResult returns the latest scan, and whether one is running.
func (*Controller) TracksClasses ¶ added in v1.3.8
func (c *Controller) TracksClasses() bool
TracksClasses reports whether hosts are being given a size class, which is when a host's size tag has to be one.
func (*Controller) TransferProgress ¶ added in v1.3.8
func (c *Controller) TransferProgress(ctx context.Context) (TransferProgress, error)
TransferProgress is where preparation stands, with the sentence that says so. The store counts and names what is in the way; the words are written here, where the fleet's other reasons are, so the page and the CLI show the same ones.
func (*Controller) Unfence ¶
func (c *Controller) Unfence(ctx context.Context) error
Unfence lifts the fence and lets the fleet act again.
It writes the database first and the in-memory copy second, so a failed write leaves a fenced controller rather than one that believes it is free.
func (*Controller) UnwaiveKennelFinding ¶ added in v1.3.8
func (c *Controller) UnwaiveKennelFinding(ctx context.Context, repositoryID, waiverID string) (*KennelRepositoryView, *store.KennelWaiver, error)
UnwaiveKennelFinding ends a waiver. It returns the waiver it ended, which is what the audit row records as what was.
func (*Controller) UpdateConfig ¶
func (c *Controller) UpdateConfig(fn func(*config.Config)) *config.Config
UpdateConfig changes the running configuration.
fn is applied to a copy of the current snapshot, which then replaces it, so a loop in the middle of a pass finishes on the values it started with and the next pass sees the new ones. Anything built once from the configuration -- the log level's gate, the scheduler's and poller's timers -- is retuned here, which is what lets PATCH /settings promise that an accepted change is in effect and not merely recorded.
func (*Controller) UpdatesView ¶ added in v1.3.8
func (c *Controller) UpdatesView(ctx context.Context) (*UpdatesView, error)
UpdatesView works out the status now.
func (*Controller) ValidateProviderSettings ¶ added in v1.3.8
func (c *Controller) ValidateProviderSettings(kind store.ProviderKind, settings map[string]string) ([]config.Finding, error)
ValidateProviderSettings runs a driver's own offline check over a draft's answers. It dials nothing and needs no credential, which is what lets the wizard run it as somebody types; CheckProvider is the call that talks to the hypervisor.
func (*Controller) VerifiedAIContextSnapshot ¶ added in v1.3.8
func (c *Controller) VerifiedAIContextSnapshot(ctx context.Context, id string) (*aicontext.Snapshot, *store.AIContextFreshness, error)
VerifiedAIContextSnapshot repeats live access and workflow checks before returning source. Background polling alone is not an access gate.
func (*Controller) WaiveKennelFinding ¶ added in v1.3.8
func (c *Controller) WaiveKennelFinding(ctx context.Context, repositoryID string, in KennelWaiverInput, by KennelActor) (*KennelRepositoryView, *store.KennelWaiver, error)
WaiveKennelFinding records a decision that a finding is acceptable here, and works the repository out again so the answer already says so.
It is for a finding that exists. A waiver made ahead of one is a standing exception nobody has looked at, so a code and subject that match no open or waived finding are refused; and one for an error needs the senior role, because an error is a stranger running code on the fleet and the decision that it is acceptable is not an operator's to take alone.
type DaemonShareChange ¶ added in v1.3.8
type DaemonShareChange struct {
}
DaemonShareChange is a pool's Docker sidecar share, as a percentage of the slot, for each resource a notice proposes moving. A resource it leaves out is one the notice has no advice for, or advice that would cost the pool its runners, and applying the change leaves that share where it is.
type DoctorView ¶ added in v1.3.8
DoctorView is a host's OS report as the API renders it: the report the agent wrote, untouched, and beside it the controller's own count of it. The count is not a field of hosttune.Report because that type is also what an agent posts and what the hosts table stores; a Summary there would be agent-supplied and would outlive the results it counts. Summary here shadows the promoted Report.Summary method on purpose -- the JSON key is the point -- so the count is worked out on every read and a heartbeat that sends one has it ignored.
type EffectiveProfileView ¶ added in v1.3.8
type EffectiveProfileView struct {
Minimum EffectiveSizeView `json:"minimum"`
Standard EffectiveStandardView `json:"standard"`
}
EffectiveProfileView is what a runner on a host is held to, with the fleet's setting standing in wherever the host says nothing. It is what the host's own form shows beside the fields an operator can edit, so that an empty field reads as "follows the fleet's 2 CPU" rather than as nothing.
func EffectiveProfile ¶ added in v1.3.8
func EffectiveProfile(h *store.Host, fleet config.Runners) EffectiveProfileView
EffectiveProfile resolves h's runner profile against the fleet's settings: the host's own figure on each field it names, and runners.minimum_* and runners.default_* where it does not.
A host's minimum that follows the fleet is shown as such, but a pool that sets a minimum of its own still wins over the fleet's for the runners it places there: the host's own figure is a floor under the pool's, and the fleet's is only the answer the pool follows when it says nothing.
type EffectiveSizeView ¶ added in v1.3.8
type EffectiveSizeView struct {
CPUs float64 `json:"cpus"`
MemoryMB int64 `json:"memory_mb"`
CPUsSource string `json:"cpus_source,omitempty"`
MemoryMBSource string `json:"memory_mb_source,omitempty"`
}
EffectiveSizeView is one tier of a host's effective profile: the figure in force on each field, and whose it is.
type EffectiveStandardView ¶ added in v1.3.8
type EffectiveStandardView struct {
EffectiveSizeView
BurstMaxCPUs float64 `json:"burst_max_cpus,omitempty"`
BurstMaxCPUsSource string `json:"burst_max_cpus_source,omitempty"`
// BurstMaxMemoryMB is the most memory one runner here may hold, lent memory
// included, and BurstMaxMemoryMBSource whose it is. Absent where the host
// names none, which leaves a pool's own ceiling, or half as much again as a
// runner's guarantee.
BurstMaxMemoryMB int64 `json:"burst_max_memory_mb,omitempty"`
BurstMaxMemoryMBSource string `json:"burst_max_memory_mb_source,omitempty"`
}
EffectiveStandardView is the standard tier, which carries the most CPU one runner may be lent as well.
type EliAutomaticRepository ¶ added in v1.3.8
type EliAutomaticRepository struct {
Repo string `json:"repo"`
InstallationID string `json:"installation_id"`
ProviderID string `json:"provider_id"`
// ProviderName and Model are empty when the policy has no provider, which is
// what deleting a provider leaves behind.
ProviderName string `json:"provider_name"`
Model string `json:"model"`
// Problem is present only when automatic repairs here cannot run, in a
// sentence that says what to do about it.
Problem string `json:"problem,omitempty"`
AllowWorkflows bool `json:"allow_workflows"`
DailyLimit int `json:"daily_limit"`
// Used is every attempt on the repository in the last 24 hours, by anyone and
// by any trigger: the figure the daily limit is held against.
Used int `json:"used"`
// NextFreeAt is when the oldest of those attempts leaves the window, which is
// when a full allowance has a place again.
NextFreeAt *time.Time `json:"next_free_at,omitempty"`
Running int `json:"running"`
Last *store.EliAutomaticLast `json:"last,omitempty"`
}
EliAutomaticRepository is one repository that repairs its own failed checks, with what an administrator needs to trust that or stop it: who pays, whether they can, what has been spent of the allowance and what the automation did last. It is an administrator's view; automatic repairs have no owner, so an ordinary user cannot read any of them.
type EliAutomaticStop ¶ added in v1.3.8
type EliAutomaticStop struct {
Repo string `json:"repo"`
// Changed is false for a repository that was not automatic any more, so a
// second press or a second administrator is not an error.
Changed bool `json:"changed"`
Error string `json:"error,omitempty"`
}
EliAutomaticStop is what happened to one repository in a stop.
type EliBlocker ¶ added in v1.3.8
type EliCheck ¶ added in v1.3.8
type EliCheck struct {
Code string `json:"code"`
Status string `json:"status"`
Message string `json:"message"`
// Blocker is the code of the blocker that stopped a blocked check. A check
// says where readiness stopped and a blocker says why, and the two are not
// the same thing: GitHub not answering is folded into whichever check it was
// making. When the target has changed the answer's Blockers hold that change
// alone, and a check blocked before it was found still names what stopped it.
Blocker string `json:"blocker,omitempty"`
}
EliCheck is one thing readiness looks at and what it found. Status is EliCheckOK, EliCheckBlocked, or EliCheckUnchecked for a check readiness never reached because an earlier one stopped it: a check that was not made is not a check that passed, and the page must not draw it as one.
type EliErrorOutput ¶ added in v1.3.8
EliErrorOutput is the lines of a failed job's log that say why it failed. Note is a sentence for the person when there are none to show.
type EliReadiness ¶ added in v1.3.8
type EliReadiness struct {
Ready bool `json:"ready"`
Repo string `json:"repo"`
PullNumber int `json:"pull_number"`
HeadSHA string `json:"head_sha"`
// Pull is the pull request in its own words. It is set only after the
// caller's linked GitHub account has been shown to write to the repository,
// so a person who may not see the repository is never told what is in it.
Pull *EliReadinessPull `json:"pull,omitempty"`
Provider string `json:"provider"`
Model string `json:"model"`
AllowWorkflows bool `json:"allow_workflows"`
Remaining int `json:"remaining"`
ResetAt *time.Time `json:"reset_at,omitempty"`
// PolicyMode is how the repository's policy lets Eli help: automatic,
// ask_first or manual. A page that offers to start a repair needs it to say
// whether the repository would have started one itself. It is set once
// readiness reaches the policy check, and not before.
PolicyMode string `json:"policy_mode,omitempty"`
// Blockers is what stands in the way, as it always has been. When the target
// has changed (fixed, closed, superseded) it is that alone, which is the
// answer to what the person asked; Checks still say what each check found.
Blockers []EliBlocker `json:"blockers"`
// Checks is every check readiness makes, in the order it makes them, so a
// page can show what passed as well as what did not.
Checks []EliCheck `json:"checks"`
}
type EliReadinessPull ¶ added in v1.3.8
type EliReadinessPull struct {
Number int `json:"number"`
Title string `json:"title"`
Author string `json:"author"`
Branch string `json:"branch"`
Base string `json:"base"`
URL string `json:"url"`
Open bool `json:"open"`
}
EliReadinessPull is the pull request a readiness answer is about.
type Evidence ¶ added in v1.3.8
type Evidence struct {
Kind string `json:"kind"`
Label string `json:"label"`
Value string `json:"value"`
Unit string `json:"unit,omitempty"`
// Ref is where the evidence lives: a path in this UI, or a URL.
Ref string `json:"ref,omitempty"`
}
Evidence is one fact a person can check for themselves: where it came from, what it said, and where to look.
type ExperimentAdmissionError ¶ added in v1.3.8
func (*ExperimentAdmissionError) Error ¶ added in v1.3.8
func (e *ExperimentAdmissionError) Error() string
func (*ExperimentAdmissionError) Unwrap ¶ added in v1.3.8
func (e *ExperimentAdmissionError) Unwrap() error
type ExperimentAttemptSelection ¶ added in v1.3.8
type ExperimentComparisonRecord ¶ added in v1.3.8
type ExperimentComparisonRecord struct {
Kind string `json:"kind"`
Repository string `json:"repository"`
InitiatingUser string `json:"initiating_user"`
Hypothesis string `json:"hypothesis"`
IntendedDelta string `json:"intended_delta"`
EvidenceID string `json:"evidence_id"`
RevisionDeltaID string `json:"revision_delta_id"`
Since time.Time `json:"since"`
Until time.Time `json:"until"`
}
type ExperimentComparisonReport ¶ added in v1.3.8
type ExperimentComparisonReport struct {
WindowBasis string `json:"window_basis"`
ExecutionBasis string `json:"execution_basis"`
Snapshot analysis.ExperimentSnapshot `json:"snapshot"`
Measurement analysis.ExperimentMeasurement `json:"measurement"`
}
func AssembleExperimentComparison ¶ added in v1.3.8
func AssembleExperimentComparison(record ExperimentComparisonRecord, a, b *ExperimentJoinedEvidence) (*ExperimentComparisonReport, error)
AssembleExperimentComparison does no collection or authorisation. Its caller must retain the input evidence beside the returned snapshot. An operator's intended delta is a hypothesis, not evidence of past runner configuration.
type ExperimentJoinedAttempt ¶ added in v1.3.8
type ExperimentJoinedAttempt struct {
Remote *github.ExperimentAttemptEvidence `json:"remote"`
RetainedCoverage string `json:"retained_coverage"`
FleetIdentityCoverage string `json:"fleet_identity_coverage"`
MatchedJobs []ExperimentMatchedJob `json:"matched_jobs"`
MissingJobIDs []int64 `json:"missing_job_ids"`
ExtraFleetJobIDs []int64 `json:"extra_fleet_job_ids"`
}
type ExperimentJoinedEvidence ¶ added in v1.3.8
type ExperimentJoinedEvidence struct {
Repository string `json:"repository"`
InstallationID string `json:"installation_id"`
SelectionComplete bool `json:"selection_complete"`
Attempts []ExperimentJoinedAttempt `json:"attempts"`
}
type ExperimentMatchedJob ¶ added in v1.3.8
type ExperimentMatchedJob struct {
RunnerCreation *store.RunnerCreationObservation `json:"runner_creation,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
PoolID string `json:"pool_id,omitempty"`
HostID string `json:"host_id,omitempty"`
RecordedGrant *ExperimentRecordedGrant `json:"recorded_grant,omitempty"`
GitHubJobID int64 `json:"github_job_id"`
FleetJobID string `json:"fleet_job_id"`
}
type ExperimentRecordedGrant ¶ added in v1.3.8
type ExperimentRecordedGrant struct {
Basis string `json:"basis"`
Source string `json:"source"`
CPUs *float64 `json:"cpus"`
MemoryMB *int64 `json:"memory_mb"`
}
ExperimentRecordedGrant is a controller stamp, not backend attestation. It records the guaranteed assignment size, not burst limits, usage or an image. No observation timestamp is invented from the job's execution timestamps.
type ExperimentRecordedGrantView ¶ added in v1.3.8
type ExperimentRetainedAttempt ¶ added in v1.3.8
type ExperimentRetainedAttempt struct {
Selection ExperimentAttemptSelection `json:"selection"`
// retained_only is never full workflow coverage, even when the query fits.
Coverage string `json:"coverage"`
Jobs []ExperimentRetainedJob `json:"jobs"`
}
type ExperimentRetainedEvidence ¶ added in v1.3.8
type ExperimentRetainedEvidence struct {
Repository string `json:"repository"`
InstallationID string `json:"installation_id"`
SelectionComplete bool `json:"selection_complete"`
Attempts []ExperimentRetainedAttempt `json:"attempts"`
}
type ExperimentRetainedJob ¶ added in v1.3.8
type ExperimentRetainedJob struct {
RunnerCreation *store.RunnerCreationObservation `json:"runner_creation,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
PoolID string `json:"pool_id,omitempty"`
HostID string `json:"host_id,omitempty"`
RecordedGrant *ExperimentRecordedGrant `json:"recorded_grant,omitempty"`
JobID string `json:"job_id"`
GitHubJobID int64 `json:"github_job_id"`
HeadSHA string `json:"head_sha"`
State store.JobState `json:"state"`
Conclusion string `json:"conclusion"`
QueuedAt time.Time `json:"queued_at"`
StartedAt *time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at"`
}
type ExperimentRootSourceView ¶ added in v1.3.8
type ExperimentRunnerEvidence ¶ added in v1.3.8
type ExperimentRunnerEvidence struct {
Version string `json:"version"`
Baseline ExperimentRunnerEvidenceArm `json:"baseline"`
Candidate ExperimentRunnerEvidenceArm `json:"candidate"`
}
This response projection is separate from the stored report. Older envelopes still replay byte-for-byte reports; descriptive facts come only from their validated retained inputs, never a current runner or configuration lookup.
type ExperimentRunnerEvidenceArm ¶ added in v1.3.8
type ExperimentRunnerEvidenceArm struct {
SelectedJobs int `json:"selected_jobs"`
MatchedJobs int `json:"matched_jobs"`
RecordedGrants int `json:"recorded_grants"`
RunnerObservations int `json:"runner_observations"`
RowsOmitted bool `json:"rows_omitted"`
Jobs []ExperimentRunnerEvidenceJob `json:"jobs"`
}
type ExperimentRunnerEvidenceJob ¶ added in v1.3.8
type ExperimentRunnerEvidenceJob struct {
RunID int64 `json:"run_id,string"`
Attempt int `json:"attempt"`
GitHubJobID int64 `json:"github_job_id,string"`
FleetMatched bool `json:"fleet_matched"`
RecordedGrant *ExperimentRecordedGrantView `json:"recorded_grant"`
Observation *ExperimentRunnerObservationView `json:"observation"`
}
type ExperimentRunnerObservationView ¶ added in v1.3.8
type ExperimentRunnerObservationView struct {
SHA256 string `json:"sha256"`
IssuedAt time.Time `json:"issued_at"`
ReceivedAt time.Time `json:"received_at"`
Requested ExperimentRunnerRequestView `json:"requested"`
ImageDigest *string `json:"image_digest"`
DigestCoverage string `json:"digest_coverage"`
AgentCompletedAt *time.Time `json:"agent_completed_at"`
AgentContainerStartedAt *time.Time `json:"agent_container_started_at"`
}
type ExperimentRunnerRequestView ¶ added in v1.3.8
type ExperimentRunnerRequestView struct {
Backend string `json:"backend"`
ImageReferenceSHA256 string `json:"image_reference_sha256"`
CPUs *float64 `json:"cpus"`
MemoryMB *int64 `json:"memory_mb"`
ResourceSource string `json:"resource_source"`
DockerMode string `json:"docker_mode"`
CPUTyped bool `json:"cpu_typed"`
MemoryTyped bool `json:"memory_typed"`
}
Keep an explicit whitelist even when the private store type gains fields. The response deliberately omits host, pool, runner, task and actor identities.
type ExperimentWorkflowEvidence ¶ added in v1.3.8
type ExperimentWorkflowEvidence struct {
Version string `json:"version"`
Baseline ExperimentWorkflowEvidenceArm `json:"baseline"`
Candidate ExperimentWorkflowEvidenceArm `json:"candidate"`
}
Workflow evidence is a response-only whitelist over validated retained inputs. It never enriches an old record with current files or changes report identity.
type ExperimentWorkflowEvidenceArm ¶ added in v1.3.8
type ExperimentWorkflowEvidenceArm struct {
SelectedAttempts int `json:"selected_attempts"`
RootSources int `json:"root_sources"`
RowsOmitted bool `json:"rows_omitted"`
Attempts []ExperimentWorkflowEvidenceAttempt `json:"attempts"`
}
type ExperimentWorkflowEvidenceAttempt ¶ added in v1.3.8
type ExperimentWorkflowEvidenceAttempt struct {
RunID int64 `json:"run_id,string"`
Attempt int `json:"attempt"`
Event *string `json:"event"`
WorkflowPathSHA256 *string `json:"workflow_path_sha256"`
RootSource *ExperimentRootSourceView `json:"root_source"`
}
type Fence ¶
type Fence = store.RecoveryFence
Fence is the recovery fence as the API renders it. It is an alias so the transport layer names a controller type rather than reaching into the store.
type FleetState ¶ added in v1.3.8
type FleetState string
FleetState is the one word the status projection leads with.
const ( // FleetHealthy is a fleet with nothing on its own list above info. FleetHealthy FleetState = "healthy" // FleetDegraded is a fleet whose worst problem is a warning: jobs still // run, slower or with less room than they should have. FleetDegraded FleetState = "degraded" // FleetBlocked is a fleet whose worst problem is an error: something the // fleet is asked to do is not happening, and waiting will not fix it. FleetBlocked FleetState = "blocked" )
type FleetStatus ¶ added in v1.3.8
type FleetStatus struct {
State FleetState `json:"state"`
// Since is when this process first saw the fleet in this state.
Since time.Time `json:"since"`
Version string `json:"version"`
// Queued and Running are the fleet's own jobs, banded.
Queued Band `json:"queued"`
Running Band `json:"running"`
// The queue wait over the last hour, rounded to the minute.
MedianWaitMinutes int `json:"median_wait_minutes"`
P95WaitMinutes int `json:"p95_wait_minutes"`
// Reasons are the fleet's current problems, one per code, worst first.
Reasons []StatusReason `json:"reasons"`
// Explanations is the public sentence for each code in Reasons. It is
// beside the reasons rather than in them so that a reason stays three
// fields and nothing else.
Explanations map[string]string `json:"explanations"`
}
FleetStatus is what GET /api/v1/status returns: a projection, not a view.
It is the one payload in the API that is deliberately not a resource's GET shape, because every resource view carries names -- a pool's, a host's, a repository's -- and this is for the developer with no account whose job has queued. So it is built the other way round: it carries no string that came from a row. Its reasons are codes, its counts are bands, its waits are whole minutes, and the only prose in it is the fixed public sentence for each code. Proving that is a test that searches a body for every name a fixture fleet has, which is a check rather than a promise renewed every time somebody edits a sentence.
func ProjectStatus ¶ added in v1.3.8
func ProjectStatus(problems []Problem, stats *Stats) FleetStatus
ProjectStatus builds the name-free status from the operator's problems list and the Overview's numbers. It is pure so that the disclosure boundary can be tested without a fleet.
Only the fleet's half of the problems split is read, the half a signed-in fleet operator without the platform role is shown, so a platform finding -- the backup remote, the lease, the controller's own release -- cannot reach it even by a mistake in the sentences below.
type HostAcceptInvalidError ¶ added in v1.3.8
type HostAcceptInvalidError struct{ Fields []KennelFieldError }
HostAcceptInvalidError is a request to accept that is wrong in a way the person can fix, each in the words of the field it belongs to.
func (*HostAcceptInvalidError) Error ¶ added in v1.3.8
func (e *HostAcceptInvalidError) Error() string
type HostActor ¶ added in v1.3.8
type HostActor struct{ ID, Name string }
HostActor is who is making a decision about a host: the name is kept with the acceptance, so it still reads right after the person's account is gone.
type HostAutoPoolView ¶ added in v1.3.8
type HostAutoPoolView struct {
Counted bool `json:"counted"`
// Pool is the pool's name, or under shadow the name it would have. PoolID is
// empty until there is a pool.
Pool string `json:"pool,omitempty"`
PoolID string `json:"pool_id,omitempty"`
// Reason is, for a host that counts towards none, why, and ReasonCode the
// stable form of the same thing.
Reason string `json:"reason,omitempty"`
ReasonCode string `json:"reason_code,omitempty"`
}
HostAutoPoolView says which automatic pool a host counts towards, or why it counts towards none.
type HostCheckChangedError ¶ added in v1.3.8
type HostCheckChangedError struct{ Now string }
HostCheckChangedError is an acceptance asked for a value the check no longer has. The operator decided about what they saw, and an agent has reported since: accepting what they did not see would be a decision about nothing.
func (*HostCheckChangedError) Error ¶ added in v1.3.8
func (e *HostCheckChangedError) Error() string
type HostCheckCooldownError ¶ added in v1.3.8
type HostCheckCooldownError struct {
Name string
Until time.Time
// contains filtered or unexported fields
}
HostCheckCooldownError says the host was asked a moment ago.
func (*HostCheckCooldownError) Error ¶ added in v1.3.8
func (e *HostCheckCooldownError) Error() string
type HostCheckError ¶ added in v1.3.8
type HostCheckError struct{ Code, Message string }
HostCheckError is a refusal the operator can act on. The API renders it as a conflict with Message as the sentence.
func (*HostCheckError) Error ¶ added in v1.3.8
func (e *HostCheckError) Error() string
type HostCheckView ¶ added in v1.3.8
type HostCheckView struct {
State string `json:"state"`
AskedAt time.Time `json:"asked_at"`
Outcome string `json:"outcome,omitempty"`
Message string `json:"message,omitempty"`
NextAt *time.Time `json:"next_at,omitempty"`
}
HostCheckView is the in-flight or just-finished request on a host's view.
type HostExclusion ¶
type HostExclusion struct {
Host string `json:"host"`
// Code is which of the placement rules turned this host down, for a caller
// that wants to group or colour them: unavailable, backend, platform, size,
// profile.
Code string `json:"code"`
Reason string `json:"reason"`
}
HostExclusion is one host a pool's selector reaches that could not run it, and why. The reason is a sentence about the host with the host's name left out, so a caller can put the name where its own layout wants it.
type HostFit ¶
type HostFit struct {
Count int
Detail string
// Alternatives are the backends offered by the hosts that match this pool
// in every way except its backend, in the order a pool would move to them.
// The wizard turns them into the second half of its warning, in the same
// words the scheduler uses once the pool is real.
Alternatives []string
// PlatformMismatch counts the hosts that fit in every other way but are
// not the machine the pool asked for. It is called out separately because
// it is the one mismatch no backend change can fix: the answer is a
// different host, or a different platform on the pool.
PlatformMismatch int
// Selected is how many hosts the pool's host selector reaches at all,
// whatever became of them afterwards. It is the number the wizard's
// placement step shows while a selector is being typed, and Count is the
// number its review step shows -- so when the two differ, something
// happened between them that an operator has to be told about.
Selected int
// Excluded is that difference, host by host: everything the selector
// reaches and the fleet cannot run, with the reason in the operator's
// terms. It is what turns "2 hosts match" followed by "1 host can run
// this pool" from a contradiction into an explanation.
Excluded []HostExclusion
// Reduced are hosts that can run the pool, counted in Count, where its
// runners get less than they would on a larger machine: the pool's
// minimum is doing its job there. It is information for the wizard to
// show as such -- a host listed here is not a problem with the pool.
Reduced []HostExclusion
}
HostFit is what the pool wizard asks before a pool exists: how many hosts could run it as configured, and, when none can, the first host's own account of why and the backends those hosts do offer.
Zero is worth saying out loud before a pool is created: a pool whose selector matches nothing looks completely healthy and never starts a runner. The explanation matters as much as the count, because the usual cause is not a missing machine but a daemon the agent on an existing one could not reach, and the backends those same hosts do offer are the other way out.
type HostSizeClassView ¶ added in v1.3.8
type HostSizeClassView struct {
// Class is the class in force: an operator's size tag where there is one, and
// the class the host's measurements put it in otherwise.
Class store.SizeClass `json:"class"`
// Source is "tag" when an operator's tag decided it and "measured" when the
// host's own CPUs and memory did.
Source string `json:"source"`
// Measured is what the host's measurements name right now, set only when it
// is not the class in force: because a tag replaces it, or because a change
// is being held back.
Measured store.SizeClass `json:"measured,omitempty"`
// Pending is a different class the measurements have named without a break
// since PendingSince, and PendingUntil is when the host moves if they keep
// doing so. The times are carried rather than written into Reason, so the
// page can count down against the viewer's own clock.
Pending store.SizeClass `json:"pending,omitempty"`
PendingSince *time.Time `json:"pending_since,omitempty"`
PendingUntil *time.Time `json:"pending_until,omitempty"`
// Reason is what put the host in Class, as a sentence.
Reason string `json:"reason"`
}
HostSizeClassView says which size class a host is in and why, in the terms the Hosts page shows it.
type HostStats ¶
type HostStats struct {
Total int `json:"total"`
Healthy int `json:"healthy"`
Cordoned int `json:"cordoned"`
Capacity int `json:"capacity"`
Used int `json:"used"`
}
HostStats summarises the agents and the room they have left.
type HostUpdateView ¶ added in v1.3.8
type HostUpdateView struct {
// State is the latest attempt's state while it says something about the
// host: requested, succeeded, failed, timed_out or cancelled. It is none when
// there is no such attempt, including one that failed before the host
// reached its release some other way (attemptIsHistory says what counts as
// that), and unsupported in its place for a host behind the controller that
// the helper can never be installed on.
State string `json:"state"`
// Reason is the sentence the card shows. For an attempt that ended without
// the update it is the reason recorded for it, often the helper's own, which
// can name a path on the host: only the platform role reads it (see For).
Reason string `json:"reason"`
// CanUpdate says whether asking for an update now would be taken.
CanUpdate bool `json:"can_update"`
// AttemptID is the attempt State describes, and empty with none.
AttemptID string `json:"attempt_id"`
}
HostUpdateView is a host's part in updating, as its card shows it: the latest attempt that still says something about the host, whether it can be updated now, and why in a sentence.
It holds nothing that moves with the clock or with a heartbeat, so the card is sent again only when one of these changes.
func (HostUpdateView) For ¶ added in v1.3.8
func (u HostUpdateView) For(platform bool) HostUpdateView
For is the update block as one audience may read it. The platform reads it whole; every other role is given a fixed sentence for an ended attempt in place of its reason, and still learns that it ended and how. It works on the fields alone, so the event stream can apply it to a frame it has decoded.
type HostView ¶
type HostView struct {
RecoveryState string `json:"recovery_state,omitempty"`
Retired bool `json:"retired"`
// HealthCheck is the last "Check now" asked of this host's agent, in memory
// only and omitted when there is nothing to say: no request, or one old
// enough that the page has no use for it.
HealthCheck *HostCheckView `json:"health_check,omitempty"`
Doctor *DoctorView `json:"doctor,omitempty"`
Usage *store.HostUsage `json:"usage,omitempty"`
UsageFresh bool `json:"usage_fresh"`
AdmissionReason string `json:"admission_reason,omitempty"`
// Throttle is the rung the controller has stepped this host down to after
// sustained pressure, absent when it is on none, and ThrottleReason is the
// same thing as the sentence the host card shows: what it took, why, what
// it is doing to the jobs already running, and how it ends. Both are the
// controller's alone; a heartbeat carries the measurements and never the
// decision.
Throttle *store.HostThrottle `json:"throttle,omitempty"`
ThrottleReason string `json:"throttle_reason"`
// AutoAdjust is the host's own answer to whether the controller keeps it at
// its recommendation (empty follows the fleet), AutoAdjustEffective what is
// true once the fleet's default is counted, and AutoAdjustedAt when the
// controller last moved it.
AutoAdjust string `json:"auto_adjust"`
AutoAdjustEffective bool `json:"auto_adjust_effective"`
AutoAdjustedAt *time.Time `json:"auto_adjusted_at,omitempty"`
// RuntimeRecovering is the container-runtime cooldown the agent last
// reported, absent when there is none, and RuntimeReason the card's
// sentence for it. The times are carried rather than written into the
// sentence, so the card can count down to the retry and say how old the
// report is against the viewer's own clock.
RuntimeRecovering *store.RuntimeIncident `json:"runtime_recovering,omitempty"`
RuntimeReason string `json:"runtime_reason,omitempty"`
// ImagePullFailed is the last start or prewarm here that could not make
// its pool's image ready, naming the registry, absent when there is none.
ImagePullFailed *store.ImagePullIncident `json:"image_pull_failed,omitempty"`
// EffectiveCapacity is the slots the host takes right now: Slots stepped
// down by the throttle, and Slots itself when there is none. Free is
// measured against it, so a throttled host's card does not promise slots
// the next pass will refuse.
EffectiveCapacity int `json:"effective_capacity"`
// Slots is how many runners the host takes before any throttle: its
// capacity, or -- where the operator has given it a standard runner size --
// what its machine holds of that size, up to the capacity. SlotsLimitedBy
// says what sets it where there is a standard: "cpu" or "memory" when the
// machine does, "capacity" when the operator's number is below what the
// machine holds, and nothing when the two agree or there is no standard.
Slots int `json:"slots"`
SlotsLimitedBy string `json:"slots_limited_by,omitempty"`
// RunnerProfile is what the operator has said about how big a runner is on
// this host, as they said it; absent when they have said nothing, which is
// every host until somebody does. EffectiveProfile is what is in force,
// with the fleet's settings standing in for every field the host leaves out
// and each figure's source, which is what the form shows beside the fields
// it lets an operator edit.
RunnerProfile *store.RunnerProfile `json:"runner_profile,omitempty"`
EffectiveProfile EffectiveProfileView `json:"effective_profile"`
// Priority is where this host stands in placement, and PrioritySource
// whether the operators' own number or the score the specs earn (see
// scheduler.HostPriority, which the scheduler's placement reads the same
// way). PriorityReason is the sentence the card shows beside it.
Priority int `json:"priority"`
PrioritySource string `json:"priority_source"`
PriorityReason string `json:"priority_reason"`
// Tags are what can be said about this host in the terms a pool's host
// selector asks in: the labels stored on it, and the automatic ones no label
// has taken the place of, each marked as which it is. SizeClass is the class
// the host is in and why, absent until one is worked out, and AutoPool the
// automatic pool the host counts towards or the reason it counts towards
// none, absent while automatic pools are off.
Tags []scheduler.Tag `json:"tags"`
SizeClass *HostSizeClassView `json:"size_class,omitempty"`
AutoPool *HostAutoPoolView `json:"auto_pool,omitempty"`
// UnlimitedRunners is how many of the live runners here were created
// with no CPU quota -- a pool with none and defaults off, a process pool,
// a daemon that cannot apply one, or a row from before allocations were
// recorded. They are the runners a CPU hold can mean something about.
UnlimitedRunners int `json:"unlimited_runners,omitempty"`
Connection string `json:"connection"`
ID string `json:"id"`
Name string `json:"name"`
Address string `json:"address,omitempty"`
Embedded bool `json:"embedded"`
Capacity int `json:"capacity"`
ActiveRunners int `json:"active_runners"`
Free int `json:"free"`
Backends []string `json:"backends"`
BackendInfo []BackendInfoView `json:"backend_info"`
Labels map[string]string `json:"labels"`
OS string `json:"os,omitempty"`
Distro string `json:"distro,omitempty"`
OSVersion string `json:"os_version,omitempty"`
Arch string `json:"arch,omitempty"`
// CPUs and MemoryMB are how much machine this host is, as its agent
// reported it: the daemon's view of the machine where that is larger than
// the agent's own share, because a container runner runs beside the agent
// rather than inside its cgroup.
CPUs int `json:"cpus,omitempty"`
MemoryMB int64 `json:"memory_mb,omitempty"`
// DiskTotalMB and DiskFreeMB are the filesystem holding the agent's work
// directory, which is where a runner's checkout and its caches land -- so
// it is the disk that decides whether a job has anywhere to go, and the
// answer to "the host has slots free, why did nothing start?".
//
// Free is what a runner may write to rather than what is unused; the two
// differ by the reserve the filesystem keeps for root, and a runner is not
// root. Zero on both is "not measured" -- an agent too old to report it,
// or a platform with no portable way to ask -- and is not a full disk.
DiskTotalMB int64 `json:"disk_total_mb,omitempty"`
DiskFreeMB int64 `json:"disk_free_mb,omitempty"`
// ReserveCPUs, ReserveMemoryMB and ReserveDiskMB are what the operator has
// held back from placement, for the machine's own sake rather than for any
// pool's. They are the operator's alone: a heartbeat never writes them,
// exactly as it never writes capacity.
ReserveCPUs int `json:"reserve_cpus,omitempty"`
ReserveMemoryMB int64 `json:"reserve_memory_mb,omitempty"`
ReserveDiskMB int64 `json:"reserve_disk_mb,omitempty"`
// AllocatableCPUs, AllocatableMemoryMB and AllocatableDiskMB are the
// machine less its reserve: what the scheduler may actually place onto,
// which is the figure a "how full is this host" question is asked against.
// The floors under the reserve -- half a core or 5% of the CPUs, 512 MB
// of memory and 2 GB of disk -- are applied here too, so what is shown is
// what is used. The CPU floor is what keeps the daemon, the agent and the
// kernel a core the runners' quotas can never take.
AllocatableCPUs float64 `json:"allocatable_cpus,omitempty"`
AllocatableMemoryMB int64 `json:"allocatable_memory_mb,omitempty"`
AllocatableDiskMB int64 `json:"allocatable_disk_mb,omitempty"`
// ReservedCPUs and ReservedMemoryMB are what the runners already on this
// host have promised away, as of the last scheduling pass and from the
// snapshot that pass decided on. Disk is deliberately absent: free disk is
// a measurement of the filesystem as it is now, so what those runners have
// written is in DiskFreeMB already, and adding their reservations would
// charge the same bytes twice.
//
// ReservedKnown is false until a pass has run, because zero would read as
// an idle machine rather than as an unanswered question.
ReservedCPUs float64 `json:"reserved_cpus,omitempty"`
ReservedMemoryMB int64 `json:"reserved_memory_mb,omitempty"`
ReservedKnown bool `json:"reserved_known"`
// ResourcesKnown is whether this host has reported what machine it is at
// all. An agent too old to say is placed by slots alone, which is what
// keeps an upgrade from emptying a fleet -- and the page has to say so,
// because a host showing no figures looks broken rather than old.
ResourcesKnown bool `json:"resources_known"`
// Platform is what this host is in the terms a pool asks in, and
// PlatformLabel is the same thing as a sentence: "Ubuntu 24.04, arm64".
Platform store.Platform `json:"platform"`
PlatformLabel string `json:"platform_label,omitempty"`
// CanonicalName is the name this machine would be given today. It is shown
// beside a host called something that says nothing, so an operator can see
// what renaming it would buy them.
CanonicalName string `json:"canonical_name,omitempty"`
Version string `json:"version,omitempty"`
VersionChannel string `json:"version_channel,omitempty"`
// MachineID is the machine this host is, when Zoomies rented it, and empty
// for a host somebody installed. It is the one fact a card needs to tell a
// rented machine from a host with an owner: a machine holds no shell
// anybody can reach, it is destroyed once it has been idle, and the
// machine that replaces it is cloned from the template its provider builds
// from, so "upgrade the agent" and "run this on the host" are advice nobody
// can carry out for one. The provider's own problem names that template.
MachineID string `json:"machine_id,omitempty"`
// Features is what the agent advertises it can do, and ElasticCPU the one
// answer a pool cares about: whether a runner placed here can be lent CPU
// at all. Rendered as a flag rather than left for the browser to find in
// the list, so the card and the pool wizard cannot disagree about which
// feature name means what.
Features []string `json:"features"`
ElasticCPU bool `json:"elastic_cpu"`
// ElasticMemory is the same answer for the memory valve: whether a runner
// placed here can be lent memory while it runs, and MemoryPool what the host
// can still lend, absent for a host with no runner the valve applies to.
ElasticMemory bool `json:"elastic_memory"`
MemoryPool *MemoryPoolView `json:"memory_pool,omitempty"`
Cordoned bool `json:"cordoned"`
// ProtocolVersion is the agent protocol this host reported, and
// Incompatible whether this controller can work with it. An incompatible
// host is excluded from placement exactly as a cordoned one is, so the
// Hosts page has to say which of the two it is: nothing is broken, the
// host is up and heartbeating, and it has quietly stopped taking work.
ProtocolVersion int `json:"protocol_version,omitempty"`
Incompatible bool `json:"incompatible"`
IncompatibleReason string `json:"incompatible_reason,omitempty"`
// VersionSkew is how this host's release stands to the controller's:
// "behind", "ahead", "differs", or absent when they match. It is computed
// here rather than in the browser because the controller is the side that
// knows its own version, and because the agent's own warning comes from
// the same comparison -- the two used to disagree for two builds of one
// tag, and a badge that contradicts a log line is worse than neither.
VersionSkew string `json:"version_skew,omitempty"`
UpgradeCommand string `json:"upgrade_command,omitempty"`
UpgradeVersion string `json:"upgrade_version,omitempty"`
UpgradeNote string `json:"upgrade_note,omitempty"`
Healthy bool `json:"healthy"`
LastHeartbeat time.Time `json:"last_heartbeat"`
CreatedAt time.Time `json:"created_at"`
// Update is the host's part in updating from here: whether it can be, why,
// and its latest attempt, read from what the update loop last saw rather
// than queried for each host. The upgrade command stays beside it as the
// way to update by hand.
Update *HostUpdateView `json:"update"`
}
HostView is one agent host and the room it has left.
func (HostView) For ¶ added in v1.3.8
For is the host as one audience may read it: HostView renders the platform's form, and every handler that answers with a host passes it through here with the caller's role. The view it returns has an update block of its own, so the one it was called on, which may be shared, is never changed.
type InstallationArchive ¶ added in v1.3.8
type InstallationArchive struct {
Kind string `json:"kind"`
ArchiveVersion int `json:"archive_version"`
ExportedAt time.Time `json:"exported_at"`
ExportedFrom string `json:"exported_from,omitempty"`
Version string `json:"version"`
InstallationID string `json:"installation_id"`
Target string `json:"target"`
// Secrets is the installation's private key and webhook secret, sealed
// under the passphrase the export was given. It is absent when none was:
// the archive is then the installation's history without the means to
// act as it, and an import asks for the key to be entered by hand.
Secrets *ArchiveSecrets `json:"secrets,omitempty"`
Tables []store.ArchiveTable `json:"tables"`
}
InstallationArchive is everything about one installation, as one document.
type InstallationView ¶
type InstallationView struct {
ID string `json:"id"`
AppID int64 `json:"app_id"`
InstallationID int64 `json:"installation_id"`
Target string `json:"target"`
TargetType store.TargetType `json:"target_type"`
APIBaseURL string `json:"api_base_url"`
AppSlug string `json:"app_slug,omitempty"`
WebURL string `json:"web_url,omitempty"`
// SettingsURL is the App's own settings page on GitHub. It is carried on
// every installation, not only on the one the connect flow just created,
// because the one thing a manifest cannot do is set the App's avatar --
// GitHub takes it as an upload -- and an operator who missed that step
// during setup has nowhere else to be told about it. Empty when the slug
// is unknown, which is what a hand-added installation looks like.
SettingsURL string `json:"settings_url,omitempty"`
Enterprise bool `json:"enterprise"`
Healthy bool `json:"healthy"`
LastError string `json:"last_error,omitempty"`
LastCheckedAt *time.Time `json:"last_checked_at"`
PoolCount int `json:"pool_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
InstallationView is a GitHub App installation as the API returns it.
The private key and the webhook secret are absent, and there is no field they could be put in: the store keeps them sealed and tagged `json:"-"`, and this type names every field explicitly so that adding one to the domain model cannot leak it here by accident.
func NewInstallationView ¶
func NewInstallationView(i *store.Installation, pools int) InstallationView
NewInstallationView renders an installation, given how many pools depend on it.
type JobExplanation ¶
type JobExplanation struct {
JobID string `json:"job_id"`
State store.JobState `json:"state"`
// Summary is the sentence. It is always set, including for a job that is
// running or finished: "nothing is wrong" is an answer to the question, and
// a caller that has to special-case an empty string will print nothing on
// the one page an operator opened to be told something.
Summary string `json:"summary"`
// Detail is what the summary leaves out, in the scheduler's own words
// where it has any.
Detail string `json:"detail,omitempty"`
// Fix is what to do. Empty means there is nothing to do, which is the
// normal case and is different from not knowing.
Fix string `json:"fix,omitempty"`
// Waiting is whether the job is still waiting on something. Blocked is
// whether waiting will not on its own end it: a fleet that is merely busy
// clears, and a pool nothing can place never will.
Waiting bool `json:"waiting"`
Blocked bool `json:"blocked"`
// PoolID, RunnerID and HostID are what the explanation is about, so a
// caller can link to them rather than parse them back out of the prose.
PoolID string `json:"pool_id,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
HostID string `json:"host_id,omitempty"`
ComputedAt time.Time `json:"computed_at"`
// Class is the one-word answer, from the closed set in why.go, and
// Confidence how far it rests on a recorded fact; ConfidenceReason says
// what was missing whenever that is not high.
Class WhyClass `json:"class"`
Confidence WhyConfidence `json:"confidence"`
ConfidenceReason string `json:"confidence_reason,omitempty"`
// Evidence is the facts the class rests on, each one checkable; never
// null, so a reader can range over it.
Evidence []Evidence `json:"evidence"`
// LogExcerpt is the kept lines around the decisive one, null when none
// were asked for or none exist.
LogExcerpt *LogExcerpt `json:"log_excerpt"`
// ProblemCode and CheckCode name the catalog entry, when one applies.
ProblemCode string `json:"problem_code,omitempty"`
CheckCode string `json:"check_code,omitempty"`
// NextSteps is what to do, in order; never null.
NextSteps []NextStep `json:"next_steps"`
}
JobExplanation is the answer to "why is this job not running?", computed once, on the side that knows.
The browser used to work this out for itself from the pool's live counts, and the CLI could only say "unmatched": two answers to one question, neither of which could see the scheduler's own reason for refusing to place a runner. This is that reason plus the four facts around it -- the last plan, the pool's warnings, the runner's stamps and its host's heartbeat -- so the drawer, the CLI and the support bundle read from one place and cannot disagree.
type JobRenderer ¶
type JobRenderer struct {
// contains filtered or unexported fields
}
JobRenderer names pools without a query per job.
type JobSummaryView ¶ added in v1.3.8
type JobSummaryView struct {
ID string `json:"id"`
Repo string `json:"repo"`
Workflow string `json:"workflow"`
JobName string `json:"job_name"`
State store.JobState `json:"state"`
Conclusion string `json:"conclusion,omitempty"`
FaultDomain string `json:"fault_domain,omitempty"`
QueuedAt time.Time `json:"queued_at"`
StartedAt *time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at"`
QueueWaitMS int64 `json:"queue_wait_ms"`
DurationMS int64 `json:"duration_ms"`
// Pool is the pool's name, Host the host's ID as stamped when the job was
// assigned, and Runner the runner's name.
Pool string `json:"pool,omitempty"`
Host string `json:"host,omitempty"`
Runner string `json:"runner,omitempty"`
ControllerVersion string `json:"controller_version,omitempty"`
ControllerChannel string `json:"controller_channel,omitempty"`
AgentVersion string `json:"agent_version,omitempty"`
// PeakMemoryMB and OOMKilled are JobView's, so a caller comparing jobs can
// see which of them were heavy without opening each one.
PeakMemoryMB int64 `json:"peak_memory_mb,omitempty"`
OOMKilled bool `json:"oom_killed,omitempty"`
// SizeClass and RanClass are JobView's: the class the job was put in and the
// class of the host that took it, which is what a caller comparing jobs reads
// to see whether they went where they were classed.
SizeClass store.SizeClass `json:"size_class,omitempty"`
RanClass store.SizeClass `json:"ran_class,omitempty"`
}
JobSummaryView is a job without its steps: what GET /jobs returns under include_steps=false. A job's step list is most of its weight -- a dozen entries, each with two timestamps -- and a caller comparing a hundred jobs for their durations has no use for any of it. This is the shape that fits a hundred of them in a model's context; get_job or GET /jobs/{id} has the rest.
It names the pool, host and runner rather than carrying their IDs and the job's labels, and it is not a subset of JobView by field name for that reason: it is the columns somebody comparing jobs reads, in the words they would use.
func NewJobSummaryView ¶ added in v1.3.8
func NewJobSummaryView(j *store.Job, poolName string) JobSummaryView
NewJobSummaryView renders a job as its summary, given its pool's name.
type JobView ¶
type JobView struct {
Provisioning string `json:"provisioning"`
ProvisionNow bool `json:"provision_now"`
ID string `json:"id"`
GitHubJobID int64 `json:"github_job_id"`
GitHubRunID int64 `json:"github_run_id"`
Repo string `json:"repo"`
Workflow string `json:"workflow"`
JobName string `json:"job_name"`
Labels []string `json:"labels"`
State store.JobState `json:"state"`
Conclusion string `json:"conclusion,omitempty"`
// InstallationID is the GitHub App installation covering this job's
// repository. It is read-only and derived at ingest; a pool only ever runs
// work in its own installation's target, so this is half of why a job is
// or is not claimed.
InstallationID string `json:"installation_id,omitempty"`
PoolID string `json:"pool_id,omitempty"`
PoolName string `json:"pool_name,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
RunnerName string `json:"runner_name,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
Matched bool `json:"matched"`
// EligibleAt is when this fleet could first have acted on the job: the
// moment an enabled pool claimed its labels. It is the start of the
// scheduling-latency interval, and it is not queued_at -- the wait
// before anything could run the job is not this fleet's to answer for.
// Absent on a job nothing has claimed, and on one recorded before the
// column existed.
EligibleAt *time.Time `json:"eligible_at,omitempty"`
// Hosted is true when every label names a runner somebody else operates:
// GitHub's own or a hosted-runner vendor's. Such a job is theirs to run,
// so it being unmatched here is expected rather than a job going nowhere.
Hosted bool `json:"hosted"`
HeadBranch string `json:"head_branch,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
RunAttempt int `json:"run_attempt,omitempty"`
// RunNumber is GitHub's own sequential number for this workflow run -- the
// "#1009" its Actions UI shows next to the workflow name -- so an operator
// can find the same run there. Zero until a workflow_run lookup backfills
// it, since the webhook that recorded the job never carries it.
RunNumber int64 `json:"run_number,omitempty"`
Steps []store.JobStep `json:"steps"`
// FailedStep is the step a failed job stopped at, worked out here from the
// steps so that the grid and the drawer name the same one. Null when the
// job did not fail on a step it ran.
FailedStep *store.JobStep `json:"failed_step"`
// RunnerFault is set when the runner executing this job stopped before
// GitHub reported the job over: the fleet's own explanation of a failure
// GitHub records like any other.
RunnerFault string `json:"runner_fault,omitempty"`
// FaultKind is the same failure as a category, and FaultDomain says whose
// the failure is at all: "fleet" when this deployment is the reason, and
// "workflow" when the job failed on its own merits and the fleet did its
// part. Both are empty on a job that did not fail.
//
// The domain is rendered here rather than worked out in the browser
// because the same judgement is made by the Overview's counts, the
// problems panel and the CLI, and four places deciding "is this ours"
// separately is four places to disagree about the number on the tile.
FaultKind store.FaultKind `json:"fault_kind,omitempty"`
// FaultFix is what to do about a fault of this kind, so a page showing the
// failure can show the remedy without keeping its own copy of the table.
FaultDomain string `json:"fault_domain,omitempty"`
FaultFix string `json:"fault_fix,omitempty"`
// AcknowledgedAt and AcknowledgedBy say when somebody marked this failure
// as known and who, by the name they go by. Both are absent on a failure
// nobody has triaged (the ordinary state) and on a job that did not
// fail. The Jobs page's attention view and the Overview's failures panel
// read them; the failed view and every count of failures ignore them.
AcknowledgedAt *time.Time `json:"acknowledged_at,omitempty"`
AcknowledgedBy string `json:"acknowledged_by,omitempty"`
QueuedAt time.Time `json:"queued_at"`
StartedAt *time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at"`
QueueWaitMS int64 `json:"queue_wait_ms"`
DurationMS int64 `json:"duration_ms"`
// ControllerVersion and ControllerChannel are the controller build that
// claimed the job, AgentVersion the agent of the host that ran it, and
// HostID that host. Each is stamped once and never rewritten, and absent
// on a job nothing here claimed or one recorded before they existed --
// those are not guessed at.
ControllerVersion string `json:"controller_version,omitempty"`
ControllerChannel string `json:"controller_channel,omitempty"`
AgentVersion string `json:"agent_version,omitempty"`
HostID string `json:"host_id,omitempty"`
// PeakCPUs and PeakMemoryMB are the most the job's runner was measured
// using while the job ran, absent when it was never measured. OOMKilled
// says the kernel killed the runner or one of its steps for memory, which
// is the fleet's failure and the one history sizing corrects for.
PeakCPUs float64 `json:"peak_cpus,omitempty"`
PeakMemoryMB int64 `json:"peak_memory_mb,omitempty"`
OOMKilled bool `json:"oom_killed,omitempty"`
// ScratchPeaks is how full each in-memory folder of the job's runner got
// while the job ran, absent when none was measured. A folder near its
// ceiling on a failed job is what the explanation reads a full folder from.
ScratchPeaks []ScratchPeakView `json:"scratch_peaks,omitempty"`
// GrantedCPUs and GrantedMemoryMB are the guaranteed size of the machine
// the job ran on -- for a docker-in-docker runner, the runner and its daemon
// together -- and GrantedSource says where that size came from: the pool,
// the host's slot share, a host's runner profile, a reduced size on a host
// short of room, or job history. They are copied from the runner when it
// takes the job and never rewritten, and absent on a job from before they
// were recorded and on a runner created with no limits. CPU lent to the
// runner later is not part of them.
GrantedCPUs float64 `json:"granted_cpus,omitempty"`
GrantedMemoryMB int64 `json:"granted_memory_mb,omitempty"`
GrantedSource string `json:"granted_source,omitempty"`
// SizeClass is the class the controller put the job in when it was queued,
// SizeBasis how it decided (explicit, pin, history or default), SizeReason
// why in a sentence that finishes "classed medium because", and SizeFloorMB
// the memory the job's runs show it needing. RoutedClass is where it is sent
// while it waits, which is its own class unless it was sent elsewhere, and
// RoutedNote says why when it was. RanClass is the class of the host that
// took it. All are absent on a job nobody classed, which is every job while
// size routing is off, and RoutedClass is absent while it is only watched.
SizeClass store.SizeClass `json:"size_class,omitempty"`
SizeBasis string `json:"size_basis,omitempty"`
SizeReason string `json:"size_reason,omitempty"`
SizeFloorMB int64 `json:"size_floor_mb,omitempty"`
RoutedClass store.SizeClass `json:"routed_class,omitempty"`
RoutedNote string `json:"routed_note,omitempty"`
RanClass store.SizeClass `json:"ran_class,omitempty"`
// back in by its CPU limit, null when the agent never sampled it.
ThrottledShare *float64 `json:"throttled_share"`
}
JobView is one job with its pool named and its waits measured.
func NewJobView ¶
NewJobView renders a job, given the name of the pool that claimed it.
func (JobView) For ¶ added in v1.3.8
For is the job as one audience may read it. A visitor to a public view is told that a failure was marked as known, and when, but never by whom: the name is an account's, and a public view shows nothing about the people who run the fleet. Every other audience reads the job whole.
It narrows a copy. The view is rendered once and handed to every audience.
type KennelActor ¶ added in v1.3.8
type KennelActor struct {
ID, Name string
// CanWaiveErrors is whether the caller holds kennel.waive_error. The policy
// table says who does; the controller only asks.
CanWaiveErrors bool
// CanUntrack is whether the caller holds kennel.untrack. Stopping Kennel Club
// looking at a repository silences its errors, which is what makes it the
// administrator's; starting it again only makes Kennel Club stricter.
CanUntrack bool
}
KennelActor is who is waiving, as far as the rules need to know.
type KennelAttentionView ¶ added in v1.3.8
type KennelAttentionView struct {
ID string `json:"id"`
Name string `json:"name"`
Visibility string `json:"visibility"`
State kennel.State `json:"state"`
Counts kennel.Counts `json:"counts"`
}
KennelAttentionView is a repository that needs looking at, as a line in the Overview's list.
type KennelCheckInfo ¶ added in v1.3.8
type KennelCheckInfo struct {
Code kennel.Code `json:"code"`
Area kennel.Area `json:"area"`
Severity kennel.Severity `json:"severity"`
Detects string `json:"detects"`
Fix string `json:"fix"`
Verify string `json:"verify"`
Docs string `json:"docs"`
Needs []KennelNeed `json:"needs"`
// Disabled says the operator turned it off, by its code or its area.
Disabled bool `json:"disabled"`
}
KennelCheckInfo is one entry in the catalogue of what is checked.
type KennelCheckView ¶ added in v1.3.8
type KennelCheckView struct {
Code kennel.Code `json:"code"`
Area kennel.Area `json:"area"`
Severity kennel.Severity `json:"severity"`
Detects string `json:"detects"`
// Repositories is how many have this check open.
Repositories int `json:"repositories"`
// Disabled says the operator turned it off, by its code or its area, so the
// page shows it as off in Settings and not as clear.
Disabled bool `json:"disabled"`
}
KennelCheckView is one entry in the Overview's by-check table.
type KennelCooldownError ¶ added in v1.3.8
KennelCooldownError is a recheck asked for too soon.
func (*KennelCooldownError) Error ¶ added in v1.3.8
func (e *KennelCooldownError) Error() string
type KennelCoverageSummary ¶ added in v1.3.8
type KennelCoverageSummary struct {
Source kennel.Source `json:"source"`
Label string `json:"label"`
Permission string `json:"permission"`
States map[string]int `json:"states"`
}
KennelCoverageSummary is how many repositories are in each state of reading one source: the numbers behind the Overview's coverage panel.
type KennelCoverageView ¶ added in v1.3.8
type KennelCoverageView struct {
Source kennel.Source `json:"source"`
Label string `json:"label"`
State kennel.CoverageState `json:"state"`
Reason string `json:"reason"`
Permission string `json:"permission"`
}
KennelCoverageView is how far one source could be read, with the sentence that says why when it could not, and the permission that would fix it.
type KennelFieldError ¶ added in v1.3.8
type KennelFieldError struct{ Field, Message string }
KennelFieldError is one thing wrong with a request, in the words the field it belongs to should show.
type KennelFileView ¶ added in v1.3.8
KennelFileView is one workflow file of the inventory: the SHA a finding's evidence names, and the path a person reads.
type KennelFindingView ¶ added in v1.3.8
KennelFindingView is an open finding with the prompt a coding agent is handed for it, rendered here and nowhere else so the page's button, the API and the CLI copy one text. A waived finding is the bare finding: nobody is asked to fix it.
type KennelGuidanceApproval ¶ added in v1.3.8
type KennelGuidanceApproval struct {
PlanHash string `json:"plan_hash"`
}
type KennelGuidancePreview ¶ added in v1.3.8
type KennelGuidancePreview struct {
BaseCommit string `json:"base_commit"`
Base string `json:"base"`
Branch string `json:"branch"`
PlanHash string `json:"plan_hash"`
Issues []agentguidance.Issue `json:"issues"`
Files []agentguidance.Change `json:"files"`
PullRequest *github.PullRequest `json:"pull_request,omitempty"`
}
type KennelInstallationNote ¶ added in v1.3.8
type KennelInstallationNote struct {
InstallationID string `json:"installation_id"`
Target string `json:"target"`
State kennel.CoverageState `json:"state"`
Reason string `json:"reason"`
Since time.Time `json:"since"`
}
KennelInstallationNote says an installation's reads from GitHub are not getting through, which is the one thing a per-repository coverage state cannot say: a repository nothing has been read for has no row to say it on.
type KennelInvalidError ¶ added in v1.3.8
type KennelInvalidError struct{ Fields []KennelFieldError }
KennelInvalidError is a request the controller understood and will not act on.
func (*KennelInvalidError) Error ¶ added in v1.3.8
func (e *KennelInvalidError) Error() string
type KennelListFilter ¶ added in v1.3.8
type KennelListFilter struct {
Q, Severity, Code, State, InstallationID string
// Active, when set, keeps the repositories the fleet has served a job for in
// Kennel Club's window (true) or the ones it has not (false). The window is
// the one every sentence on the Overview names: thirty days, or as long as the
// fleet keeps its jobs if that is shorter.
Active *bool
// Tracked, when set, keeps the repositories Kennel Club is looking at (true) or
// the ones it has been told not to (false). Left alone, both are listed.
Tracked *bool
// Incomplete keeps the repositories that are only partly checked: something could
// not be read (partial) or has not been looked at yet (pending). It is what the
// Overview's "Partly checked" card adds up, and State can name only one of the two.
Incomplete bool
// Waived keeps the repositories with a waived finding (true) or none (false).
Waived *bool
}
KennelListFilter narrows the list of repositories. Every field is validated here, because the values reach SQL as parameters and a typo in one should be an answer and not an empty page.
type KennelNeed ¶ added in v1.3.8
type KennelNeed struct {
Source kennel.Source `json:"source"`
Label string `json:"label"`
// Permission is empty for what this fleet already knows, which needs none.
Permission string `json:"permission"`
// Conditional says it is read only for the repositories the check applies to:
// the run history, for example, is read for public repositories and no others.
Conditional bool `json:"conditional"`
}
KennelNeed is a source a check reads, and the permission it takes.
type KennelNeedsAdminError ¶ added in v1.3.8
KennelNeedsAdminError is a waiver of an error finding by somebody who may waive only the lesser ones. It says which finding, so the answer is about something.
func (*KennelNeedsAdminError) Error ¶ added in v1.3.8
func (e *KennelNeedsAdminError) Error() string
type KennelOverviewView ¶ added in v1.3.8
type KennelOverviewView struct {
// Enabled is false when Kennel Club is off, and then nothing else is filled:
// the page needs a 200 to render its explanation, and an off feature has
// read nothing to count.
Enabled bool `json:"enabled"`
Scope string `json:"scope"`
// Repositories is every one it is tracking. A repository somebody told it not
// to look at is in NotTracked and nowhere else, so that it is never read as
// one nothing has looked at yet.
Repositories int `json:"repositories"`
// NotTracked is how many repositories Kennel Club has been told not to look at.
NotTracked int `json:"not_tracked"`
States KennelStateCounts `json:"states"`
// Counts are the open findings across every repository, by severity, and the
// waived ones beside them.
Counts kennel.Counts `json:"counts"`
Checks []KennelCheckView `json:"checks"`
Attention []KennelAttentionView `json:"attention"`
Coverage []KennelCoverageSummary `json:"coverage"`
OldestEvaluation *time.Time `json:"oldest_evaluation"`
// DisabledChecks are the names the operator turned off, as written.
DisabledChecks []string `json:"disabled_checks"`
}
KennelOverviewView is the Overview's document. It is what GET /kennel returns and what kennel.summary carries, computed rather than stored.
type KennelRepositoryView ¶ added in v1.3.8
type KennelRepositoryView struct {
ID string `json:"id"`
Name string `json:"name"`
RepositoryID int64 `json:"repository_id"`
InstallationID string `json:"installation_id"`
Visibility string `json:"visibility"`
// State is pending until a first evaluation lands, and then the evaluator's
// own answer.
State kennel.State `json:"state"`
EvaluatedAt *time.Time `json:"evaluated_at"`
// NextDueAt is when the reads from GitHub are next due. Null means they are
// due now.
NextDueAt *time.Time `json:"next_due_at"`
Counts kennel.Counts `json:"counts"`
// Complete is whether every enabled check ran against everything it needs.
Complete bool `json:"complete"`
Coverage []KennelCoverageView `json:"coverage"`
Findings []KennelFindingView `json:"findings"`
Waived []kennel.WaivedFinding `json:"waived"`
// Lapsed are waivers that match an open finding and no longer cover it,
// because they ended or the finding got worse.
Lapsed []kennel.Waiver `json:"lapsed"`
Skipped []KennelSkippedView `json:"skipped"`
Disabled []kennel.Code `json:"disabled"`
// Files is the workflow inventory the findings' file evidence points into,
// by blob SHA, with each path as the gate let it through or "" for one it
// did not, which the page says is a workflow with an unusual name.
Files []KennelFileView `json:"files"`
// Tracking says whether Kennel Club is looking at this repository, and for one
// it is not, who stopped it, when and why. An untracked repository has no
// findings, counts or coverage to read, and its state is pending: nothing is
// evaluated for it, so there is nothing to be in a state.
Tracking KennelTrackingView `json:"tracking"`
}
KennelRepositoryView is one repository and what Kennel Club last concluded about it. It is what GET /kennel/repositories/{id} returns, an item in the list, and the payload of kennel.updated.
type KennelSkippedView ¶ added in v1.3.8
type KennelSkippedView struct {
Code kennel.Code `json:"code"`
Source kennel.Source `json:"source"`
State kennel.CoverageState `json:"state"`
Reason string `json:"reason"`
}
KennelSkippedView is a check that did not run, and why.
type KennelStateCounts ¶ added in v1.3.8
type KennelStateCounts struct {
Pending int `json:"pending"`
Partial int `json:"partial"`
Attention int `json:"attention"`
BestInShow int `json:"best_in_show"`
}
KennelStateCounts is how many repositories are in each standing.
type KennelTrackingInput ¶ added in v1.3.8
type KennelTrackingInput struct {
Tracked bool
// Reason is why it should not look, and is only read when stopping: starting
// again is a return to what every repository is.
Reason string
}
KennelTrackingInput is a request to stop Kennel Club looking at a repository, or to start again.
type KennelTrackingView ¶ added in v1.3.8
type KennelTrackingView struct {
Tracked bool `json:"tracked"`
Reason string `json:"reason"`
By string `json:"by"`
Since *time.Time `json:"since"`
}
KennelTrackingView is whether Kennel Club is looking at a repository. Reason, By and Since are filled in only when it is not.
type KennelWaiverInput ¶ added in v1.3.8
KennelWaiverInput is a request to waive a finding.
type LimitError ¶ added in v1.3.8
type LimitError struct {
Setting string
Limit int
What string
// Free says how to make room without changing the setting. Empty is
// "remove one first", which is right for everything stored.
Free string
}
LimitError is ErrLimitReached with the setting that refused, so the message an operator reads names the key they would change -- or the one they would ask whoever runs the instance to change, since every limit is platform-scoped.
func (*LimitError) Error ¶ added in v1.3.8
func (e *LimitError) Error() string
func (*LimitError) Unwrap ¶ added in v1.3.8
func (e *LimitError) Unwrap() error
type LogExcerpt ¶ added in v1.3.8
LogExcerpt is the few lines of runner output around the one that decided the class. Note says why there are none, when there are none.
type LogLine ¶ added in v1.3.8
type LogLine struct {
N int `json:"n"`
Text string `json:"text"`
Decisive bool `json:"decisive,omitempty"`
}
LogLine is one numbered line, numbered from the first line the fleet kept.
type MachineLimits ¶ added in v1.3.8
type MachineLimits struct {
// MaxMachines is how many machines the whole fleet may own at once, across
// every provider, and MaxCreatesInFlight how many it may be building.
MaxMachines int
MaxCreatesInFlight int
// IdleTimeout answers for a provider whose row names none of its own, so a
// provider nobody thought about is not the one machine that never leaves.
IdleTimeout time.Duration
// ScaleDownCooldown is how long idleness has to keep being true before a
// machine is given up, on top of the idle timeout that started it.
ScaleDownCooldown time.Duration
// DeleteGrace is how long a machine's host has to have been silent before
// that silence is believed. Without it a blip releases a machine, because a
// quiet host is ruled out for every pool and the test that would have said
// "the fleet still wants this" is skipped rather than failed.
DeleteGrace time.Duration
}
MachineLimits are the fleet-wide bounds, gathered from configuration by the caller so that nothing in this file reads configuration for itself.
A maximum of zero is zero, for the fleet exactly as for a pool's max_runners: the one number that decides the size of an invoice is not allowed to mean "unbounded" because somebody left it unset.
type MachinePlan ¶ added in v1.3.8
type MachinePlan struct {
Providers []ProviderPlan `json:"providers"`
// Unserved is the pools whose queued work a machine would have answered,
// where a provider could have built one, and nobody was allowed to. The
// money was never the obstacle, so it is not a ProviderPlan's Blocked: an
// operator raising a ceiling would be sent to the wrong screen.
Unserved []UnservedPool `json:"unserved,omitempty"`
// Pools is a verdict for each pool the planner has something to say
// about: what this pass decided about renting for it and why, one a pool,
// in pool name order. A pool the scheduler did not report blocked has
// none, and neither has one the fleet's free slots cover. It is the
// planner's reading alone. Whether renting is switched on, or a provider
// may buy at the moment, is for the controller to lay over it.
Pools []PoolRenting `json:"pools,omitempty"`
}
MachinePlan is what one pass should do, per provider.
func DecideMachines ¶ added in v1.3.8
func DecideMachines(s MachineSnapshot) MachinePlan
DecideMachines turns a snapshot into the machines each provider should buy and release. See the file comment for what it promises.
type MachineRenderer ¶ added in v1.3.8
type MachineRenderer struct {
// contains filtered or unexported fields
}
MachineRenderer renders a page of machines with their provider, pool and host names filled in, taking the lookups once rather than per row.
func (*MachineRenderer) View ¶ added in v1.3.8
func (r *MachineRenderer) View(m *store.Machine) MachineView
View renders one machine.
type MachineSnapshot ¶ added in v1.3.8
type MachineSnapshot struct {
// Now is the decision time, a field rather than a clock read.
Now time.Time
// Plan is the caller's own scheduler.Decide over these same rows. Its pool
// plans are where demand comes from: Desired, Current and the two blockage
// flags are the scheduler's reading of the queue, and re-deriving them here
// would be the copied rule this file exists not to have.
Plan scheduler.Plan
Pools []*store.Pool
Hosts []*store.Host
Runners map[string][]*store.Runner
Jobs []*store.Job
Machines []*store.Machine
Providers []*store.Provider
Limits MachineLimits
}
MachineSnapshot is everything the decision reads. It is a value rather than a set of accessors for the reason scheduler.Snapshot is: a test can place a machine exactly one second either side of a timeout, and nothing in the calculation can reach past it for a fact nobody wrote down.
type MachineTimelineEntry ¶ added in v1.3.8
MachineTimelineEntry is one phase a machine has reached, so the detail page reads as a life rather than as a row of timestamps.
type MachineView ¶ added in v1.3.8
type MachineView struct {
ID string `json:"id"`
ProviderID string `json:"provider_id"`
ProviderName string `json:"provider_name,omitempty"`
Kind store.ProviderKind `json:"provider_kind,omitempty"`
Name string `json:"name"`
State store.MachineState `json:"state"`
Message string `json:"message,omitempty"`
PoolID string `json:"pool_id,omitempty"`
PoolName string `json:"pool_name,omitempty"`
ResourceZone string `json:"resource_zone,omitempty"`
ResourceID string `json:"resource_id,omitempty"`
Address string `json:"address,omitempty"`
// OwnerFingerprint is carried on the type so the orphan page's server side
// can compare, and never rendered.
OwnerFingerprint string `json:"-"`
OwnershipVerifiedAt *time.Time `json:"ownership_verified_at,omitempty"`
OwnershipError string `json:"ownership_error,omitempty"`
HostID string `json:"host_id,omitempty"`
HostName string `json:"host_name,omitempty"`
Capacity int `json:"capacity,omitempty"`
Labels map[string]string `json:"labels"`
// Test is true for the machine an operator asked for to prove the
// provider works. It is released when it reports ready, and the page reads
// the provider's test from it.
Test bool `json:"test,omitempty"`
// Operation and OperationHandle are what an operator pastes into the
// provider's own task log when they want to see the other half of a step
// that is taking too long.
Operation store.MachineOpKind `json:"operation,omitempty"`
OperationID string `json:"operation_id,omitempty"`
OperationHandle string `json:"operation_handle,omitempty"`
OperationHolder string `json:"operation_holder,omitempty"`
OperationSince *time.Time `json:"operation_since,omitempty"`
OutcomeUnknown bool `json:"outcome_unknown,omitempty"`
Attempts int `json:"attempts,omitempty"`
NextAttemptAt *time.Time `json:"next_attempt_at,omitempty"`
ProviderError string `json:"provider_error,omitempty"`
BootstrapError string `json:"bootstrap_error,omitempty"`
SafeToDelete bool `json:"safe_to_delete"`
SafeToDeleteWhy string `json:"safe_to_delete_why,omitempty"`
Timeline []MachineTimelineEntry `json:"timeline"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ReadyAt *time.Time `json:"ready_at,omitempty"`
IdleSince *time.Time `json:"idle_since,omitempty"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
}
MachineView is one rented machine, as the API returns it.
The ownership fingerprint is deliberately absent from the JSON. It is not a secret, but it is the mark a delete is checked against, and putting it on a page invites somebody to write it onto a resource by hand.
type MemoryPoolView ¶ added in v1.3.8
type MemoryPoolView struct {
// Supported is whether the host's agent carries the valve's rules out.
Supported bool `json:"supported"`
// CapacityMB is the most that may be lent on the host in all, LentMB what is
// lent now and PoolMB what is left. FloorMB is the least free memory a loan
// leaves the host.
CapacityMB int64 `json:"capacity_mb"`
LentMB int64 `json:"lent_mb"`
PoolMB int64 `json:"pool_mb"`
FloorMB int64 `json:"floor_mb"`
// CommittedMB, IdleReserveMB and StartReserveMB are the promises the capacity
// was taken after, so a pool of nothing can say whose guarantees it went to.
CommittedMB int64 `json:"committed_mb"`
IdleReserveMB int64 `json:"idle_reserve_mb"`
StartReserveMB int64 `json:"start_reserve_mb"`
// Binding says what limited the capacity: "ledger" for the promises already
// made, "measured" for the memory the host reported as free.
Binding string `json:"binding"`
// Observing and Enforcing count the runners here with a rule, by mode.
Observing int `json:"observing"`
Enforcing int `json:"enforcing"`
// ShortAt is when a runner here was last refused memory because the host had
// none to give, and ShortCode which of pool_empty or host_floor it was.
ShortAt *time.Time `json:"short_at,omitempty"`
ShortCode string `json:"short_code,omitempty"`
// At is when the pool was last worked out.
At time.Time `json:"at"`
}
MemoryPoolView is a host's pool of memory to lend, as the controller last worked it out: what is left of the machine once every promise is kept and the floor is left alone, and how much of it has been lent already.
type MemoryResourceView ¶ added in v1.3.8
type MemoryResourceView struct {
// State is MemoryWatching, MemoryObserving, MemoryLent or MemorySpilled;
// Mode is observe, automatic, or off for a runner whose pool has since
// turned the valve off while a loan it made stands.
State string `json:"state"`
Mode string `json:"mode"`
// Blocked is the agent's latest word when it wanted to lend more and could
// not -- at_ceiling, pool_empty, host_floor -- or could not lend at all --
// unmeasured, unsupported, failed. Empty when nothing is in the way. It is
// beside State and not instead of it: a runner can hold a loan and be at its
// ceiling.
Blocked string `json:"blocked,omitempty"`
// Reason is the sentence for the last thing that was not "healthy".
Reason string `json:"reason,omitempty"`
// GuaranteedMB is what the runner was created with, its containers together;
// CurrentMB what they hold now; CeilingMB the most they may.
GuaranteedMB int64 `json:"guaranteed_mb"`
CurrentMB int64 `json:"current_mb"`
CeilingMB int64 `json:"ceiling_mb"`
// LentMB is CurrentMB less GuaranteedMB. SpillMB is the swap the runner may
// use beyond its limits, and SpillAllowedMB what its pool allows each
// container.
LentMB int64 `json:"lent_mb"`
SpillMB int64 `json:"spill_mb,omitempty"`
SpillAllowedMB int64 `json:"spill_allowed_mb,omitempty"`
// WouldLendMB and WouldSpillMB are what an observing valve would hold if it
// were allowed to: zero outside observe mode.
WouldLendMB int64 `json:"would_lend_mb,omitempty"`
WouldSpillMB int64 `json:"would_spill_mb,omitempty"`
// NearLimit is whether the runner has come within a tenth of a limit, and
// Raises how many times a limit was raised for it.
NearLimit bool `json:"near_limit,omitempty"`
Raises int `json:"raises,omitempty"`
}
MemoryResourceView is what the memory valve has done for one runner, in exact numbers and a stable state. It is the memory counterpart of CPUResourceView, and differs in the one way the two resources do: what is lent here stays lent, so the figures only ever go up while the runner lives.
type MigrationApplyRequest ¶
type MigrationApplyRequest struct {
InstallationID string `json:"installation_id"`
Repos []string `json:"repos"`
Mapping map[string]string `json:"mapping"`
// Overrides are the exceptions to Mapping. They sit alongside Workflows
// rather than inside it: Workflows says which files move at all, and an
// override says where one job in one of them lands.
Overrides []migrate.Override `json:"overrides"`
// Workflows narrows a repository to the workflow files named here, keyed by
// repository. A repository absent from the map gets every file the mapping
// would change, which is what a client that does not know about the field
// asks for. It exists because a repository with a dozen workflow files is
// rarely one where all dozen should move at once.
Workflows map[string][]string `json:"workflows"`
// Title, Body and CommitMessage override the defaults. They are here
// because the pull request lands in somebody else's repository, and an
// organisation with a pull-request template or a commit convention should
// not have to accept ours.
Title string `json:"title"`
Body string `json:"body"`
CommitMessage string `json:"commit_message"`
// Badge says whether each pull request also adds the "CI has the
// Zoomies" badge to the repository's README. It is a pointer because
// the default is yes: a client that does not know the field asks for the
// badge, and only an explicit false leaves the README alone. The badge is
// how the people who read a README find out what runs its CI, and a
// checkbox is a fair price for a line in somebody else's front page.
Badge *bool `json:"badge"`
}
MigrationApplyRequest opens the pull requests a plan described.
func (MigrationApplyRequest) WantsBadge ¶
func (r MigrationApplyRequest) WantsBadge() bool
WantsBadge reports whether the request asks for the badge, which it does unless it said not to.
type MigrationOutcome ¶
type MigrationOutcome struct {
Results []MigrationResult `json:"results"`
Opened int `json:"opened"`
Skipped int `json:"skipped"`
Failed int `json:"failed"`
// Branch is the branch every pull request was opened from, for the audit
// row; each result carries its own for the wire.
Branch string `json:"-"`
}
MigrationOutcome is what applying a migration did.
type MigrationPlan ¶
type MigrationPlan struct {
InstallationID string `json:"installation_id"`
Target string `json:"target"`
// Repositories is every repository looked at, whether or not it changed.
// A repository with nothing to do is information: it means its workflows
// are already somewhere deliberate.
Repositories []migrate.RepoPlan `json:"repositories"`
// HostedLabels is every hosted-runner label found across them -- GitHub's
// own and the vendors' -- which is what the mapping step lists.
HostedLabels []string `json:"hosted_labels"`
// Mapping is what was applied -- the request's, or the proposal the server
// made from the pools that exist.
Mapping map[string]string `json:"mapping"`
// Overrides is what was applied on top of it, echoed back so that a plan
// describes itself: every `to` under Repositories came either from Mapping
// or from one of these.
Overrides []migrate.Override `json:"overrides"`
// Unmapped are the hosted labels no pool was proposed for. They are the
// operator's decision, and the reason a plan can be empty.
Unmapped []string `json:"unmapped"`
// Pools is what the mapping step chooses between.
Pools []MigrationPoolOption `json:"pools"`
Counts migrate.Counts `json:"counts"`
// Truncated says there are more repositories after this page. It is kept
// alongside NextCursor because it is what a client reads to know the
// listing is incomplete, whether or not it can page.
Truncated bool `json:"truncated"`
// NextCursor is what to send as Cursor to read the next page. Empty means
// this was the last one.
NextCursor string `json:"next_cursor,omitempty"`
// TotalRepos is how many repositories the installation can see, so a wizard
// showing a page can say what fraction of the whole it is.
TotalRepos int `json:"total_repos"`
// MissingPermissions is what the App still needs before the apply step can
// work. It is reported here, in the step before, because discovering it
// halfway through opening pull requests leaves half of them open.
MissingPermissions []string `json:"missing_permissions"`
// PermissionHint is the sentence that fixes MissingPermissions.
PermissionHint string `json:"permission_hint,omitempty"`
// SettingsURL is where to go and fix it.
SettingsURL string `json:"settings_url,omitempty"`
}
MigrationPlan is the whole review step.
type MigrationPlanRequest ¶
type MigrationPlanRequest struct {
InstallationID string `json:"installation_id"`
// Repos limits the plan to these repositories. Empty means every
// repository the installation can see, up to the limit.
Repos []string `json:"repos"`
// Mapping is hosted label -> the runs-on value that replaces it. Empty asks
// the server to propose one from the pools that exist.
Mapping map[string]string `json:"mapping"`
// Overrides are the exceptions to Mapping, each naming one job in one file
// in one repository. Empty is the common case: most fleets want one answer
// per hosted-runner label everywhere.
Overrides []migrate.Override `json:"overrides"`
// Cursor asks for the page of repositories after this one. It is the full
// name of the last repository the previous page returned, because the
// listing is sorted by name: a name is stable when the App gains or loses
// a repository between two pages, and an offset is not.
Cursor string `json:"cursor"`
}
MigrationPlanRequest asks what a migration would change.
type MigrationPoolOption ¶
type MigrationPoolOption struct {
ID string `json:"id"`
Name string `json:"name"`
Labels []string `json:"labels"`
// RunsOn is what a workflow writes to reach this pool: the value the
// mapping should hold.
RunsOn string `json:"runs_on"`
Enabled bool `json:"enabled"`
}
MigrationPoolOption is one pool the wizard can map a hosted label to.
type MigrationResult ¶
type MigrationResult struct {
Repo string `json:"repo"`
// Status is "opened", "skipped" or "failed".
Status string `json:"status"`
// PullRequestURL and PullRequestNumber are set when Status is "opened".
PullRequestURL string `json:"pull_request_url,omitempty"`
PullRequestNumber int `json:"pull_request_number,omitempty"`
Branch string `json:"branch,omitempty"`
// Workflows is how many files the pull request changed.
Workflows int `json:"workflows"`
// Jobs is how many runs-on lines it rewrote.
Jobs int `json:"jobs"`
// Reason explains a skip or a failure.
Reason string `json:"reason,omitempty"`
// Badge says what became of the README badge on a pull request that was
// opened: "added", "present" when the README already carried it,
// "no_readme" when there was nowhere Markdown to put it, "unread" when
// GitHub would not hand the README over, and "off" when the request
// asked for none. BadgeReason says which of the no_readme and unread
// cases it was. A badge that could not be added never stops the
// migration: the runs-on lines are the work, and the badge is the thanks.
Badge string `json:"badge,omitempty"`
BadgeReason string `json:"badge_reason,omitempty"`
}
MigrationResult is what happened to one repository.
type NextStep ¶ added in v1.3.8
type NextStep struct {
Text string `json:"text"`
Kind string `json:"kind"`
Link string `json:"link,omitempty"`
}
NextStep is one thing to do, in the order to do them. Kind says whether it is something to read, something to change, or the re-run that follows a change, so a surface can offer a button where one applies.
type NotFoundError ¶ added in v1.3.8
type NotFoundError struct {
// Kind is "pool" or "host".
Kind, ID string
}
NotFoundError is a pool or host an analysis was narrowed to that the fleet does not have. It carries what was asked for, so a caller can say so in its own words rather than reading this error's text, which a later wrap would change; it unwraps to store.ErrNotFound, so errors.Is still finds it.
func (NotFoundError) Error ¶ added in v1.3.8
func (e NotFoundError) Error() string
func (NotFoundError) Unwrap ¶ added in v1.3.8
func (e NotFoundError) Unwrap() error
type OptimisationCheckoutProvenance ¶ added in v1.3.8
type OptimisationCheckoutProvenance struct {
Version string `json:"version"`
Basis string `json:"basis"`
Selection github.CheckoutSelection `json:"selection"`
StepNumber int64 `json:"step_number"`
BlobSHA string `json:"blob_sha"`
JobNameSHA256 string `json:"job_name_sha256"`
StepNameSHA256 string `json:"step_name_sha256"`
SourceFunding string `json:"source_funding"`
}
OptimisationCheckoutProvenance contains no raw API names, URLs or logs. Nil remains unknown for previews retained before evidence admission.
type OptimisationPolicyCheck ¶ added in v1.3.8
type OptimisationPolicyCheck func(context.Context) (optimisation.Policy, error)
OptimisationPolicyCheck must read current server authorisation/settings. It is called before source reads and again before retention; request flags cannot authorise source access or workflow previews. No transport exposes this yet.
type Options ¶
type Options struct {
Doctor *hosttune.Monitor
// Store is the only writer of persistent state.
Store *store.Store
// Config is the validated configuration; the controller reads the
// scheduler tunables, the GitHub settings and the retention windows.
Config *config.Config
// Key unseals the GitHub App private keys and webhook secrets held in the
// database. Without it no installation can be used.
Key *cryptox.Key
// Auth mints agent tokens, redeems join tokens and records audit rows.
Auth *auth.Service
// Events carries every state change to the UI's SSE stream.
Events *events.Bus
// GitHub builds a client per installation; nil uses the real GitHub App
// factory, and tests pass one backed by github.NewFake.
GitHub github.Factory
// Backends is only needed when this process also runs the embedded agent.
Backends *backend.Registry
// Providers is the set of infrastructure providers this build can make.
// Nil is an empty registry, so a configuration row naming a kind nothing
// can build is refused with a sentence rather than a nil dereference on
// the first pass that tries to rent a machine.
Providers *provider.Registry
Logger *slog.Logger
// Clock is injectable so tests can freeze time.
Clock func() time.Time
// HTTPClient delivers capacity-demand events. Tests may inject a transport.
HTTPClient *http.Client
// ProviderHTTPClient replaces the client every provider would build for
// itself. Tests use it to reach a fake hypervisor; production leaves it
// nil so that a row's certificate settings and private connection apply.
ProviderHTTPClient *http.Client
// BackupRemoteHTTPClient replaces the client the backup remotes would
// build for themselves. Tests use it to reach a fake object store;
// production leaves it nil, because the transfer of a whole database
// wants the transport internal/backup builds for that and not the one a
// webhook delivery uses.
BackupRemoteHTTPClient *http.Client
// LogLevel is the gate the process logger is filtered at, when the caller
// built one that can move. UpdateConfig sets it from log.level, so that a
// level changed through PATCH /settings or SIGHUP is the level the process
// actually logs at, not merely the one the settings page shows.
LogLevel *slog.LevelVar
// Lease is this controller's claim on the database, taken before the
// controller was built. A nil lease means nothing renews and nothing is
// reported, which is what an embedded or test controller wants.
Lease *store.ControllerLease
// UpdateDir is the update folder the controller shares with its update
// helper. Empty finds it as the installer recorded it: the pointer beside the
// --config file, or <shared>/update in a container. A test names one, so that
// what it sees is never the real host's.
UpdateDir string
// HelperHost says what this controller's machine is, as far as whether the
// update helper could be installed beside it. Nil reads the machine itself
// (agent.LocalHelperHost); a test names one, so that the status it sees never
// depends on whether the suite runs in a container or under systemd.
HelperHost func() updates.HelperHost
}
Options are the collaborators the controller needs. Everything except the store and the configuration has a defensible default, because a caller that forgets the event bus should get a working controller rather than a nil dereference three loops later.
type OrphanReportView ¶ added in v1.3.8
type OrphanReportView struct {
ProviderID string `json:"provider_id"`
ProviderName string `json:"provider_name"`
LastSweepAt *time.Time `json:"last_sweep_at,omitempty"`
// Untracked is a resource wearing this fleet's naming grammar that no row
// accounts for. It is never deleted from here: the row is the only record
// of what was rented, and a resource with no row may be another fleet's.
Untracked []OrphanView `json:"untracked"`
// NoResource is a row that believes it holds nothing, which is a row an
// operator can release without anything being lost.
NoResource []MachineView `json:"no_resource"`
// Unverified is a machine whose ownership nothing has confirmed, including
// every quarantined one. Until a person decides, nothing will touch them.
Unverified []MachineView `json:"unverified"`
}
OrphanReportView is the review page in one answer: the three ways a row and a resource can fail to agree. Nothing here is ever acted on automatically -- each section is a list of things for a person to look at, and the only destructive act on the page asks for a name to be typed.
type OrphanView ¶ added in v1.3.8
type OrphanView struct {
Name string `json:"name"`
// Note is what an operator should do about it, which for an untracked
// resource is always "look at it yourself": Zoomies will not delete a
// machine it has no record of creating.
Note string `json:"note"`
}
OrphanView is one untracked resource, as the last sweep saw it.
type PRDelayAdmissionError ¶ added in v1.3.8
func (*PRDelayAdmissionError) Error ¶ added in v1.3.8
func (e *PRDelayAdmissionError) Error() string
func (*PRDelayAdmissionError) Unwrap ¶ added in v1.3.8
func (e *PRDelayAdmissionError) Unwrap() error
type PRDelayInput ¶ added in v1.3.8
type PRDelayInput struct {
Repository string
InstallationID string
WindowStart time.Time
ObservedAt time.Time
Evidence *github.PRDelayEvidence
Jobs []PRDelayJobEvidence
JobsCoverage analysis.Coverage
}
PRDelayInput is assembled by an authorised reader. Identity checks here prevent an accidental cross-installation join; they do not grant read access.
type PRDelayJobEvidence ¶ added in v1.3.8
PRDelayJobEvidence includes an optional provisioning-start measurement, not the runner's registration time or a second copy of total queue wait.
type PRDelayReport ¶ added in v1.3.8
type PRDelayReport struct {
JobID string `json:"job_id"`
Repository string `json:"repository"`
InstallationID string `json:"installation_id"`
PullNumber int `json:"pull_number"`
// WindowBasis prevents the earliest retained job from being mistaken for
// the time the developer pushed this revision.
WindowBasis string `json:"window_basis"`
Result analysis.MergeDelayResult `json:"result"`
}
type PairingView ¶ added in v1.3.8
type PairingView struct {
ProviderID string `json:"provider_id"`
ProviderName string `json:"provider_name"`
PoolID string `json:"pool_id"`
PoolName string `json:"pool_name"`
// Serves is the answer: this provider would rent a machine for this pool.
Serves bool `json:"serves"`
// Agrees is whether the two selectors allow it. By says which side refused,
// "provider" or "pool", and Why and Fix say what did not match and what to
// change.
Agrees bool `json:"agrees"`
By string `json:"by,omitempty"`
// Fits is whether the machine the provider would build suits the pool.
// FitWhy is the first thing that does not, in the setting's own terms.
Fits bool `json:"fits"`
FitWhy string `json:"fit_why,omitempty"`
Why string `json:"why,omitempty"`
Fix string `json:"fix,omitempty"`
}
PairingView is one provider and one pool, and whether the provider would rent a machine for it.
A pool uses a provider only when three things are true, and an operator looking at an empty Machines list needs to know which one is not. The two selectors are the opt-in each side gives (the provider's pool_selector, the pool's provider_selector); the third is that the machine the provider builds is one the pool's runners could be placed on at all. They are reported apart because the first two are choices somebody made and the third is a mismatch of shape.
type PoolAutoView ¶ added in v1.3.8
type PoolAutoView struct {
// Key is the architecture and class the pool is kept for.
Key string `json:"key"`
Arch string `json:"arch"`
Class store.SizeClass `json:"class"`
// Warm, Cap and Paused are the operator's: runners to keep ready, the most
// runners to allow however many slots the hosts give, and a pause. Zero is
// none for the first two.
Warm int `json:"warm"`
Cap int `json:"cap"`
Paused bool `json:"paused"`
// Kept says whether the controller is keeping the pool now: automatic pools
// are on, and it belongs to the installation they are kept for. A pool that is
// not kept holds the figures it had, takes a pause the moment it is asked for,
// and applies a cap or a warm count when it is kept again; and deleting it is
// not undone by the next pass, because nothing will make it again.
Kept bool `json:"kept"`
// Hosts are the hosts that count towards the pool and Slots what they hold
// between them, as of the last pass of the reconciler.
Hosts []string `json:"hosts"`
Slots int `json:"slots"`
Summary string `json:"summary"`
}
PoolAutoView is what is particular to a pool the controller keeps: what an operator has asked of it, and what the hosts in it give.
type PoolCountsView ¶
type PoolCountsView struct {
Provisioning int `json:"provisioning"`
Registering int `json:"registering"`
Idle int `json:"idle"`
Busy int `json:"busy"`
Draining int `json:"draining"`
Failed int `json:"failed"`
Live int `json:"live"`
}
PoolCountsView is a pool's live runner tally, in the shape the OpenAPI document's Pool.counts has.
type PoolHostRoom ¶ added in v1.3.8
type PoolHostRoom struct {
HostID string `json:"host_id"`
Host string `json:"host"`
// Slots is the host's runner capacity, less any throttle in force.
Slots int `json:"slots"`
// Fits is how many runners of this pool the machine has room for,
// ignoring the slot count -- so a host whose slots outrun its machine can
// be told from one sized to match.
Fits int `json:"fits"`
// Room is what the pool can actually expect here: the smaller of the two.
Room int `json:"room"`
// LimitedBy is what ran out first: slots, cpu, memory or disk. It is empty
// on a host that has measured nothing, where only its slots bind.
LimitedBy string `json:"limited_by,omitempty"`
// ChargeCPUs and ChargeMemoryMB are what one runner of this pool costs
// here, which is not always what the pool says: a docker-in-docker runner
// is charged for its sidecar too.
ChargeCPUs float64 `json:"charge_cpus"`
ChargeMemoryMB int64 `json:"charge_memory_mb"`
// The machine less its reserve, which is what the charge is taken from.
// Zero with the matching known flag false means the agent has not said.
CPUs float64 `json:"cpus"`
MemoryMB int64 `json:"memory_mb"`
DiskMB int64 `json:"disk_mb"`
CPUsKnown bool `json:"cpus_known"`
MemoryKnown bool `json:"memory_known"`
DiskKnown bool `json:"disk_known"`
// ElasticCPU is whether this host's agent can move a live runner's CPU
// quota. An elastic pool is honoured only where it is true; a runner of
// one placed elsewhere is held at its share, and nothing but this says so
// while the pool is still being edited.
ElasticCPU bool `json:"elastic_cpu"`
// ElasticMemory is the same for the memory valve: whether this host's agent
// carries out the rules that let a runner be lent memory while it runs.
ElasticMemory bool `json:"elastic_memory"`
// Tmpfs is whether this host's agent mounts a pool's in-memory folders. A
// pool that asks for them is honoured only where it is true.
Tmpfs bool `json:"tmpfs"`
// pool's sidecar shares. It is for the warnings and the advice, not for an editor.
DaemonShare bool `json:"-"`
// TmpfsOff is whether this host's operator turned in-memory folders off, in
// its runner profile. A pool that asks for them is not given them here, which
// is a decision of the host's owner and not a fault, but is not something the
// pool's own page can show unless somebody says it.
TmpfsOff bool `json:"tmpfs_off,omitempty"`
// TmpfsPolicy is this host's whole say over in-memory folders (its standard
// sizes and ceiling), which the warnings place a pool's folders from. It is
// not part of the answer an editor shows, so it is not sent.
TmpfsPolicy store.HostTmpfs `json:"-"`
// Sizing is how a runner of this pool is sized here -- its standard, its
// floor and its CPU ceiling, each with where it came from -- and Excluded
// is the sentence, with ExcludedBy its code, where the host's runner profile
// keeps the pool off it altogether. Excluded hosts are listed, with no room,
// rather than dropped: "this host is left out, and this is the limit" is the
// row an operator came to read.
Sizing PoolHostSizing `json:"sizing"`
Excluded string `json:"excluded,omitempty"`
ExcludedBy string `json:"excluded_by,omitempty"`
}
PoolHostRoom is one host's answer, in the terms the machine was set up in.
func (PoolHostRoom) Overcommitted ¶ added in v1.3.8
func (r PoolHostRoom) Overcommitted() bool
Overcommitted reports whether this host promises more slots than the machine can back at this pool's size -- the state where the fleet's own capacity figures say there is room and every create for that room is refused.
A host the pool is kept off is not one. It is listed so its row can say why, but the pool is never asked to place a runner there, so its slots are not promises about this pool, and telling an operator to lower the capacity of a host that is working as set would be the wrong fix for a right result.
type PoolHostSizing ¶ added in v1.3.8
type PoolHostSizing struct {
// Standard is what one runner of the pool is given there: the pool's own
// figure, the host's standard (or the fleet's default standing in for it)
// for a pool that takes its size from the host, or one slot's share.
Standard RunnerSizeView `json:"standard"`
StandardCPUsSource string `json:"standard_cpus_source,omitempty"`
StandardMemoryMBSource string `json:"standard_memory_mb_source,omitempty"`
// Floor is the least a runner is given there: the larger of the pool's
// minimum -- its own, or the fleet's where it follows it -- and the host's.
Floor RunnerSizeView `json:"floor"`
FloorCPUsSource string `json:"floor_cpus_source,omitempty"`
FloorMemoryMBSource string `json:"floor_memory_mb_source,omitempty"`
// Ceiling is the most CPU one runner may use there, its guarantee and a
// loan together, for a pool that lends CPU: the smaller of the pool's and
// the host's. Zero is "as much as the host's allocatable CPU".
CeilingCPUs float64 `json:"ceiling_cpus,omitempty"`
CeilingSource string `json:"ceiling_source,omitempty"`
// CeilingMemoryMB is the same for the memory valve: the most memory one
// runner may hold there, its guarantee and what it is lent together, for a
// pool that has the valve on. CeilingMemorySource says whose figure it is --
// the pool's, the host's (the smaller of the two applies), or "default" for
// half as much again as the runner's guarantee.
CeilingMemoryMB int64 `json:"ceiling_memory_mb,omitempty"`
CeilingMemorySource string `json:"ceiling_memory_source,omitempty"`
}
PoolHostSizing is how one pool is sized on one host, with where each figure came from. It is the row an operator reads to see why a runner of this pool on that host is the size it is, and what they would change to move it.
type PoolMinimumView ¶ added in v1.3.8
type PoolMinimumView struct {
CPUs float64 `json:"cpus"`
MemoryMB int64 `json:"memory_mb"`
CPUsInherited bool `json:"cpus_inherited"`
MemoryMBInherited bool `json:"memory_mb_inherited"`
// CPUsSource and MemoryMBSource say the same as the two booleans in the
// words every other figure's source uses: "pool" where the pool set it,
// "global" where it follows the fleet's runners.minimum_*, and nothing
// where nobody did. A host's own minimum is applied on top, per host, and
// is shown on the host's row (PoolHostSizing), not here.
CPUsSource string `json:"cpus_source,omitempty"`
MemoryMBSource string `json:"memory_mb_source,omitempty"`
}
PoolMinimumView is a pool's minimum in force, and which half of it came from the fleet rather than from the pool.
type PoolRenderer ¶
type PoolRenderer struct {
// contains filtered or unexported fields
}
PoolRenderer is everything needed to render pools without one query per pool.
type PoolRenting ¶ added in v1.3.8
type PoolRenting struct {
PoolID string `json:"pool_id"`
PoolName string `json:"pool_name"`
State RentingState `json:"state"`
// Summary is the one sentence an operator reads and Fix what to change,
// both written to be shown as they are. Setting is the one setting the
// fix changes, when there is one: a provider's own limits are on its own
// form, not in Settings, so a fix to one of them names none.
Summary string `json:"summary"`
Fix string `json:"fix,omitempty"`
Setting string `json:"setting,omitempty"`
// ProviderID and ProviderName are the provider the pool's shortfall was
// charged to or, for on_its_way, the one building the oldest machine that
// covers it. A pool that is waiting, or that no provider will rent for,
// was charged to none.
ProviderID string `json:"provider_id,omitempty"`
ProviderName string `json:"provider_name,omitempty"`
// Queued is the queued jobs the pool claims, counted as the purchase
// sentence counts them, so that a job two pools could run is counted for
// one. Short is the runner slots it is missing. For a pool the scheduler
// is waiting on hosts for, that is the scheduler's own shortfall, whether
// the verdict is waiting or, because no provider could serve it,
// unserved. Otherwise it is what the free slots on hosts that could run
// it leave and, for every state but on_its_way, what the machines on
// their way leave as well.
Queued int `json:"queued"`
Short int `json:"short"`
// Machines is, for renting, the machines this pool alone needs, at most
// what the provider rents this pass. Pools that share a machine each
// count it, so the figures are never to be added up. For on_its_way it is
// how many of the named provider's machines are coming. For held and off
// it is what the pass would have rented had nothing stood in the way,
// which is none for a pool a ceiling stopped or one the machines already
// on their way cover.
Machines int `json:"machines"`
// Since is when the oldest machine on its way for this pool was asked for.
// It is a field rather than a phrase in the summary because a sentence with
// a clock in it would differ on every pass, and whatever reaches the
// problems list is sent again each time it differs.
Since *time.Time `json:"since,omitempty"`
// Because is, for ceiling only, the ceiling that stopped the purchase
// without the summary's prefix or full stop, so that a sentence laid over
// the verdict (renting switched off as well) can say it in its own words.
// It is not sent, because the summary already says it.
Because string `json:"-"`
}
PoolRenting is the verdict on one pool: what the planner decided about renting for it, why, and what would change that.
func (PoolRenting) Aside ¶ added in v1.3.8
func (v PoolRenting) Aside() string
Aside is what a page already showing the scheduler's sentence adds to it. A waiting verdict's summary quotes that sentence, so only its tail is news; every other verdict is news in full.
type PoolRoom ¶ added in v1.3.8
type PoolRoom struct {
// Runners is how many runners of this pool the matching hosts could hold
// between them. It is the number a maximum is worth comparing against.
Runners int `json:"runners"`
// Slots is what those hosts' capacities add up to, whatever the size.
Slots int `json:"slots"`
Hosts []PoolHostRoom `json:"hosts"`
// SmallestDiskMB is the least free disk on any matching host, which is
// what a cache size limit has to live inside. Known is false when no
// matching host has measured its disk.
SmallestDiskMB int64 `json:"smallest_disk_mb"`
SmallestDiskHost string `json:"smallest_disk_host,omitempty"`
DiskKnown bool `json:"disk_known"`
// TmpfsPlan is what the pool's in-memory folders come to on these hosts, and
// what would change it. Present only for a pool that keeps a folder in memory
// automatically, which is the setting that decides per host and so needs
// saying per host.
TmpfsPlan *TmpfsPlan `json:"tmpfs_plan,omitempty"`
// SplitPlan prices the ways of dividing a slot between the runner and its
// Docker daemon on these hosts, and names the one to start from. Present only
// for a docker-in-docker pool whose size comes from its hosts.
SplitPlan *SplitPlan `json:"split_plan,omitempty"`
}
PoolRoom is the fleet's answer, and the per-host detail behind it.
func (PoolRoom) Overcommitted ¶ added in v1.3.8
func (r PoolRoom) Overcommitted() []PoolHostRoom
Overcommitted is every host promising more slots than it can back.
func (PoolRoom) Placeable ¶ added in v1.3.8
func (r PoolRoom) Placeable() []PoolHostRoom
Placeable is the hosts a runner of this pool can be placed on. An excluded host is listed with no room rather than dropped, and takes no part in any count, charge or warning about where the pool lands.
type PoolStats ¶
type PoolStats struct {
PoolID string `json:"pool_id"`
PoolName string `json:"pool_name"`
Min int `json:"min"`
Max int `json:"max"`
Live int `json:"live"`
Busy int `json:"busy"`
Idle int `json:"idle"`
// Queued is the number of queued jobs this pool has claimed.
Queued int `json:"queued"`
Utilisation float64 `json:"utilisation"`
}
PoolStats is one row of the Overview's per-pool utilisation.
type PoolView ¶
type PoolView struct {
ID string `json:"id"`
Name string `json:"name"`
InstallationID string `json:"installation_id"`
InstallationTarget string `json:"installation_target,omitempty"`
Labels []string `json:"labels"`
RunnerGroup string `json:"runner_group,omitempty"`
Backend store.BackendKind `json:"backend"`
// Platform is the machine this pool's runners need. It picks the runner
// image and restricts which hosts the scheduler may place them on.
Platform store.Platform `json:"platform"`
Image string `json:"image"`
// EffectiveImage is the image runners will actually boot: Image when the
// pool names one, otherwise the variant its platform selects, otherwise
// the instance default. A pool page that showed a blank image field and
// nothing else would leave an operator guessing at the single most
// important thing about their runners.
EffectiveImage string `json:"effective_image"`
PullPolicy store.PullPolicy `json:"pull_policy"`
RunnerVersion string `json:"runner_version,omitempty"`
MinRunners int `json:"min_runners"`
MaxRunners int `json:"max_runners"`
Priority int `json:"priority"`
// RepositoryScaleUpLimit and CostPerRunnerHour are accepted on the way in,
// so they are rendered on the way out: a field the API takes but never
// shows again is a field an operator cannot check, edit or explain.
RepositoryScaleUpLimit int `json:"repository_scale_up_limit"`
CostPerRunnerHour *float64 `json:"cost_per_runner_hour"`
IdleTimeout store.Duration `json:"idle_timeout"`
Ephemeral bool `json:"ephemeral"`
DockerMode store.DockerMode `json:"docker_mode"`
Resources store.Resources `json:"resources"`
CPUBurst store.CPUBurstPolicy `json:"cpu_burst"`
// MemoryBurst is the memory valve's policy for this pool.
MemoryBurst store.MemoryBurstPolicy `json:"memory_burst"`
// SizeFromProfile is the stored choice that this pool takes its runners'
// size from the host they land on, as that host's runner profile says it.
// It excludes typed CPU and memory, and it is what makes Sizing "profile".
// FleetStandard is what such a pool's runner is on a host whose profile
// names no standard: the fleet's default size, carried here so the pool's
// own page can say so without the browser knowing the fleet's settings.
SizeFromProfile bool `json:"size_from_profile"`
FleetStandard *RunnerSizeView `json:"fleet_standard,omitempty"`
// Auto is present on a pool the controller keeps from the hosts it has: what
// an operator has asked of it, and what the hosts in it give. Its minimum and
// maximum above are worked out, not typed.
Auto *PoolAutoView `json:"auto,omitempty"`
// Sizing is how this pool decides what one runner gets: "automatic", one
// slot's share of whichever host it lands on, "elastic", the same share
// with spare CPU lent to it, "profile", the size each host's runner profile
// names, or "fixed", the figures in Resources. It is derived from Resources
// and SizeFromProfile rather than stored beside them, so they can never
// disagree -- but it is rendered, because a browser reading "no CPU limit"
// has no way to tell "the host decides" from "nobody has set one", and
// those used to be the same thing.
Sizing string `json:"sizing"`
// EffectiveMinimum is the minimum the fleet holds this pool's runners to:
// Resources' own minimum where the pool set one, and the fleet's
// runners.minimum_* where it did not. Resources keeps the pool's own
// figures so that saving the pool never turns an inherited minimum into
// one of its own; this is where an operator sees what is inherited.
EffectiveMinimum PoolMinimumView `json:"effective_minimum"`
// RunnerSettings is what this pool overrides of the fleet's runner
// timings. Every field is absent on a pool that follows the fleet, which
// is what an unedited pool does.
RunnerSettings store.RunnerSettings `json:"runner_settings"`
Cache store.CacheConfig `json:"cache"`
Tmpfs store.TmpfsConfig `json:"tmpfs"`
HostSelector map[string]string `json:"host_selector"`
// ProviderSelector is which providers may rent machines for this pool,
// matched against each provider's name, kind and machine labels. Empty
// means any provider.
ProviderSelector map[string]string `json:"provider_selector"`
Env map[string]string `json:"env"`
RunAsRoot bool `json:"run_as_root"`
// NoDefaultLabels says the pool's runners advertise only Labels, without
// self-hosted and the operating-system and architecture labels.
NoDefaultLabels bool `json:"no_default_labels"`
Enabled bool `json:"enabled"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Counts PoolCountsView `json:"counts"`
QueuedJobs int `json:"queued_jobs"`
Utilisation float64 `json:"utilisation"`
Warnings []Problem `json:"warnings,omitempty"`
}
PoolView is a pool plus what an operator needs to see next to it: which installation it belongs to, how many runners it has in each state, how much of itself it is using, and every dangerous setting it has in effect.
func (PoolView) WithoutEnvValues ¶
WithoutEnvValues returns the view with every environment value blanked and every key left in place.
Env is injected into every runner a pool creates, which makes it the one field on this view an operator may reasonably have put a registry password or a proxy credential in -- and reading a pool is a viewer action while setting one is an operator action, so the two were not the same audience. Viewer is documented as reading everything except secrets; this is what makes that true of pools.
The keys stay because they are what the pool page renders -- it lists names and never values -- so a viewer still sees which variables a pool sets, and only the operator who could have written them can read them back.
type PrivateConnectionFault ¶ added in v1.3.8
PrivateConnectionFault is why the private-connection listener cannot be reached by the hosts that enrolled through it, and since when.
The listener belongs to the API server, which owns the socket-shaped half of the process; the controller only keeps the fact, because the problems list is built here and a listener that fails with nothing but a log line is the failure this exists to design out.
type Problem ¶
type Problem struct {
// Code is a stable identifier such as "host.unhealthy", suitable for
// grouping or suppressing in an alerting rule.
Code string `json:"code"`
Severity config.Severity `json:"severity"`
// Setting names the configuration key involved, when there is one.
Setting string `json:"setting,omitempty"`
// Source is the layer that set it: the file, this fleet's database, or a
// ZOOMIES_* variable. It is carried because the fix below is otherwise
// half an instruction -- an operator told to change a setting will edit
// the configuration file, and a value stored in the database or pinned by
// the environment is one the file cannot change.
Source config.Source `json:"source,omitempty"`
// Undo is the command that takes the value back out of that layer, for the
// case the settings page cannot fix: a stored value that stops the
// controller starting is unreachable from a page the controller serves.
Undo string `json:"undo,omitempty"`
Title string `json:"title"`
Detail string `json:"detail,omitempty"`
Fix string `json:"fix,omitempty"`
// TargetKind and TargetID let the UI link a problem to the pool, host,
// runner or installation it is about.
TargetKind string `json:"target_kind,omitempty"`
TargetID string `json:"target_id,omitempty"`
// Alternatives are the choices the fix leaves open, when the fix is a
// choice: for a pool no host can run, the backends its hosts do offer. They
// are carried apart from the prose so the UI can put the change one click
// away rather than leaving an operator to find the pool's edit form.
Alternatives []string `json:"alternatives,omitempty"`
// apart from the prose for the same reason: an operator who is told a
// number should be able to make the change with one click, and a UI that had
// to parse "--daemon-cpu-share 20" out of a sentence would be one reworded
// sentence from applying the wrong figure.
DaemonShare *DaemonShareChange `json:"daemon_share,omitempty"`
// Remedy is the change the controller proposes, as the update that makes it:
// see remedy.go. Absent when the fix is a decision rather than a change, or
// when what would fix it has not been priced.
Remedy *Remedy `json:"remedy,omitempty"`
// Since is when the situation started, where that is knowable.
Since *time.Time `json:"since,omitempty"`
// Audience is whose problem this is. It is filled in by Problems() from
// the code, in one pass, rather than at each of the thirty-odd places a
// Problem is made -- a field set at the site is a field somebody forgets
// at the site, which is the drift the settings registry exists to
// prevent.
Audience Audience `json:"audience"`
}
Problem is one thing an operator should know about, in the shape the API's /problems endpoint returns.
It carries the same four sentences a config.Finding does -- what is true, why it matters, and what to change -- because an operator reading the problems drawer should never have to go and look up what a code means.
func PoolRoomWarnings ¶ added in v1.3.8
PoolRoomWarnings is what the room says about the pool's own figures.
All three are the same class of failure: a pool that is valid, matches its hosts, shows green on every page, and cannot do what its settings promise. Nothing else catches them, because each is a disagreement between two settings that are correct on their own -- a maximum and a fleet, a host's slots and a runner's size, a cache limit and a disk.
func PoolWarnings ¶
type ProblemsView ¶
ProblemsView carries the drawer's own "nothing is wrong" flag rather than leaving the UI to infer it from an empty array, so that "we checked and all is well" and "we have not looked yet" cannot be rendered the same way.
func NewProblemsView ¶
func NewProblemsView(items []Problem) ProblemsView
NewProblemsView wraps a problem list. A nil list renders as an empty array, never as null, because the UI reads "nothing needs your attention" from exactly that.
func NewProblemsViewFor ¶ added in v1.3.8
func NewProblemsViewFor(items []Problem, platform bool) ProblemsView
NewProblemsViewFor is NewProblemsView for one of the two audiences.
OK is computed after the filter, not before it. A fleet whose own runners are fine, on an instance whose backups are failing, is a fleet with nothing to do: showing it "something needs your attention" above an empty drawer would send somebody looking for a problem they are not allowed to see.
type ProviderCheckView ¶ added in v1.3.8
type ProviderCheckView struct {
ProviderID string `json:"provider_id"`
OK bool `json:"ok"`
Reachable bool `json:"reachable"`
Version string `json:"version,omitempty"`
Findings []config.Finding `json:"findings"`
CheckedAt time.Time `json:"checked_at"`
}
ProviderCheckView is a preflight result: whether the hypervisor answered, what it said it is, and everything an operator has to fix before a machine will ever be created. The findings are config.Finding so that "what is wrong with this provider" reads exactly like "what is wrong with this configuration", in the wizard, in the problems drawer and in the CLI.
type ProviderChoiceView ¶ added in v1.3.8
type ProviderChoiceView struct {
Value string `json:"value"`
Label string `json:"label,omitempty"`
Consequence string `json:"consequence,omitempty"`
// CPUs and MemoryMB are the size of a node's hardware or a template's
// shape, for the limits step's arithmetic. Absent when the provider did
// not say.
CPUs int `json:"cpus,omitempty"`
MemoryMB int64 `json:"memory_mb,omitempty"`
}
ProviderChoiceView is one option in a guided form.
type ProviderDiscoveryView ¶ added in v1.3.8
type ProviderDiscoveryView struct {
Nodes []ProviderChoiceView `json:"nodes"`
Storages []ProviderChoiceView `json:"storages"`
Bridges []ProviderChoiceView `json:"bridges"`
Templates []ProviderChoiceView `json:"templates"`
// asked: the address did not answer, the credential was refused. A draft
// in a wizard is expected to be wrong at first, and a sentence beside the
// form is what corrects it; the form asks for identifiers meanwhile.
Unavailable string `json:"unavailable,omitempty"`
}
ProviderDiscoveryView is what a credential can actually see. A provider with no such concept leaves a list empty rather than inventing one.
type ProviderGuideStepView ¶ added in v1.3.8
type ProviderGuideStepView struct {
Title string `json:"title"`
Detail string `json:"detail,omitempty"`
Command string `json:"command,omitempty"`
}
ProviderGuideStepView is one thing to do before a provider of a kind works.
type ProviderKindView ¶ added in v1.3.8
type ProviderKindView struct {
Kind store.ProviderKind `json:"kind"`
Label string `json:"label"`
// Bootstrap says how the enrolment payload reaches a guest, which is the
// one capability an operator has to care about before they buy anything:
// "metadata" means the payload is readable by anyone who can read the
// machine's metadata.
Bootstrap string `json:"bootstrap"`
CanStartStop bool `json:"can_start_stop"`
CanDiscover bool `json:"can_discover"`
CanMarkOwnership bool `json:"can_mark_ownership"`
AsyncOperations bool `json:"async_operations"`
CostUnit string `json:"cost_unit,omitempty"`
EndpointExample string `json:"endpoint_example,omitempty"`
// Where the three answers every kind is asked for are found, in the
// provider's own console's terms.
EndpointSource string `json:"endpoint_source,omitempty"`
CredentialSource string `json:"credential_source,omitempty"`
CASource string `json:"ca_source,omitempty"`
// Guide is what has to exist before this kind can rent anything, in the
// order it is done, so the wizard can say it before its first question.
Guide []ProviderGuideStepView `json:"guide"`
Settings []ProviderSettingView `json:"settings"`
}
ProviderKindView is one provider driver this build carries, with the questions its configuration form has to ask. The form, the CLI and docs/providers.md all render this one description, so a setting cannot appear in one of them and be missing from the others.
type ProviderPlan ¶ added in v1.3.8
type ProviderPlan struct {
ProviderID string `json:"provider_id"`
// Wanted is how many machines this provider should have, and Have how many
// it already has: one that owns a resource, or one on the way to owning
// one. Both are readings, not increments -- a pass that has already bought
// what the queue asked for wants the same number again, not one more.
Wanted int `json:"wanted"`
Have int `json:"have"`
// Create is this pass's purchase, after every ceiling has been applied.
Create int `json:"create"`
// Drain is the machines that have stopped earning their keep, newest
// created first so that the one with the least warmed cache goes first.
// Unfit is those of them that could never have earned it: no enabled
// pool's runner fits on them, so they went without waiting out the idle
// timeout, and the drain says why in different words.
Drain []string `json:"drain,omitempty"`
Unfit []string `json:"unfit,omitempty"`
Reason string `json:"reason,omitempty"`
// Blocked says why Create is below what the queue asked for, and
// BlockedFix what to change. They are separate because the problems drawer
// shows the two differently.
Blocked string `json:"blocked,omitempty"`
BlockedFix string `json:"blocked_fix,omitempty"`
}
ProviderPlan is the decision for one provider, with the sentence that justified it in the scheduler's voice -- an operator reading "buy 1 machine on proxmox-lab: pool linux-x64 is 2 runner slots short with 3 jobs queued, and no host in the fleet can run it" needs nothing else explained.
type ProviderSettingView ¶ added in v1.3.8
type ProviderSettingView struct {
Key string `json:"key"`
Label string `json:"label"`
Kind string `json:"kind"`
Required bool `json:"required"`
Advanced bool `json:"advanced"`
Help string `json:"help,omitempty"`
// Consequence says what choosing this costs, in the voice the pool form
// already uses. A list of identifiers with no consequences is a list
// somebody guesses at.
Consequence string `json:"consequence,omitempty"`
Discovers string `json:"discovers,omitempty"`
Default string `json:"default,omitempty"`
// Source says where to find the answer when discovery cannot offer it.
Source string `json:"source,omitempty"`
}
ProviderSettingView is one answer a provider needs.
type ProviderView ¶ added in v1.3.8
type ProviderView struct {
ID string `json:"id"`
Kind store.ProviderKind `json:"kind"`
Name string `json:"name"`
// Endpoint is where this controller reaches the provider. It is not a
// secret -- it is the address an operator typed -- and showing it is how
// somebody tells two clusters apart on a page listing both.
Endpoint string `json:"endpoint,omitempty"`
InsecureSkipVerify bool `json:"insecure_skip_verify,omitempty"`
// CAPEM is the certificate this controller trusts for the endpoint instead of
// the system's.
CAPEM string `json:"ca_pem,omitempty"`
// MachineCAPEM is the certificate a machine built here trusts for this
// controller, and nothing else when it is set. A different certificate from
// CAPEM in general, and returned for the same reason: a form can only keep
// what it is shown.
MachineCAPEM string `json:"machine_ca_pem,omitempty"`
// Connection is how the endpoint is reached: "direct" over the network,
// or "tailcat" through a gateway beside the provider. The gateway's
// address is sealed on the row and, like the credential, has no field
// here: it is a lasting capability to open connections to the
// hypervisor's API, and this view is on every page and in every audit row.
Connection string `json:"connection"`
Settings map[string]string `json:"settings"`
// CredentialsConfigured says a credential is sealed in the row. The value
// never leaves this process, so this is what the form renders instead.
CredentialsConfigured bool `json:"credentials_configured"`
MachineLabels map[string]string `json:"machine_labels"`
MachineCapacity int `json:"machine_capacity"`
MachineBackend store.BackendKind `json:"machine_backend"`
MachinePlatform store.Platform `json:"machine_platform"`
MachineCPUs float64 `json:"machine_cpus,omitempty"`
MachineMemoryMB int64 `json:"machine_memory_mb,omitempty"`
MachineDiskMB int64 `json:"machine_disk_mb,omitempty"`
PoolSelector map[string]string `json:"pool_selector"`
MaxMachines int `json:"max_machines"`
MinMachines int `json:"min_machines"`
MaxCreatesInFlight int `json:"max_creates_in_flight"`
IdleTimeoutMS int64 `json:"idle_timeout_ms,omitempty"`
CostPerMachineHour float64 `json:"cost_per_machine_hour,omitempty"`
Enabled bool `json:"enabled"`
Paused bool `json:"paused"`
PausedReason string `json:"paused_reason,omitempty"`
PausedUntil *time.Time `json:"paused_until,omitempty"`
// Held is why no new machine may be bought right now, in one sentence, or
// empty when one may. It is computed rather than stored because it answers
// for three switches at once -- the fence, the configuration and the row --
// and a page that showed only the row's would say a fenced fleet was fine.
Held string `json:"held,omitempty"`
ConsecutiveFailures int `json:"consecutive_failures,omitempty"`
LastCheckAt *time.Time `json:"last_check_at,omitempty"`
LastCheckError string `json:"last_check_error,omitempty"`
// LastCheck is the whole of that check, findings with their detail and fix,
// so a page can show what the sentence above was the title of without the
// operator pressing Check again. Absent for a provider never checked, and
// for one last checked before the report was kept.
LastCheck *ProviderCheckView `json:"last_check,omitempty"`
LastSweepAt *time.Time `json:"last_sweep_at,omitempty"`
// Machines is how many this provider has, by state, so the card can show
// the band without a second request.
Machines map[string]int `json:"machines"`
// Owned is how many still believe they have a resource, which is the
// number the ceiling and the bill are both counted in.
Owned int `json:"owned"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ProviderView is one place machines are rented from, as the API returns it.
It carries no credential and has no field one could be put in. What it says about the credential is whether there is one, which is the only thing a page needs: an audit row and a screenshot both outlive the person who took them.
type Remedy ¶ added in v1.3.8
type Remedy struct {
// ID names this exact change, so that an apply is for what the person was
// shown: if the controller has since worked out a different one, the ID is
// different and the apply is refused as out of date rather than made.
ID string `json:"id"`
// Label is the button: what the change is, in a few words.
Label string `json:"label"`
// Effect is what the controller priced it at -- what it keeps and what it
// gains -- said before it is applied, because a change whose cost is found
// out afterwards is not a suggestion.
Effect string `json:"effect,omitempty"`
Kind RemedyKind `json:"kind"`
TargetID string `json:"target_id"`
Body json.RawMessage `json:"body"`
// Base is what the body was built from -- the pool's resources or the host's
// runner profile as the controller read them -- as RemedyBase hashes it. The body
// replaces that whole object, so applying it to one that has been edited since
// would put back whatever the edit changed; the apply compares the two and
// refuses. It is the controller's own check and never leaves it.
Base string `json:"-"`
}
Remedy is one change a problem proposes.
type RemedyKind ¶ added in v1.3.8
type RemedyKind string
RemedyKind says which update a remedy is, and so which role may apply it.
const ( // RemedyPoolUpdate is a PATCH of a pool; Body is its request. RemedyPoolUpdate RemedyKind = "pool.update" // RemedyHostUpdate is a PATCH of a host; Body is its request. RemedyHostUpdate RemedyKind = "host.update" )
type RemoteBackupStatus ¶ added in v1.3.8
type RemoteBackupStatus struct {
// Name is what this destination is called, and what the API addresses it
// by.
Name string `json:"name"`
// Where is the bucket and prefix, and Endpoint the service, so an
// operator can tell two buckets apart without opening the configuration.
Where string `json:"where"`
Endpoint string `json:"endpoint"`
// Encrypted says the archive is sealed before it leaves this host.
Encrypted bool `json:"encrypted"`
// Keep is this remote's own retention; 0 keeps every copy.
Keep int `json:"keep"`
// Disabled is a remote that is configured and switched off, which is
// shown rather than hidden: a destination nobody can see is one nobody
// notices has stopped.
Disabled bool `json:"disabled"`
// Source says where this destination is described -- "file" for
// zoomies.yaml and the environment, "database" for one added on the page.
// The page needs it to know what it may edit, and an operator needs it to
// know where to go and change something.
Source string `json:"source"`
// ID is the stored destination's row id, empty for one the file
// describes. Region, Bucket, Prefix and AccessKeyID are the rest of the
// form, so the page can open an editor without a second request.
ID string `json:"id,omitempty"`
Region string `json:"region,omitempty"`
Bucket string `json:"bucket,omitempty"`
Prefix string `json:"prefix,omitempty"`
AccessKeyID string `json:"access_key_id,omitempty"`
// PathStyle is the tri-state: null asks for the style to be chosen from
// the endpoint.
PathStyle *bool `json:"path_style"`
// Shadowed is a stored destination the file overrides by name. Nothing is
// sent to it, and the page says why rather than leaving a row that
// quietly does nothing.
Shadowed bool `json:"shadowed"`
// Problem is why this destination cannot be used at all -- almost always
// that this controller's key does not open its stored secrets.
Problem string `json:"problem,omitempty"`
// HasSecretKey says a secret key is held for this destination. The secret
// itself is never served: whether there is one is the only part of it a
// page can act on.
HasSecretKey bool `json:"has_secret_key"`
// Uploading says something is being sent right now.
Uploading bool `json:"uploading"`
// Copies and Bytes are what the last listing found, and ListedAt when.
Copies int `json:"copies"`
Bytes int64 `json:"bytes"`
ListedAt *time.Time `json:"listed_at"`
// LastUploadAt and LastUploadID are the last copy that reached it.
LastUploadAt *time.Time `json:"last_upload_at"`
LastUploadID string `json:"last_upload_id,omitempty"`
// LastError is why the last attempt did not work, in the words the
// service used.
LastError string `json:"last_error,omitempty"`
}
RemoteBackupStatus is one destination as the Backups tab and the problems drawer see it.
type RemotePruning ¶ added in v1.3.8
type RemotePruning struct {
Name string `json:"name"`
// Keep is this destination's own retention; zero keeps every copy.
Keep int `json:"keep"`
Removed []string `json:"removed"`
// Error is the service's own refusal, so a bucket that would not answer
// reads differently from one that had nothing to remove.
Error string `json:"error,omitempty"`
}
RemotePruning is what retention removed from one destination.
type RentingState ¶ added in v1.3.8
type RentingState string
RentingState is what the planner decided about renting for one pool.
const ( // RentingBuying is a pool this pass rents machines for: all it is short // of, or as much as the ceilings allow. RentingBuying RentingState = "renting" // RentingOnItsWay is a pool the machines already being built cover. RentingOnItsWay RentingState = "on_its_way" // RentingWaiting is a pool the scheduler could not place for a reason a // machine does not answer: a host that could run it is cordoned, silent, // incompatible, held or still starting runners. Mending a host is cheaper // than renting one, so nothing is rented until every host that could run // the pool is full. A pool no provider could ever serve is unserved // instead, because waiting would promise it a machine that never comes. RentingWaiting RentingState = "waiting" // RentingCeiling is a pool whose machine a limit stopped. RentingCeiling RentingState = "ceiling" // RentingUnserved is a pool no provider will rent for: a selector says no, // or no provider builds a machine that suits it. RentingUnserved RentingState = "unserved" // RentingHeld and RentingOff are never decided by the planner. The // controller lays them over a verdict (overlayRenting), because it knows // what the pure planner does not: that a provider may not buy at the // moment, or that renting is switched off. RentingHeld RentingState = "held" RentingOff RentingState = "off" )
type RentingView ¶ added in v1.3.8
type RentingView struct {
// State is "none" when no provider may rent (a demo fixture, or a provider
// whose own row is disabled, is not one that may), "off" when renting is
// switched off, "no_ceiling" when it is on and the fleet may rent no
// machines, and "on" otherwise.
State string `json:"state"`
// Summary is the state in one sentence, Fix what to change, and Setting
// the one setting the fix changes.
Summary string `json:"summary"`
Fix string `json:"fix,omitempty"`
Setting string `json:"setting,omitempty"`
// Enabled, Paused and MaxMachines are provider.enabled, provider.paused
// and provider.max_machines as they stand.
Enabled bool `json:"enabled"`
Paused bool `json:"paused"`
MaxMachines int `json:"max_machines"`
// SuggestedMaxMachines is the fleet ceiling a page offers to set: the
// ceilings of the providers that may rent, added up, and never less than
// one, so that the click that switches renting on cannot leave a fleet
// that may rent nothing.
SuggestedMaxMachines int `json:"suggested_max_machines,omitempty"`
// Owned is how many machines still own a resource, and so are still being
// paid for, as the last pass counted them: zero before the first.
Owned int `json:"owned"`
// DecidedAt is when the pass the verdicts come from ran, and absent before
// the first one.
DecidedAt *time.Time `json:"decided_at,omitempty"`
// Pools is never nil, so that a page is sent an empty list rather than
// null before the first pass.
Pools []PoolRenting `json:"pools"`
}
RentingView is the whole of what the fleet says about renting machines: which switch, if any, is holding it back, and the verdict on each pool the last machine pass had something to say about, with the switches laid over it.
The switches are read with the view and the verdicts are as old as the last pass. An operator who has just switched renting on reads the page to see that it took, so the view cannot wait for the loop to wake before it says so; and the verdicts are never worked out again for a read, because the decision that explains has to be the one that buys.
type RetainedExperimentComparison ¶ added in v1.3.8
type RetainedExperimentComparison struct {
WorkflowEvidence *ExperimentWorkflowEvidence `json:"workflow_evidence,omitempty"`
RunnerEvidence *ExperimentRunnerEvidence `json:"runner_evidence,omitempty"`
ID string `json:"id"`
SHA256 string `json:"sha256"`
CreatedAt time.Time `json:"created_at"`
Report *ExperimentComparisonReport `json:"report"`
}
type RetainedOptimisationPreview ¶ added in v1.3.8
type RolloutChange ¶ added in v1.3.8
RolloutChange is what a person's start, resume or cancel did: the rollout it acted on, and whether that moved. The handler audits it, so a press that moved nothing (a resume of a rollout already running) is still recorded, and says so rather than claiming it resumed something.
type RunnerRenderer ¶
type RunnerRenderer struct {
// contains filtered or unexported fields
}
RunnerRenderer names pools and hosts without a query per runner.
func (*RunnerRenderer) View ¶
func (v *RunnerRenderer) View(r *store.Runner) RunnerView
View renders one runner.
type RunnerSizeView ¶ added in v1.3.8
RunnerSizeView is a CPU and memory figure, as the API renders one.
type RunnerStats ¶
type RunnerStats struct {
Provisioning int `json:"provisioning"`
Registering int `json:"registering"`
Idle int `json:"idle"`
Busy int `json:"busy"`
Draining int `json:"draining"`
Failed int `json:"failed"`
Total int `json:"total"`
}
RunnerStats counts the fleet by runner state.
type RunnerView ¶
type RunnerView struct {
ResourceSample json.RawMessage `json:"resource_sample,omitempty"`
ID string `json:"id"`
Name string `json:"name"`
PoolID string `json:"pool_id"`
PoolName string `json:"pool_name,omitempty"`
HostID string `json:"host_id"`
HostName string `json:"host_name,omitempty"`
State store.RunnerState `json:"state"`
GitHubRunnerID int64 `json:"github_runner_id,omitempty"`
ContainerID string `json:"container_id,omitempty"`
Ephemeral bool `json:"ephemeral"`
Labels []string `json:"labels"`
Image string `json:"image,omitempty"`
ImageDigest string `json:"image_digest,omitempty"`
RunnerVersion string `json:"runner_version,omitempty"`
CurrentJobID string `json:"current_job_id,omitempty"`
CurrentJob *JobView `json:"current_job,omitempty"`
Message string `json:"message,omitempty"`
// FaultKind categorises why a failed runner failed, and FaultFix is what
// to do about it. Empty on a runner that did not fail. A runner that never
// took a job is the case these exist for: nothing else in the system says
// why a pool's containers will not start.
FaultKind store.FaultKind `json:"fault_kind,omitempty"`
FaultFix string `json:"fault_fix,omitempty"`
JobsHandled int `json:"jobs_handled"`
CPUPercent float64 `json:"cpu_percent,omitempty"`
MemoryBytes int64 `json:"memory_bytes,omitempty"`
// AllocatedCPUs and AllocatedMemoryMB are the limits this runner's
// workload was created with, and AllocationSource says whether they are
// the pool's own ("pool") or one slot's share of the host it landed on
// ("host"). Absent on a runner created with no limit at all. They are on
// the view so that an OOM kill on a defaulted limit points an operator at
// the host's capacity rather than at a pool field nobody set.
AllocatedCPUs float64 `json:"allocated_cpus,omitempty"`
AllocatedMemoryMB int64 `json:"allocated_memory_mb,omitempty"`
AllocationSource string `json:"allocation_source,omitempty"`
CPUResource *CPUResourceView `json:"cpu_resource,omitempty"`
// MemoryResource is what the memory valve has done for this runner and
// Scratch which of its folders its pool keeps in memory. Both are absent
// where there is nothing to say, which is every runner of a pool that uses
// neither.
MemoryResource *MemoryResourceView `json:"memory_resource,omitempty"`
Scratch *ScratchView `json:"scratch,omitempty"`
CreatedAt time.Time `json:"created_at"`
// ContainerStartedAt and RegisteredAt are the two halves of coming up, and
// they are on the view because the gap between them is the whole diagnosis
// of a runner stuck in `registering`: a container that never started is a
// backend or image problem on the host, and a container that started and
// never registered is a credential, network or GitHub one. Without both, a
// stuck runner has one symptom and two unrelated causes.
CreateTaskIssuedAt *time.Time `json:"create_task_issued_at,omitempty"`
HostRemovedAt *time.Time `json:"host_removed_at,omitempty"`
RegistrationDeletedAt *time.Time `json:"registration_deleted_at,omitempty"`
CleanupEstimatedAt *time.Time `json:"cleanup_estimated_at,omitempty"`
ContainerStartedAt *time.Time `json:"container_started_at,omitempty"`
RegisteredAt *time.Time `json:"registered_at,omitempty"`
StartedAt *time.Time `json:"started_at"`
LastIdleAt *time.Time `json:"last_idle_at"`
FinishedAt *time.Time `json:"finished_at"`
// CleanupError and its companions describe a runner Zoomies could not
// finish taking away. An empty error is the normal case; a non-empty one
// means something is still on a host or on GitHub.
CleanupError string `json:"cleanup_error,omitempty"`
CleanupFailedAt *time.Time `json:"cleanup_failed_at,omitempty"`
CleanupAttempts int `json:"cleanup_attempts,omitempty"`
// CleanedUpAt is the end of the runner's life: nothing of it left, on the
// host or on GitHub.
CleanedUpAt *time.Time `json:"cleaned_up_at,omitempty"`
}
RunnerView is one runner, with the pool and host named rather than only referenced: a runner grid that shows two opaque IDs per row is a grid nobody can read.
func (RunnerView) For ¶ added in v1.3.8
func (v RunnerView) For(visitor bool) RunnerView
For is the runner as one audience may read it: the job it is still pointed at is narrowed as a job is, because the runner's page and frames carry the same job the jobs routes do. It narrows a copy, so the job the view points to, which may be shared, is never changed.
type SSOTrouble ¶ added in v1.3.8
type SSOTrouble struct {
// Issuer is the identity provider that could not be set up.
Issuer string
// Reason is the last failure, written for the operator.
Reason string
// Since is when the first attempt failed.
Since time.Time
// Attempts is how many times discovery has been tried.
Attempts int
// Retrying says the API is trying again by itself, and NextAttempt when.
// False is a failure no retry can fix: a setting is missing.
Retrying bool
NextAttempt time.Time
}
SSOTrouble is single sign-on that is configured and not working, as the API -- which owns the identity provider -- reports it. The controller only carries it to the problems list, because that list is where an operator looks and the API has no list of its own.
type ScopedJobStats ¶
type ScopedJobStats struct {
QueuedJobs int `json:"queued_jobs"`
RunningJobs int `json:"running_jobs"`
Completed int `json:"completed"`
Succeeded int `json:"succeeded"`
Failed int `json:"failed"`
// FleetFailed is the part of Failed this fleet caused. See Stats.
FleetFailed int `json:"fleet_failed"`
Cancelled int `json:"cancelled"`
Unknown int `json:"unknown"`
MedianWaitMS int64 `json:"median_wait_ms"`
P95WaitMS int64 `json:"p95_wait_ms"`
}
ScopedJobStats is the job half of Stats over one scope.
GitHub reports every job in an installed repository, and on an organisation that also uses hosted runners most of them are somebody else's. A queue depth that counts those answers "why is my fleet slow?" with a number nobody here can act on, and a median wait computed from them is somebody else's queue.
type ScratchFolderView ¶ added in v1.3.8
type ScratchFolderView struct {
Kind store.ScratchKind `json:"kind"`
Label string `json:"label"`
Path string `json:"path"`
InMemory bool `json:"in_memory"`
SizeMB int64 `json:"size_mb,omitempty"`
AskedMB int64 `json:"asked_mb,omitempty"`
Auto bool `json:"auto,omitempty"`
Why store.ScratchWhy `json:"why,omitempty"`
Note string `json:"note,omitempty"`
}
ScratchFolderView is one folder: what it is, where it lives in the runner, what was asked for and what it was given. A folder the pool wanted in memory that the runner was not given there says why, in Note.
type ScratchPeakView ¶ added in v1.3.8
type ScratchPeakView struct {
Kind store.ScratchKind `json:"kind,omitempty"`
Label string `json:"label,omitempty"`
Path string `json:"path"`
PeakMB int64 `json:"peak_mb"`
SizeMB int64 `json:"size_mb"`
Percent int `json:"percent"`
}
ScratchPeakView is how full one of a job's in-memory folders got, for the job's page: the folder, what was written in it at most, its ceiling, and the one as a share of the other.
type ScratchView ¶ added in v1.3.8
type ScratchView struct {
// InMemory counts the folders the runner was given in memory.
InMemory int `json:"in_memory"`
Folders []ScratchFolderView `json:"folders"`
// Estimated says the folders were worked out by a build other than the one
// that mounted them, and Note says so in a sentence that names both. The
// controller records a runner's folders from its own placement rule, and
// the agent on the host mounts them from its own copy of that rule, so
// while a fleet runs two builds the row can say 2 GB of a folder the agent
// mounted at 1 GB. Absent while the two are the same build.
Estimated bool `json:"estimated,omitempty"`
Note string `json:"note,omitempty"`
}
ScratchView is which of a runner's folders its pool keeps in memory, as they were worked out when it was created. Nil for a runner whose pool keeps none.
type SizeClassLimits ¶ added in v1.3.8
type SizeClassLimits struct {
Class store.SizeClass `json:"class"`
// Label is the runs-on label that asks for the class by name.
Label string `json:"label"`
// HostMaxCPUs and HostMaxMemoryMB are the most allocatable a host in the
// class has; both are absent for the largest, which has no limit above.
HostMaxCPUs float64 `json:"host_max_cpus,omitempty"`
HostMaxMemoryMB int64 `json:"host_max_memory_mb,omitempty"`
RunnerCPUs float64 `json:"runner_cpus"`
RunnerMemoryMB int64 `json:"runner_memory_mb"`
}
SizeClassLimits is what one class is: how large a host in it is, and how large a runner.
type SplitOption ¶ added in v1.3.8
type SplitOption struct {
ID string `json:"id"`
CPUPercent int `json:"cpu_percent"`
MemoryPercent int `json:"memory_percent"`
// Runners is how many runners the hosts could hold under this division, and
// Loses is whether that is fewer than under the pool's own now.
Runners int `json:"runners"`
Loses bool `json:"loses"`
}
SplitOption is one way of dividing a slot, priced on the pool's hosts.
type SplitPlan ¶ added in v1.3.8
type SplitPlan struct {
Options []SplitOption `json:"options"`
// RunnersNow is the room under the division the pool has now.
RunnersNow int `json:"runners_now"`
// Recommended is the preset to preselect: the first that suits a pool that
// builds images and loses no runner, or "even" when none does.
Recommended string `json:"recommended"`
}
SplitPlan prices the presets and names the one to start from.
type Stats ¶
type Stats struct {
// Window is the period the completed counts and the wait percentiles
// cover. Completed is Succeeded + Failed + Cancelled + Unknown; a rate
// computed from Completed and Failed alone would count a job GitHub
// stopped reporting as a success, which is why the split is here.
Window string `json:"window"`
QueuedJobs int `json:"queued_jobs"`
RunningJobs int `json:"running_jobs"`
Completed int `json:"completed"`
Succeeded int `json:"succeeded"`
Failed int `json:"failed"`
// FleetFailed is how many of Failed this deployment caused rather than the
// workflows: a runner that never started, or one that stopped under the
// job. It is a subset rather than a fifth outcome -- GitHub's answer for
// such a job is still "failure", and a split that did not add up would be
// a worse lie than no split.
//
// It is the number the taxonomy exists for. "Eleven failures this hour" is
// a question; "eleven, nine of them ours" is an answer, and it sends a
// different person to a different page.
FleetFailed int `json:"fleet_failed"`
// Faults counts those failures by category, so the Overview can say which
// of the fleet's problems this is rather than only that it has one. Absent
// categories are absent rather than zero.
Faults map[store.FaultKind]int `json:"faults,omitempty"`
// RunnerStartFaults counts the runners that failed before taking a job,
// also by category. These are in no job count anywhere, because the jobs
// they were meant for are still queued -- which is exactly why a fleet
// that cannot start a container reads as a fleet that is merely busy.
RunnerStartFaults map[store.FaultKind]int `json:"runner_start_faults,omitempty"`
Cancelled int `json:"cancelled"`
Unknown int `json:"unknown"`
MedianWaitMS int64 `json:"median_wait_ms"`
P95WaitMS int64 `json:"p95_wait_ms"`
P50StartupMS int64 `json:"p50_startup_ms"`
P95StartupMS int64 `json:"p95_startup_ms"`
P50RegistrationMS int64 `json:"p50_registration_ms"`
P95RegistrationMS int64 `json:"p95_registration_ms"`
// Fleet is every job figure above, narrowed to the jobs this fleet has a
// hand in. Both are carried in one payload rather than chosen by a query
// parameter because the same numbers arrive over the event stream, which
// is one frame for every viewer: a per-request scope would be correct
// until the next frame overwrote it, a second or two later.
Fleet ScopedJobStats `json:"fleet"`
Runners RunnerStats `json:"runners"`
Hosts HostStats `json:"hosts"`
Pools []PoolStats `json:"pools"`
}
Stats is the Overview payload: what the queue is doing, what the fleet is doing, and how long jobs are waiting.
type StatusReason ¶ added in v1.3.8
type StatusReason struct {
Code string `json:"code"`
Severity config.Severity `json:"severity"`
Since *time.Time `json:"since,omitempty"`
}
StatusReason is one code on the fleet's list: which, how bad, and since when. Nothing else -- the operator's title and detail name the pool or host they are about, and that is exactly what this must not carry.
type Stranding ¶ added in v1.3.8
type Stranding struct {
PoolID string `json:"pool_id"`
Pool string `json:"pool"`
// Host is the machine whose refusal Reason quotes: the host being edited,
// or, for a pool edit, one that used to have room for it.
Host string `json:"host"`
// Code is which of the placement rules it now fails, in the same
// vocabulary HostFit's exclusions use: selector, backend, platform, size,
// profile.
Code string `json:"code"`
Reason string `json:"reason"`
}
Stranding is one pool an edit would leave with no host in the fleet that could ever run it, and the refusal that is the nearest miss -- a host that could run it before the edit and could not after, with that host's own account of why. The name is the operator's way in: a code is something to group by, and the machine that stopped fitting is the one to go and look at.
type TmpfsFolderPlan ¶ added in v1.3.8
type TmpfsFolderPlan struct {
Name string `json:"name"`
// AskMB is what the folder is asked for there and MB what a runner is given;
// zero is disk.
AskMB int64 `json:"ask_mb"`
MB int64 `json:"mb"`
Auto bool `json:"auto"`
}
TmpfsFolderPlan is one folder on one host.
type TmpfsHostPlan ¶ added in v1.3.8
type TmpfsHostPlan struct {
Host string `json:"host"`
RunnerMB int64 `json:"runner_mb"`
DaemonMB int64 `json:"daemon_mb,omitempty"`
Folders []TmpfsFolderPlan `json:"folders"`
}
TmpfsHostPlan is what a runner of the pool is given on one host.
type TmpfsPlan ¶ added in v1.3.8
type TmpfsPlan struct {
Hosts []TmpfsHostPlan `json:"hosts"`
// InMemory and Total count folder placements across the hosts: how many of the
// folders asked for are in memory.
InMemory int `json:"in_memory"`
Total int `json:"total"`
// Share is the daemon share that would put the most folders in memory, when
// moving it would put more than now. Sizes are, per host, the runner size
// that would put the work folder there. Either may be empty: the plan says
// only what would help.
Sizes []TmpfsSizeOption `json:"sizes,omitempty"`
}
TmpfsPlan is what a pool's in-memory folders come to, host by host, and what would change it.
type TmpfsShareOption ¶ added in v1.3.8
type TmpfsShareOption struct {
// InMemory is how many folder placements are in memory across the hosts at
// this share, against Now at the pool's. Runners is how many the hosts could
// hold at it, against RunnersNow: moving a share can raise what a runner is
// charged, which is how it costs capacity.
}
TmpfsShareOption is a daemon share that would put more folders in memory.
type TmpfsSizeOption ¶ added in v1.3.8
type TmpfsSizeOption struct {
Host string `json:"host"`
MemoryMB int64 `json:"memory_mb"`
Slots int `json:"slots"`
SlotsNow int `json:"slots_now"`
// Lever is what changes the runner's size on this pool: "standard", the host's
// standard runner size in its runner profile, for a pool that takes its size
// from its hosts; or "capacity", the host's slot count, for a pool sized by a
// slot's share of the machine, where fewer slots are bigger ones.
Lever string `json:"lever"`
}
TmpfsSizeOption is the runner size on one host at which the work folder would be in memory there.
type ToolCacheFill ¶ added in v1.3.8
type ToolCacheFill struct {
HostID string `json:"host_id"`
HostName string `json:"host_name"`
// State is pending while the agent works, then succeeded or failed. A
// fill that succeeded may still have skipped or failed requests; Tools
// says which.
State string `json:"state"`
Requested int `json:"requested"`
Tools []backend.ToolFill `json:"tools"`
Error string `json:"error,omitempty"`
QueuedAt time.Time `json:"queued_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
}
ToolCacheFill is one pool's fill on one host.
type ToolchainDemand ¶ added in v1.3.8
type ToolchainDemand struct {
Tool string `json:"tool"`
Version string `json:"version,omitempty"`
Distribution string `json:"distribution,omitempty"`
// Unresolved says why the version is not known from the workflows; see
// toolscan.Requirement.
Unresolved string `json:"unresolved,omitempty"`
// Jobs is how many workflow jobs ask for it, counting each matrix
// combination once, and Repositories which repositories they are in.
Jobs int `json:"jobs"`
Repositories []string `json:"repositories"`
}
ToolchainDemand is one toolchain version a pool's jobs ask for.
type ToolchainScan ¶ added in v1.3.8
type ToolchainScan struct {
Running bool `json:"running"`
StartedAt *time.Time `json:"started_at,omitempty"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
// Pools maps a pool ID to what its jobs ask for.
Pools map[string][]ToolchainDemand `json:"pools"`
// Unmatched is what jobs ask for that no pool would run: jobs on
// GitHub-hosted labels, on labels no pool carries, or on labels an
// expression chooses.
Unmatched []ToolchainDemand `json:"unmatched"`
Installations []ToolchainScanInstallation `json:"installations"`
// Fills maps a pool ID to its tool cache's latest fill on each host,
// for the pools that keep one; see toolfill.go.
Fills map[string][]ToolCacheFill `json:"fills"`
}
ToolchainScan is the latest scan.
type ToolchainScanInstallation ¶ added in v1.3.8
type ToolchainScanInstallation struct {
InstallationID string `json:"installation_id"`
Target string `json:"target"`
Repositories int `json:"repositories"`
Workflows int `json:"workflows"`
// Error is why this installation was not read, or only partly: GitHub
// refusing it, a rate-limit hold, or an App without the Contents
// permission, whose every repository would otherwise look empty.
Error string `json:"error,omitempty"`
// Unreadable lists repositories GitHub would not give up workflows for,
// with the reason.
Unreadable map[string]string `json:"unreadable,omitempty"`
}
ToolchainScanInstallation is how the scan went for one installation.
type TransferProgress ¶ added in v1.3.8
type TransferProgress = store.TransferProgress
type UnservedPool ¶ added in v1.3.8
type UnservedPool struct {
Pool string `json:"pool"`
Why string `json:"why"`
Fix string `json:"fix,omitempty"`
}
UnservedPool is one pool no provider will rent for, with the sentence that says whose selector said no.
type UpdateActor ¶ added in v1.3.8
type UpdateActor struct {
ID, Name string
}
UpdateActor is who asked for an update, as the request and the attempt record it. It is only ever written down: the API checks the caller's role and writes the audit row before it gets here.
type UpdatesAttempt ¶ added in v1.3.8
type UpdatesAttempt struct {
ID string `json:"id"`
// State is requested until it ends, then succeeded, failed, timed_out or
// cancelled.
State string `json:"state"`
// From is the build that asked, as it reports itself, and To the release tag
// it asked for.
From string `json:"from"`
To string `json:"to"`
// Trigger is manual for a person and auto for the update mode.
Trigger string `json:"trigger"`
RequestedAt time.Time `json:"requested_at"`
FinishedAt *time.Time `json:"finished_at"`
// Error is why it did not succeed, often the helper's own sentence, and empty
// otherwise. Below the platform role it is a fixed sentence for the state (see
// For), because the text can name a folder on the controller's host.
Error string `json:"error"`
// Backup is the copy the engine took before it changed anything, for a page
// to offer a restore from after a failed update. It names a folder on the
// controller's host, so below the platform role it is empty (see For).
Backup string `json:"backup"`
// RolledBack says the engine put the previous release back because the new one
// did not answer, so the attempt is a failure that was undone rather than one
// left in place.
RolledBack bool `json:"rolled_back"`
}
UpdatesAttempt is one request to update, and how it ended.
type UpdatesDevelopment ¶ added in v1.3.8
type UpdatesHelper ¶ added in v1.3.8
type UpdatesHelper struct {
// State is ready, missing, or unsupported where it can never be installed.
State string `json:"state"`
// Reason is the sentence the page shows. It names no path, because every role
// reads it.
Reason string `json:"reason"`
// InstallCommand is what installs the helper, for a person to copy, and empty
// when it is ready or cannot be installed.
InstallCommand string `json:"install_command"`
// UpgradeCommand is what updates the controller by hand on its host, for a
// person to copy, and empty unless the helper cannot be installed: anywhere
// else the helper is the way, and the command would be a second answer.
UpgradeCommand string `json:"upgrade_command"`
}
UpdatesHelper is the update helper beside the controller, as far as the controller can see it: its marker, in the folder the installer recorded.
type UpdatesRelease ¶ added in v1.3.8
type UpdatesRelease struct {
Tag string `json:"tag"`
// URL is the release's page, so its notes can be read before it is taken.
URL string `json:"url"`
// PublishedAt is when GitHub published it, which is where the soak starts.
PublishedAt time.Time `json:"published_at"`
}
UpdatesRelease is a release on offer.
type UpdatesRollout ¶ added in v1.3.8
type UpdatesRollout struct {
ID string `json:"id"`
Target string `json:"target"`
// State is running or halted while it is open, then done or cancelled.
State string `json:"state"`
// HaltedReason is the sentence it halted with, and empty unless it is
// halted now: it names the host and the release and never the helper's
// text, which can name a path on the host, so every role reads it.
HaltedReason string `json:"halted_reason"`
// Done is the hosts it has updated, and Total those and the hosts it would
// still update. Neither moves with a heartbeat, only with a host's version.
Done int `json:"done"`
Total int `json:"total"`
// Current is the name of the host being updated now, and empty with none.
Current string `json:"current"`
}
UpdatesRollout is a walk of the fleet to one release, as far as it has got.
type UpdatesRunning ¶ added in v1.3.8
type UpdatesRunning struct {
Version string `json:"version"`
// Release says the build came from a release. A build from main is usually
// ahead of the newest release, so only one that did can be offered an update
// without it being a downgrade.
Release bool `json:"release"`
}
UpdatesRunning is the build being updated, as it reports itself: a release binary says "1.3.5", without the v its tag has.
type UpdatesSigning ¶ added in v1.3.8
type UpdatesSigning struct {
// Keys is one id per trusted release key, empty when none is compiled in.
// The keys themselves are not exposed here: an id names one, which is all a
// page needs to say what this build trusts.
Keys []string `json:"keys"`
}
UpdatesSigning is the release signing key state of the running build, so a page can say whether a download is held to a signature and by which keys.
type UpdatesTarget ¶ added in v1.3.8
type UpdatesTarget struct {
Tag string `json:"tag"`
// Newer says the release is a later one than the running build. Only then is
// there anything to take, and only then does DueAt mean anything.
Newer bool `json:"newer"`
// DueAt is the earliest time the mode takes the release: the end of the soak
// in auto. It is null in manual, where the person asking is the only wait.
DueAt *time.Time `json:"due_at"`
}
UpdatesTarget is what the mode would do about the newest release.
type UpdatesView ¶ added in v1.3.8
type UpdatesView struct {
// Mode is updates.mode as the controller acts on it, so a word the registry
// does not know reads here, as everywhere else, as off.
Mode string `json:"mode"`
// Soak is updates.soak as the Settings page writes it. manual ignores it.
Soak string `json:"soak"`
Running UpdatesRunning `json:"running"`
// Development compares the stamped build with main. It does not claim
// that main's image has finished publishing to the dev channel.
Development *UpdatesDevelopment `json:"development,omitempty"`
// Latest is the newest release that could be installed on this system,
// whether or not the running build is behind it.
Latest *UpdatesRelease `json:"latest"`
// Target is what the mode would do about Latest.
Target *UpdatesTarget `json:"target"`
// Reason is the sentence the page shows: the planner's, wherever a list has
// been read, which is the release rule's own unless something else (an open
// attempt, a rollout, the helper) decides what happens next. It holds no
// elapsed time that moves with a heartbeat, so the panel is not repainted
// for nothing.
Reason string `json:"reason"`
// CheckedAt is when the list Latest was chosen from was read.
CheckedAt *time.Time `json:"checked_at"`
// Helper says whether this controller can update itself, and if not, how a
// person with root on its host makes it able to, or why nobody can.
Helper UpdatesHelper `json:"helper"`
// Signing says whether this build holds a release's checksums to a signature,
// and the ids of the keys it trusts. No keys means it takes the checksums on
// trust, which is what a build from before a key was committed does.
Signing UpdatesSigning `json:"signing"`
// Rollback says a controller that does not come back is put back on the
// release it ran, which is a native service running the binary. A container's
// service is its image, which the upgrade does not keep the one before, so
// this is false there.
Rollback bool `json:"rollback"`
// Controller is this controller's latest update attempt, open or ended, and
// null when it has never had one.
Controller *UpdatesAttempt `json:"controller"`
// Rollout is the open rollout, or the last one that ended, and null when
// there has been none.
Rollout *UpdatesRollout `json:"rollout"`
}
UpdatesView is what the update mode would do about the releases on offer, and why.
It is worked out when asked and never stored. It changes when the clock passes the end of a soak as much as when a list is read, and no row is written for either.
Latest, Target and CheckedAt are null while updating is off and until a list has been read. A list that was read and holds nothing that can be installed is not the same: it has a time, and a sentence of its own.
func (UpdatesView) For ¶ added in v1.3.8
func (v UpdatesView) For(platform bool) UpdatesView
For is the status as one audience may read it. The platform reads it whole.
An attempt's error is often the helper's own sentence, or the controller's about a folder it could not write, and either can name a path on the controller's host. That host is the platform's to know about, so every other role is given a sentence for the state in its place, and still learns that the attempt ended and how. The helper's own sentence stays: it is fixed, and names no path, because every role reads it.
It narrows a copy. The view is rendered once and handed to every audience, and the attempt it points to is shared.
type WhyClass ¶ added in v1.3.8
type WhyClass string
WhyClass is the one-word answer to "why is this job where it is". The set is closed on purpose: a class is something a person can act on and a skill can match, and a new one is a change to both.
const ( WhyOOM WhyClass = "oom" WhyTimeout WhyClass = "timeout" WhyCancelled WhyClass = "cancelled" WhyQueuedUnmatched WhyClass = "queued-unmatched" WhyQueuedBlocked WhyClass = "queued-blocked" WhyQueuedCapacity WhyClass = "queued-capacity" WhyQueued WhyClass = "queued" WhyRunnerStartupFailure WhyClass = "runner-startup-failure" WhyHostLost WhyClass = "host-lost" WhyDisk WhyClass = "disk" WhyScratchFull WhyClass = "scratch-full" WhyWorkflowFailure WhyClass = "workflow-failure" WhyHeldByGitHub WhyClass = "held-by-github" WhyRunning WhyClass = "running" WhySucceeded WhyClass = "succeeded" WhyUnknown WhyClass = "unknown" )
type WhyConfidence ¶ added in v1.3.8
type WhyConfidence string
WhyConfidence says how far the class rests on a recorded fact. High is a fact the fleet wrote down; medium is an inference or a fact with a gap in it, and the reason says which; low is a guess, and unknown is always low.
const ( WhyHigh WhyConfidence = "high" WhyMedium WhyConfidence = "medium" WhyLow WhyConfidence = "low" )
type WorkflowRunView ¶ added in v1.3.8
type WorkflowRunView struct {
Repo string `json:"repo"`
Workflow string `json:"workflow"`
GitHubRunID int64 `json:"github_run_id"`
RunNumber int64 `json:"run_number,omitempty"`
RunAttempt int `json:"run_attempt,omitempty"`
HeadBranch string `json:"head_branch,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
InstallationID string `json:"installation_id,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
// State and Conclusion are the run's own, worked out from its jobs the
// way GitHub's run page does it: see store.WorkflowRun.
State store.JobState `json:"state"`
Conclusion string `json:"conclusion,omitempty"`
// Managed is whether this fleet has a hand in any job of the run, and
// Hosted whether every job runs on somebody else's runners -- the same
// two things a job says about itself, lifted to the run.
Managed bool `json:"managed"`
Hosted bool `json:"hosted"`
// Cancelling is whether an operator's cancellation of the run has been
// accepted by GitHub and not yet confirmed by its jobs completing.
Cancelling bool `json:"cancelling"`
Jobs store.RunJobCounts `json:"jobs"`
QueuedAt time.Time `json:"queued_at"`
StartedAt *time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at"`
QueueWaitMS int64 `json:"queue_wait_ms"`
DurationMS int64 `json:"duration_ms"`
}
WorkflowRunView is one workflow run -- the "#1009" in GitHub's Actions tab -- with its jobs summed up and its waits measured: the shape GET /workflow-runs returns and the Workflows page lists.
func NewWorkflowRunView ¶ added in v1.3.8
func NewWorkflowRunView(r *store.WorkflowRun) WorkflowRunView
NewWorkflowRunView renders a run. Nothing is looked up: every field is the store's own aggregate, so a page of runs costs one query.
Source Files
¶
- agent_limits.go
- agents.go
- ai_context.go
- ai_context_diagnosis.go
- ai_context_ingestion.go
- ai_context_maintenance.go
- ai_context_setup.go
- ai_context_upload.go
- analysis.go
- assistant.go
- assistant_chat.go
- assistant_models.go
- assistant_tools.go
- auto_adjust.go
- autopools.go
- background.go
- backups.go
- backups_remote.go
- bootstrap.go
- capacity_demand.go
- clients.go
- conflict.go
- controller.go
- democlient.go
- derived.go
- elastic_cpu.go
- elastic_memory.go
- eli_automatic.go
- eli_error_output.go
- eli_experience.go
- eli_repair_case.go
- eli_repairs.go
- enrichment.go
- experiment_collect.go
- experiment_dependency_view.go
- experiment_grants.go
- experiment_join.go
- experiment_retention.go
- experiment_runner_creations.go
- experiment_runner_view.go
- experiment_snapshot.go
- experiment_workflow_view.go
- explain.go
- fleet_reads.go
- host_acceptances.go
- host_check.go
- host_cleanup.go
- host_doctor.go
- host_health_problems.go
- host_priority.go
- host_recovery.go
- host_upgrade.go
- hostadvice.go
- hostfit.go
- incidents.go
- installation_archive.go
- job_attention.go
- job_versions.go
- jobs.go
- jobtrends.go
- kennel.go
- kennel_budget.go
- kennel_guidance.go
- kennel_guidance_setup.go
- kennel_operations.go
- kennel_problems.go
- kennel_protection.go
- kennel_settings.go
- kennel_setup.go
- kennel_snapshot.go
- kennel_views.go
- kennel_workflows.go
- lease.go
- limits.go
- logs.go
- machinedemand.go
- machineenrol.go
- machinerecovery.go
- machines.go
- machines_tailcat.go
- memory_views.go
- metrics.go
- migrations.go
- minimum.go
- optimisation_capture.go
- optimisation_inspect.go
- optimisation_retention.go
- pairings.go
- pairshare.go
- placement_intent.go
- poller.go
- poolminimum.go
- poolqueue.go
- poolroom.go
- pr_delay.go
- pr_delay_admission.go
- pr_delay_collect.go
- private_connection.go
- problems.go
- problems_flight.go
- profile.go
- provider_certificate.go
- provideradmin.go
- provisioning.go
- reconcile.go
- registration_admission.go
- remedy.go
- renting.go
- runner_creation_observation.go
- runner_readiness.go
- runnerenv.go
- scratch_full.go
- scratch_unmeasured.go
- seed.go
- seed_analysis.go
- seed_memory.go
- seed_stuck.go
- seed_updates.go
- size.go
- size_views.go
- sso.go
- stats.go
- status.go
- testmachine.go
- throttle.go
- timings.go
- tmpfs.go
- tmpfsplan.go
- toolchains.go
- toolfill.go
- transfer.go
- updates.go
- updates_apply.go
- updates_auto.go
- updates_errors.go
- updates_hosts.go
- updates_loop.go
- updates_unsupported.go
- updates_views.go
- views.go
- webhooks.go
- why.go