options to split image steps and manifest steps

Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
Avi Deitcher
2020-05-10 22:05:48 +03:00
parent 58434279cb
commit ea18be414e
4 changed files with 157 additions and 44 deletions

View File

@@ -22,6 +22,9 @@ func pkgPush(args []string) {
force := flags.Bool("force", false, "Force rebuild")
release := flags.String("release", "", "Release the given version")
nobuild := flags.Bool("nobuild", false, "Skip the build")
manifest := flags.Bool("manifest", true, "Create and push multi-arch manifest")
image := flags.Bool("image", true, "Build and push image for the current platform")
sign := flags.Bool("sign", true, "sign the manifest, if a manifest is created; ignored if --manifest=false")
p, err := pkglib.NewFromCLI(flags, args...)
if err != nil {
@@ -44,6 +47,16 @@ func pkgPush(args []string) {
if *release != "" {
opts = append(opts, pkglib.WithRelease(*release))
}
if *manifest {
opts = append(opts, pkglib.WithBuildManifest())
}
if *image {
opts = append(opts, pkglib.WithBuildImage())
}
// only sign manifests; ignore for image only
if *sign && *manifest {
opts = append(opts, pkglib.WithBuildSign())
}
if *nobuild {
fmt.Printf("Pushing %q without building\n", p.Tag())

View File

@@ -18,6 +18,9 @@ type buildOpts struct {
force bool
push bool
release string
manifest bool
sign bool
image bool
}
// BuildOpt allows callers to specify options to Build
@@ -47,6 +50,30 @@ func WithBuildPush() BuildOpt {
}
}
// WithBuildImage builds the image
func WithBuildImage() BuildOpt {
return func(bo *buildOpts) error {
bo.image = true
return nil
}
}
// WithBuildManifest creates a multi-arch manifest for the image
func WithBuildManifest() BuildOpt {
return func(bo *buildOpts) error {
bo.manifest = true
return nil
}
}
// WithBuildSign signs the image and/or the index
func WithBuildSign() BuildOpt {
return func(bo *buildOpts) error {
bo.sign = true
return nil
}
}
// WithRelease releases as the given version after push
func WithRelease(r string) BuildOpt {
return func(bo *buildOpts) error {
@@ -64,7 +91,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
}
}
if _, ok := os.LookupEnv("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"); !ok && p.trust && bo.push {
if _, ok := os.LookupEnv("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"); !ok && bo.sign && p.trust && bo.push {
return fmt.Errorf("Pushing with trust enabled requires $DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE to be set")
}
@@ -98,7 +125,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
return fmt.Errorf("Cannot release %q if not pushing", bo.release)
}
d := newDockerRunner(p.trust, p.cache)
d := newDockerRunner(p.trust, p.cache, bo.sign)
if !bo.force {
ok, err := d.pull(p.Tag())
@@ -111,7 +138,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
fmt.Println("No image pulled, continuing with build")
}
if !bo.skipBuild {
if bo.image && !bo.skipBuild {
var args []string
if err := p.dockerDepends.Do(d); err != nil {
@@ -171,7 +198,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
// matters given we do either pull or build above in the
// !force case.
if err := d.pushWithManifest(p.Tag(), suffix); err != nil {
if err := d.pushWithManifest(p.Tag(), suffix, bo.image, bo.manifest, bo.sign); err != nil {
return err
}
@@ -189,7 +216,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
return err
}
if err := d.pushWithManifest(relTag, suffix); err != nil {
if err := d.pushWithManifest(relTag, suffix, bo.image, bo.manifest, bo.sign); err != nil {
return err
}

View File

@@ -39,6 +39,7 @@ var platforms = []string{
type dockerRunner struct {
dct bool
cache bool
sign bool
// Optional build context to use
ctx buildContext
@@ -49,8 +50,8 @@ type buildContext interface {
Copy(io.WriteCloser) error
}
func newDockerRunner(dct, cache bool) dockerRunner {
return dockerRunner{dct: dct, cache: cache}
func newDockerRunner(dct, cache, sign bool) dockerRunner {
return dockerRunner{dct: dct, cache: cache, sign: sign}
}
func isExecErrNotFound(err error) bool {
@@ -83,7 +84,10 @@ func (dr dockerRunner) command(args ...string) error {
cmd.Env = os.Environ()
dct := ""
if dr.dct {
// when we are doing a push, we need to disable DCT if not signing
isPush := len(args) >= 2 && args[0] == "image" && args[1] == "push"
if dr.dct && (!isPush || dr.sign) {
cmd.Env = append(cmd.Env, dctEnableEnv)
dct = dctEnableEnv + " "
}
@@ -147,10 +151,19 @@ func (dr dockerRunner) push(img string) error {
return dr.command("image", "push", img)
}
func (dr dockerRunner) pushWithManifest(img, suffix string) error {
fmt.Printf("Pushing %s\n", img+suffix)
if err := dr.push(img + suffix); err != nil {
return err
func (dr dockerRunner) pushWithManifest(img, suffix string, pushImage, pushManifest, sign bool) error {
var (
digest string
l int
err error
)
if pushImage {
fmt.Printf("Pushing %s\n", img+suffix)
if err := dr.push(img + suffix); err != nil {
return err
}
} else {
fmt.Print("Image push disabled, skipping...\n")
}
auth, err := getDockerAuth()
@@ -158,16 +171,24 @@ func (dr dockerRunner) pushWithManifest(img, suffix string) error {
return fmt.Errorf("failed to get auth: %v", err)
}
fmt.Printf("Pushing %s to manifest %s\n", img+suffix, img)
digest, l, err := manifestPush(img, auth)
if err != nil {
return err
if pushManifest {
fmt.Printf("Pushing %s to manifest %s\n", img+suffix, img)
digest, l, err = manifestPush(img, auth)
if err != nil {
return err
}
} else {
fmt.Print("Manifest push disabled, skipping...\n")
}
// if trust is not enabled, nothing more to do
if !dr.dct {
fmt.Println("trust disabled, not signing")
return nil
}
if !sign {
fmt.Println("signing disabled, not signing")
return nil
}
fmt.Printf("Signing manifest for %s\n", img)
return signManifest(img, digest, l, auth)
}
@@ -279,7 +300,7 @@ func signManifest(img, digest string, length int, auth dockertypes.AuthConfig) e
}
// report output
fmt.Printf("New signed multi-arch image: %s:%s\n", repo, tag)
fmt.Printf("Signed manifest index: %s:%s\n", repo, tag)
return nil
}