Browse code

Add swarmkit fields to stack service.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/10/29 06:30:20
Showing 2 changed files
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"io/ioutil"
6 6
 	"os"
7 7
 	"strings"
8
-	"time"
9 8
 
10 9
 	"github.com/spf13/cobra"
11 10
 	"golang.org/x/net/context"
... ...
@@ -19,6 +18,8 @@ import (
19 19
 	"github.com/docker/docker/cli"
20 20
 	"github.com/docker/docker/cli/command"
21 21
 	servicecmd "github.com/docker/docker/cli/command/service"
22
+	runconfigopts "github.com/docker/docker/runconfig/opts"
23
+	"github.com/docker/docker/opts"
22 24
 	"github.com/docker/go-connections/nat"
23 25
 )
24 26
 
... ...
@@ -343,23 +344,37 @@ func convertService(
343 343
 		return swarm.ServiceSpec{}, err
344 344
 	}
345 345
 
346
+	resources, err := convertResources(service.Deploy.Resources)
347
+	if err != nil {
348
+		return swarm.ServiceSpec{}, err
349
+	}
350
+
351
+	restartPolicy, err := convertRestartPolicy(
352
+		service.Restart, service.Deploy.RestartPolicy)
353
+	if err != nil {
354
+		return swarm.ServiceSpec{}, err
355
+	}
356
+
346 357
 	serviceSpec := swarm.ServiceSpec{
347 358
 		Annotations: swarm.Annotations{
348 359
 			Name:   name,
349
-			Labels: getStackLabels(namespace, service.Labels),
360
+			Labels: getStackLabels(namespace, service.Deploy.Labels),
350 361
 		},
351 362
 		TaskTemplate: swarm.TaskSpec{
352 363
 			ContainerSpec: swarm.ContainerSpec{
353
-				Image:    service.Image,
354
-				Command:  service.Entrypoint,
355
-				Args:     service.Command,
356
-				Hostname: service.Hostname,
357
-				Env:      convertEnvironment(service.Environment),
358
-				Labels:   getStackLabels(namespace, service.Deploy.Labels),
359
-				Dir:      service.WorkingDir,
360
-				User:     service.User,
361
-				Mounts:   mounts,
364
+				Image:           service.Image,
365
+				Command:         service.Entrypoint,
366
+				Args:            service.Command,
367
+				Hostname:        service.Hostname,
368
+				Env:             convertEnvironment(service.Environment),
369
+				Labels:          getStackLabels(namespace, service.Labels),
370
+				Dir:             service.WorkingDir,
371
+				User:            service.User,
372
+				Mounts:          mounts,
373
+				StopGracePeriod: service.StopGracePeriod,
362 374
 			},
375
+			Resources:     resources,
376
+			RestartPolicy: restartPolicy,
363 377
 			Placement: &swarm.Placement{
364 378
 				Constraints: service.Deploy.Placement.Constraints,
365 379
 			},
... ...
@@ -367,18 +382,75 @@ func convertService(
367 367
 		EndpointSpec: endpoint,
368 368
 		Mode:         mode,
369 369
 		Networks:     convertNetworks(service.Networks, namespace, service.Name),
370
+		UpdateConfig: convertUpdateConfig(service.Deploy.UpdateConfig),
370 371
 	}
371 372
 
372
-	if service.StopGracePeriod != nil {
373
-		stopGrace, err := time.ParseDuration(*service.StopGracePeriod)
373
+	return serviceSpec, nil
374
+}
375
+
376
+func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*swarm.RestartPolicy, error) {
377
+	// TODO: log if restart is being ignored
378
+	if source == nil {
379
+		policy, err := runconfigopts.ParseRestartPolicy(restart)
374 380
 		if err != nil {
375
-			return swarm.ServiceSpec{}, err
381
+			return nil, err
382
+		}
383
+		// TODO: is this an accurate convertion?
384
+		switch {
385
+		case policy.IsNone(), policy.IsAlways(), policy.IsUnlessStopped():
386
+			return nil, nil
387
+		case policy.IsOnFailure():
388
+			attempts := uint64(policy.MaximumRetryCount)
389
+			return &swarm.RestartPolicy{
390
+				Condition:   swarm.RestartPolicyConditionOnFailure,
391
+				MaxAttempts: &attempts,
392
+			}, nil
376 393
 		}
377
-		serviceSpec.TaskTemplate.ContainerSpec.StopGracePeriod = &stopGrace
378 394
 	}
395
+	return &swarm.RestartPolicy{
396
+		Condition:   swarm.RestartPolicyCondition(source.Condition),
397
+		Delay:       source.Delay,
398
+		MaxAttempts: source.MaxAttempts,
399
+		Window:      source.Window,
400
+	}, nil
401
+}
379 402
 
380
-	// TODO: convert mounts
381
-	return serviceSpec, nil
403
+func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig {
404
+	if source == nil {
405
+		return nil
406
+	}
407
+	return &swarm.UpdateConfig{
408
+		Parallelism:     source.Parallelism,
409
+		Delay:           source.Delay,
410
+		FailureAction:   source.FailureAction,
411
+		Monitor:         source.Monitor,
412
+		MaxFailureRatio: source.MaxFailureRatio,
413
+	}
414
+}
415
+
416
+func convertResources(source composetypes.Resources) (*swarm.ResourceRequirements, error) {
417
+	resources := &swarm.ResourceRequirements{}
418
+	if source.Limits != nil {
419
+		cpus, err := opts.ParseCPUs(source.Limits.NanoCPUs)
420
+		if err != nil {
421
+			return nil, err
422
+		}
423
+		resources.Limits = &swarm.Resources{
424
+			NanoCPUs:    cpus,
425
+			MemoryBytes: int64(source.Limits.MemoryBytes),
426
+		}
427
+	}
428
+	if source.Reservations != nil {
429
+		cpus, err := opts.ParseCPUs(source.Reservations.NanoCPUs)
430
+		if err != nil {
431
+			return nil, err
432
+		}
433
+		resources.Reservations = &swarm.Resources{
434
+			NanoCPUs:    cpus,
435
+			MemoryBytes: int64(source.Reservations.MemoryBytes),
436
+		}
437
+	}
438
+	return resources, nil
382 439
 }
383 440
 
384 441
 func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
... ...
@@ -407,17 +479,17 @@ func convertEnvironment(source map[string]string) []string {
407 407
 	return output
408 408
 }
409 409
 
410
-func convertDeployMode(mode string, replicas uint64) (swarm.ServiceMode, error) {
410
+func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) {
411 411
 	serviceMode := swarm.ServiceMode{}
412 412
 
413 413
 	switch mode {
414 414
 	case "global":
415
-		if replicas != 0 {
415
+		if replicas != nil {
416 416
 			return serviceMode, fmt.Errorf("replicas can only be used with replicated mode")
417 417
 		}
418 418
 		serviceMode.Global = &swarm.GlobalService{}
419 419
 	case "replicated":
420
-		serviceMode.Replicated = &swarm.ReplicatedService{Replicas: &replicas}
420
+		serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas}
421 421
 	default:
422 422
 		return serviceMode, fmt.Errorf("Unknown mode: %s", mode)
423 423
 	}
... ...
@@ -331,16 +331,9 @@ func (c *NanoCPUs) String() string {
331 331
 
332 332
 // Set sets the value of the NanoCPU by passing a string
333 333
 func (c *NanoCPUs) Set(value string) error {
334
-	cpu, ok := new(big.Rat).SetString(value)
335
-	if !ok {
336
-		return fmt.Errorf("Failed to parse %v as a rational number", value)
337
-	}
338
-	nano := cpu.Mul(cpu, big.NewRat(1e9, 1))
339
-	if !nano.IsInt() {
340
-		return fmt.Errorf("value is too precise")
341
-	}
342
-	*c = NanoCPUs(nano.Num().Int64())
343
-	return nil
334
+	cpus, err := ParseCPUs(value)
335
+	*c = NanoCPUs(cpus)
336
+	return err
344 337
 }
345 338
 
346 339
 // Type returns the type
... ...
@@ -352,3 +345,16 @@ func (c *NanoCPUs) Type() string {
352 352
 func (c *NanoCPUs) Value() int64 {
353 353
 	return int64(*c)
354 354
 }
355
+
356
+// ParseCPUs takes a string ratio and returns an integer value of nano cpus
357
+func ParseCPUs(value string) (int64, error) {
358
+	cpu, ok := new(big.Rat).SetString(value)
359
+	if !ok {
360
+		return 0, fmt.Errorf("failed to parse %v as a rational number", value)
361
+	}
362
+	nano := cpu.Mul(cpu, big.NewRat(1e9, 1))
363
+	if !nano.IsInt() {
364
+		return 0, fmt.Errorf("value is too precise")
365
+	}
366
+	return nano.Num().Int64(), nil
367
+}