// // Package updatemanifests contains the `cfg update-manifests` CLI command, which // // can be used in CI pipelines to update the container images a set of existing // // manifests reference and apply build metadata labels, e.g., commit, version, // // etc. // // // // The goal of this command is to allow easy integration between an existing // // CI pipeline and the Edge platform CI pipeline. // package updatemanifests // Package updatemanifests contains the `cfg update-manifests` CLI command, which // can be used in CI pipelines to update the container images a set of existing // manifests reference and apply build metadata labels, e.g., commit, version, // etc. // // The goal of this command is to allow easy integration between an existing // CI pipeline and the Edge platform CI pipeline. package updatemanifests import ( "context" "fmt" "path/filepath" "strings" goerrors "errors" "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" "edge-infra.dev/pkg/edge/component/build/image" "edge-infra.dev/pkg/edge/component/build/updatemanifests" "edge-infra.dev/pkg/edge/constants" "edge-infra.dev/pkg/edge/edgecli" "edge-infra.dev/pkg/edge/edgecli/flagutil" "edge-infra.dev/pkg/edge/gitops/fns/edgerelease" "edge-infra.dev/pkg/lib/build/bazel" "edge-infra.dev/pkg/lib/cli/command" "edge-infra.dev/pkg/lib/cli/rags" "edge-infra.dev/pkg/lib/errors" ) // NewCmd creates a new cli.Command and returns it. func NewCmd(_ *edgecli.Config) *command.Command { var flagsets []*rags.Rag var imgFlag, manifestFlag, componentFlag string var cmd *command.Command cmd = &command.Command{ ShortUsage: "edgeadmin cfg update-manifests", ShortHelp: "updates manifests with provided image digests", LongHelp: fmt.Sprintf("update manifests for a K8s component, based on the Edge platform labels (%s)", constants.PlatformComponent), Flags: append(flagsets, &rags.Rag{ Name: flagutil.Manifest, Short: "m", Usage: "path to directory containing K8s manifests to update, relative to working directory", Required: true, Value: &rags.String{Var: &manifestFlag}, }, &rags.Rag{ Name: flagutil.Image, Usage: `the image ref and container name for the component that the manifests should be updated to reference in the format name=ref. e.g.: --image bff=us-east1-docker.pkg.dev/ret-edge-pltf-infra/workloads/bff:dev --image controller=us-east1-docker.pkg.dev/ret-edge-pltf-infra/workloads/talaria:dev`, Required: true, Value: &rags.String{Var: &imgFlag}, }, &rags.Rag{ Name: flagutil.Components, Short: "c", Usage: fmt.Sprintf("the component that will have its manifests updated. only manifests where the label %s matches this value will be updated", constants.PlatformComponent), Required: true, Value: &rags.String{Var: &componentFlag}, }, ), Exec: func(_ context.Context, _ []string) error { if err := flagutil.ValidateRequiredFlags(cmd.Rags); err != nil { return err } refs := map[string]name.Reference{} img := flagutil.GetStringFlag(cmd.Rags, flagutil.Image) tokens := strings.Split(img, "=") if len(tokens) != 2 { return goerrors.New("--image value is invalid, should be container=ref." + "see `edgeadmin cfg update-manifests --help`") } fmt.Println("parsing image reference...", img) ref, err := name.ParseReference(tokens[1], name.StrictValidation) if err != nil { return errors.New(fmt.Sprintf("%s is not a valid image ref", img), err) } refs[tokens[0]] = ref // bazel.ResolveWd simply resolves the wd whether or not we are // running via Bazel run or not wd, err := bazel.ResolveWd() if err != nil { return errors.New("failed to determine current working directory", err) } // build full path to our manifests directory manifests := filepath.Join(wd, flagutil.GetStringFlag(cmd.Rags, flagutil.Manifest)) component := edgerelease.Component{Name: flagutil.GetStringFlag(cmd.Rags, flagutil.Components)} for name, ref := range refs { fmt.Printf("resolving digest for %s...\n", ref) digest, err := crane.Digest(ref.String()) if err != nil { return errors.New( fmt.Sprintf("failed to resolve digest for %s", ref.String()), err, ) } fmt.Println("resolved digest:", digest) component.Images = append(component.Images, edgerelease.PodImage{ Name: name, Image: image.Image{ Registry: ref.Context().RegistryStr(), Repository: ref.Context().RepositoryStr(), Digest: digest, }, }) } edgeRelease := edgerelease.New(edgerelease.Spec{ AddBuildLabels: false, Components: []edgerelease.Component{component}, }) if err := updatemanifests.Update(edgeRelease, manifests); err != nil { return errors.New("failed to update manifests", err) } fmt.Println("successfully updated manifests for component:", flagutil.GetStringFlag(cmd.Rags, flagutil.Components)) return nil }, } return cmd }