github.com/docker/compose-on-kubernetes@v0.5.0/internal/conversions/v1alpha3.go (about) 1 package conversions 2 3 import ( 4 "regexp" 5 "strconv" 6 "strings" 7 8 composetypes "github.com/docker/cli/cli/compose/types" 9 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3" 10 "github.com/docker/compose-on-kubernetes/internal/internalversion" 11 "github.com/docker/compose-on-kubernetes/internal/parsing" 12 "k8s.io/apimachinery/pkg/conversion" 13 "k8s.io/apimachinery/pkg/runtime" 14 ) 15 16 // RegisterV1alpha3Conversions adds conversion functions to the given scheme. 17 // Public to allow building arbitrary schemes. 18 func RegisterV1alpha3Conversions(scheme *runtime.Scheme) error { 19 return scheme.AddConversionFuncs( 20 ownerToInternalV1alpha3, 21 ownerFromInternalV1alpha3, 22 stackToInternalV1alpha3, 23 stackFromInternalV1alpha3, 24 stackListToInternalV1alpha3, 25 stackListFromInternalV1alpha3, 26 ) 27 } 28 29 func ownerToInternalV1alpha3(in *v1alpha3.Owner, out *internalversion.Owner, _ conversion.Scope) error { 30 out.ObjectMeta = in.ObjectMeta 31 out.Owner = in.Owner 32 return nil 33 } 34 35 func ownerFromInternalV1alpha3(in *internalversion.Owner, out *v1alpha3.Owner, _ conversion.Scope) error { 36 out.ObjectMeta = in.ObjectMeta 37 out.Owner = in.Owner 38 return nil 39 } 40 41 func stackToInternalV1alpha3(in *v1alpha3.Stack, out *internalversion.Stack, _ conversion.Scope) error { 42 out.ObjectMeta = in.ObjectMeta 43 out.Spec.Stack = in.Spec 44 if in.Status != nil { 45 out.Status = &internalversion.StackStatus{ 46 Message: in.Status.Message, 47 Phase: internalversion.StackPhase(in.Status.Phase), 48 } 49 } else { 50 out.Status = nil 51 } 52 return nil 53 } 54 55 func stackFromInternalV1alpha3(in *internalversion.Stack, out *v1alpha3.Stack, _ conversion.Scope) error { 56 out.ObjectMeta = in.ObjectMeta 57 out.Spec = in.Spec.Stack 58 if in.Spec.Stack == nil && in.Spec.ComposeFile != "" { 59 composeConfig, err := parsing.LoadStackData([]byte(in.Spec.ComposeFile), map[string]string{}) 60 if err == nil { 61 return err 62 } 63 // This should only occur if old v1beta1-era objects are present in storage 64 // In that case we need to provide a Spec 65 config := FromComposeConfig(composeConfig) 66 out.Spec = config 67 } 68 if in.Status != nil { 69 out.Status = &v1alpha3.StackStatus{ 70 Message: in.Status.Message, 71 Phase: v1alpha3.StackPhase(in.Status.Phase), 72 } 73 } else { 74 out.Status = nil 75 } 76 return nil 77 } 78 79 // FromComposeConfig converts a cli/compose/types.Config to a v1alpha3 Config struct. 80 // Use it only for backward compat between v1beta1 and later. 81 func FromComposeConfig(c *composetypes.Config) *v1alpha3.StackSpec { 82 if c == nil { 83 return nil 84 } 85 serviceConfigs := make([]v1alpha3.ServiceConfig, len(c.Services)) 86 for i, s := range c.Services { 87 serviceConfigs[i] = fromComposeServiceConfig(s) 88 } 89 return &v1alpha3.StackSpec{ 90 Services: serviceConfigs, 91 Secrets: fromComposeSecrets(c.Secrets), 92 Configs: fromComposeConfigs(c.Configs), 93 } 94 } 95 96 func fromComposeSecrets(s map[string]composetypes.SecretConfig) map[string]v1alpha3.SecretConfig { 97 if s == nil { 98 return nil 99 } 100 m := map[string]v1alpha3.SecretConfig{} 101 for key, value := range s { 102 m[key] = v1alpha3.SecretConfig{ 103 Name: value.Name, 104 File: value.File, 105 External: v1alpha3.External{ 106 Name: value.External.Name, 107 External: value.External.External, 108 }, 109 Labels: value.Labels, 110 } 111 } 112 return m 113 } 114 115 func fromComposeConfigs(s map[string]composetypes.ConfigObjConfig) map[string]v1alpha3.ConfigObjConfig { 116 if s == nil { 117 return nil 118 } 119 m := map[string]v1alpha3.ConfigObjConfig{} 120 for key, value := range s { 121 m[key] = v1alpha3.ConfigObjConfig{ 122 Name: value.Name, 123 File: value.File, 124 External: v1alpha3.External{ 125 Name: value.External.Name, 126 External: value.External.External, 127 }, 128 Labels: value.Labels, 129 } 130 } 131 return m 132 } 133 134 func fromComposeServiceConfig(s composetypes.ServiceConfig) v1alpha3.ServiceConfig { 135 var userID *int64 136 if s.User != "" { 137 numerical, err := strconv.Atoi(s.User) 138 if err == nil { 139 unixUserID := int64(numerical) 140 userID = &unixUserID 141 } 142 } 143 return v1alpha3.ServiceConfig{ 144 Name: s.Name, 145 CapAdd: s.CapAdd, 146 CapDrop: s.CapDrop, 147 Command: s.Command, 148 Configs: fromComposeServiceConfigs(s.Configs), 149 Deploy: v1alpha3.DeployConfig{ 150 Mode: s.Deploy.Mode, 151 Replicas: s.Deploy.Replicas, 152 Labels: s.Deploy.Labels, 153 UpdateConfig: fromComposeUpdateConfig(s.Deploy.UpdateConfig), 154 Resources: fromComposeResources(s.Deploy.Resources), 155 RestartPolicy: fromComposeRestartPolicy(s.Deploy.RestartPolicy), 156 Placement: fromComposePlacement(s.Deploy.Placement), 157 }, 158 Entrypoint: s.Entrypoint, 159 Environment: s.Environment, 160 ExtraHosts: s.ExtraHosts, 161 Hostname: s.Hostname, 162 HealthCheck: fromComposeHealthcheck(s.HealthCheck), 163 Image: s.Image, 164 Ipc: s.Ipc, 165 Labels: s.Labels, 166 Pid: s.Pid, 167 Ports: fromComposePorts(s.Ports), 168 Privileged: s.Privileged, 169 ReadOnly: s.ReadOnly, 170 Secrets: fromComposeServiceSecrets(s.Secrets), 171 StdinOpen: s.StdinOpen, 172 StopGracePeriod: composetypes.ConvertDurationPtr(s.StopGracePeriod), 173 Tmpfs: s.Tmpfs, 174 Tty: s.Tty, 175 User: userID, 176 Volumes: fromComposeServiceVolumeConfig(s.Volumes), 177 WorkingDir: s.WorkingDir, 178 } 179 } 180 181 func fromComposePorts(ports []composetypes.ServicePortConfig) []v1alpha3.ServicePortConfig { 182 if ports == nil { 183 return nil 184 } 185 p := make([]v1alpha3.ServicePortConfig, len(ports)) 186 for i, port := range ports { 187 p[i] = v1alpha3.ServicePortConfig{ 188 Mode: port.Mode, 189 Target: port.Target, 190 Published: port.Published, 191 Protocol: port.Protocol, 192 } 193 } 194 return p 195 } 196 197 func fromComposeServiceSecrets(secrets []composetypes.ServiceSecretConfig) []v1alpha3.ServiceSecretConfig { 198 if secrets == nil { 199 return nil 200 } 201 c := make([]v1alpha3.ServiceSecretConfig, len(secrets)) 202 for i, secret := range secrets { 203 c[i] = v1alpha3.ServiceSecretConfig{ 204 Source: secret.Source, 205 Target: secret.Target, 206 UID: secret.UID, 207 Mode: secret.Mode, 208 } 209 } 210 return c 211 } 212 213 func fromComposeServiceConfigs(configs []composetypes.ServiceConfigObjConfig) []v1alpha3.ServiceConfigObjConfig { 214 if configs == nil { 215 return nil 216 } 217 c := make([]v1alpha3.ServiceConfigObjConfig, len(configs)) 218 for i, config := range configs { 219 c[i] = v1alpha3.ServiceConfigObjConfig{ 220 Source: config.Source, 221 Target: config.Target, 222 UID: config.UID, 223 Mode: config.Mode, 224 } 225 } 226 return c 227 } 228 229 func fromComposeHealthcheck(h *composetypes.HealthCheckConfig) *v1alpha3.HealthCheckConfig { 230 if h == nil { 231 return nil 232 } 233 return &v1alpha3.HealthCheckConfig{ 234 Test: h.Test, 235 Timeout: composetypes.ConvertDurationPtr(h.Timeout), 236 Interval: composetypes.ConvertDurationPtr(h.Interval), 237 Retries: h.Retries, 238 } 239 } 240 241 func fromComposePlacement(p composetypes.Placement) v1alpha3.Placement { 242 return v1alpha3.Placement{ 243 Constraints: fromComposeConstraints(p.Constraints), 244 } 245 } 246 247 var constraintEquals = regexp.MustCompile(`([\w\.]*)\W*(==|!=)\W*([\w\.]*)`) 248 249 const ( 250 swarmOs = "node.platform.os" 251 swarmArch = "node.platform.arch" 252 swarmHostname = "node.hostname" 253 swarmLabelPrefix = "node.labels." 254 ) 255 256 func fromComposeConstraints(s []string) *v1alpha3.Constraints { 257 if len(s) == 0 { 258 return nil 259 } 260 constraints := &v1alpha3.Constraints{} 261 for _, constraint := range s { 262 matches := constraintEquals.FindStringSubmatch(constraint) 263 if len(matches) == 4 { 264 key := matches[1] 265 operator := matches[2] 266 value := matches[3] 267 constraint := &v1alpha3.Constraint{ 268 Operator: operator, 269 Value: value, 270 } 271 switch { 272 case key == swarmOs: 273 constraints.OperatingSystem = constraint 274 case key == swarmArch: 275 constraints.Architecture = constraint 276 case key == swarmHostname: 277 constraints.Hostname = constraint 278 case strings.HasPrefix(key, swarmLabelPrefix): 279 if constraints.MatchLabels == nil { 280 constraints.MatchLabels = map[string]v1alpha3.Constraint{} 281 } 282 constraints.MatchLabels[strings.TrimPrefix(key, swarmLabelPrefix)] = *constraint 283 } 284 } 285 } 286 return constraints 287 } 288 289 func fromComposeResources(r composetypes.Resources) v1alpha3.Resources { 290 return v1alpha3.Resources{ 291 Limits: fromComposeResourcesResource(r.Limits), 292 Reservations: fromComposeResourcesResource(r.Reservations), 293 } 294 } 295 296 func fromComposeResourcesResource(r *composetypes.Resource) *v1alpha3.Resource { 297 if r == nil { 298 return nil 299 } 300 return &v1alpha3.Resource{ 301 MemoryBytes: int64(r.MemoryBytes), 302 NanoCPUs: r.NanoCPUs, 303 } 304 } 305 306 func fromComposeUpdateConfig(u *composetypes.UpdateConfig) *v1alpha3.UpdateConfig { 307 if u == nil { 308 return nil 309 } 310 return &v1alpha3.UpdateConfig{ 311 Parallelism: u.Parallelism, 312 } 313 } 314 315 func fromComposeRestartPolicy(r *composetypes.RestartPolicy) *v1alpha3.RestartPolicy { 316 if r == nil { 317 return nil 318 } 319 return &v1alpha3.RestartPolicy{ 320 Condition: r.Condition, 321 } 322 } 323 324 func fromComposeServiceVolumeConfig(vs []composetypes.ServiceVolumeConfig) []v1alpha3.ServiceVolumeConfig { 325 if vs == nil { 326 return nil 327 } 328 volumes := []v1alpha3.ServiceVolumeConfig{} 329 for _, v := range vs { 330 volumes = append(volumes, v1alpha3.ServiceVolumeConfig{ 331 Type: v.Type, 332 Source: v.Source, 333 Target: v.Target, 334 ReadOnly: v.ReadOnly, 335 }) 336 } 337 return volumes 338 } 339 340 // StackFromInternalV1alpha3 converts an internal stack to v1alpha3 flavor 341 func StackFromInternalV1alpha3(in *internalversion.Stack) (*v1alpha3.Stack, error) { 342 if in == nil { 343 return nil, nil 344 } 345 out := new(v1alpha3.Stack) 346 err := stackFromInternalV1alpha3(in, out, nil) 347 return out, err 348 } 349 350 func stackListToInternalV1alpha3(in *v1alpha3.StackList, out *internalversion.StackList, s conversion.Scope) error { 351 out.ListMeta = in.ListMeta 352 if in.Items != nil { 353 inSlice, outSlice := &in.Items, &out.Items 354 *outSlice = make([]internalversion.Stack, len(*inSlice)) 355 for i := range *inSlice { 356 if err := stackToInternalV1alpha3(&(*inSlice)[i], &(*outSlice)[i], s); err != nil { 357 return err 358 } 359 } 360 } else { 361 out.Items = nil 362 } 363 return nil 364 } 365 366 func stackListFromInternalV1alpha3(in *internalversion.StackList, out *v1alpha3.StackList, s conversion.Scope) error { 367 out.ListMeta = in.ListMeta 368 if in.Items != nil { 369 inSlice, outSlice := &in.Items, &out.Items 370 *outSlice = make([]v1alpha3.Stack, len(*inSlice)) 371 for i := range *inSlice { 372 if err := stackFromInternalV1alpha3(&(*inSlice)[i], &(*outSlice)[i], s); err != nil { 373 return err 374 } 375 } 376 } else { 377 out.Items = make([]v1alpha3.Stack, 0) 378 } 379 return nil 380 }