From bb9e4fba61492e1546389d2384527c5ac2c5b28c Mon Sep 17 00:00:00 2001 From: Suraj Deshmukh Date: Wed, 9 Nov 2016 20:15:58 +0530 Subject: [PATCH] Generic service type handler for kompose Moved label handling code from Transformer to loader, to make it generic to handle creating service types. Added new attribute to ServiceConfig which gets populated in loader. Fixes #273 --- pkg/kobject/kobject.go | 1 + pkg/loader/compose/compose.go | 24 ++++++++ pkg/loader/compose/compose_test.go | 43 ++++++++++++++ pkg/transformer/kubernetes/k8sutils.go | 16 +---- pkg/transformer/kubernetes/k8sutils_test.go | 65 +-------------------- 5 files changed, 72 insertions(+), 77 deletions(-) create mode 100644 pkg/loader/compose/compose_test.go diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index 1789fb60..1d5554ae 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -143,6 +143,7 @@ type ServiceConfig struct { Restart string User string VolumesFrom []string + ServiceType string } // EnvVar holds the environment variable struct of a container diff --git a/pkg/loader/compose/compose.go b/pkg/loader/compose/compose.go index 9e138c66..5a3abb9b 100644 --- a/pkg/loader/compose/compose.go +++ b/pkg/loader/compose/compose.go @@ -207,6 +207,16 @@ func (c *Compose) LoadFile(file string) kobject.KomposeObject { } } + // canonical "Custom Labels" handler + // Labels used to influence conversion of kompose will be handled + // from here for docker-compose. Each loader will have such handler. + for key, value := range composeServiceConfig.Labels { + switch key { + case "kompose.service.type": + serviceConfig.ServiceType = handleServiceType(value) + } + } + // convert compose labels to annotations serviceConfig.Annotations = map[string]string(composeServiceConfig.Labels) @@ -227,3 +237,17 @@ func (c *Compose) LoadFile(file string) kobject.KomposeObject { return komposeObject } + +func handleServiceType(ServiceType string) string { + switch strings.ToLower(ServiceType) { + case "", "clusterip": + return string(api.ServiceTypeClusterIP) + case "nodeport": + return string(api.ServiceTypeNodePort) + case "loadbalancer": + return string(api.ServiceTypeLoadBalancer) + default: + logrus.Fatalf("Unknown value '%s', supported values are 'NodePort, ClusterIP or LoadBalancer'", ServiceType) + return "" + } +} diff --git a/pkg/loader/compose/compose_test.go b/pkg/loader/compose/compose_test.go new file mode 100644 index 00000000..d9d08129 --- /dev/null +++ b/pkg/loader/compose/compose_test.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package compose + +import "testing" + +// Test if service types are parsed properly on user input +// give a service type and expect correct input +func TestHandleServiceType(t *testing.T) { + tests := []struct { + labelValue string + serviceType string + }{ + {"NodePort", "NodePort"}, + {"nodeport", "NodePort"}, + {"LoadBalancer", "LoadBalancer"}, + {"loadbalancer", "LoadBalancer"}, + {"ClusterIP", "ClusterIP"}, + {"clusterip", "ClusterIP"}, + {"", "ClusterIP"}, + } + + for _, tt := range tests { + result := handleServiceType(tt.labelValue) + if result != tt.serviceType { + t.Errorf("Expected %q, got %q", tt.serviceType, result) + } + } +} diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index f9dedcbe..2580c560 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -244,21 +244,7 @@ func (k *Kubernetes) CreateService(name string, service kobject.ServiceConfig, o servicePorts := k.ConfigServicePorts(name, service) svc.Spec.Ports = servicePorts - // Configure service types - for key, value := range service.Annotations { - if key == "kompose.service.type" { - if strings.ToLower(value) == "nodeport" { - svc.Spec.Type = "NodePort" - } else if strings.ToLower(value) == "clusterip" { - svc.Spec.Type = "ClusterIP" - } else if strings.ToLower(value) == "loadbalancer" { - svc.Spec.Type = "LoadBalancer" - } else { - logrus.Fatalf("Unknown value '%s', supported values are 'NodePort, ClusterIP and LoadBalancer' " , value) - } - } - } - + svc.Spec.Type = api.ServiceType(service.ServiceType) // Configure annotations annotations := transformer.ConfigAnnotations(service) svc.ObjectMeta.Annotations = annotations diff --git a/pkg/transformer/kubernetes/k8sutils_test.go b/pkg/transformer/kubernetes/k8sutils_test.go index e3da748e..c20f4f5e 100644 --- a/pkg/transformer/kubernetes/k8sutils_test.go +++ b/pkg/transformer/kubernetes/k8sutils_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 Skippbox, Ltd All rights reserved. +Copyright 2016 The Kubernetes Authors All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,9 +17,10 @@ limitations under the License. package kubernetes import ( + "testing" + "github.com/kubernetes-incubator/kompose/pkg/kobject" "k8s.io/kubernetes/pkg/api" - "testing" ) /* @@ -64,63 +65,3 @@ func TestCreateService(t *testing.T) { t.Errorf("Expected port 123 upon conversion, actual %d", svc.Spec.Ports[0].Port) } } - -/* - Test the creation of a service with a specified annotation (kompose.service.type) as "nodeport". - The expected result is that Kompose will convert the spec type to "NodePort" upon generation. -*/ -func TestCreateServiceWithServiceTypeNodePort(t *testing.T) { - - // An example service - service := kobject.ServiceConfig{ - ContainerName: "name", - Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: api.ProtocolTCP}}, - Command: []string{"cmd"}, - WorkingDir: "dir", - Args: []string{"arg1", "arg2"}, - Volumes: []string{"/tmp/volume"}, - Network: []string{"network1", "network2"}, // not supported - Labels: nil, - Annotations: map[string]string{"kompose.service.type": "nodeport"}, - CPUSet: "cpu_set", // not supported - CPUShares: 1, // not supported - CPUQuota: 1, // not supported - CapAdd: []string{"cap_add"}, // not supported - CapDrop: []string{"cap_drop"}, // not supported - Expose: []string{"expose"}, // not supported - Privileged: true, - Restart: "always", - User: "user", // not supported - } - - // An example object generated via k8s runtime.Objects() - kompose_object := kobject.KomposeObject{ - ServiceConfigs: map[string]kobject.ServiceConfig{"app": service}, - } - k := Kubernetes{} - tests := []struct { - labelValue string - serviceType string - }{ - {"NodePort", "NodePort"}, - {"nodeport", "NodePort"}, - {"LoadBalancer", "LoadBalancer"}, - {"loadbalancer", "LoadBalancer"}, - {"ClusterIP", "ClusterIP"}, - {"clusterip", "ClusterIP"}, - } - - for _, tt := range tests { - kompose_object.ServiceConfigs["app"].Annotations["kompose.service.type"] = tt.labelValue - - objects := k.Transform(kompose_object, kobject.ConvertOptions{CreateD: true, Replicas: 3}) - - // Test the creation of the service with modified annotations (kompose.service.type) - svc := k.CreateService("foo", service, objects) - if svc.Spec.Type != api.ServiceType(tt.serviceType) { - t.Errorf("Expected NodePort, actual %d", svc.Spec.Type) - } - } -}