diff --git a/cmd/ate-setup/commands.md b/cmd/ate-setup/commands.md index 954856eaa..e69ccb659 100644 --- a/cmd/ate-setup/commands.md +++ b/cmd/ate-setup/commands.md @@ -49,6 +49,15 @@ apiserver, the controller, atenet, and atelet. It creates every `create` resource below on the way, so those subcommands are only needed to redo one on a running cluster. +## Publish + +| `ate-setup` | `hack/install-ate.sh` | +|---|---| +| `publish worker-images` | (no shell equivalent) | + +Builds and pushes the ateom worker images for the checked-out build and prints +their refs; a WorkerPool points `spec.workerImage` to a build to use the ateom. + ## Delete | `ate-setup` | `hack/install-ate.sh` | diff --git a/cmd/ate-setup/internal/cmd/publish.go b/cmd/ate-setup/internal/cmd/publish.go new file mode 100644 index 000000000..96525ace9 --- /dev/null +++ b/cmd/ate-setup/internal/cmd/publish.go @@ -0,0 +1,44 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "github.com/spf13/cobra" +) + +var publishCmd = &cobra.Command{ + Use: "publish", + Short: "Build and push images that no manifest references", +} + +var publishWorkerImagesCmd = &cobra.Command{ + Use: "worker-images", + Short: "Build and push the ateom worker images for this build and print their refs", + Long: `Build and push the ateom worker images (one per sandbox class) for the +checked-out build and print their pushed references, one ": " +line per image. + +A WorkerPool moves to a build by pointing spec.workerImage at that build's +ateom ref.`, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return env.PublishWorkerImages(cmd.Context(), cmd.OutOrStdout()) + }, +} + +func init() { + rootCmd.AddCommand(publishCmd) + publishCmd.AddCommand(publishWorkerImagesCmd) +} diff --git a/cmd/ate-setup/internal/ko/ko.go b/cmd/ate-setup/internal/ko/ko.go index 76ed0057c..3cb80a17d 100644 --- a/cmd/ate-setup/internal/ko/ko.go +++ b/cmd/ate-setup/internal/ko/ko.go @@ -108,6 +108,31 @@ func (r *Runner) Resolve(ctx context.Context, path string, stdinManifest []byte) return stdout.Bytes(), nil } +// Build builds and publishes one Go binary's image and returns its pushed +// reference (the last line ko prints). Resolve covers everything a manifest +// references; Build is for the images with no manifest names, such as the ateom +// worker images a WorkerPool points at through workerImage. +func (r *Runner) Build(ctx context.Context, importPath string) (string, error) { + args := []string{"build", importPath} + for _, flag := range r.ldflags() { + args = append(args, "--ldflags="+flag) + } + cmd := exec.CommandContext(ctx, r.binary, args...) + cmd.Dir = r.Root + cmd.Env = append(os.Environ(), r.Env...) + var stdout bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = r.Stderr + if err := cmd.Run(); err != nil { + return "", fmt.Errorf("while running ko build %s: %w", importPath, err) + } + lines := strings.Fields(stdout.String()) + if len(lines) == 0 { + return "", fmt.Errorf("ko build %s printed no image reference", importPath) + } + return lines[len(lines)-1], nil +} + // ResolvePath resolves a manifest file or directory. func (r *Runner) ResolvePath(ctx context.Context, path string) ([]byte, error) { return r.Resolve(ctx, path, nil) diff --git a/cmd/ate-setup/internal/steps/publish.go b/cmd/ate-setup/internal/steps/publish.go new file mode 100644 index 000000000..f5533d90b --- /dev/null +++ b/cmd/ate-setup/internal/steps/publish.go @@ -0,0 +1,62 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package steps + +import ( + "context" + "fmt" + "io" + + "github.com/agent-substrate/substrate/cmd/ate-setup/internal/log" +) + +// workerImages are the ateom images a WorkerPool points at through +// workerImage, one per sandbox class. No manifest references them, so the +// install never publishes them as a side effect. +var workerImages = []string{"ateom-gvisor", "ateom-microvm"} + +// PublishWorkerImages builds and pushes the ateom images for this build and +// writes their pushed references to w, one ": " line per image, +// after every build has finished so the refs sit together below ko's build +// output. A WorkerPool moves to this build by pointing its workerImage at +// the ref. +func (e *Env) PublishWorkerImages(ctx context.Context, w io.Writer) error { + version, _, err := e.SubstrateVersion() + if err != nil { + return err + } + log.Stepf("publish_worker_images (%s)", version) + runner, err := e.Ko() + if err != nil { + return err + } + refs := make([]string, 0, len(workerImages)) + for _, img := range workerImages { + ref, err := runner.Build(ctx, "./cmd/"+img) + if err != nil { + return err + } + refs = append(refs, img+": "+ref) + } + if _, err := fmt.Fprintf(w, "\nWorker images for %s:\n", version); err != nil { + return err + } + for _, line := range refs { + if _, err := fmt.Fprintln(w, line); err != nil { + return err + } + } + return nil +}