github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/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 obj, err := fileObjectConfig(namespace, name, composetypes.FileObjectConfig(secret)) 110 if err != nil { 111 return nil, err 112 } 113 result = append(result, swarm.SecretSpec{Annotations: obj.Annotations, Data: obj.Data}) 114 } 115 return result, nil 116 } 117 118 // Configs converts config objects from the Compose type to the engine API type 119 func Configs(namespace Namespace, configs map[string]composetypes.ConfigObjConfig) ([]swarm.ConfigSpec, error) { 120 result := []swarm.ConfigSpec{} 121 for name, config := range configs { 122 if config.External.External { 123 continue 124 } 125 126 obj, err := fileObjectConfig(namespace, name, composetypes.FileObjectConfig(config)) 127 if err != nil { 128 return nil, err 129 } 130 result = append(result, swarm.ConfigSpec{Annotations: obj.Annotations, Data: obj.Data}) 131 } 132 return result, nil 133 } 134 135 type swarmFileObject struct { 136 Annotations swarm.Annotations 137 Data []byte 138 } 139 140 func fileObjectConfig(namespace Namespace, name string, obj composetypes.FileObjectConfig) (swarmFileObject, error) { 141 data, err := ioutil.ReadFile(obj.File) 142 if err != nil { 143 return swarmFileObject{}, err 144 } 145 146 if obj.Name != "" { 147 name = obj.Name 148 } else { 149 name = namespace.Scope(name) 150 } 151 152 return swarmFileObject{ 153 Annotations: swarm.Annotations{ 154 Name: name, 155 Labels: AddStackLabel(namespace, obj.Labels), 156 }, 157 Data: data, 158 }, nil 159 }