github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/packager/cnab.go (about) 1 package packager 2 3 import ( 4 "encoding/json" 5 6 "github.com/deislabs/cnab-go/bundle" 7 "github.com/deislabs/cnab-go/bundle/definition" 8 "github.com/docker/app/internal" 9 "github.com/docker/app/internal/compose" 10 "github.com/docker/app/types" 11 "github.com/sirupsen/logrus" 12 ) 13 14 const ( 15 // CNABVersion1_0_0 is the CNAB Schema version 1.0.0 16 CNABVersion1_0_0 = "v1.0.0" 17 ) 18 19 // DockerAppArgs represent the object passed to the invocation image 20 // by Docker App. 21 type DockerAppArgs struct { 22 // Labels are the labels to add to containers on run 23 Labels map[string]string `json:"labels,omitempty"` 24 } 25 26 // ToCNAB creates a CNAB bundle from an app package 27 func ToCNAB(app *types.App, invocationImageName string) (*bundle.Bundle, error) { 28 mapping := ExtractCNABParameterMapping(app.Parameters()) 29 flatParameters := app.Parameters().Flatten() 30 definitions := definition.Definitions{ 31 internal.ParameterArgs: { 32 Type: "string", 33 Default: "", 34 Title: "Arguments", 35 Description: "Arguments that are passed by file to the invocation image", 36 }, 37 internal.ParameterOrchestratorName: { 38 Type: "string", 39 Enum: []interface{}{ 40 "", 41 "swarm", 42 "kubernetes", 43 }, 44 Default: "", 45 Title: "Orchestrator", 46 Description: "Orchestrator on which to deploy", 47 }, 48 internal.ParameterKubernetesNamespaceName: { 49 Type: "string", 50 Default: "", 51 Title: "Namespace", 52 Description: "Namespace in which to deploy", 53 }, 54 internal.ParameterRenderFormatName: { 55 Type: "string", 56 Enum: []interface{}{ 57 "yaml", 58 "json", 59 }, 60 Default: "yaml", 61 Title: "Render format", 62 Description: "Output format for the render command", 63 }, 64 internal.ParameterInspectFormatName: { 65 Type: "string", 66 Enum: []interface{}{ 67 "json", 68 "pretty", 69 }, 70 Default: "json", 71 Title: "Inspect format", 72 Description: "Output format for the inspect command", 73 }, 74 internal.ParameterShareRegistryCredsName: { 75 Type: "boolean", 76 Default: false, 77 Title: "Share registry credentials", 78 Description: "Share registry credentials with the invocation image", 79 }, 80 } 81 parameters := map[string]bundle.Parameter{ 82 internal.ParameterArgs: { 83 Destination: &bundle.Location{ 84 Path: internal.DockerArgsPath, 85 }, 86 ApplyTo: []string{ 87 "install", 88 "upgrade", 89 }, 90 Definition: internal.ParameterArgs, 91 }, 92 internal.ParameterOrchestratorName: { 93 Destination: &bundle.Location{ 94 EnvironmentVariable: internal.DockerStackOrchestratorEnvVar, 95 }, 96 ApplyTo: []string{ 97 "install", 98 "upgrade", 99 "uninstall", 100 internal.ActionStatusName, 101 }, 102 Definition: internal.ParameterOrchestratorName, 103 }, 104 internal.ParameterKubernetesNamespaceName: { 105 Destination: &bundle.Location{ 106 EnvironmentVariable: internal.DockerKubernetesNamespaceEnvVar, 107 }, 108 ApplyTo: []string{ 109 "install", 110 "upgrade", 111 "uninstall", 112 internal.ActionStatusName, 113 }, 114 Definition: internal.ParameterKubernetesNamespaceName, 115 }, 116 internal.ParameterRenderFormatName: { 117 Destination: &bundle.Location{ 118 EnvironmentVariable: internal.DockerRenderFormatEnvVar, 119 }, 120 ApplyTo: []string{ 121 internal.ActionRenderName, 122 }, 123 Definition: internal.ParameterRenderFormatName, 124 }, 125 internal.ParameterInspectFormatName: { 126 Destination: &bundle.Location{ 127 EnvironmentVariable: internal.DockerInspectFormatEnvVar, 128 }, 129 ApplyTo: []string{ 130 internal.ActionInspectName, 131 }, 132 Definition: internal.ParameterInspectFormatName, 133 }, 134 internal.ParameterShareRegistryCredsName: { 135 Destination: &bundle.Location{ 136 EnvironmentVariable: "DOCKER_SHARE_REGISTRY_CREDS", 137 }, 138 Definition: internal.ParameterShareRegistryCredsName, 139 }, 140 } 141 for name, envVar := range mapping.ParameterToCNABEnv { 142 definitions[name] = &definition.Schema{ 143 Type: "string", 144 Default: flatParameters[name], 145 } 146 parameters[name] = bundle.Parameter{ 147 Destination: &bundle.Location{ 148 EnvironmentVariable: envVar, 149 }, 150 Definition: name, 151 } 152 } 153 var maintainers []bundle.Maintainer 154 for _, m := range app.Metadata().Maintainers { 155 maintainers = append(maintainers, bundle.Maintainer{ 156 Email: m.Email, 157 Name: m.Name, 158 }) 159 } 160 161 bundleImages, err := extractBundleImages(app.Composes()) 162 if err != nil { 163 return nil, err 164 } 165 166 payload, err := newCustomPayload() 167 if err != nil { 168 return nil, err 169 } 170 171 bndl := &bundle.Bundle{ 172 SchemaVersion: CNABVersion1_0_0, 173 Custom: map[string]interface{}{ 174 internal.CustomDockerAppName: DockerAppCustom{ 175 Version: DockerAppPayloadVersionCurrent, 176 Payload: payload, 177 }, 178 }, 179 Credentials: map[string]bundle.Credential{ 180 internal.CredentialDockerContextName: { 181 Location: bundle.Location{ 182 Path: internal.CredentialDockerContextPath, 183 }, 184 }, 185 internal.CredentialRegistryName: { 186 Location: bundle.Location{ 187 Path: internal.CredentialRegistryPath, 188 }, 189 }, 190 }, 191 Description: app.Metadata().Description, 192 InvocationImages: []bundle.InvocationImage{ 193 { 194 BaseImage: bundle.BaseImage{ 195 Image: invocationImageName, 196 ImageType: "docker", 197 }, 198 }, 199 }, 200 Maintainers: maintainers, 201 Name: app.Metadata().Name, 202 Version: app.Metadata().Version, 203 Parameters: parameters, 204 Definitions: definitions, 205 Actions: map[string]bundle.Action{ 206 internal.ActionInspectName: { 207 Modifies: false, 208 Stateless: true, 209 }, 210 internal.ActionRenderName: { 211 Modifies: false, 212 Stateless: true, 213 }, 214 internal.ActionStatusName: { 215 Modifies: false, 216 }, 217 internal.ActionStatusJSONName: { 218 Modifies: false, 219 }, 220 }, 221 Images: bundleImages, 222 } 223 224 if js, err := json.Marshal(bndl); err == nil { 225 logrus.Debugf("App converted to CNAB %q", string(js)) 226 } 227 228 return bndl, nil 229 } 230 231 func extractBundleImages(composeFiles [][]byte) (map[string]bundle.Image, error) { 232 _, images, err := compose.Load(composeFiles) 233 if err != nil { 234 return nil, err 235 } 236 237 bundleImages := map[string]bundle.Image{} 238 for serviceName, imageName := range images { 239 bundleImages[serviceName] = bundle.Image{ 240 Description: imageName, 241 BaseImage: bundle.BaseImage{ 242 Image: imageName, 243 ImageType: "docker", 244 }, 245 } 246 } 247 return bundleImages, nil 248 }