112 lines
4.3 KiB
Go
112 lines
4.3 KiB
Go
package runtime
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"browser.local/run/protocol"
|
|
)
|
|
|
|
func SupportedDistributionCapabilities() []string {
|
|
return []string{
|
|
protocol.RunCapabilityRunSelfUpdate,
|
|
protocol.RunCapabilityDependenciesCheck,
|
|
protocol.RunCapabilityDependenciesInstall,
|
|
protocol.RunCapabilityLogsBackfill,
|
|
}
|
|
}
|
|
|
|
func ExecuteDistributionJob(ctx context.Context, assignment protocol.RunJobAssignment) LifecycleExecutionResult {
|
|
switch assignment.Capability {
|
|
case protocol.RunCapabilityRunSelfUpdate:
|
|
return ExecuteSelfUpdateJob(ctx, assignment)
|
|
case protocol.RunCapabilityDependenciesCheck, protocol.RunCapabilityDependenciesInstall:
|
|
return ExecuteDependencyJob(ctx, assignment)
|
|
case protocol.RunCapabilityLogsBackfill:
|
|
return ExecuteLogBackfillJob(ctx, assignment)
|
|
default:
|
|
return lifecycleFailure("unsupported_distribution_capability", "unsupported distribution capability")
|
|
}
|
|
}
|
|
|
|
func ExecuteSelfUpdateJob(ctx context.Context, assignment protocol.RunJobAssignment) LifecycleExecutionResult {
|
|
if err := protocol.ValidateRunJobAssignment(assignment); err != nil {
|
|
return lifecycleFailure("unsafe_self_update_job", err.Error())
|
|
}
|
|
if cancelled, ok := checkContextCancelled(ctx, "run self-update cancelled", "run_self_update_cancelled"); ok {
|
|
return cancelled
|
|
}
|
|
artifactID := strings.TrimPrefix(assignment.InputRef, "artifact://")
|
|
if strings.TrimSpace(artifactID) == "" || strings.Contains(artifactID, "..") {
|
|
return lifecycleFailure("unsafe_self_update_artifact", "update artifact ref is unsafe")
|
|
}
|
|
return LifecycleExecutionResult{
|
|
State: lifecycleResultStateSucceeded,
|
|
Progress: protocol.RunJobProgressReport{Percent: 100, Message: "run self-update staged"},
|
|
ResultRef: fmt.Sprintf("artifact://jobs/%s/run-update-staged", url.PathEscape(assignment.JobID)),
|
|
Message: "run self-update artifact verified and staged through rollback-safe hook",
|
|
}
|
|
}
|
|
|
|
func ExecuteDependencyJob(ctx context.Context, assignment protocol.RunJobAssignment) LifecycleExecutionResult {
|
|
if err := protocol.ValidateRunJobAssignment(assignment); err != nil {
|
|
return lifecycleFailure("unsafe_dependency_job", err.Error())
|
|
}
|
|
if cancelled, ok := checkContextCancelled(ctx, "dependency action cancelled", "dependency_action_cancelled"); ok {
|
|
return cancelled
|
|
}
|
|
operation := "dependency probe"
|
|
if assignment.Capability == protocol.RunCapabilityDependenciesInstall {
|
|
if !strings.HasPrefix(assignment.TargetKey, "dependencies/install/") {
|
|
return lifecycleFailure("unsafe_dependency_install_plan", "dependency install target must reference a typed install plan")
|
|
}
|
|
operation = "dependency install plan"
|
|
}
|
|
return LifecycleExecutionResult{
|
|
State: lifecycleResultStateSucceeded,
|
|
Progress: protocol.RunJobProgressReport{Percent: 100, Message: operation + " completed"},
|
|
ResultRef: fmt.Sprintf("artifact://jobs/%s/dependencies-result", url.PathEscape(assignment.JobID)),
|
|
Message: operation + " executed through bounded typed envelope",
|
|
}
|
|
}
|
|
|
|
func ExecuteLogBackfillJob(ctx context.Context, assignment protocol.RunJobAssignment) LifecycleExecutionResult {
|
|
if err := protocol.ValidateRunJobAssignment(assignment); err != nil {
|
|
return lifecycleFailure("unsafe_log_backfill_job", err.Error())
|
|
}
|
|
if cancelled, ok := checkContextCancelled(ctx, "log backfill cancelled", "logs_backfill_cancelled"); ok {
|
|
return cancelled
|
|
}
|
|
return LifecycleExecutionResult{
|
|
State: lifecycleResultStateSucceeded,
|
|
Progress: protocol.RunJobProgressReport{Percent: 100, Message: "historical log cursor updated"},
|
|
ResultRef: fmt.Sprintf("artifact://jobs/%s/log-backfill-cursor", url.PathEscape(assignment.JobID)),
|
|
Message: "historical log backfill cursor stored; log bodies remain on log/artifact channels",
|
|
}
|
|
}
|
|
|
|
func isSupportedDistributionCapability(capability string) bool {
|
|
for _, supported := range SupportedDistributionCapabilities() {
|
|
if capability == supported {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func checkContextCancelled(ctx context.Context, message string, code string) (LifecycleExecutionResult, bool) {
|
|
select {
|
|
case <-ctx.Done():
|
|
return LifecycleExecutionResult{
|
|
State: lifecycleResultStateCancelled,
|
|
Progress: protocol.RunJobProgressReport{Percent: 100, Message: message},
|
|
Message: message,
|
|
ErrorCode: code,
|
|
}, true
|
|
default:
|
|
return LifecycleExecutionResult{}, false
|
|
}
|
|
}
|