From c01f6f1763c2d40aa049463741b04751c4495143 Mon Sep 17 00:00:00 2001 From: gitlawr Date: Thu, 18 May 2017 13:58:26 +0800 Subject: [PATCH] To solve #440 This commit Add support for stop_grace_period which maps to Pod.Spec.TerminationGracePeriodSeconds Updated conversion.md on support for the key --- docs/conversion.md | 2 +- pkg/kobject/kobject.go | 61 +++++++++++---------- pkg/loader/compose/compose.go | 1 + pkg/transformer/kubernetes/k8sutils.go | 24 +++++++- pkg/transformer/kubernetes/k8sutils_test.go | 30 +++++++++- 5 files changed, 85 insertions(+), 33 deletions(-) diff --git a/docs/conversion.md b/docs/conversion.md index e22a4cb6..c077a5df 100644 --- a/docs/conversion.md +++ b/docs/conversion.md @@ -35,7 +35,7 @@ This document outlines all the conversion details regarding `docker-compose.yaml | pid | | N | | | | ports | | Y | [Service.Spec.Ports](https://kubernetes.io/docs/api-reference/v1/definitions/#_v1_containerport) | | | security_opt | | N | | | -| stop_grace_period | | N | | | +| stop_grace_period | | Y | [Pod.Spec.TerminationGracePeriodSeconds](https://kubernetes.io/docs/resources-reference/v1.6/#podspec-v1-core) | | | stop_signal | | N | | | | sysctls | | N | | | | ulimits | | N | | See this [issue](https://github.com/kubernetes/kubernetes/issues/3595) on the k8s repo | diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index 594ee085..3572423d 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -59,36 +59,37 @@ type ConvertOptions struct { // ServiceConfig holds the basic struct of a container type ServiceConfig struct { // use tags to mark from what element this value comes - ContainerName string - Image string `compose:"image" bundle:"Image"` - Environment []EnvVar `compose:"environment" bundle:"Env"` - Port []Ports `compose:"ports" bundle:"Ports"` - Command []string `compose:"command" bundle:"Command"` - WorkingDir string `compose:"" bundle:"WorkingDir"` - Args []string `compose:"args" bundle:"Args"` - Volumes []string `compose:"volumes" bundle:"Volumes"` - Network []string `compose:"network" bundle:"Networks"` - Labels map[string]string `compose:"labels" bundle:"Labels"` - Annotations map[string]string `compose:"" bundle:""` - CPUSet string `compose:"cpuset" bundle:""` - CPUShares int64 `compose:"cpu_shares" bundle:""` - CPUQuota int64 `compose:"cpu_quota" bundle:""` - CapAdd []string `compose:"cap_add" bundle:""` - CapDrop []string `compose:"cap_drop" bundle:""` - Expose []string `compose:"expose" bundle:""` - Privileged bool `compose:"privileged" bundle:""` - Restart string `compose:"restart" bundle:""` - User string `compose:"user" bundle:"User"` - VolumesFrom []string `compose:"volumes_from" bundle:""` - ServiceType string `compose:"kompose.service.type" bundle:""` - Build string `compose:"build" bundle:""` - BuildArgs map[string]*string `compose:"build-args" bundle:""` - ExposeService string `compose:"kompose.service.expose" bundle:""` - Stdin bool `compose:"stdin_open" bundle:""` - Tty bool `compose:"tty" bundle:""` - MemLimit yaml.MemStringorInt `compose:"mem_limit" bundle:""` - TmpFs []string `compose:"tmpfs" bundle:""` - Dockerfile string `compose:"dockerfile" bundle:""` + ContainerName string + Image string `compose:"image" bundle:"Image"` + Environment []EnvVar `compose:"environment" bundle:"Env"` + Port []Ports `compose:"ports" bundle:"Ports"` + Command []string `compose:"command" bundle:"Command"` + WorkingDir string `compose:"" bundle:"WorkingDir"` + Args []string `compose:"args" bundle:"Args"` + Volumes []string `compose:"volumes" bundle:"Volumes"` + Network []string `compose:"network" bundle:"Networks"` + Labels map[string]string `compose:"labels" bundle:"Labels"` + Annotations map[string]string `compose:"" bundle:""` + CPUSet string `compose:"cpuset" bundle:""` + CPUShares int64 `compose:"cpu_shares" bundle:""` + CPUQuota int64 `compose:"cpu_quota" bundle:""` + CapAdd []string `compose:"cap_add" bundle:""` + CapDrop []string `compose:"cap_drop" bundle:""` + Expose []string `compose:"expose" bundle:""` + Privileged bool `compose:"privileged" bundle:""` + Restart string `compose:"restart" bundle:""` + User string `compose:"user" bundle:"User"` + VolumesFrom []string `compose:"volumes_from" bundle:""` + ServiceType string `compose:"kompose.service.type" bundle:""` + StopGracePeriod string `compose:"stop_grace_period" bundle:""` + Build string `compose:"build" bundle:""` + BuildArgs map[string]*string `compose:"build-args" bundle:""` + ExposeService string `compose:"kompose.service.expose" bundle:""` + Stdin bool `compose:"stdin_open" bundle:""` + Tty bool `compose:"tty" bundle:""` + MemLimit yaml.MemStringorInt `compose:"mem_limit" bundle:""` + TmpFs []string `compose:"tmpfs" bundle:""` + Dockerfile string `compose:"dockerfile" bundle:""` } // EnvVar holds the environment variable struct of a container diff --git a/pkg/loader/compose/compose.go b/pkg/loader/compose/compose.go index e8c093c6..61b97d92 100644 --- a/pkg/loader/compose/compose.go +++ b/pkg/loader/compose/compose.go @@ -373,6 +373,7 @@ func (c *Compose) LoadFile(files []string) (kobject.KomposeObject, error) { serviceConfig.Tty = composeServiceConfig.Tty serviceConfig.MemLimit = composeServiceConfig.MemLimit serviceConfig.TmpFs = composeServiceConfig.Tmpfs + serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig if normalizeServiceNames(name) != name { log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name)) diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index 01a67b47..f40100a3 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -27,6 +27,7 @@ import ( "strconv" "strings" "text/template" + "time" log "github.com/Sirupsen/logrus" "github.com/ghodss/yaml" @@ -38,10 +39,11 @@ import ( "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/runtime" + "sort" + deployapi "github.com/openshift/origin/pkg/deploy/api" "github.com/pkg/errors" "k8s.io/kubernetes/pkg/api/resource" - "sort" ) /** @@ -382,6 +384,13 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic template.Spec.Containers[0].TTY = service.Tty template.Spec.Volumes = volumes + if service.StopGracePeriod != "" { + template.Spec.TerminationGracePeriodSeconds, err = DurationStrToSecondsInt(service.StopGracePeriod) + if err != nil { + log.Warningf("Failed to parse duration \"%v\" for service \"%v\"", service.StopGracePeriod, name) + } + } + // Configure the resource limits if service.MemLimit != 0 { memoryResourceList := api.ResourceList{ @@ -553,3 +562,16 @@ func SortedKeys(komposeObject kobject.KomposeObject) []string { sort.Strings(sortedKeys) return sortedKeys } + +//converts duration string to *int64 in seconds +func DurationStrToSecondsInt(s string) (*int64, error) { + if s == "" { + return nil, nil + } + duration, err := time.ParseDuration(s) + if err != nil { + return nil, err + } + r := (int64)(duration.Seconds()) + return &r, nil +} diff --git a/pkg/transformer/kubernetes/k8sutils_test.go b/pkg/transformer/kubernetes/k8sutils_test.go index 34d6aa45..7c2ed342 100644 --- a/pkg/transformer/kubernetes/k8sutils_test.go +++ b/pkg/transformer/kubernetes/k8sutils_test.go @@ -26,10 +26,11 @@ import ( "github.com/kubernetes-incubator/kompose/pkg/kobject" "github.com/kubernetes-incubator/kompose/pkg/testutils" + "reflect" + "github.com/pkg/errors" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/extensions" - "reflect" ) /* @@ -296,3 +297,30 @@ func TestSortedKeys(t *testing.T) { t.Logf("Test Fail output should be %s", c) } } + +//test conversion from duration string to seconds *int64 +func TestDurationStrToSecondsInt(t *testing.T) { + testCases := map[string]struct { + in string + out *int64 + }{ + "5s": {in: "5s", out: &[]int64{5}[0]}, + "1m30s": {in: "1m30s", out: &[]int64{90}[0]}, + "empty": {in: "", out: nil}, + "onlynumber": {in: "2", out: nil}, + "illegal": {in: "abc", out: nil}, + } + + for name, test := range testCases { + result, _ := DurationStrToSecondsInt(test.in) + if test.out == nil && result != nil { + t.Errorf("Case '%v' for TestDurationStrToSecondsInt fail, Expected 'nil' , got '%v'", name, *result) + } + if test.out != nil && result == nil { + t.Errorf("Case '%v' for TestDurationStrToSecondsInt fail, Expected '%v' , got 'nil'", name, *test.out) + } + if test.out != nil && result != nil && *test.out != *result { + t.Errorf("Case '%v' for TestDurationStrToSecondsInt fail, Expected '%v' , got '%v'", name, *test.out, *result) + } + } +}