Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

manifest push using yaml file #866

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

clnperez
Copy link
Contributor

@clnperez clnperez commented Feb 8, 2018

Instead of:
manifest create list image1 image2
manifest annotate list image1
manifest push list

You can do:
manifest push --file=myfile.yaml list:tag

Signed-off-by: Christy Norman christy@linux.vnet.ibm.com

- What I did

- How I did it

- How to verify it

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@clnperez
Copy link
Contributor Author

clnperez commented Feb 8, 2018

I still need to add a test. If anyone wants to give this a quick once-over in the meantime feel free.

@clnperez clnperez mentioned this pull request Feb 8, 2018
1 task
@clnperez
Copy link
Contributor Author

clnperez commented Feb 8, 2018

Also, so I don't forget, I need to update the doc to add this, and and to include how to set the cli experimental. It's confusing, because it's "true" for the engine, but "enabled" for the cli. :D

return cmd
}

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

if opts.target == "" && opts.file == "" {
return errors.New("please specify either a file or local manifest name")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we generally avoid "please" in error messages. Maybe "either a filename or local manifest name is required" or something like that?

}
if err := annotateListFromYaml(dockerCli, yamlInput); err != nil {
return err
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit odd to me that push would create local files. could this push directly from yaml without creating the files locally?

If we want to support "load defaults from yaml" or something like that we could have create accept the same yaml format (either in this PR or a separate one).

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.StringVar(&opts.file, "filename", "", "create, annotate, and push using a yaml file")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if file should be a boolean flag that changes the positional argument from a "local manifest target" to "a filepath". I'm not sure if that's more or less expected than having a conditional argument.

I think it would at least make the validation easier, because with a bool flag a positional argument would always be necessary.


if _, err := os.Stat(yamlFile); err != nil {
return yamlManifestList{}, err
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this Stat necessary? I think you'd get the same error from ReadFile().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, thanks!

if err != nil {
return yamlManifestList{}, err
}
if err := yaml.UnmarshalStrict(yamlBuf, &yamlInput); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if is unnecessary:

return yamlInput, yaml.UnmarshalStrict(yamlBuf, &yamlInput)

@clnperez
Copy link
Contributor Author

clnperez commented Jun 1, 2018

Redid this (no longer uses local fs) but haven't tested the original path yet, so I'll get to that on Monday, and also take the rest of @dnephin's comments into account. Sorry for abandoning this for so long!

@clnperez clnperez force-pushed the manifest-list-yaml branch 4 times, most recently from c37ebc3 to b25349f Compare June 6, 2018 22:21
@clnperez
Copy link
Contributor Author

clnperez commented Jun 6, 2018

tests added for yaml. removing [WIP]

@vdemeester @thaJeztah the week before dockercon, so, you've got time to take a look at this now right? 👼

@clnperez clnperez changed the title [WIP] manifest push using yaml file manifest push using yaml file Jun 6, 2018
@clnperez
Copy link
Contributor Author

clnperez commented Jun 6, 2018

cc @tianon @StefanScherer @AceHack

Copy link
Collaborator

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the idea, but I feel docker push --file=true my.yaml is not correct.

The current behavior is docker manifest push an-image-ref-which-is-a-list, so… for the file, I really feels we should have something more like docker manifest push --file=my.yaml an-image-ref-which-is-a-list.

cc @thaJeztah @silvin-lubecki @dnephin

@StefanScherer
Copy link
Member

Thanks @clnperez I'll look into it in the next days. Haven't looked into the details, but agree that pushing a yaml should be done with the docker manifest push command.

@clnperez
Copy link
Contributor Author

clnperez commented Jun 7, 2018

@vdemeester i wasn't a huge fan of the file change but it grew on me and did make validation easier. i'm open to changes for sure. but i'm not sure i like having someone specify any information on the command line that could be also in a yaml file (in this case, the target ref).

@vdemeester
Copy link
Collaborator

vdemeester commented Jun 7, 2018

@clnperez I really like the file, but in the current proposal there is two things that I feel could be better

  • cli UX, a flag should not change the meaning of the positional args ; e.g. in the current design, having --file=true makes the positionnal arg being either a list (from the manifest store) or a file.
  • the list is a image reference, and I think even with the file, we should specify that image reference as positional arguments. It would make the file not tied to the image reference pushed — it would be possible to do something like : docker manifest push --file=foo.yml vdemeester/foo && docker manifest push --file=foo.yml grc.io/vdemeester/foo — and the command would not be far from the current usage (we just add the possibility to pass a file)

So my proposal is to make the file something like the following :

manifests:
    - image: test/hello-world-ppc64le:latest
      platform:
          architecture: ppc64le
    - image: test/hello-world-amd64:latest
      platform:
          architecture: amd64
          os: linux
    - image: test/hello-world-s390x:latest
      platform:
          architecture: s390x 
          os: linux
          osversion: 1.1
          variant: xyz
          osfeatures: [a,b,c]

And have the cli being docker manifest push --file=myfile.yaml list.

@thaJeztah wdyt ?

@dnephin
Copy link
Contributor

dnephin commented Jun 7, 2018

I agree with @vdemeester

@clnperez
Copy link
Contributor Author

clnperez commented Jun 7, 2018

@vdemeester can you clarify: the file not tied to the image reference pushed...? The image reference pushed is the first line in the file the way the manifest tool works, and the way I intended this one to work as well. What's the meaning of vdemeester/foo in your example? Would it overwrite the target image on the first line of the file?

@vdemeester
Copy link
Collaborator

@clnperez yes, my sugestion would be to not have the image: … first line in the file (so just listing in the manifest file the manifests).

I updated my example above as I realized I did not remove that first line 😅.

@clnperez
Copy link
Contributor Author

clnperez commented Jun 7, 2018

Thanks @vdemeester. That's a simple enough code change. I'd like to hear from some others before we get attached. :D

Copy link
Contributor

@silvin-lubecki silvin-lubecki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nits

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: too much empty lines

return err
}
if len(yamlInput.Manifests) == 0 {
return errors.Errorf("no manifests specified in file input")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: errors.Errorf is not needed here. You can use errors.New instead.

}

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty line

@@ -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 {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty line

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty line

}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can move the var declaration closer to where it is used.

@tianon
Copy link
Contributor

tianon commented Jun 13, 2018

I think it's relevant to bring up estesp/manifest-tool#23 (multiple tags pushed at once; estesp/manifest-tool#32) in the context of removing image: from the YAML itself -- being able to simply docker manifest push --file xyz.yml abc:1.2.3 abc:1.2 abc:1 abc:latest would be great (especially if it's efficient about skipping the expensive digest lookups and cross-blob mounts).

