diff --git a/docs/user-guide.md b/docs/user-guide.md index 5416536c..e16a7dc6 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -301,6 +301,7 @@ The currently supported options are: | kompose.service.expose | true / hostname | | kompose.service.expose.tls-secret | secret name | | kompose.volume.size | kubernetes supported volume size | +| kompose.controller.type | deployment / daemonset / replicationcontroller | **Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail. @@ -364,6 +365,39 @@ services: - db-data:/var/lib/postgresql/data ``` +- `kompose.controller.type` defines which controller type should convert for this service + +For example: + +``` +web: + image: wordpress:4.5 + ports: + - '80' + environment: + WORDPRESS_AUTH_KEY: changeme + WORDPRESS_SECURE_AUTH_KEY: changeme + WORDPRESS_LOGGED_IN_KEY: changeme + WORDPRESS_NONCE_KEY: changeme + WORDPRESS_AUTH_SALT: changeme + WORDPRESS_SECURE_AUTH_SALT: changeme + WORDPRESS_LOGGED_IN_SALT: changeme + WORDPRESS_NONCE_SALT: changeme + WORDPRESS_NONCE_AA: changeme + restart: always + links: + - 'db:mysql' +db: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: password + restart: always + labels: + project.logs: /var/log/mysql + kompose.controller.type: daemonset +``` + +Service `web` will be converted to `Deployment` as default, service `db` will be converted to `DaemonSet` because of `kompose.controller.type` label. ## Restart diff --git a/pkg/loader/compose/utils.go b/pkg/loader/compose/utils.go index 216620d9..d67732e1 100644 --- a/pkg/loader/compose/utils.go +++ b/pkg/loader/compose/utils.go @@ -33,6 +33,8 @@ const ( LabelServiceExpose = "kompose.service.expose" // LabelServiceExposeTLSSecret provides the name of the TLS secret to use with the Kubernetes ingress controller LabelServiceExposeTLSSecret = "kompose.service.expose.tls-secret" + // LabelControllerType defines the type of controller to be created + LabelControllerType = "kompose.controller.type" // ServiceTypeHeadless ... ServiceTypeHeadless = "Headless" diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index e041cf2a..eaeb5b2e 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -48,6 +48,7 @@ import ( "sort" "strings" + "github.com/kubernetes/kompose/pkg/loader/compose" "github.com/pkg/errors" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/labels" @@ -67,6 +68,12 @@ const TIMEOUT = 300 // PVCRequestSize (Persistent Volume Claim) has default size const PVCRequestSize = "100Mi" +const ( + DeploymentController = "deployment" + DaemonSetController = "daemonset" + ReplicationController = "replicationcontroller" +) + // CheckUnsupportedKey checks if given komposeObject contains // keys that are not supported by this transformer. // list of all unsupported keys are stored in unsupportedKey variable @@ -635,13 +642,25 @@ func (k *Kubernetes) CreateKubernetesObjects(name string, service kobject.Servic } } - if opt.CreateD || opt.Controller == "deployment" { + + //Resolve labels first + if val, ok := service.Labels[compose.LabelControllerType]; ok { + opt.CreateD = false + opt.CreateDS = false + opt.CreateRC = false + if opt.Controller != "" { + log.Warnf("Use label %s type %s for service %s, ignore %s flags", compose.LabelControllerType, val, name, opt.Controller) + } + opt.Controller = val + } + + if opt.CreateD || opt.Controller == DeploymentController { objects = append(objects, k.InitD(name, service, replica)) } - if opt.CreateDS || opt.Controller == "daemonset" { + if opt.CreateDS || opt.Controller == DaemonSetController { objects = append(objects, k.InitDS(name, service)) } - if opt.CreateRC || opt.Controller == "replicationcontroller" { + if opt.CreateRC || opt.Controller == ReplicationController { objects = append(objects, k.InitRC(name, service, replica)) } diff --git a/script/test/cmd/tests.sh b/script/test/cmd/tests.sh index 02f16369..079e15d8 100755 --- a/script/test/cmd/tests.sh +++ b/script/test/cmd/tests.sh @@ -741,5 +741,22 @@ cmd="kompose convert --controller deployment --stdout -j -f $KOMPOSE_ROOT/script sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/controller/output-k8s-global-deployment-template.json > /tmp/output-k8s.json convert::expect_success_and_warning "$cmd" "/tmp/output-k8s.json" +## Test label kompose.controller.type +cmd="kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/controller/compose-controller-label.yml" +sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/controller/output-k8s-controller-template.json > /tmp/output-k8s.json +convert::expect_success_and_warning "$cmd" "/tmp/output-k8s.json" + +cmd="kompose convert --controller deployment --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/controller/compose-controller-label.yml" +sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/controller/output-k8s-controller-template.json > /tmp/output-k8s.json +convert::expect_success_and_warning "$cmd" "/tmp/output-k8s.json" + +cmd="kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/controller/compose-controller-label-v3.yml" +sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/controller/output-k8s-controller-v3-template.json > /tmp/output-k8s.json +convert::expect_success "$cmd" "/tmp/output-k8s.json" + +cmd="kompose --provider=openshift convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/controller/compose-controller-label-v3.yml" +sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/controller/output-os-controller-v3-template.json > /tmp/output-os.json +convert::expect_success "$cmd" "/tmp/output-os.json" + rm /tmp/output-k8s.json /tmp/output-os.json exit $EXIT_STATUS diff --git a/script/test/fixtures/controller/compose-controller-label-v3.yml b/script/test/fixtures/controller/compose-controller-label-v3.yml new file mode 100644 index 00000000..20b7035f --- /dev/null +++ b/script/test/fixtures/controller/compose-controller-label-v3.yml @@ -0,0 +1,29 @@ +version: '3' +services: + web: + image: wordpress:4 + environment: + - WORDPRESS_DB_PASSWORD=password + - WORDPRESS_AUTH_KEY=changeme + - WORDPRESS_SECURE_AUTH_KEY=changeme + - WORDPRESS_LOGGED_IN_KEY=changeme + - WORDPRESS_NONCE_KEY=changeme + - WORDPRESS_AUTH_SALT=changeme + - WORDPRESS_SECURE_AUTH_SALT=changeme + - WORDPRESS_LOGGED_IN_SALT=changeme + - WORDPRESS_NONCE_SALT=changeme + - WORDPRESS_NONCE_AA=changeme + ports: + - 80 + depends_on: + - mysql + deploy: + replicas: 3 + labels: + port: wordpress + mysql: + image: mysql:5.7 + environment: + - MYSQL_ROOT_PASSWORD=password + labels: + kompose.controller.type: daemonset \ No newline at end of file diff --git a/script/test/fixtures/controller/compose-controller-label.yml b/script/test/fixtures/controller/compose-controller-label.yml new file mode 100644 index 00000000..03075ef1 --- /dev/null +++ b/script/test/fixtures/controller/compose-controller-label.yml @@ -0,0 +1,25 @@ +web: + image: wordpress:4.5 + ports: + - '80' + environment: + WORDPRESS_AUTH_KEY: changeme + WORDPRESS_SECURE_AUTH_KEY: changeme + WORDPRESS_LOGGED_IN_KEY: changeme + WORDPRESS_NONCE_KEY: changeme + WORDPRESS_AUTH_SALT: changeme + WORDPRESS_SECURE_AUTH_SALT: changeme + WORDPRESS_LOGGED_IN_SALT: changeme + WORDPRESS_NONCE_SALT: changeme + WORDPRESS_NONCE_AA: changeme + restart: always + links: + - 'db:mysql' +db: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: password + restart: always + labels: + project.logs: /var/log/mysql + kompose.controller.type: daemonset \ No newline at end of file diff --git a/script/test/fixtures/controller/output-k8s-controller-template.json b/script/test/fixtures/controller/output-k8s-controller-template.json new file mode 100644 index 00000000..f72877a1 --- /dev/null +++ b/script/test/fixtures/controller/output-k8s-controller-template.json @@ -0,0 +1,166 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "io.kompose.service": "web" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DaemonSet", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "db", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "db" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.controller.type": "daemonset", + "project.logs": "/var/log/mysql" + } + }, + "spec": { + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "db" + } + }, + "spec": { + "containers": [ + { + "name": "db", + "image": "mysql:5.7", + "env": [ + { + "name": "MYSQL_ROOT_PASSWORD", + "value": "password" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + } + }, + "status": { + "currentNumberScheduled": 0, + "numberMisscheduled": 0, + "desiredNumberScheduled": 0 + } + }, + { + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "replicas": 1, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "containers": [ + { + "name": "web", + "image": "wordpress:4.5", + "ports": [ + { + "containerPort": 80 + } + ], + "env": [ + { + "name": "WORDPRESS_AUTH_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_AUTH_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_LOGGED_IN_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_LOGGED_IN_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_AA", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_SECURE_AUTH_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_SECURE_AUTH_SALT", + "value": "changeme" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + }, + "strategy": {} + }, + "status": {} + } + ] +} \ No newline at end of file diff --git a/script/test/fixtures/controller/output-k8s-controller-v3-template.json b/script/test/fixtures/controller/output-k8s-controller-v3-template.json new file mode 100644 index 00000000..5ea77141 --- /dev/null +++ b/script/test/fixtures/controller/output-k8s-controller-v3-template.json @@ -0,0 +1,171 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "port": "wordpress" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "io.kompose.service": "web" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DaemonSet", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "mysql", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.controller.type": "daemonset" + } + }, + "spec": { + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": "mysql:5.7", + "env": [ + { + "name": "MYSQL_ROOT_PASSWORD", + "value": "password" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + } + }, + "status": { + "currentNumberScheduled": 0, + "numberMisscheduled": 0, + "desiredNumberScheduled": 0 + } + }, + { + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "port": "wordpress" + } + }, + "spec": { + "replicas": 3, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "containers": [ + { + "name": "web", + "image": "wordpress:4", + "ports": [ + { + "containerPort": 80 + } + ], + "env": [ + { + "name": "WORDPRESS_AUTH_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_AUTH_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_DB_PASSWORD", + "value": "password" + }, + { + "name": "WORDPRESS_LOGGED_IN_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_LOGGED_IN_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_AA", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_SECURE_AUTH_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_SECURE_AUTH_SALT", + "value": "changeme" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + }, + "strategy": {} + }, + "status": {} + } + ] +} \ No newline at end of file diff --git a/script/test/fixtures/controller/output-os-controller-v3-template.json b/script/test/fixtures/controller/output-os-controller-v3-template.json new file mode 100644 index 00000000..afd53a7e --- /dev/null +++ b/script/test/fixtures/controller/output-os-controller-v3-template.json @@ -0,0 +1,320 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "port": "wordpress" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "io.kompose.service": "web" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DaemonSet", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "mysql", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.controller.type": "daemonset", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": "mysql:5.7", + "env": [ + { + "name": "MYSQL_ROOT_PASSWORD", + "value": "password" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + } + }, + "status": { + "currentNumberScheduled": 0, + "numberMisscheduled": 0, + "desiredNumberScheduled": 0 + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "mysql", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.controller.type": "daemonset", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "strategy": { + "resources": {} + }, + "triggers": [ + { + "type": "ConfigChange" + }, + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "mysql" + ], + "from": { + "kind": "ImageStreamTag", + "name": "mysql:5.7" + } + } + } + ], + "replicas": 1, + "test": false, + "selector": { + "io.kompose.service": "mysql" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": " ", + "env": [ + { + "name": "MYSQL_ROOT_PASSWORD", + "value": "password" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + } + }, + "status": {} + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "mysql", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "mysql" + } + }, + "spec": { + "tags": [ + { + "name": "5.7", + "annotations": null, + "from": { + "kind": "DockerImage", + "name": "mysql:5.7" + }, + "generation": null, + "importPolicy": {} + } + ] + }, + "status": { + "dockerImageRepository": "" + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "port": "wordpress" + } + }, + "spec": { + "strategy": { + "resources": {} + }, + "triggers": [ + { + "type": "ConfigChange" + }, + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "web" + ], + "from": { + "kind": "ImageStreamTag", + "name": "web:4" + } + } + } + ], + "replicas": 3, + "test": false, + "selector": { + "io.kompose.service": "web" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "containers": [ + { + "name": "web", + "image": " ", + "ports": [ + { + "containerPort": 80 + } + ], + "env": [ + { + "name": "WORDPRESS_AUTH_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_AUTH_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_DB_PASSWORD", + "value": "password" + }, + { + "name": "WORDPRESS_LOGGED_IN_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_LOGGED_IN_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_AA", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_NONCE_SALT", + "value": "changeme" + }, + { + "name": "WORDPRESS_SECURE_AUTH_KEY", + "value": "changeme" + }, + { + "name": "WORDPRESS_SECURE_AUTH_SALT", + "value": "changeme" + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + } + }, + "status": {} + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "tags": [ + { + "name": "4", + "annotations": null, + "from": { + "kind": "DockerImage", + "name": "wordpress:4" + }, + "generation": null, + "importPolicy": {} + } + ] + }, + "status": { + "dockerImageRepository": "" + } + } + ] +} \ No newline at end of file