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

Commit d59eaa9

Browse files
Transform render command as a CNAB custom action, running in the invocation image as a stateless action.
Adding a new custom parameter "com.docker.app.render-format" used only by the render action. Signed-off-by: Silvin Lubecki <[email protected]>
1 parent 7ab554b commit d59eaa9

File tree

6 files changed

+157
-51
lines changed

6 files changed

+157
-51
lines changed

cmd/cnab-run/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var (
1717
"uninstall": uninstallAction,
1818
internal.Namespace + "status": statusAction,
1919
internal.Namespace + "inspect": inspectAction,
20+
internal.Namespace + "render": renderAction,
2021
}
2122
)
2223

cmd/cnab-run/render.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/docker/app/internal"
8+
9+
"github.com/docker/app/internal/formatter"
10+
"github.com/docker/app/internal/packager"
11+
"github.com/docker/app/render"
12+
)
13+
14+
func renderAction(instanceName string) error {
15+
app, err := packager.Extract("")
16+
// todo: merge additional compose file
17+
if err != nil {
18+
return err
19+
}
20+
defer app.Cleanup()
21+
22+
imageMap, err := getBundleImageMap()
23+
if err != nil {
24+
return err
25+
}
26+
27+
formatDriver, ok := os.LookupEnv(internal.DockerRenderFormatEnvVar)
28+
if !ok {
29+
return fmt.Errorf("%q is undefined", internal.DockerRenderFormatEnvVar)
30+
}
31+
32+
parameters := packager.ExtractCNABParametersValues(packager.ExtractCNABParameterMapping(app.Parameters()), os.Environ())
33+
34+
rendered, err := render.Render(app, parameters, imageMap)
35+
if err != nil {
36+
return err
37+
}
38+
res, err := formatter.Format(rendered, formatDriver)
39+
if err != nil {
40+
return err
41+
}
42+
fmt.Printf(res)
43+
44+
return nil
45+
}

