ate-setup: add a subcommand to publish the worker images at current build (#1386)

A useful command to publish the worker images at current build, current
used in OSS upgrade flow.

Part of  #1272 

> It's a good idea to open an issue first for discussion.

- [x] Tests pass
- [x] Appropriate changes to documentation are included in the PR
This commit is contained in:
Haven Xia
2026-09-01 21:28:48 -07:00
committed by GitHub
parent 8968cb090e
commit 6101fe402c
4 changed files with 140 additions and 0 deletions
+9
View File
@@ -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` |
+44
View File
@@ -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 "<binary>: <ref>"
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)
}
+25
View File
@@ -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)
+62
View File
@@ -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 "<binary>: <ref>" 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
}