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

Commit 99c2957

Browse files
committed
Image inspect non-app CNABs
Allow `image inspect` of CNABs not created with docker app. The command will output basic information that is read from the bundle.json file including: * metadata (version, name, description, maintainers) * services (name and image) * parameters (including default values if present) Signed-off-by: Nick Adcock <[email protected]>
1 parent 3328d80 commit 99c2957

File tree

5 files changed

+294
-1
lines changed

5 files changed

+294
-1
lines changed

internal/commands/image/inspect.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/deislabs/cnab-go/action"
1111
"github.com/docker/app/internal"
1212
"github.com/docker/app/internal/cnab"
13+
"github.com/docker/app/internal/inspect"
1314
appstore "github.com/docker/app/internal/store"
1415
"github.com/docker/cli/cli"
1516
"github.com/docker/cli/cli/command"
@@ -88,7 +89,12 @@ func runInspect(dockerCli command.Cli, appname string, opts inspectOptions) erro
8889

8990
installation.SetParameter(internal.ParameterInspectFormatName, format)
9091

91-
if err := a.Run(&installation.Claim, nil); err != nil {
92+
err = a.Run(&installation.Claim, nil)
93+
if err == action.ErrUndefinedAction {
94+
err = inspect.ImageInspectCNAB(os.Stdout, bndl.Bundle, format)
95+
}
96+
97+
if err != nil {
9298
return fmt.Errorf("inspect failed: %s\n%s", err, errBuf)
9399
}
94100
return nil

internal/inspect/inspect.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,49 @@ func ImageInspect(out io.Writer, app *types.App, argParameters map[string]string
114114
return printImageAppInfo(out, appInfo, outputFormat)
115115
}
116116

117+
func ImageInspectCNAB(out io.Writer, bndl *bundle.Bundle, outputFormat string) error {
118+
meta := metadata.AppMetadata{
119+
Description: bndl.Description,
120+
Name: bndl.Name,
121+
Version: bndl.Version,
122+
Maintainers: []metadata.Maintainer{},
123+
}
124+
for _, m := range bndl.Maintainers {
125+
meta.Maintainers = append(meta.Maintainers, metadata.Maintainer{
126+
Name: m.Name,
127+
Email: m.Email,
128+
})
129+
}
130+
131+
paramKeys := []string{}
132+
params := map[string]string{}
133+
for _, v := range bndl.Parameters {
134+
paramKeys = append(paramKeys, v.Definition)
135+
if d, ok := bndl.Definitions[v.Definition]; ok && d.Default != nil {
136+
params[v.Definition] = fmt.Sprint(d.Default)
137+
} else {
138+
params[v.Definition] = ""
139+
}
140+
}
141+
142+
services := []Service{}
143+
for k, v := range bndl.Images {
144+
services = append(services, Service{
145+
Name: k,
146+
Image: v.Image,
147+
})
148+
}
149+
150+
appInfo := ImageAppInfo{
151+
Metadata: meta,
152+
parametersKeys: paramKeys,
153+
Parameters: params,
154+
Services: services,
155+
}
156+
157+
return printImageAppInfo(out, appInfo, outputFormat)
158+
}
159+
117160
func printAppInfo(out io.Writer, app AppInfo, format string) error {
118161
switch format {
119162
case "pretty":

internal/inspect/inspect_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package inspect
22

33
import (
44
"bytes"
5+
"encoding/json"
56
"fmt"
67
"os"
78
"testing"
@@ -132,6 +133,22 @@ text: hello`),
132133
})
133134
}
134135

136+
func TestImageInspectCNAB(t *testing.T) {
137+
s := golden.Get(t, "bundle-json.golden")
138+
var bndl bundle.Bundle
139+
err := json.Unmarshal(s, &bndl)
140+
assert.NilError(t, err)
141+
142+
expected := golden.Get(t, "inspect-bundle-json.golden")
143+
144+
outBuffer := new(bytes.Buffer)
145+
err = ImageInspectCNAB(outBuffer, &bndl, "json")
146+
assert.NilError(t, err)
147+
148+
result := outBuffer.String()
149+
assert.Equal(t, string(expected), result)
150+
}
151+
135152
func testImageInspect(t *testing.T, dir *fs.Dir, testcase inspectTestCase, suffix string) {
136153
app, err := types.NewAppFromDefaultFiles(dir.Join(testcase.name))
137154
assert.NilError(t, err)
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
{
2+
"schemaVersion": "v1.0.0",
3+
"name": "packing",
4+
"version": "0.1.0",
5+
"description": "hello",
6+
"maintainers": [
7+
{
8+
"name": "dev1",
9+
"email": "[email protected]"
10+
},
11+
{
12+
"name": "dev2",
13+
"email": "[email protected]"
14+
}
15+
],
16+
"invocationImages": [
17+
{
18+
"imageType": "docker",
19+
"image": "test-image"
20+
}
21+
],
22+
"images": {
23+
"app-watcher": {
24+
"imageType": "docker",
25+
"image": "watcher",
26+
"description": "watcher"
27+
},
28+
"debug": {
29+
"imageType": "docker",
30+
"image": "busybox:latest",
31+
"description": "busybox:latest"
32+
},
33+
"front": {
34+
"imageType": "docker",
35+
"image": "nginx",
36+
"description": "nginx"
37+
},
38+
"monitor": {
39+
"imageType": "docker",
40+
"image": "busybox:latest",
41+
"description": "busybox:latest"
42+
}
43+
},
44+
"actions": {
45+
"com.docker.app.inspect": {
46+
"stateless": true
47+
},
48+
"com.docker.app.render": {
49+
"stateless": true
50+
},
51+
"io.cnab.status": {},
52+
"io.cnab.status+json": {}
53+
},
54+
"parameters": {
55+
"com.docker.app.args": {
56+
"definition": "com.docker.app.args",
57+
"applyTo": [
58+
"install",
59+
"upgrade"
60+
],
61+
"destination": {
62+
"path": "/cnab/app/args.json"
63+
}
64+
},
65+
"com.docker.app.inspect-format": {
66+
"definition": "com.docker.app.inspect-format",
67+
"applyTo": [
68+
"com.docker.app.inspect"
69+
],
70+
"destination": {
71+
"env": "DOCKER_INSPECT_FORMAT"
72+
}
73+
},
74+
"com.docker.app.kubernetes-namespace": {
75+
"definition": "com.docker.app.kubernetes-namespace",
76+
"applyTo": [
77+
"install",
78+
"upgrade",
79+
"uninstall",
80+
"io.cnab.status"
81+
],
82+
"destination": {
83+
"env": "DOCKER_KUBERNETES_NAMESPACE"
84+
}
85+
},
86+
"com.docker.app.orchestrator": {
87+
"definition": "com.docker.app.orchestrator",
88+
"applyTo": [
89+
"install",
90+
"upgrade",
91+
"uninstall",
92+
"io.cnab.status"
93+
],
94+
"destination": {
95+
"env": "DOCKER_STACK_ORCHESTRATOR"
96+
}
97+
},
98+
"com.docker.app.render-format": {
99+
"definition": "com.docker.app.render-format",
100+
"applyTo": [
101+
"com.docker.app.render"
102+
],
103+
"destination": {
104+
"env": "DOCKER_RENDER_FORMAT"
105+
}
106+
},
107+
"com.docker.app.share-registry-creds": {
108+
"definition": "com.docker.app.share-registry-creds",
109+
"destination": {
110+
"env": "DOCKER_SHARE_REGISTRY_CREDS"
111+
}
112+
},
113+
"watcher.cmd": {
114+
"definition": "watcher.cmd",
115+
"destination": {
116+
"env": "docker_param1"
117+
}
118+
}
119+
},
120+
"credentials": {
121+
"com.docker.app.registry-creds": {
122+
"path": "/cnab/app/registry-creds.json"
123+
},
124+
"docker.context": {
125+
"path": "/cnab/app/context.dockercontext"
126+
}
127+
},
128+
"definitions": {
129+
"com.docker.app.args": {
130+
"default": "",
131+
"description": "Arguments that are passed by file to the invocation image",
132+
"title": "Arguments",
133+
"type": "string"
134+
},
135+
"com.docker.app.inspect-format": {
136+
"default": "json",
137+
"description": "Output format for the inspect command",
138+
"enum": [
139+
"json",
140+
"pretty"
141+
],
142+
"title": "Inspect format",
143+
"type": "string"
144+
},
145+
"com.docker.app.kubernetes-namespace": {
146+
"default": "",
147+
"description": "Namespace in which to deploy",
148+
"title": "Namespace",
149+
"type": "string"
150+
},
151+
"com.docker.app.orchestrator": {
152+
"default": "",
153+
"description": "Orchestrator on which to deploy",
154+
"enum": [
155+
"",
156+
"swarm",
157+
"kubernetes"
158+
],
159+
"title": "Orchestrator",
160+
"type": "string"
161+
},
162+
"com.docker.app.render-format": {
163+
"default": "yaml",
164+
"description": "Output format for the render command",
165+
"enum": [
166+
"yaml",
167+
"json"
168+
],
169+
"title": "Render format",
170+
"type": "string"
171+
},
172+
"com.docker.app.share-registry-creds": {
173+
"default": false,
174+
"description": "Share registry credentials with the invocation image",
175+
"title": "Share registry credentials",
176+
"type": "boolean"
177+
},
178+
"watcher.cmd": {
179+
"default": "foo",
180+
"type": "string"
181+
}
182+
}
183+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"Metadata": {
3+
"version": "0.1.0",
4+
"name": "packing",
5+
"description": "hello",
6+
"maintainers": [
7+
{
8+
"name": "dev1",
9+
"email": "[email protected]"
10+
},
11+
{
12+
"name": "dev2",
13+
"email": "[email protected]"
14+
}
15+
]
16+
},
17+
"Services": [
18+
{
19+
"Name": "app-watcher",
20+
"Image": "watcher"
21+
},
22+
{
23+
"Name": "debug",
24+
"Image": "busybox:latest"
25+
},
26+
{
27+
"Name": "front",
28+
"Image": "nginx"
29+
},
30+
{
31+
"Name": "monitor",
32+
"Image": "busybox:latest"
33+
}
34+
],
35+
"Parameters": {
36+
"com.docker.app.args": "",
37+
"com.docker.app.inspect-format": "json",
38+
"com.docker.app.kubernetes-namespace": "",
39+
"com.docker.app.orchestrator": "",
40+
"com.docker.app.render-format": "yaml",
41+
"com.docker.app.share-registry-creds": "false",
42+
"watcher.cmd": "foo"
43+
}
44+
}

0 commit comments

Comments
 (0)