support multi commands

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2016-03-16 10:06:31 +01:00
parent d0fd876d7e
commit 3fd3adc58e
9 changed files with 85 additions and 67 deletions

View File

@ -11,7 +11,7 @@ a repository or a tag before pulling it (using disk space) - e.g. - which tags a
Examples:
```sh
# show repository's labels of rhel7:latest
$ skopeo registry.access.redhat.com/rhel7 | jq '.Config.Labels'
$ skopeo inspect registry.access.redhat.com/rhel7 | jq '.Config.Labels'
{
"Architecture": "x86_64",
"Authoritative_Registry": "registry.access.redhat.com",
@ -24,7 +24,7 @@ $ skopeo registry.access.redhat.com/rhel7 | jq '.Config.Labels'
}
# show repository's tags
$ skopeo docker.io/fedora | jq '.RepoTags'
$ skopeo inspect docker.io/fedora | jq '.RepoTags'
[
"20",
"21",
@ -36,11 +36,11 @@ $ skopeo docker.io/fedora | jq '.RepoTags'
]
# show image's digest
$ skopeo docker.io/fedora:rawhide | jq '.Digest'
$ skopeo inspect docker.io/fedora:rawhide | jq '.Digest'
"sha256:905b4846938c8aef94f52f3e41a11398ae5b40f5855fb0e40ed9c157e721d7f8"
# show image's label "Name"
$ skopeo registry.access.redhat.com/rhel7 | jq '.Config.Labels.Name'
$ skopeo inspect registry.access.redhat.com/rhel7 | jq '.Config.Labels.Name'
"rhel7/rhel"
```
@ -65,15 +65,15 @@ $ cat /home/runcom/.docker/config.json
}
# we can see I'm already authenticated via docker login so everything will be fine
$ skopeo myregistrydomain.com:5000/busybox
$ skopeo inspect myregistrydomain.com:5000/busybox
{"Tag":"latest","Digest":"sha256:473bb2189d7b913ed7187a33d11e743fdc2f88931122a44d91a301b64419f092","RepoTags":["latest"],"Comment":"","Created":"2016-01-15T18:06:41.282540103Z","ContainerConfig":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["/bin/sh","-c","#(nop) CMD [\"sh\"]"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"DockerVersion":"1.8.3","Author":"","Config":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["sh"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"Architecture":"amd64","Os":"linux"}
# let's try now to fake a non existent Docker's config file
$ skopeo --docker-cfg="" myregistrydomain.com:5000/busybox
$ skopeo --docker-cfg="" inspect myregistrydomain.com:5000/busybox
FATA[0000] Get https://myregistrydomain.com:5000/v2/busybox/manifests/latest: no basic auth credentials
# passing --username and --password - we can see that everything goes fine
$ skopeo --docker-cfg="" --username=testuser --password=testpassword myregistrydomain.com:5000/busybox
$ skopeo --docker-cfg="" --username=testuser --password=testpassword inspect myregistrydomain.com:5000/busybox
{"Tag":"latest","Digest":"sha256:473bb2189d7b913ed7187a33d11e743fdc2f88931122a44d91a301b64419f092","RepoTags":["latest"],"Comment":"","Created":"2016-01-15T18:06:41.282540103Z","ContainerConfig":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["/bin/sh","-c","#(nop) CMD [\"sh\"]"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"DockerVersion":"1.8.3","Author":"","Config":{"Hostname":"aded96b43f48","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["sh"],"Image":"9e77fef7a1c9f989988c06620dabc4020c607885b959a2cbd7c2283c91da3e33","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"Architecture":"amd64","Os":"linux"}
```
If your cli config is found but it doesn't contain the necessary credentials for the queried registry

View File

@ -47,7 +47,7 @@ func (f fallbackError) Error() string {
}
type manifestFetcher interface {
Fetch(ctx context.Context, ref reference.Named) (*types.ImageInspect, error)
Fetch(ctx context.Context, ref reference.Named) (*types.ImageManifest, error)
}
func validateName(name string) error {
@ -62,7 +62,7 @@ func validateName(name string) error {
return nil
}
func GetData(c *cli.Context, name string) (*types.ImageInspect, error) {
func GetData(c *cli.Context, name string) (*types.ImageManifest, error) {
if err := validateName(name); err != nil {
return nil, err
}
@ -101,7 +101,7 @@ func GetData(c *cli.Context, name string) (*types.ImageInspect, error) {
ctx = context.Background()
lastErr error
discardNoSupportErrors bool
imgInspect *types.ImageInspect
imgInspect *types.ImageManifest
confirmedV2 bool
confirmedTLSRegistries = make(map[string]struct{})
)
@ -248,12 +248,12 @@ func validateRepoName(name string) error {
return nil
}
func makeImageInspect(img *image.Image, tag string, dgst digest.Digest, tagList []string) *types.ImageInspect {
func makeImageManifest(img *image.Image, tag string, dgst digest.Digest, tagList []string) *types.ImageManifest {
var digest string
if err := dgst.Validate(); err == nil {
digest = dgst.String()
}
return &types.ImageInspect{
return &types.ImageManifest{
Tag: tag,
Digest: digest,
RepoTags: tagList,

View File

@ -31,9 +31,9 @@ type v1ManifestFetcher struct {
session *registry.Session
}
func (mf *v1ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*types.ImageInspect, error) {
func (mf *v1ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*types.ImageManifest, error) {
var (
imgInspect *types.ImageInspect
imgInspect *types.ImageManifest
)
if _, isCanonical := ref.(reference.Canonical); isCanonical {
// Allowing fallback, because HTTPS v1 is before HTTP v2
@ -68,7 +68,7 @@ func (mf *v1ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*t
return imgInspect, nil
}
func (mf *v1ManifestFetcher) fetchWithSession(ctx context.Context, ref reference.Named) (*types.ImageInspect, error) {
func (mf *v1ManifestFetcher) fetchWithSession(ctx context.Context, ref reference.Named) (*types.ImageManifest, error) {
repoData, err := mf.session.GetRepositoryData(mf.repoInfo)
if err != nil {
if strings.Contains(err.Error(), "HTTP code: 404") {
@ -142,7 +142,7 @@ func (mf *v1ManifestFetcher) fetchWithSession(ctx context.Context, ref reference
return nil, fmt.Errorf("No such image %s:%s", mf.repoInfo.FullName(), tag)
}
return makeImageInspect(pulledImg, tag, "", tagList), nil
return makeImageManifest(pulledImg, tag, "", tagList), nil
}
func (mf *v1ManifestFetcher) pullImageJSON(imgID, endpoint string, token []string) (*image.Image, error) {

View File

@ -34,9 +34,9 @@ type v2ManifestFetcher struct {
service *registry.Service
}
func (mf *v2ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*types.ImageInspect, error) {
func (mf *v2ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*types.ImageManifest, error) {
var (
imgInspect *types.ImageInspect
imgInspect *types.ImageManifest
err error
)
@ -60,7 +60,7 @@ func (mf *v2ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*t
return imgInspect, err
}
func (mf *v2ManifestFetcher) fetchWithRepository(ctx context.Context, ref reference.Named) (*types.ImageInspect, error) {
func (mf *v2ManifestFetcher) fetchWithRepository(ctx context.Context, ref reference.Named) (*types.ImageManifest, error) {
var (
manifest distribution.Manifest
tagOrDigest string // Used for logging/progress only
@ -146,7 +146,7 @@ func (mf *v2ManifestFetcher) fetchWithRepository(ctx context.Context, ref refere
//ref = reference.WithDefaultTag(ref)
//}
//_ = showTags
return makeImageInspect(image, tagOrDigest, manifestDigest, tagList), nil
return makeImageManifest(image, tagOrDigest, manifestDigest, tagList), nil
}
func (mf *v2ManifestFetcher) pullSchema1(ctx context.Context, ref reference.Named, unverifiedManifest *schema1.SignedManifest) (img *image.Image, manifestDigest digest.Digest, err error) {

View File

@ -1,55 +1,49 @@
package main
import (
"encoding/json"
"fmt"
"strings"
"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"github.com/projectatomic/skopeo/docker"
"github.com/projectatomic/skopeo/types"
)
type imgKind int
const (
imgTypeDocker = "docker://"
imgTypeAppc = "appc://"
kindUnknown = iota
kindDocker
kindAppc
)
func getImgType(img string) imgKind {
if strings.HasPrefix(img, imgTypeDocker) {
return kindDocker
}
if strings.HasPrefix(img, imgTypeAppc) {
return kindAppc
}
// TODO(runcom): v2 will support this
//return kindUnknown
return kindDocker
var inspectCmd = cli.Command{
Name: "inspect",
Usage: "inspect images on a registry",
ArgsUsage: ``,
Action: func(c *cli.Context) {
// get the Image interface before inspecting...utils.go parseImage
imgInspect, err := inspect(c)
if err != nil {
logrus.Fatal(err)
}
out, err := json.Marshal(imgInspect)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(string(out))
},
}
func inspect(c *cli.Context) (*types.ImageInspect, error) {
func inspect(c *cli.Context) (*types.ImageManifest, error) {
var (
imgInspect *types.ImageInspect
imgInspect *types.ImageManifest
err error
name = c.Args().First()
kind = getImgType(name)
)
switch kind {
case kindDocker:
imgInspect, err = docker.GetData(c, strings.Replace(name, imgTypeDocker, "", -1))
switch {
case strings.HasPrefix(name, types.DockerPrefix):
imgInspect, err = docker.GetData(c, strings.Replace(name, "docker://", "", -1))
if err != nil {
return nil, err
}
case kindAppc:
return nil, fmt.Errorf("not implemented yet")
default:
return nil, fmt.Errorf("%s image is invalid, please use either 'docker://' or 'appc://'", name)
return nil, fmt.Errorf("%s image is invalid, please use 'docker://'", name)
}
return imgInspect, nil
}

1
layers.go Normal file
View File

@ -0,0 +1 @@
package main

20
main.go
View File

@ -1,8 +1,6 @@
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/Sirupsen/logrus"
@ -12,21 +10,9 @@ import (
const (
version = "0.1.12-dev"
usage = "inspect images on a registry"
usage = "interact with registries"
)
var inspectCmd = func(c *cli.Context) {
imgInspect, err := inspect(c)
if err != nil {
logrus.Fatal(err)
}
out, err := json.Marshal(imgInspect)
if err != nil {
logrus.Fatal(err)
}
fmt.Println(string(out))
}
func main() {
app := cli.NewApp()
app.Name = "skopeo"
@ -61,7 +47,9 @@ func main() {
}
return nil
}
app.Action = inspectCmd
app.Commands = []cli.Command{
inspectCmd,
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}

View File

@ -4,7 +4,24 @@ import (
containerTypes "github.com/docker/engine-api/types/container"
)
type ImageInspect struct {
type Kind int
const (
KindUnknown Kind = iota
KindDocker
KindAppc
DockerPrefix = "docker://"
)
type Image interface {
Kind() Kind
GetLayers(layers []string) error
GetManifest(version string) ([]byte, error)
GetRawManifest(version string) ([]byte, error)
}
type ImageManifest struct {
Tag string
Digest string
RepoTags []string

18
utils.go Normal file
View File

@ -0,0 +1,18 @@
package main
import (
"fmt"
"strings"
"github.com/projectatomic/skopeo/types"
)
func parseImage(img string) (types.Image, error) {
switch {
case strings.HasPrefix(img, types.DockerPrefix):
//return parseDockerImage(strings.TrimPrefix(img, dockerPrefix))
//case strings.HasPrefix(img, appcPrefix):
//
}
return nil, fmt.Errorf("no valid prefix provided")
}