github.com/ali-iotechsys/cli@v20.10.0+incompatible/cli/compose/convert/compose.go (about)

     1  package convert
     2  
     3  import (
     4  	"io/ioutil"
     5  	"strings"
     6  
     7  	composetypes "github.com/docker/cli/cli/compose/types"
     8  	"github.com/docker/docker/api/types"
     9  	networktypes "github.com/docker/docker/api/types/network"
    10  	"github.com/docker/docker/api/types/swarm"
    11  )
    12  
    13  const (
    14  	// LabelNamespace is the label used to track stack resources
    15  	LabelNamespace = "com.docker.stack.namespace"
    16  )
    17  
    18  // Namespace mangles names by prepending the name
    19  type Namespace struct {
    20  	name string
    21  }
    22  
    23  // Scope prepends the namespace to a name
    24  func (n Namespace) Scope(name string) string {
    25  	return n.name + "_" + name
    26  }
    27  
    28  // Descope returns the name without the namespace prefix
    29  func (n Namespace) Descope(name string) string {
    30  	return strings.TrimPrefix(name, n.name+"_")
    31  }
    32  
    33  // Name returns the name of the namespace
    34  func (n Namespace) Name() string {
    35  	return n.name
    36  }
    37  
    38  // NewNamespace returns a new Namespace for scoping of names
    39  func NewNamespace(name string) Namespace {
    40  	return Namespace{name: name}
    41  }
    42  
    43  // AddStackLabel returns labels with the namespace label added
    44  func AddStackLabel(namespace Namespace, labels map[string]string) map[string]string {
    45  	if labels == nil {
    46  		labels = make(map[string]string)
    47  	}
    48  	labels[LabelNamespace] = namespace.name
    49  	return labels
    50  }
    51  
    52  type networkMap map[string]composetypes.NetworkConfig
    53  
    54  // Networks from the compose-file type to the engine API type
    55  func Networks(namespace Namespace, networks networkMap, servicesNetworks map[string]struct{}) (map[string]types.NetworkCreate, []string) {
    56  	if networks == nil {
    57  		networks = make(map[string]composetypes.NetworkConfig)
    58  	}
    59  
    60  	externalNetworks := []string{}
    61  	result := make(map[string]types.NetworkCreate)
    62  	for internalName := range servicesNetworks {
    63  		network := networks[internalName]
    64  		if network.External.External {
    65  			externalNetworks = append(externalNetworks, network.Name)
    66  			continue
    67  		}
    68  
    69  		createOpts := types.NetworkCreate{
    70  			Labels:     AddStackLabel(namespace, network.Labels),
    71  			Driver:     network.Driver,
    72  			Options:    network.DriverOpts,
    73  			Internal:   network.Internal,
    74  			Attachable: network.Attachable,
    75  		}
    76  
    77  		if network.Ipam.Driver != "" || len(network.Ipam.Config) > 0 {
    78  			createOpts.IPAM = &networktypes.IPAM{}
    79  		}
    80  
    81  		if network.Ipam.Driver != "" {
    82  			createOpts.IPAM.Driver = network.Ipam.Driver
    83  		}
    84  		for _, ipamConfig := range network.Ipam.Config {
    85  			config := networktypes.IPAMConfig{
    86  				Subnet: ipamConfig.Subnet,
    87  			}
    88  			createOpts.IPAM.Config = append(createOpts.IPAM.Config, config)
    89  		}
    90  
    91  		networkName := namespace.Scope(internalName)
    92  		if network.Name != "" {
    93  			networkName = network.Name
    94  		}
    95  		result[networkName] = createOpts
    96  	}
    97  
    98  	return result, externalNetworks
    99  }
   100  
   101  // Secrets converts secrets from the Compose type to the engine API type
   102  func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig) ([]swarm.SecretSpec, error) {
   103  	result := []swarm.SecretSpec{}
   104  	for name, secret := range secrets {
   105  		if secret.External.External {
   106  			continue
   107  		}
   108  
   109  		var obj swarmFileObject
   110  		var err error
   111  		if secret.Driver != "" {
   112  			obj = driverObjectConfig(namespace, name, composetypes.FileObjectConfig(secret))
   113  		} else {
   114  			obj, err = fileObjectConfig(namespace, name, composetypes.FileObjectConfig(secret))
   115  		}
   116  		if err != nil {
   117  			return nil, err
   118  		}
   119  		spec := swarm.SecretSpec{Annotations: obj.Annotations, Data: obj.Data}
   120  		if secret.Driver != "" {
   121  			spec.Driver = &swarm.Driver{
   122  				Name:    secret.Driver,
   123  				Options: secret.DriverOpts,
   124  			}
   125  		}
   126  		if secret.TemplateDriver != "" {
   127  			spec.Templating = &swarm.Driver{
   128  				Name: secret.TemplateDriver,
   129  			}
   130  		}
   131  		result = append(result, spec)
   132  	}
   133  	return result, nil
   134  }
   135  
   136  // Configs converts config objects from the Compose type to the engine API type
   137  func Configs(namespace Namespace, configs map[string]composetypes.ConfigObjConfig) ([]swarm.ConfigSpec, error) {
   138  	result := []swarm.ConfigSpec{}
   139  	for name, config := range configs {
   140  		if config.External.External {
   141  			continue
   142  		}
   143  
   144  		obj, err := fileObjectConfig(namespace, name, composetypes.FileObjectConfig(config))
   145  		if err != nil {
   146  			return nil, err
   147  		}
   148  		spec := swarm.ConfigSpec{Annotations: obj.Annotations, Data: obj.Data}
   149  		if config.TemplateDriver != "" {
   150  			spec.Templating = &swarm.Driver{
   151  				Name: config.TemplateDriver,
   152  			}
   153  		}
   154  		result = append(result, spec)
   155  	}
   156  	return result, nil
   157  }
   158  
   159  type swarmFileObject struct {
   160  	Annotations swarm.Annotations
   161  	Data        []byte
   162  }
   163  
   164  func driverObjectConfig(namespace Namespace, name string, obj composetypes.FileObjectConfig) swarmFileObject {
   165  	if obj.Name != "" {
   166  		name = obj.Name
   167  	} else {
   168  		name = namespace.Scope(name)
   169  	}
   170  
   171  	return swarmFileObject{
   172  		Annotations: swarm.Annotations{
   173  			Name:   name,
   174  			Labels: AddStackLabel(namespace, obj.Labels),
   175  		},
   176  		Data: []byte{},
   177  	}
   178  }
   179  
   180  func fileObjectConfig(namespace Namespace, name string, obj composetypes.FileObjectConfig) (swarmFileObject, error) {
   181  	data, err := ioutil.ReadFile(obj.File)
   182  	if err != nil {
   183  		return swarmFileObject{}, err
   184  	}
   185  
   186  	if obj.Name != "" {
   187  		name = obj.Name
   188  	} else {
   189  		name = namespace.Scope(name)
   190  	}
   191  
   192  	return swarmFileObject{
   193  		Annotations: swarm.Annotations{
   194  			Name:   name,
   195  			Labels: AddStackLabel(namespace, obj.Labels),
   196  		},
   197  		Data: data,
   198  	}, nil
   199  }