瀏覽代碼

Add swarmkit fields to stack service.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin 8 年之前
父節點
當前提交
13384ba34b
共有 2 個文件被更改,包括 108 次插入30 次删除
  1. 92 20
      cli/command/stack/deploy.go
  2. 16 10
      opts/opts.go

+ 92 - 20
cli/command/stack/deploy.go

@@ -5,7 +5,6 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
@@ -19,6 +18,8 @@ import (
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cli/command"
 	"github.com/docker/docker/cli/command"
 	servicecmd "github.com/docker/docker/cli/command/service"
 	servicecmd "github.com/docker/docker/cli/command/service"
+	runconfigopts "github.com/docker/docker/runconfig/opts"
+	"github.com/docker/docker/opts"
 	"github.com/docker/go-connections/nat"
 	"github.com/docker/go-connections/nat"
 )
 )
 
 
@@ -343,23 +344,37 @@ func convertService(
 		return swarm.ServiceSpec{}, err
 		return swarm.ServiceSpec{}, err
 	}
 	}
 
 
+	resources, err := convertResources(service.Deploy.Resources)
+	if err != nil {
+		return swarm.ServiceSpec{}, err
+	}
+
+	restartPolicy, err := convertRestartPolicy(
+		service.Restart, service.Deploy.RestartPolicy)
+	if err != nil {
+		return swarm.ServiceSpec{}, err
+	}
+
 	serviceSpec := swarm.ServiceSpec{
 	serviceSpec := swarm.ServiceSpec{
 		Annotations: swarm.Annotations{
 		Annotations: swarm.Annotations{
 			Name:   name,
 			Name:   name,
-			Labels: getStackLabels(namespace, service.Labels),
+			Labels: getStackLabels(namespace, service.Deploy.Labels),
 		},
 		},
 		TaskTemplate: swarm.TaskSpec{
 		TaskTemplate: swarm.TaskSpec{
 			ContainerSpec: swarm.ContainerSpec{
 			ContainerSpec: swarm.ContainerSpec{
-				Image:    service.Image,
-				Command:  service.Entrypoint,
-				Args:     service.Command,
-				Hostname: service.Hostname,
-				Env:      convertEnvironment(service.Environment),
-				Labels:   getStackLabels(namespace, service.Deploy.Labels),
-				Dir:      service.WorkingDir,
-				User:     service.User,
-				Mounts:   mounts,
+				Image:           service.Image,
+				Command:         service.Entrypoint,
+				Args:            service.Command,
+				Hostname:        service.Hostname,
+				Env:             convertEnvironment(service.Environment),
+				Labels:          getStackLabels(namespace, service.Labels),
+				Dir:             service.WorkingDir,
+				User:            service.User,
+				Mounts:          mounts,
+				StopGracePeriod: service.StopGracePeriod,
 			},
 			},
+			Resources:     resources,
+			RestartPolicy: restartPolicy,
 			Placement: &swarm.Placement{
 			Placement: &swarm.Placement{
 				Constraints: service.Deploy.Placement.Constraints,
 				Constraints: service.Deploy.Placement.Constraints,
 			},
 			},
@@ -367,18 +382,75 @@ func convertService(
 		EndpointSpec: endpoint,
 		EndpointSpec: endpoint,
 		Mode:         mode,
 		Mode:         mode,
 		Networks:     convertNetworks(service.Networks, namespace, service.Name),
 		Networks:     convertNetworks(service.Networks, namespace, service.Name),
+		UpdateConfig: convertUpdateConfig(service.Deploy.UpdateConfig),
 	}
 	}
 
 
-	if service.StopGracePeriod != nil {
-		stopGrace, err := time.ParseDuration(*service.StopGracePeriod)
+	return serviceSpec, nil
+}
+
+func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*swarm.RestartPolicy, error) {
+	// TODO: log if restart is being ignored
+	if source == nil {
+		policy, err := runconfigopts.ParseRestartPolicy(restart)
 		if err != nil {
 		if err != nil {
-			return swarm.ServiceSpec{}, err
+			return nil, err
+		}
+		// TODO: is this an accurate convertion?
+		switch {
+		case policy.IsNone(), policy.IsAlways(), policy.IsUnlessStopped():
+			return nil, nil
+		case policy.IsOnFailure():
+			attempts := uint64(policy.MaximumRetryCount)
+			return &swarm.RestartPolicy{
+				Condition:   swarm.RestartPolicyConditionOnFailure,
+				MaxAttempts: &attempts,
+			}, nil
 		}
 		}
-		serviceSpec.TaskTemplate.ContainerSpec.StopGracePeriod = &stopGrace
 	}
 	}
+	return &swarm.RestartPolicy{
+		Condition:   swarm.RestartPolicyCondition(source.Condition),
+		Delay:       source.Delay,
+		MaxAttempts: source.MaxAttempts,
+		Window:      source.Window,
+	}, nil
+}
 
 
-	// TODO: convert mounts
-	return serviceSpec, nil
+func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig {
+	if source == nil {
+		return nil
+	}
+	return &swarm.UpdateConfig{
+		Parallelism:     source.Parallelism,
+		Delay:           source.Delay,
+		FailureAction:   source.FailureAction,
+		Monitor:         source.Monitor,
+		MaxFailureRatio: source.MaxFailureRatio,
+	}
+}
+
+func convertResources(source composetypes.Resources) (*swarm.ResourceRequirements, error) {
+	resources := &swarm.ResourceRequirements{}
+	if source.Limits != nil {
+		cpus, err := opts.ParseCPUs(source.Limits.NanoCPUs)
+		if err != nil {
+			return nil, err
+		}
+		resources.Limits = &swarm.Resources{
+			NanoCPUs:    cpus,
+			MemoryBytes: int64(source.Limits.MemoryBytes),
+		}
+	}
+	if source.Reservations != nil {
+		cpus, err := opts.ParseCPUs(source.Reservations.NanoCPUs)
+		if err != nil {
+			return nil, err
+		}
+		resources.Reservations = &swarm.Resources{
+			NanoCPUs:    cpus,
+			MemoryBytes: int64(source.Reservations.MemoryBytes),
+		}
+	}
+	return resources, nil
 }
 }
 
 
 func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
 func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
