bazel: allow custom container_prefix (#1693)

* build: allow custom container registry

* build: fix .bazeloverwriterc import
This commit is contained in:
3u13r 2023-04-27 11:52:02 +02:00 committed by GitHub
parent 12216ea997
commit 1bdf410b52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 192 additions and 257 deletions

View File

@ -26,6 +26,9 @@ build --define=gotags=netgo
# enable tpm simulator for tests
test --//bazel/settings:tpm_simulator
# set registry flag alias
build --flag_alias=container_prefix=//bazel/settings:container_prefix
# disable test caching (rerun all test cases even if they passed before)
test --cache_test_results=no
@ -52,4 +55,4 @@ build:remote_cache --experimental_remote_cache_compression
build:remote_cache --nolegacy_important_outputs
build:remote_cache_readonly --noremote_upload_local_results # Uploads logs & artifacts without writing to cache
try-import .bazeloverwriterc
try-import %workspace%/.bazeloverwriterc

View File

@ -23,12 +23,7 @@ alias(
alias(
name = "devbuild",
actual = "//bazel/devbuild:devbuild",
)
alias(
name = "push",
actual = "//bazel/release:push",
actual = "//bazel/release:build_and_push",
)
# These magic Gazelle commands need to be in the top-level BUILD file.

View File

@ -2,11 +2,8 @@
This module holds the definitions of the containers that are built.
"""
load("@rules_oci//oci:defs.bzl", _oci_push = "oci_push", _oci_tarball = "oci_tarball")
load("//bazel/oci:pin.bzl", "oci_sum")
_default_registry = "ghcr.io"
_default_prefix = "edgelesssys/constellation"
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
def containers():
return [
@ -15,9 +12,7 @@ def containers():
"image_name": "join-service",
"name": "joinservice",
"oci": "//joinservice/cmd:joinservice",
"prefix": _default_prefix,
"registry": _default_registry,
"tag_file": "//bazel/settings:tag",
"repotag_file": "//bazel/release:joinservice_tag.txt",
"used_by": ["helm"],
},
{
@ -25,9 +20,7 @@ def containers():
"image_name": "key-service",
"name": "keyservice",
"oci": "//keyservice/cmd:keyservice",
"prefix": _default_prefix,
"registry": _default_registry,
"tag_file": "//bazel/settings:tag",
"repotag_file": "//bazel/release:keyservice_tag.txt",
"used_by": ["helm"],
},
{
@ -35,9 +28,7 @@ def containers():
"image_name": "verification-service",
"name": "verificationservice",
"oci": "//verify/cmd:verificationservice",
"prefix": _default_prefix,
"registry": _default_registry,
"tag_file": "//bazel/settings:tag",
"repotag_file": "//bazel/release:verificationservice_tag.txt",
"used_by": ["helm"],
},
{
@ -45,9 +36,7 @@ def containers():
"image_name": "node-operator",
"name": "nodeoperator",
"oci": "//operators/constellation-node-operator:node_operator",
"prefix": _default_prefix,
"registry": _default_registry,
"tag_file": "//bazel/settings:tag",
"repotag_file": "//bazel/release:nodeoperator_tag.txt",
"used_by": ["helm"],
},
{
@ -55,9 +44,7 @@ def containers():
"image_name": "qemu-metadata-api",
"name": "qemumetadata",
"oci": "//hack/qemu-metadata-api:qemumetadata",
"prefix": _default_prefix,
"registry": _default_registry,
"tag_file": "//bazel/settings:tag",
"repotag_file": "//bazel/release:qemumetadata_tag.txt",
"used_by": ["config"],
},
{
@ -65,9 +52,7 @@ def containers():
"image_name": "libvirt",
"name": "libvirt",
"oci": "//cli/internal/libvirt:constellation_libvirt",
"prefix": _default_prefix,
"registry": _default_registry,
"tag_file": "//bazel/settings:tag",
"repotag_file": "//bazel/release:libvirt_tag.txt",
"used_by": ["config"],
},
]
@ -78,58 +63,21 @@ def helm_containers():
def config_containers():
return [container for container in containers() if "config" in container["used_by"]]
def container_sum(name, oci, registry, prefix, image_name, **kwargs):
tag = kwargs.get("tag", None)
tag_file = kwargs.get("tag_file", None)
oci_sum(
name = name + "_sum",
oci = oci,
registry = registry,
prefix = prefix,
image_name = image_name,
tag = tag,
tag_file = tag_file,
visibility = ["//visibility:public"],
)
def _container_reponame_impl(ctx):
container_prefix = ctx.attr._prefix[BuildSettingInfo].value
if container_prefix == None:
fail("container_prefix is not set")
def oci_push(name, image, registry, image_name, **kwargs):
"""oci_push pushes an OCI image to a registry.
full_container_tag = paths.join(container_prefix, ctx.attr.container_name)
Args:
name: The name of the target.
image: The OCI image to push.
registry: The registry to push to.
image_name: The name of the image.
**kwargs: Additional arguments to pass to oci_push.
"""
prefix = kwargs.pop("prefix", None)
tag = kwargs.pop("tag", None)
tag_file = kwargs.pop("tag_file", None)
if prefix == None:
repository = registry + "/" + image_name
else:
repository = registry + "/" + prefix + "/" + image_name
_oci_push(
name = name,
image = image,
repository = repository,
tag = tag,
tag_file = tag_file,
visibility = ["//visibility:public"],
**kwargs
)
output = ctx.actions.declare_file(ctx.attr.container_name + "_container_repotag")
ctx.actions.write(output = output, content = full_container_tag)
return [DefaultInfo(files = depset([output]))]
# TODO(malt3): allow repotags (registry + tag) to be read from a file.
def oci_tarball(name, image):
"""oci_tarball creates a tarball of an OCI image.
Args:
name: The name of the target.
image: The OCI image to create a tarball of.
"""
_oci_tarball(
name = name,
image = image,
repotags = [],
visibility = ["//visibility:public"],
)
container_reponame = rule(
implementation = _container_reponame_impl,
attrs = {
"container_name": attr.string(),
"_prefix": attr.label(default = Label("//bazel/settings:container_prefix")),
},
)

View File

@ -24,17 +24,11 @@ def stamp_tags(name, repotags, **kwargs):
def _oci_go_source_impl(ctx):
oci = ctx.file.oci
inputs = [oci]
if ctx.attr.tag_file:
inputs.append(ctx.file.tag_file)
if ctx.attr.repotag_file:
inputs.append(ctx.file.repotag_file)
output = ctx.actions.declare_file(ctx.label.name + ".go")
args = [
"codegen",
"--image-registry",
ctx.attr.registry,
"--image-prefix",
ctx.attr.prefix,
"--image-name",
ctx.attr.image_name,
"--oci-path",
oci.path,
"--package",
@ -47,9 +41,9 @@ def _oci_go_source_impl(ctx):
if ctx.attr.tag:
args.append("--image-tag")
args.append(ctx.attr.tag)
if ctx.attr.tag_file:
args.append("--image-tag-file")
args.append(ctx.file.tag_file.path)
if ctx.attr.repotag_file:
args.append("--repoimage-tag-file")
args.append(ctx.file.repotag_file.path)
ctx.actions.run(
inputs = inputs,
@ -82,20 +76,13 @@ _go_source_attrs = {
mandatory = True,
doc = "Package to use for the generated Go source.",
),
"prefix": attr.string(
doc = "Prefix to use for the generated Go source.",
),
"registry": attr.string(
mandatory = True,
doc = "Registry to use for the generated Go source.",
"repotag_file": attr.label(
allow_single_file = True,
doc = "OCI image tag file to use for the generated Go source.",
),
"tag": attr.string(
doc = "OCI image tag to use for the generated Go source.",
),
"tag_file": attr.label(
allow_single_file = True,
doc = "OCI image tag file to use for the generated Go source.",
),
"_oci_pin": attr.label(
allow_single_file = True,
executable = True,
@ -112,29 +99,19 @@ oci_go_source = rule(
def _oci_sum_impl(ctx):
oci = ctx.file.oci
inputs = [oci]
if ctx.attr.tag_file:
inputs.append(ctx.file.tag_file)
if ctx.attr.repotag_file:
inputs.append(ctx.file.repotag_file)
output = ctx.actions.declare_file(ctx.label.name + ".sha256")
args = [
"sum",
"--image-name",
ctx.attr.image_name,
"--oci-path",
oci.path,
"--output",
output.path,
"--registry",
ctx.attr.registry,
]
if ctx.attr.prefix:
args.append("--prefix")
args.append(ctx.attr.prefix)
if ctx.attr.tag:
args.append("--image-tag")
args.append(ctx.attr.tag)
if ctx.attr.tag_file:
args.append("--image-tag-file")
args.append(ctx.file.tag_file.path)
if ctx.attr.repotag_file:
args.append("--repoimage-tag-file")
args.append(ctx.file.repotag_file.path)
ctx.actions.run(
inputs = inputs,
@ -159,17 +136,7 @@ _sum_attrs = {
allow_single_file = True,
doc = "OCI image to extract the digest from.",
),
"prefix": attr.string(
doc = "Prefix to use for the sum entry.",
),
"registry": attr.string(
mandatory = True,
doc = "Registry to use for the sum entry.",
),
"tag": attr.string(
doc = "OCI image tag to use for the sum entry.",
),
"tag_file": attr.label(
"repotag_file": attr.label(
allow_single_file = True,
doc = "OCI image tag file to use for the sum entry.",
),

View File

@ -3,25 +3,48 @@ This folder contains labels used to collect release artifacts.
"""
load("@com_github_ash2k_bazel_tools//multirun:def.bzl", "multirun")
load("//bazel/oci:containers.bzl", "container_sum", "containers", "oci_push", "oci_tarball")
load("//bazel/oci:pin.bzl", "oci_sum_merge")
load("@rules_oci//oci:defs.bzl", "oci_push")
load("//bazel/oci:containers.bzl", "container_reponame", "containers")
load("//bazel/oci:pin.bzl", "oci_sum", "oci_sum_merge")
[
oci_tarball(
name = container["name"] + "_tar",
image = container["oci"],
container_reponame(
name = container["name"] + "_reponame",
container_name = container["image_name"],
)
for container in containers()
]
[
container_sum(
name = container["name"],
genrule(
name = container["name"] + "_repotag",
srcs = [
"//bazel/release:" + container["name"] + "_reponame",
"//bazel/settings:tag",
],
outs = [container["repotag_file"]],
cmd = "echo -n ':' | cat $(location //bazel/release:" + container["name"] + "_reponame) - $(location //bazel/settings:tag) > $@",
visibility = ["//visibility:public"],
)
for container in containers()
]
# TODO(3u13r): re-enable target once https://github.com/bazel-contrib/rules_oci/issues/184 is fixed
# [
# oci_tarball(
# name = container["name"] + "_tar",
# image = container["oci"],
# repotag_file = container["repotag_file"],
# )
# for container in containers()
# ]
[
oci_sum(
name = container["name"] + "_sum",
image_name = container["image_name"],
oci = container["oci"],
prefix = container["prefix"],
registry = container["registry"],
tag_file = container["tag_file"],
repotag_file = container["repotag_file"],
)
for container in containers()
]
@ -35,16 +58,11 @@ oci_sum_merge(
visibility = ["//visibility:public"],
)
# TODO(malt3): use config setting to allow devs the use of custom registries
# https://www.grahambrooks.com/software-development/2021/08/30/user-defined-bazel-arguments.html
[
oci_push(
name = container["name"] + "_push",
image = container["oci"],
image_name = container["image_name"],
prefix = container["prefix"],
registry = container["registry"],
repotags = container["tag_file"],
repotags = container["repotag_file"],
)
for container in containers()
]
@ -58,3 +76,12 @@ multirun(
jobs = 0, # execute in parallel
visibility = ["//visibility:public"],
)
multirun(
name = "build_and_push",
commands = [
"//bazel/devbuild:devbuild",
"//bazel/release:push",
],
visibility = ["//visibility:public"],
)

View File

@ -35,6 +35,12 @@ string_flag(
],
)
string_flag(
name = "container_prefix",
build_setting_default = "ghcr.io/edgelesssys/constellation",
visibility = ["//visibility:public"],
)
bool_flag(
name = "select_never",
build_setting_default = False,

View File

@ -5,11 +5,11 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
def oci_deps():
http_archive(
name = "rules_oci",
sha256 = "4a738bdbeacb0e1df070209dddfa7b55fed9bbc553b905cf3d2dd25115e0b598",
strip_prefix = "rules_oci-0.3.8",
strip_prefix = "rules_oci-0.4.0",
type = "tar.gz",
urls = [
"https://cdn.confidential.cloud/constellation/cas/sha256/4a738bdbeacb0e1df070209dddfa7b55fed9bbc553b905cf3d2dd25115e0b598",
"https://github.com/bazel-contrib/rules_oci/releases/download/v0.3.8/rules_oci-v0.3.8.tar.gz",
"https://cdn.confidential.cloud/constellation/cas/sha256/d7b0760ba28554b71941ea0bbfd0a9f089bf250fd4448f9c116e1cb7a63b3933",
"https://github.com/bazel-contrib/rules_oci/releases/download/v0.4.0/rules_oci-v0.4.0.tar.gz",
],
sha256 = "d7b0760ba28554b71941ea0bbfd0a9f089bf250fd4448f9c116e1cb7a63b3933",
)

View File

@ -24,9 +24,7 @@ go_library(
image_name = container["image_name"],
oci = container["oci"],
package = "imageversion",
prefix = container["prefix"],
registry = container["registry"],
tag_file = container["tag_file"],
repotag_file = container["repotag_file"],
visibility = ["//cli:__subpackages__"],
)
for container in helm_containers()

View File

@ -28,7 +28,9 @@ mkdir build
cd build
# build required binaries for a dev build
# and symlink them into the current directory
bazel run //:devbuild
# also push the built container images
# After the first run, set the pushed imaged to public.
bazel run //:devbuild --container_prefix=ghcr.io/USERNAME/constellation
./constellation ...
# modify code
# rerun to ensure that all binaries are up to date
@ -36,6 +38,12 @@ bazel run //:devbuild
./constellation ...
```
Overwrite the default container_prefix in the `.bazeloverwriterc` in the root of the workspace:
```bazel
# cat .bazeloverwriterc
build --container_prefix=ghcr.io/USERNAME
```
Bazel build:
```sh

View File

@ -30,17 +30,11 @@ func newCodegenCmd() *cobra.Command {
cmd.Flags().String("output", "-", "Output file. If not set, the output is written to stdout.")
cmd.Flags().String("package", "", "Name of the Go package.")
cmd.Flags().String("identifier", "", "Base name of the Go const identifiers.")
cmd.Flags().String("image-registry", "", "Registry where the image is stored.")
cmd.Flags().String("image-prefix", "", "Prefix of the image name. Optional.")
cmd.Flags().String("image-name", "", "Short name of the OCI image to pin.")
cmd.Flags().String("image-tag", "", "Tag of the OCI image to pin. Optional.")
cmd.Flags().String("image-tag-file", "", "Tag file of the OCI image to pin. Optional.")
cmd.MarkFlagsMutuallyExclusive("image-tag", "image-tag-file")
cmd.Flags().String("repoimage-tag-file", "", "Tag file of the OCI image to pin.")
must(cmd.MarkFlagRequired("oci-path"))
must(cmd.MarkFlagRequired("package"))
must(cmd.MarkFlagRequired("identifier"))
must(cmd.MarkFlagRequired("image-registry"))
must(cmd.MarkFlagRequired("image-name"))
must(cmd.MarkFlagRequired("repoimage-tag-file"))
return cmd
}
@ -53,7 +47,12 @@ func runCodegen(cmd *cobra.Command, _ []string) error {
log := logger.New(logger.PlainLog, flags.logLevel)
log.Debugf("Parsed flags: %+v", flags)
log.Debugf("Generating Go code for OCI image %s.", flags.imageName)
registry, prefix, name, tag, err := splitRepoTag(flags.imageRepoTag)
if err != nil {
return fmt.Errorf("splitting OCI image reference %q: %w", flags.imageRepoTag, err)
}
log.Debugf("Generating Go code for OCI image %s.", name)
ociIndexPath := filepath.Join(flags.ociPath, "index.json")
index, err := os.Open(ociIndexPath)
@ -84,10 +83,10 @@ func runCodegen(cmd *cobra.Command, _ []string) error {
if err := inject.Render(out, inject.PinningValues{
Package: flags.pkg,
Ident: flags.identifier,
Registry: flags.imageRegistry,
Prefix: flags.imagePrefix,
Name: flags.imageName,
Tag: flags.imageTag,
Registry: registry,
Prefix: prefix,
Name: name,
Tag: tag,
Digest: digest,
}); err != nil {
return fmt.Errorf("rendering Go code: %w", err)
@ -98,15 +97,12 @@ func runCodegen(cmd *cobra.Command, _ []string) error {
}
type codegenFlags struct {
ociPath string
output string
pkg string
identifier string
imageRegistry string
imagePrefix string
imageName string
imageTag string
logLevel zapcore.Level
ociPath string
output string
pkg string
identifier string
imageRepoTag string
logLevel zapcore.Level
}
func parseCodegenFlags(cmd *cobra.Command) (codegenFlags, error) {
@ -126,33 +122,17 @@ func parseCodegenFlags(cmd *cobra.Command) (codegenFlags, error) {
if err != nil {
return codegenFlags{}, err
}
imageRegistry, err := cmd.Flags().GetString("image-registry")
imageRepoTagFile, err := cmd.Flags().GetString("repoimage-tag-file")
if err != nil {
return codegenFlags{}, err
}
imagePrefix, err := cmd.Flags().GetString("image-prefix")
repotag, err := os.ReadFile(imageRepoTagFile)
if err != nil {
return codegenFlags{}, err
}
imageName, err := cmd.Flags().GetString("image-name")
if err != nil {
return codegenFlags{}, err
}
imageTag, err := cmd.Flags().GetString("image-tag")
if err != nil {
return codegenFlags{}, err
}
imageTagFile, err := cmd.Flags().GetString("image-tag-file")
if err != nil {
return codegenFlags{}, err
}
if imageTagFile != "" {
tag, err := os.ReadFile(imageTagFile)
if err != nil {
return codegenFlags{}, fmt.Errorf("reading image tag file %q: %w", imageTagFile, err)
}
imageTag = strings.TrimSpace(string(tag))
return codegenFlags{}, fmt.Errorf("reading image repotag file %q: %w", imageRepoTagFile, err)
}
imageRepoTag := strings.TrimSpace(string(repotag))
verbose, err := cmd.Flags().GetBool("verbose")
if err != nil {
return codegenFlags{}, err
@ -163,14 +143,11 @@ func parseCodegenFlags(cmd *cobra.Command) (codegenFlags, error) {
}
return codegenFlags{
ociPath: ociPath,
output: output,
pkg: pkg,
identifier: identifier,
imageRegistry: imageRegistry,
imagePrefix: imagePrefix,
imageName: imageName,
imageTag: imageTag,
logLevel: logLevel,
ociPath: ociPath,
output: output,
pkg: pkg,
identifier: identifier,
imageRepoTag: imageRepoTag,
logLevel: logLevel,
}, nil
}

View File

@ -11,6 +11,7 @@ import (
"fmt"
"os"
"os/signal"
"strings"
"github.com/spf13/cobra"
)
@ -83,3 +84,32 @@ func must(err error) {
panic(err)
}
}
func splitRepoTag(ref string) (registry, prefix, name, tag string, err error) {
// last colon is separator between name and tag
tagSep := strings.LastIndexByte(ref, ':')
if tagSep == -1 {
return "", "", "", "", fmt.Errorf("invalid OCI image reference %q: missing tag", ref)
}
tag = ref[tagSep+1:]
base := ref[:tagSep]
// first slash is separator between registry and full name
registrySep := strings.IndexByte(base, '/')
if registrySep == -1 {
return "", "", "", "", fmt.Errorf("invalid OCI image reference %q: missing registry", ref)
}
registry = base[:registrySep]
fullName := base[registrySep+1:]
// last slash is separator between prefix and short name
nameSep := strings.LastIndexByte(fullName, '/')
if nameSep == -1 {
name = fullName
} else {
prefix = fullName[:nameSep]
name = fullName[nameSep+1:]
}
return
}

View File

@ -28,15 +28,10 @@ func newSumCmd() *cobra.Command {
cmd.Flags().String("oci-path", "", "Path to the OCI image to pin.")
cmd.Flags().String("output", "-", "Output file. If not set, the output is written to stdout.")
cmd.Flags().String("registry", "", "OCI registry to use.")
cmd.Flags().String("prefix", "", "Prefix of the OCI image to pin.")
cmd.Flags().String("image-name", "", "Short name (suffix) of the OCI image to pin.")
cmd.Flags().String("image-tag", "", "Tag of the OCI image to pin. Optional.")
cmd.Flags().String("image-tag-file", "", "Tag file of the OCI image to pin. Optional.")
cmd.MarkFlagsMutuallyExclusive("image-tag", "image-tag-file")
must(cmd.MarkFlagRequired("registry"))
cmd.Flags().String("repoimage-tag-file", "", "Tag file of the OCI image to pin.")
must(cmd.MarkFlagRequired("repoimage-tag-file"))
must(cmd.MarkFlagRequired("oci-path"))
must(cmd.MarkFlagRequired("image-name"))
return cmd
}
@ -49,7 +44,12 @@ func runSum(cmd *cobra.Command, _ []string) error {
log := logger.New(logger.PlainLog, flags.logLevel)
log.Debugf("Parsed flags: %+v", flags)
log.Debugf("Generating sum file for OCI image %s.", flags.imageName)
registry, prefix, name, tag, err := splitRepoTag(flags.imageRepoTag)
if err != nil {
return fmt.Errorf("splitting repo tag: %w", err)
}
log.Debugf("Generating sum file for OCI image %s.", name)
ociIndexPath := filepath.Join(flags.ociPath, "index.json")
index, err := os.Open(ociIndexPath)
@ -79,10 +79,10 @@ func runSum(cmd *cobra.Command, _ []string) error {
refs := []sums.PinnedImageReference{
{
Registry: flags.registry,
Prefix: flags.prefix,
Name: flags.imageName,
Tag: flags.imageTag,
Registry: registry,
Prefix: prefix,
Name: name,
Tag: tag,
Digest: digest,
},
}
@ -96,13 +96,10 @@ func runSum(cmd *cobra.Command, _ []string) error {
}
type sumFlags struct {
ociPath string
output string
registry string
prefix string
imageName string
imageTag string
logLevel zapcore.Level
ociPath string
output string
imageRepoTag string
logLevel zapcore.Level
}
func parseSumFlags(cmd *cobra.Command) (sumFlags, error) {
@ -114,33 +111,17 @@ func parseSumFlags(cmd *cobra.Command) (sumFlags, error) {
if err != nil {
return sumFlags{}, err
}
registry, err := cmd.Flags().GetString("registry")
imageTagFile, err := cmd.Flags().GetString("repoimage-tag-file")
if err != nil {
return sumFlags{}, err
}
prefix, err := cmd.Flags().GetString("prefix")
tag, err := os.ReadFile(imageTagFile)
if err != nil {
return sumFlags{}, err
}
imageName, err := cmd.Flags().GetString("image-name")
if err != nil {
return sumFlags{}, err
}
imageTag, err := cmd.Flags().GetString("image-tag")
if err != nil {
return sumFlags{}, err
}
imageTagFile, err := cmd.Flags().GetString("image-tag-file")
if err != nil {
return sumFlags{}, err
}
if imageTagFile != "" {
tag, err := os.ReadFile(imageTagFile)
if err != nil {
return sumFlags{}, fmt.Errorf("reading image tag file %q: %w", imageTagFile, err)
}
imageTag = strings.TrimSpace(string(tag))
return sumFlags{}, fmt.Errorf("reading image repotag file %q: %w", imageTagFile, err)
}
imageRepoTag := strings.TrimSpace(string(tag))
verbose, err := cmd.Flags().GetBool("verbose")
if err != nil {
return sumFlags{}, err
@ -151,12 +132,9 @@ func parseSumFlags(cmd *cobra.Command) (sumFlags, error) {
}
return sumFlags{
ociPath: ociPath,
output: output,
registry: registry,
prefix: prefix,
imageName: imageName,
imageTag: imageTag,
logLevel: logLevel,
ociPath: ociPath,
output: output,
imageRepoTag: imageRepoTag,
logLevel: logLevel,
}, nil
}

View File

@ -24,9 +24,7 @@ go_library(
image_name = container["image_name"],
oci = container["oci"],
package = "imageversion",
prefix = container["prefix"],
registry = container["registry"],
tag_file = container["tag_file"],
repotag_file = container["repotag_file"],
visibility = ["//:__subpackages__"],
)
for container in config_containers()