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 }