From 9e25686a99315e769ccff4d478de94461e77651f Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Wed, 4 Sep 2024 06:42:02 -0700 Subject: [PATCH] FEATURE: add an option for custom namespaces (#862) Add an option to select a targeted namespace, env var DISCOURSE_NAMESPACE Configure: Add `source-tag` to select which tag to configure from. Rename old `tag` option to `target-tag` to differentiate from `source-tag` option Migrate: Add `tag` to select which tag to migrate with --- launcher_go/v2/cli_build.go | 56 ++++++++++++++++++++++++------- launcher_go/v2/cli_build_test.go | 39 +++++++++++++++++++++ launcher_go/v2/config/config.go | 4 +-- launcher_go/v2/docker/commands.go | 15 +++++---- launcher_go/v2/main.go | 1 + launcher_go/v2/utils/consts.go | 2 +- 6 files changed, 95 insertions(+), 22 deletions(-) diff --git a/launcher_go/v2/cli_build.go b/launcher_go/v2/cli_build.go index 00cdc50..b6f9294 100644 --- a/launcher_go/v2/cli_build.go +++ b/launcher_go/v2/cli_build.go @@ -40,13 +40,18 @@ func (r *DockerBuildCmd) Run(cli *Cli, ctx *context.Context) error { return err } + namespace := cli.Namespace + if namespace == "" { + namespace = utils.DefaultNamespace + } pupsArgs := "--skip-tags=precompile,migrate,db" builder := docker.DockerBuilder{ - Config: config, - Ctx: ctx, - Stdin: strings.NewReader(config.Dockerfile(pupsArgs, r.BakeEnv)), - Dir: dir, - ImageTag: r.Tag, + Config: config, + Ctx: ctx, + Stdin: strings.NewReader(config.Dockerfile(pupsArgs, r.BakeEnv)), + Dir: dir, + Namespace: namespace, + ImageTag: r.Tag, } if err := builder.Run(); err != nil { return err @@ -58,8 +63,9 @@ func (r *DockerBuildCmd) Run(cli *Cli, ctx *context.Context) error { } type DockerConfigureCmd struct { - Tag string `default:"latest" help:"Resulting image tag."` - Config string `arg:"" name:"config" help:"config" predictor:"config"` + SourceTag string `help:"Source image tag to build from."` + TargetTag string `help:"Target image tag to save as."` + Config string `arg:"" name:"config" help:"config" predictor:"config"` } func (r *DockerConfigureCmd) Run(cli *Cli, ctx *context.Context) error { @@ -78,11 +84,24 @@ func (r *DockerConfigureCmd) Run(cli *Cli, ctx *context.Context) error { } containerId := "discourse-build-" + uuidString + namespace := cli.Namespace + if namespace == "" { + namespace = utils.DefaultNamespace + } + sourceTag := "" + if len(r.SourceTag) > 0 { + sourceTag = ":" + r.SourceTag + } + targetTag := "" + if len(r.TargetTag) > 0 { + targetTag = ":" + r.TargetTag + } pups := docker.DockerPupsRunner{ Config: config, PupsArgs: "--tags=db,precompile", - SavedImageName: utils.BaseImageName + r.Config + ":" + r.Tag, + FromImageName: namespace + "/" + r.Config + sourceTag, + SavedImageName: namespace + "/" + r.Config + targetTag, ExtraEnv: []string{"SKIP_EMBER_CLI_COMPILE=1"}, Ctx: ctx, ContainerId: containerId, @@ -93,6 +112,7 @@ func (r *DockerConfigureCmd) Run(cli *Cli, ctx *context.Context) error { type DockerMigrateCmd struct { Config string `arg:"" name:"config" help:"config" predictor:"config"` + Tag string `default:"latest" help:"Image tag to migrate."` SkipPostDeploymentMigrations bool `env:"SKIP_POST_DEPLOYMENT_MIGRATIONS" help:"Skip post-deployment migrations. Runs safe migrations only. Defers breaking-change migrations. Make sure you run post-deployment migrations after a full deploy is complete if you use this option."` } @@ -106,12 +126,22 @@ func (r *DockerMigrateCmd) Run(cli *Cli, ctx *context.Context) error { if r.SkipPostDeploymentMigrations { env = append(env, "SKIP_POST_DEPLOYMENT_MIGRATIONS=1") } + + namespace := cli.Namespace + if namespace == "" { + namespace = utils.DefaultNamespace + } + tag := "" + if len(r.Tag) > 0 { + tag = ":" + r.Tag + } pups := docker.DockerPupsRunner{ - Config: config, - PupsArgs: "--tags=db,migrate", - ExtraEnv: env, - Ctx: ctx, - ContainerId: containerId, + Config: config, + PupsArgs: "--tags=db,migrate", + FromImageName: namespace + "/" + r.Config + tag, + ExtraEnv: env, + Ctx: ctx, + ContainerId: containerId, } return pups.Run() } diff --git a/launcher_go/v2/cli_build_test.go b/launcher_go/v2/cli_build_test.go index 66fe757..475a4a5 100644 --- a/launcher_go/v2/cli_build_test.go +++ b/launcher_go/v2/cli_build_test.go @@ -173,6 +173,45 @@ var _ = Describe("Build", func() { checkMigrateCmd(RanCmds[0]) }) + Context("With a custom namespace", func() { + BeforeEach(func() { + cli.Namespace = "testnamespace" + }) + + It("Should run docker build with correct namespace and custom flags", func() { + runner := ddocker.DockerBuildCmd{Config: "test", Tag: "testtag"} + runner.Run(cli, &ctx) + Expect(len(RanCmds)).To(Equal(1)) + checkBuildCmd(RanCmds[0]) + Expect(RanCmds[0].String()).To(ContainSubstring("testnamespace/test:testtag")) + }) + + It("Should run docker configure with correct namespace and tags", func() { + runner := ddocker.DockerConfigureCmd{Config: "test", SourceTag: "build", TargetTag: "configure"} + runner.Run(cli, &ctx) + Expect(len(RanCmds)).To(Equal(3)) + + Expect(RanCmds[0].String()).To(MatchRegexp( + "--name discourse-build-test " + + "testnamespace/test:build /bin/bash -c /usr/local/bin/pups --stdin --tags=db,precompile", + )) + Expect(RanCmds[1].String()).To(MatchRegexp( + "docker commit " + + `--change LABEL org\.opencontainers\.image\.created="[\d\-T:Z]+" ` + + `--change CMD \["/sbin/boot"\] ` + + "discourse-build-test testnamespace/test:configure", + )) + checkConfigureClean(RanCmds[2]) + }) + + It("Should run docker migrate with correct namespace", func() { + runner := ddocker.DockerMigrateCmd{Config: "test"} + runner.Run(cli, &ctx) + Expect(len(RanCmds)).To(Equal(1)) + Expect(RanCmds[0].String()).To(ContainSubstring("testnamespace/test ")) + }) + }) + It("Should allow skip post deployment migrations", func() { runner := ddocker.DockerMigrateCmd{Config: "test", SkipPostDeploymentMigrations: true} runner.Run(cli, &ctx) diff --git a/launcher_go/v2/config/config.go b/launcher_go/v2/config/config.go index 0b26adc..01cee72 100644 --- a/launcher_go/v2/config/config.go +++ b/launcher_go/v2/config/config.go @@ -15,7 +15,7 @@ import ( ) const defaultBootCommand = "/sbin/boot" -const defaultBaseImage = "discourse/base:2.0.20231121-0024" +const defaultBaseImage = "discourse/base:2.0.20240825-0027" type Config struct { Name string `yaml:-` @@ -217,7 +217,7 @@ func (config *Config) RunImage() string { if len(config.Run_Image) > 0 { return config.Run_Image } - return utils.BaseImageName + config.Name + return "local_discourse/" + config.Name } func (config *Config) DockerHostname(defaultHostname string) string { diff --git a/launcher_go/v2/docker/commands.go b/launcher_go/v2/docker/commands.go index fa415d4..58ec474 100644 --- a/launcher_go/v2/docker/commands.go +++ b/launcher_go/v2/docker/commands.go @@ -19,11 +19,12 @@ import ( ) type DockerBuilder struct { - Config *config.Config - Ctx *context.Context - Stdin io.Reader - Dir string - ImageTag string + Config *config.Config + Ctx *context.Context + Stdin io.Reader + Dir string + Namespace string + ImageTag string } func (r *DockerBuilder) Run() error { @@ -46,7 +47,7 @@ func (r *DockerBuilder) Run() error { cmd.Args = append(cmd.Args, "--pull") cmd.Args = append(cmd.Args, "--force-rm") cmd.Args = append(cmd.Args, "-t") - cmd.Args = append(cmd.Args, utils.BaseImageName+r.Config.Name+":"+r.ImageTag) + cmd.Args = append(cmd.Args, r.Namespace+"/"+r.Config.Name+":"+r.ImageTag) cmd.Args = append(cmd.Args, "--shm-size=512m") cmd.Args = append(cmd.Args, "-f") cmd.Args = append(cmd.Args, "-") @@ -219,6 +220,7 @@ func (r *DockerRunner) Run() error { type DockerPupsRunner struct { Config *config.Config PupsArgs string + FromImageName string SavedImageName string ExtraEnv []string Ctx *context.Context @@ -254,6 +256,7 @@ func (r *DockerPupsRunner) Run() error { Ctx: r.Ctx, ExtraEnv: r.ExtraEnv, Rm: rm, + CustomImage: r.FromImageName, ContainerId: r.ContainerId, Cmd: commands, Stdin: strings.NewReader(r.Config.Yaml()), diff --git a/launcher_go/v2/main.go b/launcher_go/v2/main.go index 55cd241..6f982cd 100644 --- a/launcher_go/v2/main.go +++ b/launcher_go/v2/main.go @@ -18,6 +18,7 @@ type Cli struct { ConfDir string `default:"./containers" hidden:"" help:"Discourse pups config directory." predictor:"dir"` TemplatesDir string `default:"." hidden:"" help:"Home project directory containing a templates/ directory which in turn contains pups yaml templates." predictor:"dir"` BuildDir string `default:"./tmp" hidden:"" help:"Temporary build folder for building images." predictor:"dir"` + Namespace string `default:"local_discourse" env:"DISCOURSE_NAMESPACE" help:"image namespace."` BuildCmd DockerBuildCmd `cmd:"" name:"build" help:"Build a base image. This command does not need a running database. Saves resulting container."` ConfigureCmd DockerConfigureCmd `cmd:"" name:"configure" help:"Configure and save an image with all dependencies and environment baked in. Updates themes and precompiles all assets. Saves resulting container."` MigrateCmd DockerMigrateCmd `cmd:"" name:"migrate" help:"Run migration tasks for a site. Running container is temporary and is not saved."` diff --git a/launcher_go/v2/utils/consts.go b/launcher_go/v2/utils/consts.go index 5fd4e64..8d6f4d2 100644 --- a/launcher_go/v2/utils/consts.go +++ b/launcher_go/v2/utils/consts.go @@ -9,7 +9,7 @@ import ( const Version = "v2.0.0" -const BaseImageName = "local_discourse/" +const DefaultNamespace = "local_discourse" // Known secrets, or otherwise not public info from config so we can build public images var KnownSecrets = []string{ -- 2.25.1