github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/cluster/convert/service.go (about) 1 package convert 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 types "github.com/docker/docker/api/types/swarm" 9 "github.com/docker/docker/pkg/namesgenerator" 10 swarmapi "github.com/docker/swarmkit/api" 11 gogotypes "github.com/gogo/protobuf/types" 12 ) 13 14 var ( 15 // ErrUnsupportedRuntime returns an error if the runtime is not supported by the daemon 16 ErrUnsupportedRuntime = errors.New("unsupported runtime") 17 ) 18 19 // ServiceFromGRPC converts a grpc Service to a Service. 20 func ServiceFromGRPC(s swarmapi.Service) (types.Service, error) { 21 curSpec, err := serviceSpecFromGRPC(&s.Spec) 22 if err != nil { 23 return types.Service{}, err 24 } 25 prevSpec, err := serviceSpecFromGRPC(s.PreviousSpec) 26 if err != nil { 27 return types.Service{}, err 28 } 29 service := types.Service{ 30 ID: s.ID, 31 Spec: *curSpec, 32 PreviousSpec: prevSpec, 33 34 Endpoint: endpointFromGRPC(s.Endpoint), 35 } 36 37 // Meta 38 service.Version.Index = s.Meta.Version.Index 39 service.CreatedAt, _ = gogotypes.TimestampFromProto(s.Meta.CreatedAt) 40 service.UpdatedAt, _ = gogotypes.TimestampFromProto(s.Meta.UpdatedAt) 41 42 // UpdateStatus 43 if s.UpdateStatus != nil { 44 service.UpdateStatus = &types.UpdateStatus{} 45 switch s.UpdateStatus.State { 46 case swarmapi.UpdateStatus_UPDATING: 47 service.UpdateStatus.State = types.UpdateStateUpdating 48 case swarmapi.UpdateStatus_PAUSED: 49 service.UpdateStatus.State = types.UpdateStatePaused 50 case swarmapi.UpdateStatus_COMPLETED: 51 service.UpdateStatus.State = types.UpdateStateCompleted 52 case swarmapi.UpdateStatus_ROLLBACK_STARTED: 53 service.UpdateStatus.State = types.UpdateStateRollbackStarted 54 case swarmapi.UpdateStatus_ROLLBACK_PAUSED: 55 service.UpdateStatus.State = types.UpdateStateRollbackPaused 56 case swarmapi.UpdateStatus_ROLLBACK_COMPLETED: 57 service.UpdateStatus.State = types.UpdateStateRollbackCompleted 58 } 59 60 startedAt, _ := gogotypes.TimestampFromProto(s.UpdateStatus.StartedAt) 61 if !startedAt.IsZero() && startedAt.Unix() != 0 { 62 service.UpdateStatus.StartedAt = &startedAt 63 } 64 65 completedAt, _ := gogotypes.TimestampFromProto(s.UpdateStatus.CompletedAt) 66 if !completedAt.IsZero() && completedAt.Unix() != 0 { 67 service.UpdateStatus.CompletedAt = &completedAt 68 } 69 70 service.UpdateStatus.Message = s.UpdateStatus.Message 71 } 72 73 return service, nil 74 } 75 76 func serviceSpecFromGRPC(spec *swarmapi.ServiceSpec) (*types.ServiceSpec, error) { 77 if spec == nil { 78 return nil, nil 79 } 80 81 serviceNetworks := make([]types.NetworkAttachmentConfig, 0, len(spec.Networks)) 82 for _, n := range spec.Networks { 83 netConfig := types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverOpts: n.DriverAttachmentOpts} 84 serviceNetworks = append(serviceNetworks, netConfig) 85 86 } 87 88 taskTemplate := taskSpecFromGRPC(spec.Task) 89 90 switch t := spec.Task.GetRuntime().(type) { 91 case *swarmapi.TaskSpec_Container: 92 containerConfig := t.Container 93 taskTemplate.ContainerSpec = containerSpecFromGRPC(containerConfig) 94 taskTemplate.Runtime = types.RuntimeContainer 95 case *swarmapi.TaskSpec_Generic: 96 switch t.Generic.Kind { 97 case string(types.RuntimePlugin): 98 taskTemplate.Runtime = types.RuntimePlugin 99 default: 100 return nil, fmt.Errorf("unknown task runtime type: %s", t.Generic.Payload.TypeUrl) 101 } 102 103 default: 104 return nil, fmt.Errorf("error creating service; unsupported runtime %T", t) 105 } 106 107 convertedSpec := &types.ServiceSpec{ 108 Annotations: annotationsFromGRPC(spec.Annotations), 109 TaskTemplate: taskTemplate, 110 Networks: serviceNetworks, 111 EndpointSpec: endpointSpecFromGRPC(spec.Endpoint), 112 } 113 114 // UpdateConfig 115 convertedSpec.UpdateConfig = updateConfigFromGRPC(spec.Update) 116 convertedSpec.RollbackConfig = updateConfigFromGRPC(spec.Rollback) 117 118 // Mode 119 switch t := spec.GetMode().(type) { 120 case *swarmapi.ServiceSpec_Global: 121 convertedSpec.Mode.Global = &types.GlobalService{} 122 case *swarmapi.ServiceSpec_Replicated: 123 convertedSpec.Mode.Replicated = &types.ReplicatedService{ 124 Replicas: &t.Replicated.Replicas, 125 } 126 } 127 128 return convertedSpec, nil 129 } 130 131 // ServiceSpecToGRPC converts a ServiceSpec to a grpc ServiceSpec. 132 func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) { 133 name := s.Name 134 if name == "" { 135 name = namesgenerator.GetRandomName(0) 136 } 137 138 serviceNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.Networks)) 139 for _, n := range s.Networks { 140 netConfig := &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverAttachmentOpts: n.DriverOpts} 141 serviceNetworks = append(serviceNetworks, netConfig) 142 } 143 144 taskNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.TaskTemplate.Networks)) 145 for _, n := range s.TaskTemplate.Networks { 146 netConfig := &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverAttachmentOpts: n.DriverOpts} 147 taskNetworks = append(taskNetworks, netConfig) 148 149 } 150 151 spec := swarmapi.ServiceSpec{ 152 Annotations: swarmapi.Annotations{ 153 Name: name, 154 Labels: s.Labels, 155 }, 156 Task: swarmapi.TaskSpec{ 157 Resources: resourcesToGRPC(s.TaskTemplate.Resources), 158 LogDriver: driverToGRPC(s.TaskTemplate.LogDriver), 159 Networks: taskNetworks, 160 ForceUpdate: s.TaskTemplate.ForceUpdate, 161 }, 162 Networks: serviceNetworks, 163 } 164 165 switch s.TaskTemplate.Runtime { 166 case types.RuntimeContainer, "": // if empty runtime default to container 167 containerSpec, err := containerToGRPC(s.TaskTemplate.ContainerSpec) 168 if err != nil { 169 return swarmapi.ServiceSpec{}, err 170 } 171 spec.Task.Runtime = &swarmapi.TaskSpec_Container{Container: containerSpec} 172 case types.RuntimePlugin: 173 spec.Task.Runtime = &swarmapi.TaskSpec_Generic{ 174 Generic: &swarmapi.GenericRuntimeSpec{ 175 Kind: string(types.RuntimePlugin), 176 Payload: &gogotypes.Any{ 177 TypeUrl: string(types.RuntimeURLPlugin), 178 }, 179 }, 180 } 181 default: 182 return swarmapi.ServiceSpec{}, ErrUnsupportedRuntime 183 } 184 185 restartPolicy, err := restartPolicyToGRPC(s.TaskTemplate.RestartPolicy) 186 if err != nil { 187 return swarmapi.ServiceSpec{}, err 188 } 189 spec.Task.Restart = restartPolicy 190 191 if s.TaskTemplate.Placement != nil { 192 var preferences []*swarmapi.PlacementPreference 193 for _, pref := range s.TaskTemplate.Placement.Preferences { 194 if pref.Spread != nil { 195 preferences = append(preferences, &swarmapi.PlacementPreference{ 196 Preference: &swarmapi.PlacementPreference_Spread{ 197 Spread: &swarmapi.SpreadOver{ 198 SpreadDescriptor: pref.Spread.SpreadDescriptor, 199 }, 200 }, 201 }) 202 } 203 } 204 var platforms []*swarmapi.Platform 205 for _, plat := range s.TaskTemplate.Placement.Platforms { 206 platforms = append(platforms, &swarmapi.Platform{ 207 Architecture: plat.Architecture, 208 OS: plat.OS, 209 }) 210 } 211 spec.Task.Placement = &swarmapi.Placement{ 212 Constraints: s.TaskTemplate.Placement.Constraints, 213 Preferences: preferences, 214 Platforms: platforms, 215 } 216 } 217 218 spec.Update, err = updateConfigToGRPC(s.UpdateConfig) 219 if err != nil { 220 return swarmapi.ServiceSpec{}, err 221 } 222 spec.Rollback, err = updateConfigToGRPC(s.RollbackConfig) 223 if err != nil { 224 return swarmapi.ServiceSpec{}, err 225 } 226 227 if s.EndpointSpec != nil { 228 if s.EndpointSpec.Mode != "" && 229 s.EndpointSpec.Mode != types.ResolutionModeVIP && 230 s.EndpointSpec.Mode != types.ResolutionModeDNSRR { 231 return swarmapi.ServiceSpec{}, fmt.Errorf("invalid resolution mode: %q", s.EndpointSpec.Mode) 232 } 233 234 spec.Endpoint = &swarmapi.EndpointSpec{} 235 236 spec.Endpoint.Mode = swarmapi.EndpointSpec_ResolutionMode(swarmapi.EndpointSpec_ResolutionMode_value[strings.ToUpper(string(s.EndpointSpec.Mode))]) 237 238 for _, portConfig := range s.EndpointSpec.Ports { 239 spec.Endpoint.Ports = append(spec.Endpoint.Ports, &swarmapi.PortConfig{ 240 Name: portConfig.Name, 241 Protocol: swarmapi.PortConfig_Protocol(swarmapi.PortConfig_Protocol_value[strings.ToUpper(string(portConfig.Protocol))]), 242 PublishMode: swarmapi.PortConfig_PublishMode(swarmapi.PortConfig_PublishMode_value[strings.ToUpper(string(portConfig.PublishMode))]), 243 TargetPort: portConfig.TargetPort, 244 PublishedPort: portConfig.PublishedPort, 245 }) 246 } 247 } 248 249 // Mode 250 if s.Mode.Global != nil && s.Mode.Replicated != nil { 251 return swarmapi.ServiceSpec{}, fmt.Errorf("cannot specify both replicated mode and global mode") 252 } 253 254 if s.Mode.Global != nil { 255 spec.Mode = &swarmapi.ServiceSpec_Global{ 256 Global: &swarmapi.GlobalService{}, 257 } 258 } else if s.Mode.Replicated != nil && s.Mode.Replicated.Replicas != nil { 259 spec.Mode = &swarmapi.ServiceSpec_Replicated{ 260 Replicated: &swarmapi.ReplicatedService{Replicas: *s.Mode.Replicated.Replicas}, 261 } 262 } else { 263 spec.Mode = &swarmapi.ServiceSpec_Replicated{ 264 Replicated: &swarmapi.ReplicatedService{Replicas: 1}, 265 } 266 } 267 268 return spec, nil 269 } 270 271 func annotationsFromGRPC(ann swarmapi.Annotations) types.Annotations { 272 a := types.Annotations{ 273 Name: ann.Name, 274 Labels: ann.Labels, 275 } 276 277 if a.Labels == nil { 278 a.Labels = make(map[string]string) 279 } 280 281 return a 282 } 283 284 func resourcesFromGRPC(res *swarmapi.ResourceRequirements) *types.ResourceRequirements { 285 var resources *types.ResourceRequirements 286 if res != nil { 287 resources = &types.ResourceRequirements{} 288 if res.Limits != nil { 289 resources.Limits = &types.Resources{ 290 NanoCPUs: res.Limits.NanoCPUs, 291 MemoryBytes: res.Limits.MemoryBytes, 292 } 293 } 294 if res.Reservations != nil { 295 resources.Reservations = &types.Resources{ 296 NanoCPUs: res.Reservations.NanoCPUs, 297 MemoryBytes: res.Reservations.MemoryBytes, 298 } 299 } 300 } 301 302 return resources 303 } 304 305 func resourcesToGRPC(res *types.ResourceRequirements) *swarmapi.ResourceRequirements { 306 var reqs *swarmapi.ResourceRequirements 307 if res != nil { 308 reqs = &swarmapi.ResourceRequirements{} 309 if res.Limits != nil { 310 reqs.Limits = &swarmapi.Resources{ 311 NanoCPUs: res.Limits.NanoCPUs, 312 MemoryBytes: res.Limits.MemoryBytes, 313 } 314 } 315 if res.Reservations != nil { 316 reqs.Reservations = &swarmapi.Resources{ 317 NanoCPUs: res.Reservations.NanoCPUs, 318 MemoryBytes: res.Reservations.MemoryBytes, 319 } 320 321 } 322 } 323 return reqs 324 } 325 326 func restartPolicyFromGRPC(p *swarmapi.RestartPolicy) *types.RestartPolicy { 327 var rp *types.RestartPolicy 328 if p != nil { 329 rp = &types.RestartPolicy{} 330 331 switch p.Condition { 332 case swarmapi.RestartOnNone: 333 rp.Condition = types.RestartPolicyConditionNone 334 case swarmapi.RestartOnFailure: 335 rp.Condition = types.RestartPolicyConditionOnFailure 336 case swarmapi.RestartOnAny: 337 rp.Condition = types.RestartPolicyConditionAny 338 default: 339 rp.Condition = types.RestartPolicyConditionAny 340 } 341 342 if p.Delay != nil { 343 delay, _ := gogotypes.DurationFromProto(p.Delay) 344 rp.Delay = &delay 345 } 346 if p.Window != nil { 347 window, _ := gogotypes.DurationFromProto(p.Window) 348 rp.Window = &window 349 } 350 351 rp.MaxAttempts = &p.MaxAttempts 352 } 353 return rp 354 } 355 356 func restartPolicyToGRPC(p *types.RestartPolicy) (*swarmapi.RestartPolicy, error) { 357 var rp *swarmapi.RestartPolicy 358 if p != nil { 359 rp = &swarmapi.RestartPolicy{} 360 361 switch p.Condition { 362 case types.RestartPolicyConditionNone: 363 rp.Condition = swarmapi.RestartOnNone 364 case types.RestartPolicyConditionOnFailure: 365 rp.Condition = swarmapi.RestartOnFailure 366 case types.RestartPolicyConditionAny: 367 rp.Condition = swarmapi.RestartOnAny 368 default: 369 if string(p.Condition) != "" { 370 return nil, fmt.Errorf("invalid RestartCondition: %q", p.Condition) 371 } 372 rp.Condition = swarmapi.RestartOnAny 373 } 374 375 if p.Delay != nil { 376 rp.Delay = gogotypes.DurationProto(*p.Delay) 377 } 378 if p.Window != nil { 379 rp.Window = gogotypes.DurationProto(*p.Window) 380 } 381 if p.MaxAttempts != nil { 382 rp.MaxAttempts = *p.MaxAttempts 383 384 } 385 } 386 return rp, nil 387 } 388 389 func placementFromGRPC(p *swarmapi.Placement) *types.Placement { 390 if p == nil { 391 return nil 392 } 393 r := &types.Placement{ 394 Constraints: p.Constraints, 395 } 396 397 for _, pref := range p.Preferences { 398 if spread := pref.GetSpread(); spread != nil { 399 r.Preferences = append(r.Preferences, types.PlacementPreference{ 400 Spread: &types.SpreadOver{ 401 SpreadDescriptor: spread.SpreadDescriptor, 402 }, 403 }) 404 } 405 } 406 407 for _, plat := range p.Platforms { 408 r.Platforms = append(r.Platforms, types.Platform{ 409 Architecture: plat.Architecture, 410 OS: plat.OS, 411 }) 412 } 413 414 return r 415 } 416 417 func driverFromGRPC(p *swarmapi.Driver) *types.Driver { 418 if p == nil { 419 return nil 420 } 421 422 return &types.Driver{ 423 Name: p.Name, 424 Options: p.Options, 425 } 426 } 427 428 func driverToGRPC(p *types.Driver) *swarmapi.Driver { 429 if p == nil { 430 return nil 431 } 432 433 return &swarmapi.Driver{ 434 Name: p.Name, 435 Options: p.Options, 436 } 437 } 438 439 func updateConfigFromGRPC(updateConfig *swarmapi.UpdateConfig) *types.UpdateConfig { 440 if updateConfig == nil { 441 return nil 442 } 443 444 converted := &types.UpdateConfig{ 445 Parallelism: updateConfig.Parallelism, 446 MaxFailureRatio: updateConfig.MaxFailureRatio, 447 } 448 449 converted.Delay = updateConfig.Delay 450 if updateConfig.Monitor != nil { 451 converted.Monitor, _ = gogotypes.DurationFromProto(updateConfig.Monitor) 452 } 453 454 switch updateConfig.FailureAction { 455 case swarmapi.UpdateConfig_PAUSE: 456 converted.FailureAction = types.UpdateFailureActionPause 457 case swarmapi.UpdateConfig_CONTINUE: 458 converted.FailureAction = types.UpdateFailureActionContinue 459 case swarmapi.UpdateConfig_ROLLBACK: 460 converted.FailureAction = types.UpdateFailureActionRollback 461 } 462 463 switch updateConfig.Order { 464 case swarmapi.UpdateConfig_STOP_FIRST: 465 converted.Order = types.UpdateOrderStopFirst 466 case swarmapi.UpdateConfig_START_FIRST: 467 converted.Order = types.UpdateOrderStartFirst 468 } 469 470 return converted 471 } 472 473 func updateConfigToGRPC(updateConfig *types.UpdateConfig) (*swarmapi.UpdateConfig, error) { 474 if updateConfig == nil { 475 return nil, nil 476 } 477 478 converted := &swarmapi.UpdateConfig{ 479 Parallelism: updateConfig.Parallelism, 480 Delay: updateConfig.Delay, 481 MaxFailureRatio: updateConfig.MaxFailureRatio, 482 } 483 484 switch updateConfig.FailureAction { 485 case types.UpdateFailureActionPause, "": 486 converted.FailureAction = swarmapi.UpdateConfig_PAUSE 487 case types.UpdateFailureActionContinue: 488 converted.FailureAction = swarmapi.UpdateConfig_CONTINUE 489 case types.UpdateFailureActionRollback: 490 converted.FailureAction = swarmapi.UpdateConfig_ROLLBACK 491 default: 492 return nil, fmt.Errorf("unrecognized update failure action %s", updateConfig.FailureAction) 493 } 494 if updateConfig.Monitor != 0 { 495 converted.Monitor = gogotypes.DurationProto(updateConfig.Monitor) 496 } 497 498 switch updateConfig.Order { 499 case types.UpdateOrderStopFirst, "": 500 converted.Order = swarmapi.UpdateConfig_STOP_FIRST 501 case types.UpdateOrderStartFirst: 502 converted.Order = swarmapi.UpdateConfig_START_FIRST 503 default: 504 return nil, fmt.Errorf("unrecognized update order %s", updateConfig.Order) 505 } 506 507 return converted, nil 508 } 509 510 func taskSpecFromGRPC(taskSpec swarmapi.TaskSpec) types.TaskSpec { 511 taskNetworks := make([]types.NetworkAttachmentConfig, 0, len(taskSpec.Networks)) 512 for _, n := range taskSpec.Networks { 513 netConfig := types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverOpts: n.DriverAttachmentOpts} 514 taskNetworks = append(taskNetworks, netConfig) 515 } 516 517 c := taskSpec.GetContainer() 518 cSpec := types.ContainerSpec{} 519 if c != nil { 520 cSpec = containerSpecFromGRPC(c) 521 } 522 523 return types.TaskSpec{ 524 ContainerSpec: cSpec, 525 Resources: resourcesFromGRPC(taskSpec.Resources), 526 RestartPolicy: restartPolicyFromGRPC(taskSpec.Restart), 527 Placement: placementFromGRPC(taskSpec.Placement), 528 LogDriver: driverFromGRPC(taskSpec.LogDriver), 529 Networks: taskNetworks, 530 ForceUpdate: taskSpec.ForceUpdate, 531 } 532 }