It probably won't be very useful for pushing to multiple registries though (hub+gcr.io for example), right? (since the manifest list image references still need to be on the same registry for cross-repository blob-mounting)

estesp/manifest-tool#22 is also relevant for the official images use-case -- we have to wait to push the manifest lists until the full set of architectures have built (see docker-library/official-images#3835), so having --ignore-missing helps us to be able to push a manifest list in the meantime, but it's only a workaround for a much larger problem in the way manifest list objects have to be created and updated (namely, the race conditions around "updating" a manifest list without API support for adding/updating entries directly to an existing tag's manifest list in an idempotent way at the registry level, which would allow us to build/update manifest lists more fluidly as architectures build and push like they were before manifest lists were implemented and we were single-arch).

It'd be neat to be able to specify this YAML content without needing a file on-disk, but that's more of a minor annoyance than a serious issue (since it's a matter of garbage collection after we build the appropriate YAML, push the bits, then clean up afterwards).

@clnperez
Copy link
Contributor Author

Thanks @tianon . I think for this PR, I can look at just redoing the --file arg so that it points to the list name (instead of it living in the yaml file), and have two follow-on PRs:

  • add support for extra optional args that specify other refs to name this same manifest list, so it's all done with only one need to cross-mount the layer blobs.
  • add the --ignore-missing parameter

@clnperez
Copy link
Contributor Author

clnperez commented Jul 2, 2018

@silvin-lubecki nits taken into account, thanks :)

@vdemeester i'll have to redo this again if we go with #1156. Unless we want to merge this one first and make @dmcgowan rebase his. ;)

for now though -- i can't get the vendor bit fixed
make -f docker.Makefile vendor ?

@clnperez clnperez force-pushed the manifest-list-yaml branch 3 times, most recently from 368e4c9 to c9a9950 Compare July 2, 2018 21:44
@clnperez
Copy link
Contributor Author

clnperez commented Jul 2, 2018

figured out vendor. i think i had switched a commit. PTAL

@clnperez
Copy link
Contributor Author

clnperez commented Jul 3, 2018

Rebased against master post-merge of #1156

@clnperez
Copy link
Contributor Author

ping @thaJeztah @vdemeester

@codecov-io
Copy link

codecov-io commented Aug 2, 2018

Codecov Report

Merging #866 into master will increase coverage by 0.07%.
The diff coverage is 82.14%.

@@            Coverage Diff            @@
##           master    #866      +/-   ##
=========================================
+ Coverage   54.63%   54.7%   +0.07%     
=========================================
  Files         293     293              
  Lines       19369   19418      +49     
=========================================
+ Hits        10582   10623      +41     
- Misses       8126    8130       +4     
- Partials      661     665       +4

@clnperez
Copy link
Contributor Author

clnperez commented Aug 2, 2018

Rebased. PTAL.

@clnperez
Copy link
Contributor Author

paging @thaJeztah & @vdemeester

Copy link
Collaborator

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design LGTM 👼

cli/command/manifest/push.go Outdated Show resolved Hide resolved
Copy link
Contributor

@silvin-lubecki silvin-lubecki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you @clnperez !

@silvin-lubecki
Copy link
Contributor

@thaJeztah are you ok to merge this PR?

Instead of:
manifest create list image1 image2
manifest annotate list image1
manifest push list

You can do:
manifiest push --file myfile.yaml registry/repo/image:tag

Signed-off-by: Christy Norman <christy@linux.vnet.ibm.com>
@clnperez
Copy link
Contributor Author

clnperez commented Sep 19, 2018

ping @thaJeztah . would love to close this 😇

@duglin
Copy link
Contributor

duglin commented Nov 5, 2018

@dnephin @vdemeester can chance of merging this one?

@clnperez
Copy link
Contributor Author

ping @thaJeztah. I saw that #1252 was merged so I have a sliver of hope that someone will take a look at this again.

@olljanat
Copy link
Contributor

Nice is very good idea. Would be nice to get this merged before #1355

@grooverdan
Copy link

Nice work @clnperez, great way to create manifests by yaml definition.

Copy link
Collaborator

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still LGTM for me
cc @thaJeztah @andrewhsu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.