github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/daemon/cluster/convert/container.go (about) 1 package convert // import "github.com/docker/docker/daemon/cluster/convert" 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/docker/docker/api/types/container" 8 mounttypes "github.com/docker/docker/api/types/mount" 9 types "github.com/docker/docker/api/types/swarm" 10 "github.com/docker/go-units" 11 swarmapi "github.com/docker/swarmkit/api" 12 gogotypes "github.com/gogo/protobuf/types" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 ) 16 17 func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec { 18 if c == nil { 19 return nil 20 } 21 containerSpec := &types.ContainerSpec{ 22 Image: c.Image, 23 Labels: c.Labels, 24 Command: c.Command, 25 Args: c.Args, 26 Hostname: c.Hostname, 27 Env: c.Env, 28 Dir: c.Dir, 29 User: c.User, 30 Groups: c.Groups, 31 StopSignal: c.StopSignal, 32 TTY: c.TTY, 33 OpenStdin: c.OpenStdin, 34 ReadOnly: c.ReadOnly, 35 Hosts: c.Hosts, 36 Secrets: secretReferencesFromGRPC(c.Secrets), 37 Configs: configReferencesFromGRPC(c.Configs), 38 Isolation: IsolationFromGRPC(c.Isolation), 39 Init: initFromGRPC(c.Init), 40 Sysctls: c.Sysctls, 41 CapabilityAdd: c.CapabilityAdd, 42 CapabilityDrop: c.CapabilityDrop, 43 Ulimits: ulimitsFromGRPC(c.Ulimits), 44 } 45 46 if c.DNSConfig != nil { 47 containerSpec.DNSConfig = &types.DNSConfig{ 48 Nameservers: c.DNSConfig.Nameservers, 49 Search: c.DNSConfig.Search, 50 Options: c.DNSConfig.Options, 51 } 52 } 53 54 // Privileges 55 if c.Privileges != nil { 56 containerSpec.Privileges = &types.Privileges{} 57 58 if c.Privileges.CredentialSpec != nil { 59 containerSpec.Privileges.CredentialSpec = credentialSpecFromGRPC(c.Privileges.CredentialSpec) 60 } 61 62 if c.Privileges.SELinuxContext != nil { 63 containerSpec.Privileges.SELinuxContext = &types.SELinuxContext{ 64 Disable: c.Privileges.SELinuxContext.Disable, 65 User: c.Privileges.SELinuxContext.User, 66 Type: c.Privileges.SELinuxContext.Type, 67 Role: c.Privileges.SELinuxContext.Role, 68 Level: c.Privileges.SELinuxContext.Level, 69 } 70 } 71 } 72 73 // Mounts 74 for _, m := range c.Mounts { 75 mount := mounttypes.Mount{ 76 Target: m.Target, 77 Source: m.Source, 78 Type: mounttypes.Type(strings.ToLower(swarmapi.Mount_MountType_name[int32(m.Type)])), 79 ReadOnly: m.ReadOnly, 80 } 81 82 if m.BindOptions != nil { 83 mount.BindOptions = &mounttypes.BindOptions{ 84 Propagation: mounttypes.Propagation(strings.ToLower(swarmapi.Mount_BindOptions_MountPropagation_name[int32(m.BindOptions.Propagation)])), 85 NonRecursive: m.BindOptions.NonRecursive, 86 } 87 } 88 89 if m.VolumeOptions != nil { 90 mount.VolumeOptions = &mounttypes.VolumeOptions{ 91 NoCopy: m.VolumeOptions.NoCopy, 92 Labels: m.VolumeOptions.Labels, 93 } 94 if m.VolumeOptions.DriverConfig != nil { 95 mount.VolumeOptions.DriverConfig = &mounttypes.Driver{ 96 Name: m.VolumeOptions.DriverConfig.Name, 97 Options: m.VolumeOptions.DriverConfig.Options, 98 } 99 } 100 } 101 102 if m.TmpfsOptions != nil { 103 mount.TmpfsOptions = &mounttypes.TmpfsOptions{ 104 SizeBytes: m.TmpfsOptions.SizeBytes, 105 Mode: m.TmpfsOptions.Mode, 106 } 107 } 108 containerSpec.Mounts = append(containerSpec.Mounts, mount) 109 } 110 111 if c.StopGracePeriod != nil { 112 grace, _ := gogotypes.DurationFromProto(c.StopGracePeriod) 113 containerSpec.StopGracePeriod = &grace 114 } 115 116 if c.Healthcheck != nil { 117 containerSpec.Healthcheck = healthConfigFromGRPC(c.Healthcheck) 118 } 119 120 return containerSpec 121 } 122 123 func initFromGRPC(v *gogotypes.BoolValue) *bool { 124 if v == nil { 125 return nil 126 } 127 value := v.GetValue() 128 return &value 129 } 130 131 func initToGRPC(v *bool) *gogotypes.BoolValue { 132 if v == nil { 133 return nil 134 } 135 return &gogotypes.BoolValue{Value: *v} 136 } 137 138 func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference { 139 refs := make([]*swarmapi.SecretReference, 0, len(sr)) 140 for _, s := range sr { 141 ref := &swarmapi.SecretReference{ 142 SecretID: s.SecretID, 143 SecretName: s.SecretName, 144 } 145 if s.File != nil { 146 ref.Target = &swarmapi.SecretReference_File{ 147 File: &swarmapi.FileTarget{ 148 Name: s.File.Name, 149 UID: s.File.UID, 150 GID: s.File.GID, 151 Mode: s.File.Mode, 152 }, 153 } 154 } 155 156 refs = append(refs, ref) 157 } 158 159 return refs 160 } 161 162 func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretReference { 163 refs := make([]*types.SecretReference, 0, len(sr)) 164 for _, s := range sr { 165 target := s.GetFile() 166 if target == nil { 167 // not a file target 168 logrus.Warnf("secret target not a file: secret=%s", s.SecretID) 169 continue 170 } 171 refs = append(refs, &types.SecretReference{ 172 File: &types.SecretReferenceFileTarget{ 173 Name: target.Name, 174 UID: target.UID, 175 GID: target.GID, 176 Mode: target.Mode, 177 }, 178 SecretID: s.SecretID, 179 SecretName: s.SecretName, 180 }) 181 } 182 183 return refs 184 } 185 186 func configReferencesToGRPC(sr []*types.ConfigReference) ([]*swarmapi.ConfigReference, error) { 187 refs := make([]*swarmapi.ConfigReference, 0, len(sr)) 188 for _, s := range sr { 189 ref := &swarmapi.ConfigReference{ 190 ConfigID: s.ConfigID, 191 ConfigName: s.ConfigName, 192 } 193 switch { 194 case s.Runtime == nil && s.File == nil: 195 return nil, errors.New("either File or Runtime should be set") 196 case s.Runtime != nil && s.File != nil: 197 return nil, errors.New("cannot specify both File and Runtime") 198 case s.Runtime != nil: 199 // Runtime target was added in API v1.40 and takes precedence over 200 // File target. However, File and Runtime targets are mutually exclusive, 201 // so we should never have both. 202 ref.Target = &swarmapi.ConfigReference_Runtime{ 203 Runtime: &swarmapi.RuntimeTarget{}, 204 } 205 case s.File != nil: 206 ref.Target = &swarmapi.ConfigReference_File{ 207 File: &swarmapi.FileTarget{ 208 Name: s.File.Name, 209 UID: s.File.UID, 210 GID: s.File.GID, 211 Mode: s.File.Mode, 212 }, 213 } 214 } 215 216 refs = append(refs, ref) 217 } 218 219 return refs, nil 220 } 221 222 func configReferencesFromGRPC(sr []*swarmapi.ConfigReference) []*types.ConfigReference { 223 refs := make([]*types.ConfigReference, 0, len(sr)) 224 for _, s := range sr { 225 226 r := &types.ConfigReference{ 227 ConfigID: s.ConfigID, 228 ConfigName: s.ConfigName, 229 } 230 if target := s.GetRuntime(); target != nil { 231 r.Runtime = &types.ConfigReferenceRuntimeTarget{} 232 } else if target := s.GetFile(); target != nil { 233 r.File = &types.ConfigReferenceFileTarget{ 234 Name: target.Name, 235 UID: target.UID, 236 GID: target.GID, 237 Mode: target.Mode, 238 } 239 } else { 240 // not a file target 241 logrus.Warnf("config target not known: config=%s", s.ConfigID) 242 continue 243 } 244 refs = append(refs, r) 245 } 246 247 return refs 248 } 249 250 func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) { 251 containerSpec := &swarmapi.ContainerSpec{ 252 Image: c.Image, 253 Labels: c.Labels, 254 Command: c.Command, 255 Args: c.Args, 256 Hostname: c.Hostname, 257 Env: c.Env, 258 Dir: c.Dir, 259 User: c.User, 260 Groups: c.Groups, 261 StopSignal: c.StopSignal, 262 TTY: c.TTY, 263 OpenStdin: c.OpenStdin, 264 ReadOnly: c.ReadOnly, 265 Hosts: c.Hosts, 266 Secrets: secretReferencesToGRPC(c.Secrets), 267 Isolation: isolationToGRPC(c.Isolation), 268 Init: initToGRPC(c.Init), 269 Sysctls: c.Sysctls, 270 CapabilityAdd: c.CapabilityAdd, 271 CapabilityDrop: c.CapabilityDrop, 272 Ulimits: ulimitsToGRPC(c.Ulimits), 273 } 274 275 if c.DNSConfig != nil { 276 containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{ 277 Nameservers: c.DNSConfig.Nameservers, 278 Search: c.DNSConfig.Search, 279 Options: c.DNSConfig.Options, 280 } 281 } 282 283 if c.StopGracePeriod != nil { 284 containerSpec.StopGracePeriod = gogotypes.DurationProto(*c.StopGracePeriod) 285 } 286 287 // Privileges 288 if c.Privileges != nil { 289 containerSpec.Privileges = &swarmapi.Privileges{} 290 291 if c.Privileges.CredentialSpec != nil { 292 cs, err := credentialSpecToGRPC(c.Privileges.CredentialSpec) 293 if err != nil { 294 return nil, errors.Wrap(err, "invalid CredentialSpec") 295 } 296 containerSpec.Privileges.CredentialSpec = cs 297 } 298 299 if c.Privileges.SELinuxContext != nil { 300 containerSpec.Privileges.SELinuxContext = &swarmapi.Privileges_SELinuxContext{ 301 Disable: c.Privileges.SELinuxContext.Disable, 302 User: c.Privileges.SELinuxContext.User, 303 Type: c.Privileges.SELinuxContext.Type, 304 Role: c.Privileges.SELinuxContext.Role, 305 Level: c.Privileges.SELinuxContext.Level, 306 } 307 } 308 } 309 310 if c.Configs != nil { 311 configs, err := configReferencesToGRPC(c.Configs) 312 if err != nil { 313 return nil, errors.Wrap(err, "invalid Config") 314 } 315 containerSpec.Configs = configs 316 } 317 318 // Mounts 319 for _, m := range c.Mounts { 320 mount := swarmapi.Mount{ 321 Target: m.Target, 322 Source: m.Source, 323 ReadOnly: m.ReadOnly, 324 } 325 326 if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok { 327 mount.Type = swarmapi.Mount_MountType(mountType) 328 } else if string(m.Type) != "" { 329 return nil, fmt.Errorf("invalid MountType: %q", m.Type) 330 } 331 332 if m.BindOptions != nil { 333 if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok { 334 mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)} 335 } else if string(m.BindOptions.Propagation) != "" { 336 return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation) 337 } 338 339 if m.BindOptions.NonRecursive { 340 if mount.BindOptions == nil { 341 // the propagation defaults to rprivate 342 mount.BindOptions = &swarmapi.Mount_BindOptions{} 343 } 344 mount.BindOptions.NonRecursive = m.BindOptions.NonRecursive 345 } 346 } 347 348 if m.VolumeOptions != nil { 349 mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{ 350 NoCopy: m.VolumeOptions.NoCopy, 351 Labels: m.VolumeOptions.Labels, 352 } 353 if m.VolumeOptions.DriverConfig != nil { 354 mount.VolumeOptions.DriverConfig = &swarmapi.Driver{ 355 Name: m.VolumeOptions.DriverConfig.Name, 356 Options: m.VolumeOptions.DriverConfig.Options, 357 } 358 } 359 } 360 361 if m.TmpfsOptions != nil { 362 mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{ 363 SizeBytes: m.TmpfsOptions.SizeBytes, 364 Mode: m.TmpfsOptions.Mode, 365 } 366 } 367 368 containerSpec.Mounts = append(containerSpec.Mounts, mount) 369 } 370 371 if c.Healthcheck != nil { 372 containerSpec.Healthcheck = healthConfigToGRPC(c.Healthcheck) 373 } 374 375 return containerSpec, nil 376 } 377 378 func credentialSpecFromGRPC(c *swarmapi.Privileges_CredentialSpec) *types.CredentialSpec { 379 cs := &types.CredentialSpec{} 380 switch c.Source.(type) { 381 case *swarmapi.Privileges_CredentialSpec_Config: 382 cs.Config = c.GetConfig() 383 case *swarmapi.Privileges_CredentialSpec_File: 384 cs.File = c.GetFile() 385 case *swarmapi.Privileges_CredentialSpec_Registry: 386 cs.Registry = c.GetRegistry() 387 } 388 return cs 389 } 390 391 func credentialSpecToGRPC(c *types.CredentialSpec) (*swarmapi.Privileges_CredentialSpec, error) { 392 var opts []string 393 394 if c.Config != "" { 395 opts = append(opts, `"config"`) 396 } 397 if c.File != "" { 398 opts = append(opts, `"file"`) 399 } 400 if c.Registry != "" { 401 opts = append(opts, `"registry"`) 402 } 403 l := len(opts) 404 switch { 405 case l == 0: 406 return nil, errors.New(`must either provide "file", "registry", or "config" for credential spec`) 407 case l == 2: 408 return nil, fmt.Errorf("cannot specify both %s and %s credential specs", opts[0], opts[1]) 409 case l > 2: 410 return nil, fmt.Errorf("cannot specify both %s, and %s credential specs", strings.Join(opts[:l-1], ", "), opts[l-1]) 411 } 412 413 spec := &swarmapi.Privileges_CredentialSpec{} 414 switch { 415 case c.Config != "": 416 spec.Source = &swarmapi.Privileges_CredentialSpec_Config{ 417 Config: c.Config, 418 } 419 case c.File != "": 420 spec.Source = &swarmapi.Privileges_CredentialSpec_File{ 421 File: c.File, 422 } 423 case c.Registry != "": 424 spec.Source = &swarmapi.Privileges_CredentialSpec_Registry{ 425 Registry: c.Registry, 426 } 427 } 428 429 return spec, nil 430 } 431 432 func healthConfigFromGRPC(h *swarmapi.HealthConfig) *container.HealthConfig { 433 interval, _ := gogotypes.DurationFromProto(h.Interval) 434 timeout, _ := gogotypes.DurationFromProto(h.Timeout) 435 startPeriod, _ := gogotypes.DurationFromProto(h.StartPeriod) 436 return &container.HealthConfig{ 437 Test: h.Test, 438 Interval: interval, 439 Timeout: timeout, 440 Retries: int(h.Retries), 441 StartPeriod: startPeriod, 442 } 443 } 444 445 func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig { 446 return &swarmapi.HealthConfig{ 447 Test: h.Test, 448 Interval: gogotypes.DurationProto(h.Interval), 449 Timeout: gogotypes.DurationProto(h.Timeout), 450 Retries: int32(h.Retries), 451 StartPeriod: gogotypes.DurationProto(h.StartPeriod), 452 } 453 } 454 455 // IsolationFromGRPC converts a swarm api container isolation to a moby isolation representation 456 func IsolationFromGRPC(i swarmapi.ContainerSpec_Isolation) container.Isolation { 457 switch i { 458 case swarmapi.ContainerIsolationHyperV: 459 return container.IsolationHyperV 460 case swarmapi.ContainerIsolationProcess: 461 return container.IsolationProcess 462 case swarmapi.ContainerIsolationDefault: 463 return container.IsolationDefault 464 } 465 return container.IsolationEmpty 466 } 467 468 func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation { 469 if i.IsHyperV() { 470 return swarmapi.ContainerIsolationHyperV 471 } 472 if i.IsProcess() { 473 return swarmapi.ContainerIsolationProcess 474 } 475 return swarmapi.ContainerIsolationDefault 476 } 477 478 func ulimitsFromGRPC(u []*swarmapi.ContainerSpec_Ulimit) []*units.Ulimit { 479 ulimits := make([]*units.Ulimit, len(u)) 480 481 for i, ulimit := range u { 482 ulimits[i] = &units.Ulimit{ 483 Name: ulimit.Name, 484 Soft: ulimit.Soft, 485 Hard: ulimit.Hard, 486 } 487 } 488 489 return ulimits 490 } 491 492 func ulimitsToGRPC(u []*units.Ulimit) []*swarmapi.ContainerSpec_Ulimit { 493 ulimits := make([]*swarmapi.ContainerSpec_Ulimit, len(u)) 494 495 for i, ulimit := range u { 496 ulimits[i] = &swarmapi.ContainerSpec_Ulimit{ 497 Name: ulimit.Name, 498 Soft: ulimit.Soft, 499 Hard: ulimit.Hard, 500 } 501 } 502 503 return ulimits 504 }