diff --git a/docs/user-guide.md b/docs/user-guide.md index 6c4f1fb3..8b2eccdd 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -313,6 +313,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 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. For example: @@ -327,6 +328,7 @@ services: - redis labels: kompose.service.expose: "counter.example.com" + kompose.service.expose.tls-secret: "example-secret" redis: image: redis:3.0 ports: @@ -338,7 +340,8 @@ The currently supported options are: | Key | Value | |----------------------|-------------------------------------| | kompose.service.type | nodeport / clusterip / loadbalancer | -| kompose.service.expose| true / hostname | +| kompose.service.expose | true / hostname | +| kompose.service.expose.tls-secret | secret name | **Note**: `kompose.service.type` label should be defined with `ports` only, otherwise `kompose` will fail. diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index 95f2214a..40e44953 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -62,48 +62,49 @@ type ConvertOptions struct { // ServiceConfig holds the basic struct of a container type ServiceConfig struct { - ContainerName string - Image string `compose:"image"` - Environment []EnvVar `compose:"environment"` - EnvFile []string `compose:"env_file"` - Port []Ports `compose:"ports"` - Command []string `compose:"command"` - WorkingDir string `compose:""` - Args []string `compose:"args"` - VolList []string `compose:"volumes"` - Network []string `compose:"network"` - Labels map[string]string `compose:"labels"` - Annotations map[string]string `compose:""` - CPUSet string `compose:"cpuset"` - CPUShares int64 `compose:"cpu_shares"` - CPUQuota int64 `compose:"cpu_quota"` - CPULimit int64 `compose:""` - CPUReservation int64 `compose:""` - CapAdd []string `compose:"cap_add"` - CapDrop []string `compose:"cap_drop"` - Expose []string `compose:"expose"` - Pid string `compose:"pid"` - Privileged bool `compose:"privileged"` - Restart string `compose:"restart"` - User string `compose:"user"` - VolumesFrom []string `compose:"volumes_from"` - ServiceType string `compose:"kompose.service.type"` - StopGracePeriod string `compose:"stop_grace_period"` - Build string `compose:"build"` - BuildArgs map[string]*string `compose:"build-args"` - ExposeService string `compose:"kompose.service.expose"` - Stdin bool `compose:"stdin_open"` - Tty bool `compose:"tty"` - MemLimit yaml.MemStringorInt `compose:"mem_limit"` - MemReservation yaml.MemStringorInt `compose:""` - DeployMode string `compose:""` - TmpFs []string `compose:"tmpfs"` - Dockerfile string `compose:"dockerfile"` - Replicas int `compose:"replicas"` - GroupAdd []int64 `compose:"group_add"` - Volumes []Volumes `compose:""` - HealthChecks HealthCheck `compose:""` - Placement map[string]string `compose:""` + ContainerName string + Image string `compose:"image"` + Environment []EnvVar `compose:"environment"` + EnvFile []string `compose:"env_file"` + Port []Ports `compose:"ports"` + Command []string `compose:"command"` + WorkingDir string `compose:""` + Args []string `compose:"args"` + VolList []string `compose:"volumes"` + Network []string `compose:"network"` + Labels map[string]string `compose:"labels"` + Annotations map[string]string `compose:""` + CPUSet string `compose:"cpuset"` + CPUShares int64 `compose:"cpu_shares"` + CPUQuota int64 `compose:"cpu_quota"` + CPULimit int64 `compose:""` + CPUReservation int64 `compose:""` + CapAdd []string `compose:"cap_add"` + CapDrop []string `compose:"cap_drop"` + Expose []string `compose:"expose"` + Pid string `compose:"pid"` + Privileged bool `compose:"privileged"` + Restart string `compose:"restart"` + User string `compose:"user"` + VolumesFrom []string `compose:"volumes_from"` + ServiceType string `compose:"kompose.service.type"` + StopGracePeriod string `compose:"stop_grace_period"` + Build string `compose:"build"` + BuildArgs map[string]*string `compose:"build-args"` + ExposeService string `compose:"kompose.service.expose"` + ExposeServiceTLS string `compose:"kompose.service.expose.tls-secret"` + Stdin bool `compose:"stdin_open"` + Tty bool `compose:"tty"` + MemLimit yaml.MemStringorInt `compose:"mem_limit"` + MemReservation yaml.MemStringorInt `compose:""` + DeployMode string `compose:""` + TmpFs []string `compose:"tmpfs"` + Dockerfile string `compose:"dockerfile"` + Replicas int `compose:"replicas"` + GroupAdd []int64 `compose:"group_add"` + Volumes []Volumes `compose:""` + HealthChecks HealthCheck `compose:""` + Placement map[string]string `compose:""` } // HealthCheck the healthcheck configuration for a service diff --git a/pkg/loader/compose/v1v2.go b/pkg/loader/compose/v1v2.go index 97f2bf57..c7ec3559 100644 --- a/pkg/loader/compose/v1v2.go +++ b/pkg/loader/compose/v1v2.go @@ -241,8 +241,13 @@ func libComposeToKomposeMapping(composeObject *project.Project) (kobject.Kompose serviceConfig.ServiceType = serviceType case "kompose.service.expose": serviceConfig.ExposeService = strings.ToLower(value) + case "kompose.service.expose.tls-secret": + serviceConfig.ExposeServiceTLS = value } } + if serviceConfig.ExposeService == "" && serviceConfig.ExposeServiceTLS != "" { + return kobject.KomposeObject{}, errors.New("kompose.service.expose.tls-secret was specifed without kompose.service.expose") + } err = checkLabelsPorts(len(serviceConfig.Port), composeServiceConfig.Labels["kompose.service.type"], name) if err != nil { return kobject.KomposeObject{}, errors.Wrap(err, "kompose.service.type can't be set if service doesn't expose any ports.") diff --git a/pkg/loader/compose/v3.go b/pkg/loader/compose/v3.go index 7510f0e5..e9068ba5 100644 --- a/pkg/loader/compose/v3.go +++ b/pkg/loader/compose/v3.go @@ -351,9 +351,15 @@ func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.Kompose serviceConfig.ServiceType = serviceType case "kompose.service.expose": serviceConfig.ExposeService = strings.ToLower(value) + case "kompose.service.expose.tls-secret": + serviceConfig.ExposeServiceTLS = value } } + if serviceConfig.ExposeService == "" && serviceConfig.ExposeServiceTLS != "" { + return kobject.KomposeObject{}, errors.New("kompose.service.expose.tls-secret was specifed without kompose.service.expose") + } + // Log if the name will been changed 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/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index 016453af..aed2b302 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -262,6 +262,16 @@ func (k *Kubernetes) initIngress(name string, service kobject.ServiceConfig, por if service.ExposeService != "true" { ingress.Spec.Rules[0].Host = service.ExposeService } + if service.ExposeServiceTLS != "" { + ingress.Spec.TLS = []extensions.IngressTLS{ + { + Hosts: []string{ + service.ExposeService, + }, + SecretName: service.ExposeServiceTLS, + }, + } + } return ingress } diff --git a/script/test/cmd/tests.sh b/script/test/cmd/tests.sh index 111dc573..f6cb3f24 100755 --- a/script/test/cmd/tests.sh +++ b/script/test/cmd/tests.sh @@ -277,16 +277,20 @@ convert::expect_failure "kompose -f $KOMPOSE_ROOT/script/test/fixtures/group-add # openshift test convert::expect_failure "kompose --provider openshift -f $KOMPOSE_ROOT/script/test/fixtures/group-add/docker-compose-fail.yml convert --stdout -j" -# Test related to kompose.expose.service label in docker compose file to ensure that services are exposed properly +# Test related to kompose.service.expose label in docker compose file to ensure that services are exposed properly #kubernetes tests # when kompose.service.expose="True" cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-true.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-true.json > /tmp/output-k8s.json convert::expect_success "kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-true.yml convert --stdout -j" "/tmp/output-k8s.json" -# when kompose.expose.service="" +# when kompose.service.expose="" cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-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-hostname.json > /tmp/output-k8s.json convert::expect_success "kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname.yml convert --stdout -j" "/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-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-hostname-tls.json > /tmp/output-k8s.json +convert::expect_success "kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname-tls.yml convert --stdout -j" "/tmp/output-k8s.json" # when kompose.service.expose="True" and multiple ports in docker compose file (first port should be selected) cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-true-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-true-multiple-ports.json > /tmp/output-k8s.json @@ -301,7 +305,7 @@ convert::expect_success "kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose-se cmd="kompose --provider openshift -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-true.yml convert --stdout -j" sed -e "s;%VERSION%;$version;g" -e "s;%CMD%;$cmd;g" $KOMPOSE_ROOT/script/test/fixtures/expose-service/provider-files/openshift-expose-true.json > /tmp/output-os.json convert::expect_success "kompose --provider openshift -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-true.yml convert --stdout -j" "/tmp/output-os.json" -# when kompose.expose.service="" +# when kompose.service.expose="" cmd="kompose --provider openshift -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-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/openshift-expose-hostname.json > /tmp/output-os.json convert::expect_success "kompose --provider openshift -f $KOMPOSE_ROOT/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname.yml convert --stdout -j" "/tmp/output-os.json" diff --git a/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname-tls.yml b/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname-tls.yml new file mode 100644 index 00000000..6a29ba77 --- /dev/null +++ b/script/test/fixtures/expose-service/compose-files/docker-compose-expose-hostname-tls.yml @@ -0,0 +1,13 @@ +web: + image: tuna/docker-counter23 + ports: + - "5000:5000" + links: + - redis + labels: + kompose.service.expose: "batman.example.com" + kompose.service.expose.tls-secret: "test-secret" +redis: + image: redis:3.0 + ports: + - "6379" diff --git a/script/test/fixtures/expose-service/provider-files/kubernetes-expose-hostname-tls.json b/script/test/fixtures/expose-service/provider-files/kubernetes-expose-hostname-tls.json new file mode 100644 index 00000000..be88a8dc --- /dev/null +++ b/script/test/fixtures/expose-service/provider-files/kubernetes-expose-hostname-tls.json @@ -0,0 +1,196 @@ +{ + "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", + "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", + "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" + ], + "secretName": "test-secret" + } + ], + "rules": [ + { + "host": "batman.example.com", + "http": { + "paths": [ + { + "backend": { + "serviceName": "web", + "servicePort": 5000 + } + } + ] + } + } + ] + }, + "status": { + "loadBalancer": {} + } + } + ] +}