This repository has been archived by the owner on May 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial push-pull implementation
Signed-off-by: Radu M <root@radu.sh>
- Loading branch information
Radu M
committed
Aug 7, 2019
1 parent
367ce6b
commit 61bb2d7
Showing
15 changed files
with
2,227 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"path/filepath" | ||
|
||
"github.com/deislabs/duffle/pkg/duffle/home" | ||
"github.com/deislabs/duffle/pkg/reference" | ||
|
||
"github.com/deislabs/cnab-go/bundle" | ||
"github.com/docker/cnab-to-oci/remotes" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type pullCmd struct { | ||
output string | ||
targetRef string | ||
insecureRegistries []string | ||
home home.Home | ||
} | ||
|
||
func newPullCmd(w io.Writer) *cobra.Command { | ||
const usage = `Pulls a bundle from an OCI repository` | ||
const pullDesc = ` | ||
Pulls a CNAB bundle from an OCI repository. | ||
The only argument for this command is the repository where | ||
the bundle can be found, and by default, this command pulls the | ||
bundle and stores it in the local bundle store. | ||
If the --output flag is passed, the bundle file will be saved in | ||
that file, and its reference will not be recorded in the local store. | ||
Insecure registries can be passed through the --insecure-registries flags. | ||
Examples: | ||
$ duffle pull registry/username/bundle:tag | ||
$ duffle pull --output path-for-bundle.json registry/username/bundle:tag | ||
` | ||
var pull pullCmd | ||
cmd := &cobra.Command{ | ||
Use: "pull [TARGET REPOSITORY] [options]", | ||
Short: usage, | ||
Long: pullDesc, | ||
Args: cobra.ExactArgs(1), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
pull.targetRef = args[0] | ||
pull.home = home.Home(homePath()) | ||
return pull.run() | ||
}, | ||
} | ||
|
||
cmd.Flags().StringVarP(&pull.output, "output", "o", "", "Output file") | ||
cmd.Flags().StringSliceVar(&pull.insecureRegistries, "insecure-registries", nil, "Use plain HTTP for those registries") | ||
return cmd | ||
} | ||
|
||
func (p *pullCmd) run() error { | ||
ref, err := reference.ParseNormalizedNamed(p.targetRef) | ||
if err != nil { | ||
return err | ||
} | ||
b, err := remotes.Pull(context.Background(), ref, createResolver(p.insecureRegistries)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return p.writeBundle(b) | ||
} | ||
|
||
func (p *pullCmd) writeBundle(bf *bundle.Bundle) error { | ||
data, digest, err := marshalBundle(bf) | ||
if err != nil { | ||
return fmt.Errorf("cannot marshal bundle: %v", err) | ||
} | ||
|
||
if p.output != "" { | ||
if err := ioutil.WriteFile(p.output, data, 0644); err != nil { | ||
return fmt.Errorf("cannot write bundle to %s: %v", p.output, err) | ||
} | ||
return nil | ||
} | ||
|
||
if err := ioutil.WriteFile(filepath.Join(p.home.Bundles(), digest), data, 0644); err != nil { | ||
return fmt.Errorf("cannot store bundle : %v", err) | ||
|
||
} | ||
|
||
return recordBundleReference(p.home, bf.Name, bf.Version, digest) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/deislabs/duffle/pkg/duffle/home" | ||
"github.com/deislabs/duffle/pkg/reference" | ||
|
||
containerdRemotes "github.com/containerd/containerd/remotes" | ||
"github.com/docker/cli/cli/config" | ||
"github.com/docker/cnab-to-oci/remotes" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type pushCmd struct { | ||
inputBundle string | ||
home home.Home | ||
bundleIsFile bool | ||
targetRef string | ||
insecureRegistries []string | ||
allowFallbacks bool | ||
} | ||
|
||
func newPushCmd(out io.Writer) *cobra.Command { | ||
const usage = `Pushes a CNAB bundle to an OCI repository.` | ||
const pushDesc = ` | ||
Pushes a CNAB bundle to an OCI registry by pushing all container | ||
images referenced in the bundle to the target repository (all images are | ||
pushed to the same repository, and are referenceable through their digest). | ||
The first argument is the bundle to push (or the path to the bundle file, if the | ||
--bundle-is-file flag is passed), and the second argument is the target repository | ||
where the bundle and all referenced images will be pushed. | ||
Insecure registries can be passed through the --insecure-registries flags, | ||
and --allow-fallbacks enables automatic compatibility fallbacks for registries | ||
without support for custom media type, or OCI manifests. | ||
Examples: | ||
$ duffle push bundle-reference registry/usernamne/bundle:tag | ||
$ duffle push path-to-bundle.json --bundle-is-file registtry/username/bundle:tag | ||
` | ||
var push pushCmd | ||
|
||
cmd := &cobra.Command{ | ||
Use: "push [BUNDLE] [TARGET REPOSITORY] [options]", | ||
Short: usage, | ||
Long: pushDesc, | ||
Args: cobra.ExactArgs(2), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
push.home = home.Home(homePath()) | ||
push.inputBundle = args[0] | ||
push.targetRef = args[1] | ||
return push.run() | ||
}, | ||
} | ||
|
||
cmd.Flags().BoolVarP(&push.bundleIsFile, "bundle-is-file", "f", false, "Indicates that the bundle source is a file path") | ||
cmd.Flags().StringSliceVar(&push.insecureRegistries, "insecure-registries", nil, "Use plain HTTP for those registries") | ||
cmd.Flags().BoolVar(&push.allowFallbacks, "allow-fallbacks", true, "Enable automatic compatibility fallbacks for registries without support for custom media type, or OCI manifests") | ||
|
||
return cmd | ||
} | ||
|
||
func (p *pushCmd) run() error { | ||
|
||
bundleFile, err := resolveBundleFilePath(p.inputBundle, p.home.String(), p.bundleIsFile) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
b, err := loadBundle(bundleFile) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resolver := createResolver(p.insecureRegistries) | ||
ref, err := reference.ParseNormalizedNamed(p.targetRef) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = remotes.FixupBundle(context.Background(), b, ref, resolver, remotes.WithEventCallback(displayEvent)) | ||
if err != nil { | ||
return err | ||
} | ||
d, err := remotes.Push(context.Background(), b, ref, resolver, p.allowFallbacks) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Printf("Pushed successfully, with digest %q\n", d.Digest) | ||
return nil | ||
} | ||
|
||
func createResolver(insecureRegistries []string) containerdRemotes.Resolver { | ||
return remotes.CreateResolver(config.LoadDefaultConfigFile(os.Stderr), insecureRegistries...) | ||
} | ||
|
||
func displayEvent(ev remotes.FixupEvent) { | ||
switch ev.EventType { | ||
case remotes.FixupEventTypeCopyImageStart: | ||
fmt.Fprintf(os.Stderr, "Starting to copy image %s...\n", ev.SourceImage) | ||
case remotes.FixupEventTypeCopyImageEnd: | ||
if ev.Error != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to copy image %s: %s\n", ev.SourceImage, ev.Error) | ||
} else { | ||
fmt.Fprintf(os.Stderr, "Completed image %s copy\n", ev.SourceImage) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.