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  }