e2e/testdata/simple-bundle.json.golden

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949
"modifies": false,
5050
"stateless": true
5151
},
52+
"com.docker.app.render": {
53+
"modifies": false,
54+
"stateless": true
55+
},
5256
"com.docker.app.status": {
5357
"modifies": false
5458
}
@@ -105,6 +109,25 @@
105109
"com.docker.app.status"
106110
]
107111
},
112+
"com.docker.app.render-format": {
113+
"type": "string",
114+
"defaultValue": "yaml",
115+
"allowedValues": [
116+
"yaml",
117+
"json"
118+
],
119+
"required": false,
120+
"metadata": {
121+
"description": "Output format for the render command"
122+
},
123+
"destination": {
124+
"path": "",
125+
"env": "DOCKER_RENDER_FORMAT"
126+
},
127+
"apply-to": [
128+
"com.docker.app.render"
129+
]
130+
},
108131
"static_subdir": {
109132
"type": "string",
110133
"defaultValue": "data/static",

internal/commands/render.go

Lines changed: 65 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,88 @@
11
package commands
22

33
import (
4-
"fmt"
4+
"io"
55
"os"
66

7+
"github.com/deislabs/duffle/pkg/action"
8+
"github.com/deislabs/duffle/pkg/claim"
79
"github.com/docker/app/internal"
8-
"github.com/docker/app/internal/formatter"
9-
"github.com/docker/app/internal/packager"
10-
"github.com/docker/app/render"
11-
"github.com/docker/app/types"
1210
"github.com/docker/cli/cli"
1311
"github.com/docker/cli/cli/command"
14-
cliopts "github.com/docker/cli/opts"
12+
"github.com/pkg/errors"
1513
"github.com/spf13/cobra"
1614
)
1715

18-
var (
19-
formatDriver string
20-
renderComposeFiles []string
21-
renderParametersFile []string
22-
renderEnv []string
23-
renderOutput string
24-
)
16+
type renderOptions struct {
17+
parametersOptions
18+
registryOptions
19+
pullOptions
20+
21+
formatDriver string
22+
renderOutput string
23+
}
2524

2625
func renderCmd(dockerCli command.Cli) *cobra.Command {
26+
var opts renderOptions
2727
cmd := &cobra.Command{
2828
Use: "render <app-name> [-s key=value...] [-f parameters-file...]",
2929
Short: "Render the Compose file for the application",
3030
Long: `Render the Compose file for the application.`,
3131
Args: cli.RequiresMaxArgs(1),
3232
RunE: func(cmd *cobra.Command, args []string) error {
33-
app, err := packager.Extract(firstOrEmpty(args),
34-
types.WithParametersFiles(renderParametersFile...),
35-
types.WithComposeFiles(renderComposeFiles...),
36-
)
37-
if err != nil {
38-
return err
39-
}
40-
defer app.Cleanup()
41-
d := cliopts.ConvertKVStringsToMap(renderEnv)
42-
rendered, err := render.Render(app, d, nil)
43-
if err != nil {
44-
return err
45-
}
46-
res, err := formatter.Format(rendered, formatDriver)
47-
if err != nil {
48-
return err
49-
}
50-
if renderOutput == "-" {
51-
fmt.Fprint(dockerCli.Out(), res)
52-
} else {
53-
f, err := os.Create(renderOutput)
54-
if err != nil {
55-
return err
56-
}
57-
fmt.Fprint(f, res)
58-
}
59-
return nil
33+
return runRender(dockerCli, firstOrEmpty(args), opts)
6034
},
6135
}
62-
if internal.Experimental == "on" {
63-
cmd.Use += " [-c <compose-files>...]"
64-
cmd.Long += `- External Compose files or template Compose files can be specified with the -c flag.
65-
(Repeat the flag for multiple files). These files will be merged in order with
66-
the app's own Compose file.`
67-
cmd.Flags().StringArrayVarP(&renderComposeFiles, "compose-files", "c", []string{}, "Override Compose file")
68-
}
69-
cmd.Flags().StringArrayVarP(&renderParametersFile, "parameters-files", "f", []string{}, "Override with parameters from files")
70-
cmd.Flags().StringArrayVarP(&renderEnv, "set", "s", []string{}, "Override parameters values")
71-
cmd.Flags().StringVarP(&renderOutput, "output", "o", "-", "Output file")
72-
cmd.Flags().StringVar(&formatDriver, "formatter", "yaml", "Configure the output format (yaml|json)")
36+
opts.parametersOptions.addFlags(cmd.Flags())
37+
opts.registryOptions.addFlags(cmd.Flags())
38+
opts.pullOptions.addFlags(cmd.Flags())
39+
cmd.Flags().StringVarP(&opts.renderOutput, "output", "o", "-", "Output file")
40+
cmd.Flags().StringVar(&opts.formatDriver, "formatter", "yaml", "Configure the output format (yaml|json)")
41+
7342
return cmd
7443
}
44+
45+
func runRender(dockerCli command.Cli, appname string, opts renderOptions) error {
46+
defer muteDockerCli(dockerCli)()
47+
48+
c, err := claim.New("render")
49+
if err != nil {
50+
return err
51+
}
52+
driverImpl, err := prepareDriver(dockerCli, bindMount{})
53+
if err != nil {
54+
return err
55+
}
56+
bundle, err := resolveBundle(dockerCli, appname, opts.pull, opts.insecureRegistries)
57+
if err != nil {
58+
return err
59+
}
60+
c.Bundle = bundle
61+
62+
parameters, err := mergeBundleParameters(c.Bundle,
63+
withFileParameters(opts.parametersFiles),
64+
withCommandLineParameters(opts.overrides),
65+
)
66+
if err != nil {
67+
return err
68+
}
69+
c.Parameters = parameters
70+
c.Parameters[internal.Namespace+"render-format"] = opts.formatDriver
71+
72+
a := &action.RunCustom{
73+
Action: internal.Namespace + "render",
74+
Driver: driverImpl,
75+
}
76+
77+
var writer io.Writer = dockerCli.Out()
78+
if opts.renderOutput != "-" {
79+
f, err := os.Create(opts.renderOutput)
80+
if err != nil {
81+
return err
82+
}
83+
defer f.Close()
84+
writer = f
85+
}
86+
err = a.Run(c, nil, writer)
87+
return errors.Wrap(err, "Render failed")
88+
}

internal/names.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const (
3131
// DockerKubernetesNamespaceEnvVar is the environment variable set by the CNAB runtime to select
3232
// the kubernetes namespace.
3333
DockerKubernetesNamespaceEnvVar = "DOCKER_KUBERNETES_NAMESPACE"
34+
// DockerRenderFormatEnvVar is the environment variable set by the CNAB runtime to select
35+
// the render output format.
36+
DockerRenderFormatEnvVar = "DOCKER_RENDER_FORMAT"
3437
)
3538

3639
var (

internal/packager/cnab.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ func ToCNAB(app *types.App, invocationImageName string) (*bundle.Bundle, error)
4949
internal.Namespace + "status",
5050
},
5151
},
52+
internal.Namespace + "render-format": {
53+
DataType: "string",
54+
AllowedValues: []interface{}{
55+
"yaml",
56+
"json",
57+
},
58+
DefaultValue: "yaml",
59+
Destination: &bundle.Location{
60+
EnvironmentVariable: internal.DockerRenderFormatEnvVar,
61+
},
62+
Metadata: &bundle.ParameterMetadata{
63+
Description: "Output format for the render command",
64+
},
65+
ApplyTo: []string{
66+
internal.Namespace + "render",
67+
},
5268
},
5369
}
5470
for name, envVar := range mapping.ParameterToCNABEnv {
@@ -97,6 +113,10 @@ func ToCNAB(app *types.App, invocationImageName string) (*bundle.Bundle, error)
97113
Modifies: false,
98114
Stateless: true,
99115
},
116+
internal.Namespace + "render": {
117+
Modifies: false,
118+
Stateless: true,
119+
},
100120
internal.Namespace + "status": {
101121
Modifies: false,
102122
},

0 commit comments

Comments
 (0)