Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 9b36d89

Browse files
committed
Introduce Push/Pull with cnab-to-oci
- Brings Push and Pull top level commands - Using any existing command on a registry ref making it pull the cnab from the registry - Added a local CNAB store to avoid pulling the CNABs more than once Signed-off-by: Simon Ferquel <[email protected]>
1 parent faf0d13 commit 9b36d89

File tree

25 files changed

+884
-992
lines changed

25 files changed

+884
-992
lines changed

cmd/docker-app/bundle.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,10 @@ func makeBundle(dockerCli command.Cli, appName string) (*bundle.Bundle, error) {
7070

7171
func makeBundleFromApp(dockerCli command.Cli, app *types.App) (*bundle.Bundle, error) {
7272
meta := app.Metadata()
73-
invocationImageName, err := makeImageName(meta)
73+
invocationImageName, err := makeInvocationImageName(meta)
7474
if err != nil {
7575
return nil, err
7676
}
77-
if _, err := makeImageName(meta); err != nil {
78-
return nil, err
79-
}
8077

8178
buildContext := bytes.NewBuffer(nil)
8279
if err := packager.PackInvocationImageContext(app, buildContext); err != nil {
@@ -98,8 +95,12 @@ func makeBundleFromApp(dockerCli command.Cli, app *types.App) (*bundle.Bundle, e
9895
return packager.ToCNAB(app, invocationImageName)
9996
}
10097

101-
func makeImageName(meta metadata.AppMetadata) (string, error) {
102-
name := fmt.Sprintf("%s:%s-invoc", meta.Name, meta.Version)
98+
func makeInvocationImageName(meta metadata.AppMetadata) (string, error) {
99+
return makeCNABImageName(meta, "-invoc")
100+
}
101+
102+
func makeCNABImageName(meta metadata.AppMetadata, suffix string) (string, error) {
103+
name := fmt.Sprintf("%s:%s%s", meta.Name, meta.Version, suffix)
103104
if _, err := reference.ParseNormalizedNamed(name); err != nil {
104105
return "", errors.Wrapf(err, "image name %q is invalid, please check name and version fields", name)
105106
}

cmd/docker-app/bundle_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestMakeInvocationImage(t *testing.T) {
2727
}
2828
for _, c := range testcases {
2929
t.Run(c.name, func(t *testing.T) {
30-
actual, err := makeImageName(c.meta)
30+
actual, err := makeInvocationImageName(c.meta)
3131
if c.err != "" {
3232
assert.ErrorContains(t, err, c.err)
3333
assert.Equal(t, actual, "", "On "+c.meta.Name)

cmd/docker-app/cnab.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import (
1414
"github.com/deislabs/duffle/pkg/loader"
1515
"github.com/docker/app/internal"
1616
"github.com/docker/app/internal/packager"
17+
bundlestore "github.com/docker/app/internal/store"
1718
"github.com/docker/cli/cli/command"
1819
"github.com/docker/cli/cli/context/store"
20+
"github.com/docker/distribution/reference"
1921
"github.com/pkg/errors"
2022
)
2123

@@ -126,7 +128,7 @@ func extractAndLoadAppBasedBundle(dockerCli command.Cli, name string) (*bundle.B
126128
return makeBundleFromApp(dockerCli, app)
127129
}
128130

129-
func resolveBundle(dockerCli command.Cli, name string) (*bundle.Bundle, error) {
131+
func resolveBundle(dockerCli command.Cli, name string, pullRef bool, insecureRegistries []string) (*bundle.Bundle, error) {
130132
// resolution logic:
131133
// - if there is a docker-app package in working directory, or an http:// / https:// prefix, use packager.Extract result
132134
// - the name has a .json or .cnab extension and refers to an existing file or web resource: load the bundle
@@ -135,15 +137,28 @@ func resolveBundle(dockerCli command.Cli, name string) (*bundle.Bundle, error) {
135137
name, kind := getAppNameKind(name)
136138
switch kind {
137139
case nameKindFile:
140+
if pullRef {
141+
return nil, errors.Errorf("%s: cannot pull when referencing a file based app", name)
142+
}
138143
if strings.HasSuffix(name, internal.AppExtension) {
139144
return extractAndLoadAppBasedBundle(dockerCli, name)
140145
}
141146
return loader.NewDetectingLoader().Load(name)
142147
case nameKindDir, nameKindEmpty:
148+
if pullRef {
149+
if kind == nameKindDir {
150+
return nil, errors.Errorf("%s: cannot pull when referencing a directory based app", name)
151+
}
152+
// XXX perhaps getAppNameKind could do the call to findApp?
153+
return nil, errors.Errorf("cannot pull when referencing a directory based app")
154+
}
143155
return extractAndLoadAppBasedBundle(dockerCli, name)
144156
case nameKindReference:
145-
// TODO: pull the bundle
146-
fmt.Fprintln(dockerCli.Err(), "WARNING: pulling a CNAB is not yet supported")
157+
ref, err := reference.ParseNormalizedNamed(name)
158+
if err != nil {
159+
return nil, errors.Wrap(err, name)
160+
}
161+
return bundlestore.LookupOrPullBundle(dockerCli, reference.TagNameOnly(ref), pullRef, insecureRegistries)
147162
}
148163
return nil, fmt.Errorf("could not resolve bundle %q", name)
149164
}

cmd/docker-app/inspect.go

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,58 @@ import (
1010
"github.com/spf13/cobra"
1111
)
1212

13+
type inspectOptions struct {
14+
parametersOptions
15+
registryOptions
16+
pull bool
17+
}
18+
1319
func inspectCmd(dockerCli command.Cli) *cobra.Command {
14-
var opts parametersOptions
20+
var opts inspectOptions
1521
cmd := &cobra.Command{
1622
Use: "inspect [<app-name>] [-s key=value...] [-f parameters-file...]",
1723
Short: "Shows metadata, parameters and a summary of the compose file for a given application",
1824
Args: cli.RequiresMaxArgs(1),
1925
RunE: func(cmd *cobra.Command, args []string) error {
20-
muteDockerCli(dockerCli)
21-
appname := firstOrEmpty(args)
26+
return runInspect(dockerCli, firstOrEmpty(args), opts)
27+
},
28+
}
29+
opts.parametersOptions.addFlags(cmd.Flags())
30+
opts.registryOptions.addFlags(cmd.Flags())
31+
cmd.Flags().BoolVar(&opts.pull, "pull", false, "Pull the bundle")
32+
return cmd
33+
}
2234

23-
c, err := claim.New("inspect")
24-
if err != nil {
25-
return err
26-
}
27-
driverImpl, err := prepareDriver(dockerCli)
28-
if err != nil {
29-
return err
30-
}
31-
bundle, err := resolveBundle(dockerCli, appname)
32-
if err != nil {
33-
return err
34-
}
35-
c.Bundle = bundle
35+
func runInspect(dockerCli command.Cli, appname string, opts inspectOptions) error {
36+
muteDockerCli(dockerCli)
3637

37-
parameters, err := mergeBundleParameters(c.Bundle,
38-
withFileParameters(opts.parametersFiles),
39-
withCommandLineParameters(opts.overrides),
40-
)
41-
if err != nil {
42-
return err
43-
}
44-
c.Parameters = parameters
38+
c, err := claim.New("inspect")
39+
if err != nil {
40+
return err
41+
}
42+
driverImpl, err := prepareDriver(dockerCli)
43+
if err != nil {
44+
return err
45+
}
46+
bundle, err := resolveBundle(dockerCli, appname, opts.pull, opts.insecureRegistries)
47+
if err != nil {
48+
return err
49+
}
50+
c.Bundle = bundle
4551

46-
a := &action.RunCustom{
47-
Action: internal.Namespace + "inspect",
48-
Driver: driverImpl,
49-
}
50-
err = a.Run(c, map[string]string{"docker.context": ""}, dockerCli.Out())
51-
return errors.Wrap(err, "Inspect failed")
52-
},
52+
parameters, err := mergeBundleParameters(c.Bundle,
53+
withFileParameters(opts.parametersFiles),
54+
withCommandLineParameters(opts.overrides),
55+
)
56+
if err != nil {
57+
return err
5358
}
54-
opts.addFlags(cmd.Flags())
55-
return cmd
59+
c.Parameters = parameters
60+
61+
a := &action.RunCustom{
62+
Action: internal.Namespace + "inspect",
63+
Driver: driverImpl,
64+
}
65+
err = a.Run(c, map[string]string{"docker.context": ""}, dockerCli.Out())
66+
return errors.Wrap(err, "Inspect failed")
5667
}

cmd/docker-app/install.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ import (
1616
type installOptions struct {
1717
parametersOptions
1818
credentialOptions
19+
registryOptions
1920
orchestrator string
2021
kubeNamespace string
2122
stackName string
22-
insecure bool
2323
sendRegistryAuth bool
24+
pull bool
2425
}
2526

2627
type nameKind uint
@@ -56,11 +57,12 @@ func installCmd(dockerCli command.Cli) *cobra.Command {
5657
}
5758
opts.parametersOptions.addFlags(cmd.Flags())
5859
opts.credentialOptions.addFlags(cmd.Flags())
60+
opts.registryOptions.addFlags(cmd.Flags())
5961
cmd.Flags().StringVarP(&opts.orchestrator, "orchestrator", "o", "", "Orchestrator to install on (swarm, kubernetes)")
6062
cmd.Flags().StringVar(&opts.kubeNamespace, "kubernetes-namespace", "default", "Kubernetes namespace to install into")
6163
cmd.Flags().StringVar(&opts.stackName, "name", "", "Installation name (defaults to application name)")
62-
cmd.Flags().BoolVar(&opts.insecure, "insecure", false, "Use insecure registry, without SSL")
6364
cmd.Flags().BoolVar(&opts.sendRegistryAuth, "with-registry-auth", false, "Sends registry auth")
65+
cmd.Flags().BoolVar(&opts.pull, "pull", false, "Pull the bundle")
6466

6567
return cmd
6668
}
@@ -72,7 +74,7 @@ func runInstall(dockerCli command.Cli, appname string, opts installOptions) erro
7274
}
7375
targetContext := getTargetContext(opts.targetContext, dockerCli.CurrentContext())
7476

75-
bndl, err := resolveBundle(dockerCli, appname)
77+
bndl, err := resolveBundle(dockerCli, appname, opts.pull, opts.insecureRegistries)
7678
if err != nil {
7779
return err
7880
}

cmd/docker-app/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func main() {
1212
dockerCli, err := command.NewDockerCli()
1313
if err != nil {
1414
fmt.Fprintln(os.Stderr, err)
15+
os.Exit(1)
1516
}
1617
logrus.SetOutput(dockerCli.Err())
1718
cmd := newRootCmd(dockerCli)

cmd/docker-app/pull.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,41 @@
11
package main
22

33
import (
4-
"github.com/docker/app/internal/packager"
4+
"fmt"
5+
6+
bundlestore "github.com/docker/app/internal/store"
57
"github.com/docker/cli/cli"
8+
"github.com/docker/cli/cli/command"
9+
"github.com/docker/distribution/reference"
10+
"github.com/pkg/errors"
611
"github.com/spf13/cobra"
712
)
813

9-
func pullCmd() *cobra.Command {
10-
return &cobra.Command{
14+
func pullCmd(dockerCli command.Cli) *cobra.Command {
15+
var opts registryOptions
16+
cmd := &cobra.Command{
1117
Use: "pull <repotag>",
1218
Short: "Pull an application from a registry",
1319
Args: cli.ExactArgs(1),
1420
RunE: func(cmd *cobra.Command, args []string) error {
15-
_, err := packager.Pull(args[0], ".")
16-
return err
21+
return runPull(dockerCli, args[0], opts)
1722
},
1823
}
24+
opts.addFlags(cmd.Flags())
25+
return cmd
26+
}
27+
28+
func runPull(dockerCli command.Cli, name string, opts registryOptions) error {
29+
ref, err := reference.ParseNormalizedNamed(name)
30+
if err != nil {
31+
return errors.Wrap(err, name)
32+
}
33+
bndl, err := bundlestore.LookupOrPullBundle(dockerCli, reference.TagNameOnly(ref), true, opts.insecureRegistries)
34+
if err != nil {
35+
return errors.Wrap(err, name)
36+
}
37+
38+
fmt.Printf("Successfully pulled %q (%s) from %s\n", bndl.Name, bndl.Version, ref.String())
39+
40+
return nil
1941
}

0 commit comments

Comments
 (0)