diff --git a/docs/user-guide.md b/docs/user-guide.md index 14b4e183..f5908a2b 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -298,7 +298,7 @@ The currently supported options are: | Key | Value | |----------------------|-------------------------------------| | kompose.service.type | nodeport / clusterip / loadbalancer / headless | -| kompose.service.expose | true / hostname | +| kompose.service.expose | true / hostnames (separated by comma) | | kompose.service.expose.tls-secret | secret name | | kompose.volume.size | kubernetes supported volume size | | kompose.controller.type | deployment / daemonset / replicationcontroller | @@ -326,7 +326,7 @@ services: ``` - `kompose.service.expose` defines if the service needs to be made accessible from outside the cluster or not. If the value is set to "true", the provider sets the endpoint automatically, and for any other value, the value is set as the hostname. If multiple ports are defined in a service, the first one is chosen to be the exposed. - - For the Kubernetes provider, an ingress resource is created and it is assumed that an ingress controller has already been configured. + - For the Kubernetes provider, an ingress resource is created and it is assumed that an ingress controller has already been configured. If the value is set to a comma sepatated list, multiple hostnames are supported. - For the OpenShift provider, a route is created. - `kompose.service.expose.tls-secret` provides the name of the TLS secret to use with the Kubernetes ingress controller. This requires kompose.service.expose to be set. @@ -342,7 +342,7 @@ services: links: - redis labels: - kompose.service.expose: "counter.example.com" + kompose.service.expose: "counter.example.com,foobar.example.com" kompose.service.expose.tls-secret: "example-secret" redis: image: redis:3.0 diff --git a/pkg/loader/compose/v1v2.go b/pkg/loader/compose/v1v2.go index 26ceb4a9..9f15b8a7 100644 --- a/pkg/loader/compose/v1v2.go +++ b/pkg/loader/compose/v1v2.go @@ -243,7 +243,7 @@ func libComposeToKomposeMapping(composeObject *project.Project) (kobject.Kompose serviceConfig.ServiceType = serviceType case LabelServiceExpose: - serviceConfig.ExposeService = strings.ToLower(value) + serviceConfig.ExposeService = strings.Trim(strings.ToLower(value), " ,") case LabelServiceExposeTLSSecret: serviceConfig.ExposeServiceTLS = value default: diff --git a/pkg/loader/compose/v3.go b/pkg/loader/compose/v3.go index e0b3d45e..1e7083a3 100644 --- a/pkg/loader/compose/v3.go +++ b/pkg/loader/compose/v3.go @@ -398,7 +398,7 @@ func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.Kompose serviceConfig.ServiceType = serviceType case LabelServiceExpose: - serviceConfig.ExposeService = strings.ToLower(value) + serviceConfig.ExposeService = strings.Trim(strings.ToLower(value), " ,") case LabelServiceExposeTLSSecret: serviceConfig.ExposeServiceTLS = value } diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index ef0f29bb..d4cc5eb6 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -19,6 +19,7 @@ package kubernetes import ( "fmt" "reflect" + "regexp" "strconv" "time" @@ -324,6 +325,8 @@ func (k *Kubernetes) InitDS(name string, service kobject.ServiceConfig) *extensi func (k *Kubernetes) initIngress(name string, service kobject.ServiceConfig, port int32) *extensions.Ingress { + hosts := regexp.MustCompile("[ ,]*,[ ,]*").Split(service.ExposeService, -1) + ingress := &extensions.Ingress{ TypeMeta: unversioned.TypeMeta{ Kind: "Ingress", @@ -334,36 +337,36 @@ func (k *Kubernetes) initIngress(name string, service kobject.ServiceConfig, por Labels: transformer.ConfigLabels(name), }, Spec: extensions.IngressSpec{ - Rules: []extensions.IngressRule{ - { - IngressRuleValue: extensions.IngressRuleValue{ - HTTP: &extensions.HTTPIngressRuleValue{ - Paths: []extensions.HTTPIngressPath{ - { - Backend: extensions.IngressBackend{ - ServiceName: name, - ServicePort: intstr.IntOrString{ - IntVal: port, - }, - }, + Rules: make([]extensions.IngressRule, len(hosts)), + }, + } + + for i, host := range hosts { + ingress.Spec.Rules[i] = extensions.IngressRule{ + IngressRuleValue: extensions.IngressRuleValue{ + HTTP: &extensions.HTTPIngressRuleValue{ + Paths: []extensions.HTTPIngressPath{ + { + Backend: extensions.IngressBackend{ + ServiceName: name, + ServicePort: intstr.IntOrString{ + IntVal: port, }, }, }, }, }, }, - }, + } + if host != "true" { + ingress.Spec.Rules[i].Host = host + } } - if service.ExposeService != "true" { - ingress.Spec.Rules[0].Host = service.ExposeService - } if service.ExposeServiceTLS != "" { ingress.Spec.TLS = []extensions.IngressTLS{ { - Hosts: []string{ - service.ExposeService, - }, + Hosts: hosts, SecretName: service.ExposeServiceTLS, }, } diff --git a/script/test/cmd/tests.sh b/script/test/cmd/tests.sh index 65312fbf..cf0d870e 100755 --- a/script/test/cmd/tests.sh +++ b/script/test/cmd/tests.sh @@ -388,6 +388,14 @@ convert::expect_success "$cmd" "/tmp/output-k8s.json" cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname-multiple-ports.yml convert --stdout -j" sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/expose-service/provider-files/kubernetes-expose-hostname-multiple-ports.json > /tmp/output-k8s.json convert::expect_success "$cmd" "/tmp/output-k8s.json" +# when kompose.service.expose=";;..." +cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname.yml convert --stdout -j" +sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname.json > /tmp/output-k8s.json +convert::expect_success "$cmd" "/tmp/output-k8s.json" +# when kompose.service.expose=";;..." and kompose.service.expose.tls-secret="" +cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname-tls.yml convert --stdout -j" +sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname-tls.json > /tmp/output-k8s.json +convert::expect_success "$cmd" "/tmp/output-k8s.json" #openshift tests # when kompose.service.expose="True" diff --git a/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname-tls.yml b/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname-tls.yml new file mode 100644 index 00000000..eb03b496 --- /dev/null +++ b/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname-tls.yml @@ -0,0 +1,13 @@ +web: + image: tuna/docker-counter23 + ports: + - "5000:5000" + links: + - redis + labels: + kompose.service.expose: "batman.example.com,batwoman.example.com" + kompose.service.expose.tls-secret: "test-secret" +redis: + image: redis:3.0 + ports: + - "6379" diff --git a/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname.yml b/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname.yml new file mode 100644 index 00000000..697d2f33 --- /dev/null +++ b/script/test/fixtures/expose-service/compose-files/docker-compose-expose-multiple-hostname.yml @@ -0,0 +1,12 @@ +web: + image: tuna/docker-counter23 + ports: + - "5000:5000" + links: + - redis + labels: + kompose.service.expose: " batman.example.com ,, batwoman.example.com " +redis: + image: redis:3.0 + ports: + - "6379" diff --git a/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname-tls.json b/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname-tls.json new file mode 100644 index 00000000..b85fac31 --- /dev/null +++ b/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname-tls.json @@ -0,0 +1,210 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "redis", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "redis" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "ports": [ + { + "name": "6379", + "port": 6379, + "targetPort": 6379 + } + ], + "selector": { + "io.kompose.service": "redis" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.service.expose": "batman.example.com,batwoman.example.com", + "kompose.service.expose.tls-secret": "test-secret" + } + }, + "spec": { + "ports": [ + { + "name": "5000", + "port": 5000, + "targetPort": 5000 + } + ], + "selector": { + "io.kompose.service": "web" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "redis", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "redis" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "replicas": 1, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "redis" + } + }, + "spec": { + "containers": [ + { + "name": "redis", + "image": "redis:3.0", + "ports": [ + { + "containerPort": 6379 + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + }, + "strategy": {} + }, + "status": {} + }, + { + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.service.expose": "batman.example.com,batwoman.example.com", + "kompose.service.expose.tls-secret": "test-secret" + } + }, + "spec": { + "replicas": 1, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "containers": [ + { + "name": "web", + "image": "tuna/docker-counter23", + "ports": [ + { + "containerPort": 5000 + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + }, + "strategy": {} + }, + "status": {} + }, + { + "kind": "Ingress", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "tls": [ + { + "hosts": [ + "batman.example.com", + "batwoman.example.com" + ], + "secretName": "test-secret" + } + ], + "rules": [ + { + "host": "batman.example.com", + "http": { + "paths": [ + { + "backend": { + "serviceName": "web", + "servicePort": 5000 + } + } + ] + } + }, + { + "host": "batwoman.example.com", + "http": { + "paths": [ + { + "backend": { + "serviceName": "web", + "servicePort": 5000 + } + } + ] + } + } + ] + }, + "status": { + "loadBalancer": {} + } + } + ] +} diff --git a/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname.json b/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname.json new file mode 100644 index 00000000..87a888fc --- /dev/null +++ b/script/test/fixtures/expose-service/provider-files/kubernetes-expose-multiple-hostname.json @@ -0,0 +1,199 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "redis", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "redis" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "ports": [ + { + "name": "6379", + "port": 6379, + "targetPort": 6379 + } + ], + "selector": { + "io.kompose.service": "redis" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.service.expose": " batman.example.com ,, batwoman.example.com " + } + }, + "spec": { + "ports": [ + { + "name": "5000", + "port": 5000, + "targetPort": 5000 + } + ], + "selector": { + "io.kompose.service": "web" + } + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "redis", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "redis" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%" + } + }, + "spec": { + "replicas": 1, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "redis" + } + }, + "spec": { + "containers": [ + { + "name": "redis", + "image": "redis:3.0", + "ports": [ + { + "containerPort": 6379 + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + }, + "strategy": {} + }, + "status": {} + }, + { + "kind": "Deployment", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + }, + "annotations": { + "kompose.cmd": "%CMD%", + "kompose.version": "%VERSION%", + "kompose.service.expose": " batman.example.com ,, batwoman.example.com " + } + }, + "spec": { + "replicas": 1, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "containers": [ + { + "name": "web", + "image": "tuna/docker-counter23", + "ports": [ + { + "containerPort": 5000 + } + ], + "resources": {} + } + ], + "restartPolicy": "Always" + } + }, + "strategy": {} + }, + "status": {} + }, + { + "kind": "Ingress", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "web", + "creationTimestamp": null, + "labels": { + "io.kompose.service": "web" + } + }, + "spec": { + "rules": [ + { + "host": "batman.example.com", + "http": { + "paths": [ + { + "backend": { + "serviceName": "web", + "servicePort": 5000 + } + } + ] + } + }, + { + "host": "batwoman.example.com", + "http": { + "paths": [ + { + "backend": { + "serviceName": "web", + "servicePort": 5000 + } + } + ] + } + } + ] + }, + "status": { + "loadBalancer": {} + } + } + ] +}