@@ -407,17 +479,17 @@ func convertEnvironment(source map[string]string) []string {
 	return output
 	return output
 }
 }
 
 
-func convertDeployMode(mode string, replicas uint64) (swarm.ServiceMode, error) {
+func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) {
 	serviceMode := swarm.ServiceMode{}
 	serviceMode := swarm.ServiceMode{}
 
 
 	switch mode {
 	switch mode {
 	case "global":
 	case "global":
-		if replicas != 0 {
+		if replicas != nil {
 			return serviceMode, fmt.Errorf("replicas can only be used with replicated mode")
 			return serviceMode, fmt.Errorf("replicas can only be used with replicated mode")
 		}
 		}
 		serviceMode.Global = &swarm.GlobalService{}
 		serviceMode.Global = &swarm.GlobalService{}
 	case "replicated":
 	case "replicated":
-		serviceMode.Replicated = &swarm.ReplicatedService{Replicas: &replicas}
+		serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas}
 	default:
 	default:
 		return serviceMode, fmt.Errorf("Unknown mode: %s", mode)
 		return serviceMode, fmt.Errorf("Unknown mode: %s", mode)
 	}
 	}

+ 16 - 10
opts/opts.go

@@ -331,16 +331,9 @@ func (c *NanoCPUs) String() string {
 
 
 // Set sets the value of the NanoCPU by passing a string
 // Set sets the value of the NanoCPU by passing a string
 func (c *NanoCPUs) Set(value string) error {
 func (c *NanoCPUs) Set(value string) error {
-	cpu, ok := new(big.Rat).SetString(value)
-	if !ok {
-		return fmt.Errorf("Failed to parse %v as a rational number", value)
-	}
-	nano := cpu.Mul(cpu, big.NewRat(1e9, 1))
-	if !nano.IsInt() {
-		return fmt.Errorf("value is too precise")
-	}
-	*c = NanoCPUs(nano.Num().Int64())
-	return nil
+	cpus, err := ParseCPUs(value)
+	*c = NanoCPUs(cpus)
+	return err
 }
 }
 
 
 // Type returns the type
 // Type returns the type
@@ -352,3 +345,16 @@ func (c *NanoCPUs) Type() string {
 func (c *NanoCPUs) Value() int64 {
 func (c *NanoCPUs) Value() int64 {
 	return int64(*c)
 	return int64(*c)
 }
 }
+
+// ParseCPUs takes a string ratio and returns an integer value of nano cpus
+func ParseCPUs(value string) (int64, error) {
+	cpu, ok := new(big.Rat).SetString(value)
+	if !ok {
+		return 0, fmt.Errorf("failed to parse %v as a rational number", value)
+	}
+	nano := cpu.Mul(cpu, big.NewRat(1e9, 1))
+	if !nano.IsInt() {
+		return 0, fmt.Errorf("value is too precise")
+	}
+	return nano.Num().Int64(), nil
+}