diff --git a/cli/app/app.go b/cli/app/app.go index 26370b8b..1205070e 100644 --- a/cli/app/app.go +++ b/cli/app/app.go @@ -155,14 +155,10 @@ func Convert(c *cli.Context) { } komposeObject = l.LoadFile(opt.InputFile) - // transformer maps komposeObject to provider's primitives - var t transformer.Transformer - if opt.Provider == "kubernetes" { - t = new(kubernetes.Kubernetes) - } else { - t = new(openshift.OpenShift) - } + // Get a transformer that maps komposeObject to provider's primitives + t := getTransformer(opt) + // Do the transformation objects := t.Transform(komposeObject, opt) // Print output @@ -190,13 +186,8 @@ func Up(c *cli.Context) { } komposeObject = l.LoadFile(opt.InputFile) - //get transfomer - var t transformer.Transformer - if opt.Provider == "kubernetes" { - t = new(kubernetes.Kubernetes) - } else { - t = new(openshift.OpenShift) - } + // Get the transformer + t := getTransformer(opt) //Submit objects to provider errDeploy := t.Deploy(komposeObject, opt) @@ -226,13 +217,8 @@ func Down(c *cli.Context) { } komposeObject = l.LoadFile(opt.InputFile) - //get transfomer - var t transformer.Transformer - if opt.Provider == "kubernetes" { - t = new(kubernetes.Kubernetes) - } else { - t = new(openshift.OpenShift) - } + // Get the transformer + t := getTransformer(opt) //Remove deployed application errUndeploy := t.Undeploy(komposeObject, opt) @@ -242,6 +228,21 @@ func Down(c *cli.Context) { } +// Convenience method to return the appropriate Transformer based on +// what provider we are using. +func getTransformer(opt kobject.ConvertOptions) transformer.Transformer { + var t transformer.Transformer + if opt.Provider == "kubernetes" { + // Create/Init new Kubernetes object + t = &kubernetes.Kubernetes{} + } else { + // Create/Init new OpenShift object that is initialized with a newly + // created Kubernetes object. Openshift inherits from Kubernetes + t = &openshift.OpenShift{kubernetes.Kubernetes{}} + } + return t +} + func askForConfirmation() bool { var response string _, err := fmt.Scanln(&response) diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index 38b9acf6..685389ee 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -227,7 +227,7 @@ func convertToVersion(obj runtime.Object, groupVersion unversioned.GroupVersion) return convertedObject, nil } -func PortsExist(name string, service kobject.ServiceConfig) bool { +func (k *Kubernetes) PortsExist(name string, service kobject.ServiceConfig) bool { if len(service.Port) == 0 { logrus.Warningf("[%s] Service cannot be created because of missing port.", name) return false @@ -237,11 +237,11 @@ func PortsExist(name string, service kobject.ServiceConfig) bool { } // create a k8s service -func CreateService(name string, service kobject.ServiceConfig, objects []runtime.Object) *api.Service { - svc := InitSvc(name, service) +func (k *Kubernetes) CreateService(name string, service kobject.ServiceConfig, objects []runtime.Object) *api.Service { + svc := k.InitSvc(name, service) // Configure the service ports. - servicePorts := ConfigServicePorts(name, service) + servicePorts := k.ConfigServicePorts(name, service) svc.Spec.Ports = servicePorts // Configure service types @@ -267,12 +267,12 @@ func CreateService(name string, service kobject.ServiceConfig, objects []runtime } // load configurations to k8s objects -func UpdateKubernetesObjects(name string, service kobject.ServiceConfig, objects *[]runtime.Object) { +func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.ServiceConfig, objects *[]runtime.Object) { // Configure the environment variables. - envs := ConfigEnvs(name, service) + envs := k.ConfigEnvs(name, service) // Configure the container volumes. - volumesMount, volumes, pvc := ConfigVolumes(name, service) + volumesMount, volumes, pvc := k.ConfigVolumes(name, service) if pvc != nil { // Looping on the slice pvc instead of `*objects = append(*objects, pvc...)` // because the type of objects and pvc is different, but when doing append @@ -283,7 +283,7 @@ func UpdateKubernetesObjects(name string, service kobject.ServiceConfig, objects } // Configure the container ports. - ports := ConfigPorts(name, service) + ports := k.ConfigPorts(name, service) // Configure annotations annotations := transformer.ConfigAnnotations(service) @@ -327,14 +327,14 @@ func UpdateKubernetesObjects(name string, service kobject.ServiceConfig, objects // update supported controller for _, obj := range *objects { - UpdateController(obj, fillTemplate, fillObjectMeta) + k.UpdateController(obj, fillTemplate, fillObjectMeta) } } // the objects that we get can be in any order this keeps services first // according to best practice kubernetes services should be created first // http://kubernetes.io/docs/user-guide/config-best-practices/ -func SortServicesFirst(objs *[]runtime.Object) { +func (k *Kubernetes) SortServicesFirst(objs *[]runtime.Object) { var svc, others, ret []runtime.Object for _, obj := range *objs { @@ -349,49 +349,49 @@ func SortServicesFirst(objs *[]runtime.Object) { *objs = ret } -func findDependentVolumes(svcname string, komposeObject kobject.KomposeObject) (volumes []api.Volume, volumeMounts []api.VolumeMount) { +func (k *Kubernetes) findDependentVolumes(svcname string, komposeObject kobject.KomposeObject) (volumes []api.Volume, volumeMounts []api.VolumeMount) { // Get all the volumes and volumemounts this particular service is dependent on for _, dependentSvc := range komposeObject.ServiceConfigs[svcname].VolumesFrom { - vols, volMounts := findDependentVolumes(dependentSvc, komposeObject) + vols, volMounts := k.findDependentVolumes(dependentSvc, komposeObject) volumes = append(volumes, vols...) volumeMounts = append(volumeMounts, volMounts...) } // add the volumes info of this service - volMounts, vols, _ := ConfigVolumes(svcname, komposeObject.ServiceConfigs[svcname]) + volMounts, vols, _ := k.ConfigVolumes(svcname, komposeObject.ServiceConfigs[svcname]) volumes = append(volumes, vols...) volumeMounts = append(volumeMounts, volMounts...) return } -func VolumesFrom(objects *[]runtime.Object, komposeObject kobject.KomposeObject) { +func (k *Kubernetes) VolumesFrom(objects *[]runtime.Object, komposeObject kobject.KomposeObject) { for _, obj := range *objects { switch t := obj.(type) { case *api.ReplicationController: svcName := t.ObjectMeta.Name for _, dependentSvc := range komposeObject.ServiceConfigs[svcName].VolumesFrom { - volumes, volumeMounts := findDependentVolumes(dependentSvc, komposeObject) + volumes, volumeMounts := k.findDependentVolumes(dependentSvc, komposeObject) t.Spec.Template.Spec.Volumes = append(t.Spec.Template.Spec.Volumes, volumes...) t.Spec.Template.Spec.Containers[0].VolumeMounts = append(t.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMounts...) } case *extensions.Deployment: svcName := t.ObjectMeta.Name for _, dependentSvc := range komposeObject.ServiceConfigs[svcName].VolumesFrom { - volumes, volumeMounts := findDependentVolumes(dependentSvc, komposeObject) + volumes, volumeMounts := k.findDependentVolumes(dependentSvc, komposeObject) t.Spec.Template.Spec.Volumes = append(t.Spec.Template.Spec.Volumes, volumes...) t.Spec.Template.Spec.Containers[0].VolumeMounts = append(t.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMounts...) } case *extensions.DaemonSet: svcName := t.ObjectMeta.Name for _, dependentSvc := range komposeObject.ServiceConfigs[svcName].VolumesFrom { - volumes, volumeMounts := findDependentVolumes(dependentSvc, komposeObject) + volumes, volumeMounts := k.findDependentVolumes(dependentSvc, komposeObject) t.Spec.Template.Spec.Volumes = append(t.Spec.Template.Spec.Volumes, volumes...) t.Spec.Template.Spec.Containers[0].VolumeMounts = append(t.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMounts...) } case *deployapi.DeploymentConfig: svcName := t.ObjectMeta.Name for _, dependentSvc := range komposeObject.ServiceConfigs[svcName].VolumesFrom { - volumes, volumeMounts := findDependentVolumes(dependentSvc, komposeObject) + volumes, volumeMounts := k.findDependentVolumes(dependentSvc, komposeObject) t.Spec.Template.Spec.Volumes = append(t.Spec.Template.Spec.Volumes, volumes...) t.Spec.Template.Spec.Containers[0].VolumeMounts = append(t.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMounts...) } diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index 6f47bdb2..236b644a 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -50,7 +50,7 @@ type Kubernetes struct { const TIMEOUT = 300 // Init RC object -func InitRC(name string, service kobject.ServiceConfig, replicas int) *api.ReplicationController { +func (k *Kubernetes) InitRC(name string, service kobject.ServiceConfig, replicas int) *api.ReplicationController { rc := &api.ReplicationController{ TypeMeta: unversioned.TypeMeta{ Kind: "ReplicationController", @@ -80,7 +80,7 @@ func InitRC(name string, service kobject.ServiceConfig, replicas int) *api.Repli } // Init Svc object -func InitSvc(name string, service kobject.ServiceConfig) *api.Service { +func (k *Kubernetes) InitSvc(name string, service kobject.ServiceConfig) *api.Service { svc := &api.Service{ TypeMeta: unversioned.TypeMeta{ Kind: "Service", @@ -98,7 +98,7 @@ func InitSvc(name string, service kobject.ServiceConfig) *api.Service { } // Init Deployment -func InitD(name string, service kobject.ServiceConfig, replicas int) *extensions.Deployment { +func (k *Kubernetes) InitD(name string, service kobject.ServiceConfig, replicas int) *extensions.Deployment { dc := &extensions.Deployment{ TypeMeta: unversioned.TypeMeta{ Kind: "Deployment", @@ -125,7 +125,7 @@ func InitD(name string, service kobject.ServiceConfig, replicas int) *extensions } // Init DS object -func InitDS(name string, service kobject.ServiceConfig) *extensions.DaemonSet { +func (k *Kubernetes) InitDS(name string, service kobject.ServiceConfig) *extensions.DaemonSet { ds := &extensions.DaemonSet{ TypeMeta: unversioned.TypeMeta{ Kind: "DaemonSet", @@ -151,7 +151,7 @@ func InitDS(name string, service kobject.ServiceConfig) *extensions.DaemonSet { } // Initialize PersistentVolumeClaim -func CreatePVC(name string, mode string) *api.PersistentVolumeClaim { +func (k *Kubernetes) CreatePVC(name string, mode string) *api.PersistentVolumeClaim { size, err := resource.ParseQuantity("100Mi") if err != nil { logrus.Fatalf("Error parsing size") @@ -183,7 +183,7 @@ func CreatePVC(name string, mode string) *api.PersistentVolumeClaim { } // Configure the container ports. -func ConfigPorts(name string, service kobject.ServiceConfig) []api.ContainerPort { +func (k *Kubernetes) ConfigPorts(name string, service kobject.ServiceConfig) []api.ContainerPort { ports := []api.ContainerPort{} for _, port := range service.Port { ports = append(ports, api.ContainerPort{ @@ -196,7 +196,7 @@ func ConfigPorts(name string, service kobject.ServiceConfig) []api.ContainerPort } // Configure the container service ports. -func ConfigServicePorts(name string, service kobject.ServiceConfig) []api.ServicePort { +func (k *Kubernetes) ConfigServicePorts(name string, service kobject.ServiceConfig) []api.ServicePort { servicePorts := []api.ServicePort{} for _, port := range service.Port { if port.HostPort == 0 { @@ -216,7 +216,7 @@ func ConfigServicePorts(name string, service kobject.ServiceConfig) []api.Servic } // Configure the container volumes. -func ConfigVolumes(name string, service kobject.ServiceConfig) ([]api.VolumeMount, []api.Volume, []*api.PersistentVolumeClaim) { +func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) ([]api.VolumeMount, []api.Volume, []*api.PersistentVolumeClaim) { volumesMount := []api.VolumeMount{} volumes := []api.Volume{} var pvc []*api.PersistentVolumeClaim @@ -256,13 +256,13 @@ func ConfigVolumes(name string, service kobject.ServiceConfig) ([]api.VolumeMoun if len(host) > 0 { logrus.Warningf("Volume mount on the host %q isn't supported - ignoring path on the host", host) } - pvc = append(pvc, CreatePVC(volumeName, mode)) + pvc = append(pvc, k.CreatePVC(volumeName, mode)) } return volumesMount, volumes, pvc } // Configure the environment variables. -func ConfigEnvs(name string, service kobject.ServiceConfig) []api.EnvVar { +func (k *Kubernetes) ConfigEnvs(name string, service kobject.ServiceConfig) []api.EnvVar { envs := []api.EnvVar{} for _, v := range service.Environment { envs = append(envs, api.EnvVar{ @@ -275,17 +275,17 @@ func ConfigEnvs(name string, service kobject.ServiceConfig) []api.EnvVar { } // Generate a Kubernetes artifact for each input type service -func CreateKubernetesObjects(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions) []runtime.Object { +func (k *Kubernetes) CreateKubernetesObjects(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions) []runtime.Object { var objects []runtime.Object if opt.CreateD { - objects = append(objects, InitD(name, service, opt.Replicas)) + objects = append(objects, k.InitD(name, service, opt.Replicas)) } if opt.CreateDS { - objects = append(objects, InitDS(name, service)) + objects = append(objects, k.InitDS(name, service)) } if opt.CreateRC { - objects = append(objects, InitRC(name, service, opt.Replicas)) + objects = append(objects, k.InitRC(name, service, opt.Replicas)) } return objects @@ -298,27 +298,27 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject. var allobjects []runtime.Object for name, service := range komposeObject.ServiceConfigs { - objects := CreateKubernetesObjects(name, service, opt) + objects := k.CreateKubernetesObjects(name, service, opt) // If ports not provided in configuration we will not make service - if PortsExist(name, service) { - svc := CreateService(name, service, objects) + if k.PortsExist(name, service) { + svc := k.CreateService(name, service, objects) objects = append(objects, svc) } - UpdateKubernetesObjects(name, service, &objects) + k.UpdateKubernetesObjects(name, service, &objects) allobjects = append(allobjects, objects...) } // If docker-compose has a volumes_from directive it will be handled here - VolumesFrom(&allobjects, komposeObject) + k.VolumesFrom(&allobjects, komposeObject) // sort all object so Services are first - SortServicesFirst(&allobjects) + k.SortServicesFirst(&allobjects) return allobjects } // Updates the given object with the given pod template update function and ObjectMeta update function -func UpdateController(obj runtime.Object, updateTemplate func(*api.PodTemplateSpec), updateMeta func(meta *api.ObjectMeta)) { +func (k *Kubernetes) UpdateController(obj runtime.Object, updateTemplate func(*api.PodTemplateSpec), updateMeta func(meta *api.ObjectMeta)) { switch t := obj.(type) { case *api.ReplicationController: if t.Spec.Template == nil { diff --git a/pkg/transformer/openshift/openshift.go b/pkg/transformer/openshift/openshift.go index 834c6311..b6ec5534 100644 --- a/pkg/transformer/openshift/openshift.go +++ b/pkg/transformer/openshift/openshift.go @@ -42,6 +42,10 @@ import ( ) type OpenShift struct { + // Anonymous field allows for inheritance. We are basically inheriting + // all of kubernetes.Kubernetes Methods and variables here. We'll overwite + // some of those methods with our own for openshift. + kubernetes.Kubernetes } // getImageTag get tag name from image name @@ -56,7 +60,7 @@ func getImageTag(image string) string { } // initImageStream initialize ImageStream object -func initImageStream(name string, service kobject.ServiceConfig) *imageapi.ImageStream { +func (o *OpenShift) initImageStream(name string, service kobject.ServiceConfig) *imageapi.ImageStream { tag := getImageTag(service.Image) is := &imageapi.ImageStream{ @@ -82,7 +86,7 @@ func initImageStream(name string, service kobject.ServiceConfig) *imageapi.Image } // initDeploymentConfig initialize OpenShifts DeploymentConfig object -func initDeploymentConfig(name string, service kobject.ServiceConfig, replicas int) *deployapi.DeploymentConfig { +func (o *OpenShift) initDeploymentConfig(name string, service kobject.ServiceConfig, replicas int) *deployapi.DeploymentConfig { tag := getImageTag(service.Image) dc := &deployapi.DeploymentConfig{ @@ -137,39 +141,39 @@ func initDeploymentConfig(name string, service kobject.ServiceConfig, replicas i // Transform maps komposeObject to openshift objects // returns objects that are already sorted in the way that Services are first -func (k *OpenShift) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) []runtime.Object { +func (o *OpenShift) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) []runtime.Object { // this will hold all the converted data var allobjects []runtime.Object for name, service := range komposeObject.ServiceConfigs { - objects := kubernetes.CreateKubernetesObjects(name, service, opt) + objects := o.CreateKubernetesObjects(name, service, opt) if opt.CreateDeploymentConfig { - objects = append(objects, initDeploymentConfig(name, service, opt.Replicas)) // OpenShift DeploymentConfigs + objects = append(objects, o.initDeploymentConfig(name, service, opt.Replicas)) // OpenShift DeploymentConfigs // create ImageStream after deployment (creating IS will trigger new deployment) - objects = append(objects, initImageStream(name, service)) + objects = append(objects, o.initImageStream(name, service)) } // If ports not provided in configuration we will not make service - if kubernetes.PortsExist(name, service) { - svc := kubernetes.CreateService(name, service, objects) + if o.PortsExist(name, service) { + svc := o.CreateService(name, service, objects) objects = append(objects, svc) } - kubernetes.UpdateKubernetesObjects(name, service, &objects) + o.UpdateKubernetesObjects(name, service, &objects) allobjects = append(allobjects, objects...) } // If docker-compose has a volumes_from directive it will be handled here - kubernetes.VolumesFrom(&allobjects, komposeObject) + o.VolumesFrom(&allobjects, komposeObject) // sort all object so Services are first - kubernetes.SortServicesFirst(&allobjects) + o.SortServicesFirst(&allobjects) return allobjects } -func (k *OpenShift) Deploy(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) error { +func (o *OpenShift) Deploy(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) error { //Convert komposeObject - objects := k.Transform(komposeObject, opt) + objects := o.Transform(komposeObject, opt) fmt.Println("We are going to create OpenShift DeploymentConfigs, Services and PersistentVolumeClaims for your Dockerized application. \n" + "If you need different kind of resources, use the 'kompose convert' and 'oc create -f' commands instead. \n") @@ -230,6 +234,6 @@ func (k *OpenShift) Deploy(komposeObject kobject.KomposeObject, opt kobject.Conv return nil } -func (k *OpenShift) Undeploy(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) error { +func (o *OpenShift) Undeploy(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) error { return errors.New("Not Implemented") }