github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/daemon/cluster/convert/service.go (about) 1 package convert // import "github.com/docker/docker/daemon/cluster/convert" 2 3 import ( 4 "fmt" 5 "strings" 6 7 types "github.com/docker/docker/api/types/swarm" 8 "github.com/docker/docker/api/types/swarm/runtime" 9 "github.com/docker/docker/pkg/namesgenerator" 10 swarmapi "github.com/docker/swarmkit/api" 11 "github.com/docker/swarmkit/api/genericresource" 12 "github.com/gogo/protobuf/proto" 13 gogotypes "github.com/gogo/protobuf/types" 14 "github.com/pkg/errors" 15 ) 16 17 var ( 18 // ErrUnsupportedRuntime returns an error if the runtime is not supported by the daemon 19 ErrUnsupportedRuntime = errors.New("unsupported runtime") 20 // ErrMismatchedRuntime returns an error if the runtime does not match the provided spec 21 ErrMismatchedRuntime = errors.New("mismatched Runtime and *Spec fields") 22 ) 23 24 // ServiceFromGRPC converts a grpc Service to a Service. 25 func ServiceFromGRPC(s swarmapi.Service) (types.Service, error) { 26 curSpec, err := serviceSpecFromGRPC(&s.Spec) 27 if err != nil { 28 return types.Service{}, err 29 } 30 prevSpec, err := serviceSpecFromGRPC(s.PreviousSpec) 31 if err != nil { 32 return types.Service{}, err 33 } 34 service := types.Service{ 35 ID: s.ID, 36 Spec: *curSpec, 37 PreviousSpec: prevSpec, 38 39 Endpoint: endpointFromGRPC(s.Endpoint), 40 } 41 42 // Meta 43 service.Version.Index = s.Meta.Version.Index 44 service.CreatedAt, _ = gogotypes.TimestampFromProto(s.Meta.CreatedAt) 45 service.UpdatedAt, _ = gogotypes.TimestampFromProto(s.Meta.UpdatedAt) 46 47 if s.JobStatus != nil { 48 service.JobStatus = &types.JobStatus{ 49 JobIteration: types.Version{ 50 Index: s.JobStatus.JobIteration.Index, 51 }, 52 } 53 service.JobStatus.LastExecution, _ = gogotypes.TimestampFromProto(s.JobStatus.LastExecution) 54 } 55 56 // UpdateStatus 57 if s.UpdateStatus != nil { 58 service.UpdateStatus = &types.UpdateStatus{} 59 switch s.UpdateStatus.State { 60 case swarmapi.UpdateStatus_UPDATING: 61 service.UpdateStatus.State = types.UpdateStateUpdating 62 case swarmapi.UpdateStatus_PAUSED: 63 service.UpdateStatus.State = types.UpdateStatePaused 64 case swarmapi.UpdateStatus_COMPLETED: 65 service.UpdateStatus.State = types.UpdateStateCompleted 66 case swarmapi.UpdateStatus_ROLLBACK_STARTED: 67 service.UpdateStatus.State = types.UpdateStateRollbackStarted 68 case swarmapi.UpdateStatus_ROLLBACK_PAUSED: 69 service.UpdateStatus.State = types.UpdateStateRollbackPaused 70 case swarmapi.UpdateStatus_ROLLBACK_COMPLETED: 71 service.UpdateStatus.State = types.UpdateStateRollbackCompleted 72 } 73 74 startedAt, _ := gogotypes.TimestampFromProto(s.UpdateStatus.StartedAt) 75 if !startedAt.IsZero() && startedAt.Unix() != 0 { 76 service.UpdateStatus.StartedAt = &startedAt 77 } 78 79 completedAt, _ := gogotypes.TimestampFromProto(s.UpdateStatus.CompletedAt) 80 if !completedAt.IsZero() && completedAt.Unix() != 0 { 81 service.UpdateStatus.CompletedAt = &completedAt 82 } 83 84 service.UpdateStatus.Message = s.UpdateStatus.Message 85 } 86 87 return service, nil 88 } 89 90 func serviceSpecFromGRPC(spec *swarmapi.ServiceSpec) (*types.ServiceSpec, error) { 91 if spec == nil { 92 return nil, nil 93 } 94 95 serviceNetworks := make([]types.NetworkAttachmentConfig, 0, len(spec.Networks)) 96 for _, n := range spec.Networks { 97 netConfig := types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverOpts: n.DriverAttachmentOpts} 98 serviceNetworks = append(serviceNetworks, netConfig) 99 100 } 101 102 taskTemplate, err := taskSpecFromGRPC(spec.Task) 103 if err != nil { 104 return nil, err 105 } 106 107 switch t := spec.Task.GetRuntime().(type) { 108 case *swarmapi.TaskSpec_Container: 109 containerConfig := t.Container 110 taskTemplate.ContainerSpec = containerSpecFromGRPC(containerConfig) 111 taskTemplate.Runtime = types.RuntimeContainer 112 case *swarmapi.TaskSpec_Generic: 113 switch t.Generic.Kind { 114 case string(types.RuntimePlugin): 115 taskTemplate.Runtime = types.RuntimePlugin 116 default: 117 return nil, fmt.Errorf("unknown task runtime type: %s", t.Generic.Payload.TypeUrl) 118 } 119 120 default: 121 return nil, fmt.Errorf("error creating service; unsupported runtime %T", t) 122 } 123 124 convertedSpec := &types.ServiceSpec{ 125 Annotations: annotationsFromGRPC(spec.Annotations), 126 TaskTemplate: taskTemplate, 127 Networks: serviceNetworks, 128 EndpointSpec: endpointSpecFromGRPC(spec.Endpoint), 129 } 130 131 // UpdateConfig 132 convertedSpec.UpdateConfig = updateConfigFromGRPC(spec.Update) 133 convertedSpec.RollbackConfig = updateConfigFromGRPC(spec.Rollback) 134 135 // Mode 136 switch t := spec.GetMode().(type) { 137 case *swarmapi.ServiceSpec_Global: 138 convertedSpec.Mode.Global = &types.GlobalService{} 139 case *swarmapi.ServiceSpec_Replicated: 140 convertedSpec.Mode.Replicated = &types.ReplicatedService{ 141 Replicas: &t.Replicated.Replicas, 142 } 143 case *swarmapi.ServiceSpec_ReplicatedJob: 144 convertedSpec.Mode.ReplicatedJob = &types.ReplicatedJob{ 145 MaxConcurrent: &t.ReplicatedJob.MaxConcurrent, 146 TotalCompletions: &t.ReplicatedJob.TotalCompletions, 147 } 148 case *swarmapi.ServiceSpec_GlobalJob: 149 convertedSpec.Mode.GlobalJob = &types.GlobalJob{} 150 } 151 152 return convertedSpec, nil 153 } 154 155 // ServiceSpecToGRPC converts a ServiceSpec to a grpc ServiceSpec. 156 func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) { 157 name := s.Name 158 if name == "" { 159 name = namesgenerator.GetRandomName(0) 160 } 161 162 serviceNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.Networks)) 163 for _, n := range s.Networks { 164 netConfig := &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverAttachmentOpts: n.DriverOpts} 165 serviceNetworks = append(serviceNetworks, netConfig) 166 } 167 168 taskNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.TaskTemplate.Networks)) 169 for _, n := range s.TaskTemplate.Networks { 170 netConfig := &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverAttachmentOpts: n.DriverOpts} 171 taskNetworks = append(taskNetworks, netConfig) 172 173 } 174 175 spec := swarmapi.ServiceSpec{ 176 Annotations: swarmapi.Annotations{ 177 Name: name, 178 Labels: s.Labels, 179 }, 180 Task: swarmapi.TaskSpec{ 181 Resources: resourcesToGRPC(s.TaskTemplate.Resources), 182 LogDriver: driverToGRPC(s.TaskTemplate.LogDriver), 183 Networks: taskNetworks, 184 ForceUpdate: s.TaskTemplate.ForceUpdate, 185 }, 186 Networks: serviceNetworks, 187 } 188 189 switch s.TaskTemplate.Runtime { 190 case types.RuntimeContainer, "": // if empty runtime default to container 191 if s.TaskTemplate.ContainerSpec != nil { 192 containerSpec, err := containerToGRPC(s.TaskTemplate.ContainerSpec) 193 if err != nil { 194 return swarmapi.ServiceSpec{}, err 195 } 196 if s.TaskTemplate.Resources != nil && s.TaskTemplate.Resources.Limits != nil { 197 // TODO remove this (or keep for backward compat) once SwarmKit API moved PidsLimit into Resources 198 containerSpec.PidsLimit = s.TaskTemplate.Resources.Limits.Pids 199 } 200 spec.Task.Runtime = &swarmapi.TaskSpec_Container{Container: containerSpec} 201 } else { 202 // If the ContainerSpec is nil, we can't set the task runtime 203 return swarmapi.ServiceSpec{}, ErrMismatchedRuntime 204 } 205 case types.RuntimePlugin: 206 if s.TaskTemplate.PluginSpec != nil { 207 if s.Mode.Replicated != nil { 208 return swarmapi.ServiceSpec{}, errors.New("plugins must not use replicated mode") 209 } 210 211 s.Mode.Global = &types.GlobalService{} // must always be global 212 213 pluginSpec, err := proto.Marshal(s.TaskTemplate.PluginSpec) 214 if err != nil { 215 return swarmapi.ServiceSpec{}, err 216 } 217 spec.Task.Runtime = &swarmapi.TaskSpec_Generic{ 218 Generic: &swarmapi.GenericRuntimeSpec{ 219 Kind: string(types.RuntimePlugin), 220 Payload: &gogotypes.Any{ 221 TypeUrl: string(types.RuntimeURLPlugin), 222 Value: pluginSpec, 223 }, 224 }, 225 } 226 } else { 227 return swarmapi.ServiceSpec{}, ErrMismatchedRuntime 228 } 229 case types.RuntimeNetworkAttachment: 230 // NOTE(dperny) I'm leaving this case here for completeness. The actual 231 // code is left out deliberately, as we should refuse to parse a 232 // Network Attachment runtime; it will cause weird behavior all over 233 // the system if we do. Instead, fallthrough and return 234 // ErrUnsupportedRuntime if we get one. 235 fallthrough 236 default: 237 return swarmapi.ServiceSpec{}, ErrUnsupportedRuntime 238 } 239 240 restartPolicy, err := restartPolicyToGRPC(s.TaskTemplate.RestartPolicy) 241 if err != nil { 242 return swarmapi.ServiceSpec{}, err 243 } 244 spec.Task.Restart = restartPolicy 245 246 if s.TaskTemplate.Placement != nil { 247 var preferences []*swarmapi.PlacementPreference 248 for _, pref := range s.TaskTemplate.Placement.Preferences { 249 if pref.Spread != nil { 250 preferences = append(preferences, &swarmapi.PlacementPreference{ 251 Preference: &swarmapi.PlacementPreference_Spread{ 252 Spread: &swarmapi.SpreadOver{ 253 SpreadDescriptor: pref.Spread.SpreadDescriptor, 254 }, 255 }, 256 }) 257 } 258 } 259 var platforms []*swarmapi.Platform 260 for _, plat := range s.TaskTemplate.Placement.Platforms { 261 platforms = append(platforms, &swarmapi.Platform{ 262 Architecture: plat.Architecture, 263 OS: plat.OS, 264 }) 265 } 266 spec.Task.Placement = &swarmapi.Placement{ 267 Constraints: s.TaskTemplate.Placement.Constraints, 268 Preferences: preferences, 269 MaxReplicas: s.TaskTemplate.Placement.MaxReplicas, 270 Platforms: platforms, 271 } 272 } 273 274 spec.Update, err = updateConfigToGRPC(s.UpdateConfig) 275 if err != nil { 276 return swarmapi.ServiceSpec{}, err 277 } 278 spec.Rollback, err = updateConfigToGRPC(s.RollbackConfig) 279 if err != nil { 280 return swarmapi.ServiceSpec{}, err 281 } 282 283 if s.EndpointSpec != nil { 284 if s.EndpointSpec.Mode != "" && 285 s.EndpointSpec.Mode != types.ResolutionModeVIP && 286 s.EndpointSpec.Mode != types.ResolutionModeDNSRR { 287 return swarmapi.ServiceSpec{}, fmt.Errorf("invalid resolution mode: %q", s.EndpointSpec.Mode) 288 } 289 290 spec.Endpoint = &swarmapi.EndpointSpec{} 291 292 spec.Endpoint.Mode = swarmapi.EndpointSpec_ResolutionMode(swarmapi.EndpointSpec_ResolutionMode_value[strings.ToUpper(string(s.EndpointSpec.Mode))]) 293 294 for _, portConfig := range s.EndpointSpec.Ports { 295 spec.Endpoint.Ports = append(spec.Endpoint.Ports, &swarmapi.PortConfig{ 296 Name: portConfig.Name, 297 Protocol: swarmapi.PortConfig_Protocol(swarmapi.PortConfig_Protocol_value[strings.ToUpper(string(portConfig.Protocol))]), 298 PublishMode: swarmapi.PortConfig_PublishMode(swarmapi.PortConfig_PublishMode_value[strings.ToUpper(string(portConfig.PublishMode))]), 299 TargetPort: portConfig.TargetPort, 300 PublishedPort: portConfig.PublishedPort, 301 }) 302 } 303 } 304 305 // Mode 306 numModes := 0 307 if s.Mode.Global != nil { 308 numModes++ 309 } 310 if s.Mode.Replicated != nil { 311 numModes++ 312 } 313 if s.Mode.ReplicatedJob != nil { 314 numModes++ 315 } 316 if s.Mode.GlobalJob != nil { 317 numModes++ 318 } 319 320 if numModes > 1 { 321 return swarmapi.ServiceSpec{}, fmt.Errorf("must specify only one service mode") 322 } 323 324 if s.Mode.Global != nil { 325 spec.Mode = &swarmapi.ServiceSpec_Global{ 326 Global: &swarmapi.GlobalService{}, 327 } 328 } else if s.Mode.GlobalJob != nil { 329 spec.Mode = &swarmapi.ServiceSpec_GlobalJob{ 330 GlobalJob: &swarmapi.GlobalJob{}, 331 } 332 } else if s.Mode.ReplicatedJob != nil { 333 // if the service is a replicated job, we have two different kinds of 334 // values that might need to be defaulted. 335 336 r := &swarmapi.ReplicatedJob{} 337 if s.Mode.ReplicatedJob.MaxConcurrent != nil { 338 r.MaxConcurrent = *s.Mode.ReplicatedJob.MaxConcurrent 339 } else { 340 r.MaxConcurrent = 1 341 } 342 343 if s.Mode.ReplicatedJob.TotalCompletions != nil { 344 r.TotalCompletions = *s.Mode.ReplicatedJob.TotalCompletions 345 } else { 346 r.TotalCompletions = r.MaxConcurrent 347 } 348 349 spec.Mode = &swarmapi.ServiceSpec_ReplicatedJob{ 350 ReplicatedJob: r, 351 } 352 } else if s.Mode.Replicated != nil && s.Mode.Replicated.Replicas != nil { 353 spec.Mode = &swarmapi.ServiceSpec_Replicated{ 354 Replicated: &swarmapi.ReplicatedService{Replicas: *s.Mode.Replicated.Replicas}, 355 } 356 } else { 357 spec.Mode = &swarmapi.ServiceSpec_Replicated{ 358 Replicated: &swarmapi.ReplicatedService{Replicas: 1}, 359 } 360 } 361 362 return spec, nil 363 } 364 365 func annotationsFromGRPC(ann swarmapi.Annotations) types.Annotations { 366 a := types.Annotations{ 367 Name: ann.Name, 368 Labels: ann.Labels, 369 } 370 371 if a.Labels == nil { 372 a.Labels = make(map[string]string) 373 } 374 375 return a 376 } 377 378 // GenericResourcesFromGRPC converts a GRPC GenericResource to a GenericResource 379 func GenericResourcesFromGRPC(genericRes []*swarmapi.GenericResource) []types.GenericResource { 380 var generic []types.GenericResource 381 for _, res := range genericRes { 382 var current types.GenericResource 383 384 switch r := res.Resource.(type) { 385 case *swarmapi.GenericResource_DiscreteResourceSpec: 386 current.DiscreteResourceSpec = &types.DiscreteGenericResource{ 387 Kind: r.DiscreteResourceSpec.Kind, 388 Value: r.DiscreteResourceSpec.Value, 389 } 390 case *swarmapi.GenericResource_NamedResourceSpec: 391 current.NamedResourceSpec = &types.NamedGenericResource{ 392 Kind: r.NamedResourceSpec.Kind, 393 Value: r.NamedResourceSpec.Value, 394 } 395 } 396 397 generic = append(generic, current) 398 } 399 400 return generic 401 } 402 403 // resourcesFromGRPC creates a ResourceRequirements from the GRPC TaskSpec. 404 // We currently require the whole TaskSpec to be passed, because PidsLimit 405 // is returned as part of the container spec, instead of Resources 406 // TODO move PidsLimit to Resources in the Swarm API 407 func resourcesFromGRPC(ts *swarmapi.TaskSpec) *types.ResourceRequirements { 408 var resources *types.ResourceRequirements 409 410 if cs := ts.GetContainer(); cs != nil && cs.PidsLimit != 0 { 411 resources = &types.ResourceRequirements{ 412 Limits: &types.Limit{ 413 Pids: cs.PidsLimit, 414 }, 415 } 416 } 417 if ts.Resources != nil { 418 if resources == nil { 419 resources = &types.ResourceRequirements{} 420 } 421 res := ts.Resources 422 if res.Limits != nil { 423 if resources.Limits == nil { 424 resources.Limits = &types.Limit{} 425 } 426 resources.Limits.NanoCPUs = res.Limits.NanoCPUs 427 resources.Limits.MemoryBytes = res.Limits.MemoryBytes 428 } 429 if res.Reservations != nil { 430 resources.Reservations = &types.Resources{ 431 NanoCPUs: res.Reservations.NanoCPUs, 432 MemoryBytes: res.Reservations.MemoryBytes, 433 GenericResources: GenericResourcesFromGRPC(res.Reservations.Generic), 434 } 435 } 436 } 437 438 return resources 439 } 440 441 // GenericResourcesToGRPC converts a GenericResource to a GRPC GenericResource 442 func GenericResourcesToGRPC(genericRes []types.GenericResource) []*swarmapi.GenericResource { 443 var generic []*swarmapi.GenericResource 444 for _, res := range genericRes { 445 var r *swarmapi.GenericResource 446 447 if res.DiscreteResourceSpec != nil { 448 r = genericresource.NewDiscrete(res.DiscreteResourceSpec.Kind, res.DiscreteResourceSpec.Value) 449 } else if res.NamedResourceSpec != nil { 450 r = genericresource.NewString(res.NamedResourceSpec.Kind, res.NamedResourceSpec.Value) 451 } 452 453 generic = append(generic, r) 454 } 455 456 return generic 457 } 458 459 func resourcesToGRPC(res *types.ResourceRequirements) *swarmapi.ResourceRequirements { 460 var reqs *swarmapi.ResourceRequirements 461 if res != nil { 462 reqs = &swarmapi.ResourceRequirements{} 463 if res.Limits != nil { 464 // TODO add PidsLimit once Swarm API has been updated to move it into Limits 465 reqs.Limits = &swarmapi.Resources{ 466 NanoCPUs: res.Limits.NanoCPUs, 467 MemoryBytes: res.Limits.MemoryBytes, 468 } 469 } 470 if res.Reservations != nil { 471 reqs.Reservations = &swarmapi.Resources{ 472 NanoCPUs: res.Reservations.NanoCPUs, 473 MemoryBytes: res.Reservations.MemoryBytes, 474 Generic: GenericResourcesToGRPC(res.Reservations.GenericResources), 475 } 476 477 } 478 } 479 return reqs 480 } 481 482 func restartPolicyFromGRPC(p *swarmapi.RestartPolicy) *types.RestartPolicy { 483 var rp *types.RestartPolicy 484 if p != nil { 485 rp = &types.RestartPolicy{} 486 487 switch p.Condition { 488 case swarmapi.RestartOnNone: 489 rp.Condition = types.RestartPolicyConditionNone 490 case swarmapi.RestartOnFailure: 491 rp.Condition = types.RestartPolicyConditionOnFailure 492 case swarmapi.RestartOnAny: 493 rp.Condition = types.RestartPolicyConditionAny 494 default: 495 rp.Condition = types.RestartPolicyConditionAny 496 } 497 498 if p.Delay != nil { 499 delay, _ := gogotypes.DurationFromProto(p.Delay) 500 rp.Delay = &delay 501 } 502 if p.Window != nil { 503 window, _ := gogotypes.DurationFromProto(p.Window) 504 rp.Window = &window 505 } 506 507 rp.MaxAttempts = &p.MaxAttempts 508 } 509 return rp 510 } 511 512 func restartPolicyToGRPC(p *types.RestartPolicy) (*swarmapi.RestartPolicy, error) { 513 var rp *swarmapi.RestartPolicy 514 if p != nil { 515 rp = &swarmapi.RestartPolicy{} 516 517 switch p.Condition { 518 case types.RestartPolicyConditionNone: 519 rp.Condition = swarmapi.RestartOnNone 520 case types.RestartPolicyConditionOnFailure: 521 rp.Condition = swarmapi.RestartOnFailure 522 case types.RestartPolicyConditionAny: 523 rp.Condition = swarmapi.RestartOnAny 524 default: 525 if string(p.Condition) != "" { 526 return nil, fmt.Errorf("invalid RestartCondition: %q", p.Condition) 527 } 528 rp.Condition = swarmapi.RestartOnAny 529 } 530 531 if p.Delay != nil { 532 rp.Delay = gogotypes.DurationProto(*p.Delay) 533 } 534 if p.Window != nil { 535 rp.Window = gogotypes.DurationProto(*p.Window) 536 } 537 if p.MaxAttempts != nil { 538 rp.MaxAttempts = *p.MaxAttempts 539 540 } 541 } 542 return rp, nil 543 } 544 545 func placementFromGRPC(p *swarmapi.Placement) *types.Placement { 546 if p == nil { 547 return nil 548 } 549 r := &types.Placement{ 550 Constraints: p.Constraints, 551 MaxReplicas: p.MaxReplicas, 552 } 553 554 for _, pref := range p.Preferences { 555 if spread := pref.GetSpread(); spread != nil { 556 r.Preferences = append(r.Preferences, types.PlacementPreference{ 557 Spread: &types.SpreadOver{ 558 SpreadDescriptor: spread.SpreadDescriptor, 559 }, 560 }) 561 } 562 } 563 564 for _, plat := range p.Platforms { 565 r.Platforms = append(r.Platforms, types.Platform{ 566 Architecture: plat.Architecture, 567 OS: plat.OS, 568 }) 569 } 570 571 return r 572 } 573 574 func driverFromGRPC(p *swarmapi.Driver) *types.Driver { 575 if p == nil { 576 return nil 577 } 578 579 return &types.Driver{ 580 Name: p.Name, 581 Options: p.Options, 582 } 583 } 584 585 func driverToGRPC(p *types.Driver) *swarmapi.Driver { 586 if p == nil { 587 return nil 588 } 589 590 return &swarmapi.Driver{ 591 Name: p.Name, 592 Options: p.Options, 593 } 594 } 595 596 func updateConfigFromGRPC(updateConfig *swarmapi.UpdateConfig) *types.UpdateConfig { 597 if updateConfig == nil { 598 return nil 599 } 600 601 converted := &types.UpdateConfig{ 602 Parallelism: updateConfig.Parallelism, 603 MaxFailureRatio: updateConfig.MaxFailureRatio, 604 } 605 606 converted.Delay = updateConfig.Delay 607 if updateConfig.Monitor != nil { 608 converted.Monitor, _ = gogotypes.DurationFromProto(updateConfig.Monitor) 609 } 610 611 switch updateConfig.FailureAction { 612 case swarmapi.UpdateConfig_PAUSE: 613 converted.FailureAction = types.UpdateFailureActionPause 614 case swarmapi.UpdateConfig_CONTINUE: 615 converted.FailureAction = types.UpdateFailureActionContinue 616 case swarmapi.UpdateConfig_ROLLBACK: 617 converted.FailureAction = types.UpdateFailureActionRollback 618 } 619 620 switch updateConfig.Order { 621 case swarmapi.UpdateConfig_STOP_FIRST: 622 converted.Order = types.UpdateOrderStopFirst 623 case swarmapi.UpdateConfig_START_FIRST: 624 converted.Order = types.UpdateOrderStartFirst 625 } 626 627 return converted 628 } 629 630 func updateConfigToGRPC(updateConfig *types.UpdateConfig) (*swarmapi.UpdateConfig, error) { 631 if updateConfig == nil { 632 return nil, nil 633 } 634 635 converted := &swarmapi.UpdateConfig{ 636 Parallelism: updateConfig.Parallelism, 637 Delay: updateConfig.Delay, 638 MaxFailureRatio: updateConfig.MaxFailureRatio, 639 } 640 641 switch updateConfig.FailureAction { 642 case types.UpdateFailureActionPause, "": 643 converted.FailureAction = swarmapi.UpdateConfig_PAUSE 644 case types.UpdateFailureActionContinue: 645 converted.FailureAction = swarmapi.UpdateConfig_CONTINUE 646 case types.UpdateFailureActionRollback: 647 converted.FailureAction = swarmapi.UpdateConfig_ROLLBACK 648 default: 649 return nil, fmt.Errorf("unrecognized update failure action %s", updateConfig.FailureAction) 650 } 651 if updateConfig.Monitor != 0 { 652 converted.Monitor = gogotypes.DurationProto(updateConfig.Monitor) 653 } 654 655 switch updateConfig.Order { 656 case types.UpdateOrderStopFirst, "": 657 converted.Order = swarmapi.UpdateConfig_STOP_FIRST 658 case types.UpdateOrderStartFirst: 659 converted.Order = swarmapi.UpdateConfig_START_FIRST 660 default: 661 return nil, fmt.Errorf("unrecognized update order %s", updateConfig.Order) 662 } 663 664 return converted, nil 665 } 666 667 func networkAttachmentSpecFromGRPC(attachment swarmapi.NetworkAttachmentSpec) *types.NetworkAttachmentSpec { 668 return &types.NetworkAttachmentSpec{ 669 ContainerID: attachment.ContainerID, 670 } 671 } 672 673 func taskSpecFromGRPC(taskSpec swarmapi.TaskSpec) (types.TaskSpec, error) { 674 taskNetworks := make([]types.NetworkAttachmentConfig, 0, len(taskSpec.Networks)) 675 for _, n := range taskSpec.Networks { 676 netConfig := types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverOpts: n.DriverAttachmentOpts} 677 taskNetworks = append(taskNetworks, netConfig) 678 } 679 680 t := types.TaskSpec{ 681 Resources: resourcesFromGRPC(&taskSpec), 682 RestartPolicy: restartPolicyFromGRPC(taskSpec.Restart), 683 Placement: placementFromGRPC(taskSpec.Placement), 684 LogDriver: driverFromGRPC(taskSpec.LogDriver), 685 Networks: taskNetworks, 686 ForceUpdate: taskSpec.ForceUpdate, 687 } 688 689 switch taskSpec.GetRuntime().(type) { 690 case *swarmapi.TaskSpec_Container, nil: 691 c := taskSpec.GetContainer() 692 if c != nil { 693 t.ContainerSpec = containerSpecFromGRPC(c) 694 } 695 case *swarmapi.TaskSpec_Generic: 696 g := taskSpec.GetGeneric() 697 if g != nil { 698 switch g.Kind { 699 case string(types.RuntimePlugin): 700 var p runtime.PluginSpec 701 if err := proto.Unmarshal(g.Payload.Value, &p); err != nil { 702 return t, errors.Wrap(err, "error unmarshalling plugin spec") 703 } 704 t.PluginSpec = &p 705 } 706 } 707 case *swarmapi.TaskSpec_Attachment: 708 a := taskSpec.GetAttachment() 709 if a != nil { 710 t.NetworkAttachmentSpec = networkAttachmentSpecFromGRPC(*a) 711 } 712 t.Runtime = types.RuntimeNetworkAttachment 713 } 714 715 return t, nil 716 }