Skip to content

Commit

Permalink
manifest push using yaml file
Browse files Browse the repository at this point in the history
Instead of:
manifest create list image1 image2
manifest annotate list image1
manifest push list

You can do:
manifiest push --file=true myfile.yaml

Signed-off-by: Christy Norman <christy@linux.vnet.ibm.com>
  • Loading branch information
clnperez committed Jun 5, 2018
1 parent 90f8ce8 commit c37ebc3
Show file tree
Hide file tree
Showing 12 changed files with 348 additions and 41 deletions.
4 changes: 2 additions & 2 deletions cli/command/manifest/annotate.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error {
imageManifest.Platform.Variant = opts.variant
}

if !isValidOSArch(imageManifest.Platform.OS, imageManifest.Platform.Architecture) {
return errors.Errorf("manifest entry for image has unsupported os/arch combination: %s/%s", opts.os, opts.arch)
if err := validateOSArch(imageManifest.Platform.OS, imageManifest.Platform.Architecture); err != nil {
return err
}
return manifestStore.Save(targetRef, imgRef, imageManifest)
}
Expand Down
97 changes: 92 additions & 5 deletions cli/command/manifest/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"

"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
Expand All @@ -14,13 +15,16 @@ import (
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/reference"
"github.com/docker/docker/registry"

"github.com/pkg/errors"
"github.com/spf13/cobra"
yaml "gopkg.in/yaml.v2"
)

type pushOpts struct {
insecure bool
purge bool
file bool
target string
}

Expand All @@ -42,32 +46,49 @@ type pushRequest struct {
insecure bool
}

type yamlManifestList struct {
Image string
Manifests []yamlManifest
}

type yamlManifest struct {
Image string
Platform manifestlist.PlatformSpec
}

func newPushListCommand(dockerCli command.Cli) *cobra.Command {
opts := pushOpts{}

cmd := &cobra.Command{
Use: "push [OPTIONS] MANIFEST_LIST",
Short: "Push a manifest list to a repository",
Short: "Push a manifest list to a repository, either after a create, or from a single file",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.target = args[0]
return runPush(dockerCli, opts)
},
}

flags := cmd.Flags()
flags.BoolVarP(&opts.purge, "purge", "p", false, "Remove the local manifest list after push")
flags.BoolVar(&opts.insecure, "insecure", false, "Allow push to an insecure registry")
flags.BoolVarP(&opts.purge, "purge", "p", false, "remove the local manifest list after push")
flags.BoolVar(&opts.insecure, "insecure", false, "allow push to an insecure registry")
flags.BoolVar(&opts.file, "file", false, "argument is yaml representation of manifest list")
return cmd
}

func runPush(dockerCli command.Cli, opts pushOpts) error {

if opts.file {
return pushListFromYaml(dockerCli, opts.target, opts.insecure)
}

return pushListFromStore(dockerCli, opts)
}

func pushListFromStore(dockerCli command.Cli, opts pushOpts) error {
targetRef, err := normalizeReference(opts.target)
if err != nil {
return err
}

manifests, err := dockerCli.ManifestStore().GetList(targetRef)
if err != nil {
return err
Expand Down Expand Up @@ -271,3 +292,69 @@ func mountBlobs(ctx context.Context, client registryclient.RegistryClient, ref r
}
return nil
}

func pushListFromYaml(dockerCli command.Cli, file string, insecure bool) error {

yamlInput, err := getYamlManifestList(file)
if err != nil {
return err
}
if len(yamlInput.Manifests) == 0 {
return errors.Errorf("no manifests specified in file input")
}

targetRef, err := normalizeReference(yamlInput.Image)
if err != nil {
return err
}

ctx := context.Background()
var manifests []types.ImageManifest
for _, manifest := range yamlInput.Manifests {
imageRef, err := normalizeReference(manifest.Image)
if err != nil {
return err
}
im, err := dockerCli.RegistryClient(insecure).GetManifest(ctx, imageRef)
if err != nil {
return err
}
addYamlAnnotations(&im, manifest)
if err := validateOSArch(im.Platform.OS, im.Platform.Architecture); err != nil {
return err
}
manifests = append(manifests, im)
}

pushRequest, err := buildPushRequest(manifests, targetRef, insecure)
if err != nil {
return err
}
return pushList(ctx, dockerCli, pushRequest)
}

func addYamlAnnotations(manifest *types.ImageManifest, ym yamlManifest) {

if ym.Platform.Variant != "" {
manifest.Platform.Variant = ym.Platform.Variant
}
if ym.Platform.OS != "" {
manifest.Platform.OS = ym.Platform.OS
}
if ym.Platform.Architecture != "" {
manifest.Platform.Architecture = ym.Platform.Architecture
}
if len(ym.Platform.OSFeatures) != 0 {
manifest.Platform.OSFeatures = ym.Platform.OSFeatures
}
}

func getYamlManifestList(yamlFile string) (yamlManifestList, error) {
var yamlInput yamlManifestList

yamlBuf, err := ioutil.ReadFile(yamlFile)
if err != nil {
return yamlManifestList{}, err
}
return yamlInput, yaml.UnmarshalStrict(yamlBuf, &yamlInput)
}
20 changes: 18 additions & 2 deletions cli/command/manifest/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package manifest

import (
"context"
"fmt"

"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/manifest/store"
Expand All @@ -14,6 +15,18 @@ type osArch struct {
arch string
}

type invalidOSArchErr struct {
osArch
}

func (e *invalidOSArchErr) Error() string {
return fmt.Sprintf("manifest entry for image has unsupported os/arch combination: %s/%s", e.os, e.arch)
}

func newInvalidOSArchErr(os1 string, arch1 string) *invalidOSArchErr {
return &invalidOSArchErr{osArch{os: os1, arch: arch1}}
}

// Remove any unsupported os/arch combo
// list of valid os/arch values (see "Optional Environment Variables" section
// of https://golang.org/doc/install/source
Expand Down Expand Up @@ -48,10 +61,13 @@ var validOSArches = map[osArch]bool{
{os: "windows", arch: "amd64"}: true,
}

func isValidOSArch(os string, arch string) bool {
func validateOSArch(os string, arch string) error {
// check for existence of this combo
_, ok := validOSArches[osArch{os, arch}]
return ok
if !ok {
return newInvalidOSArchErr(os, arch)
}
return nil
}

func normalizeReference(ref string) (reference.Named, error) {
Expand Down
2 changes: 1 addition & 1 deletion vendor.conf
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
google.golang.org/grpc v1.3.0
gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
gopkg.in/yaml.v2 d670f9405373e636a5a2765eea47fac0c9bc91a4
k8s.io/api kubernetes-1.8.2
k8s.io/apimachinery kubernetes-1.8.2
k8s.io/client-go kubernetes-1.8.2
Expand Down
Loading

0 comments on commit c37ebc3

Please sign in to comment.