Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -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 |
+} |