diff --git a/docs/conversion.md b/docs/conversion.md index 530538935..a73d565ef 100644 --- a/docs/conversion.md +++ b/docs/conversion.md @@ -38,7 +38,7 @@ We're doing our best to keep it up to date as soon as possible in our releases t | cap_add | ✓ | ✓ | ✓ | Container.SecurityContext.Capabilities.Add | | | cap_drop | ✓ | ✓ | ✓ | Container.SecurityContext.Capabilities.Drop | | | command | ✓ | ✓ | ✓ | Container.Args | | -| configs | n | n | ✓ | | | +| configs | n | n | ✓ | | | | configs: short-syntax | n | n | ✓ | | Only create configMap | | configs: long-syntax | n | n | ✓ | | If target path is /, ignore this and only create configMap | | cgroup_parent | x | x | x | | Not supported within Kubernetes. See issue https://github.com/kubernetes/kubernetes/issues/11986 | @@ -110,3 +110,10 @@ We're doing our best to keep it up to date as soon as possible in our releases t | internal | x | x | x | | | | labels | x | x | x | | | | external | x | x | x | | | +| | | | | | | +| **Configs** | x | x | x | | | +| environment | x | y | y | | | +| file | y | y | y | | | +| content | x | y | y | | | +| labels | x | x | x | | | +| external | x | x | x | | | diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index 7d43ad018..37f9a12c2 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -257,7 +257,24 @@ func (s *ServiceConfig) GetConfigMapKeyFromMeta(name string) (string, error) { return "", errors.Errorf("config %s is external", name) } - return filepath.Base(config.File), nil + if config.File != "" { + return filepath.Base(config.File), nil + } else if config.Content != "" { + // loop through s.Configs to find the config with the same name + for _, cfg := range s.Configs { + if cfg.Source == name { + if cfg.Target == "" { + return filepath.Base(cfg.Source), nil + } else { + return filepath.Base(cfg.Target), nil + } + } + } + } else { + return "", errors.Errorf("config %s is empty", name) + } + + return "", errors.Errorf("config %s not found", name) } // GetKubernetesUpdateStrategy from compose update_config diff --git a/pkg/transformer/kubernetes/k8sutils_test.go b/pkg/transformer/kubernetes/k8sutils_test.go index ae6c498de..71c7cfdb2 100644 --- a/pkg/transformer/kubernetes/k8sutils_test.go +++ b/pkg/transformer/kubernetes/k8sutils_test.go @@ -24,6 +24,7 @@ import ( "sort" "testing" + "github.com/compose-spec/compose-go/v2/types" "github.com/kubernetes/kompose/pkg/kobject" "github.com/kubernetes/kompose/pkg/loader/compose" "github.com/kubernetes/kompose/pkg/testutils" @@ -328,6 +329,97 @@ func TestCreateServiceWithServiceUser(t *testing.T) { } } +func TestCreateServiceWithConfigLongSyntax(t *testing.T) { + content := "setting: true" + target := "/etc/config.yaml" + + // An example service + service := kobject.ServiceConfig{ + ContainerName: "name", + Image: "image", + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Command: []string{"cmd"}, + Configs: []types.ServiceConfigObjConfig{{Source: "configmap", Target: target}}, + ConfigsMetaData: map[string]types.ConfigObjConfig{"configmap": {Content: content}}, + } + + komposeObject := kobject.KomposeObject{ + ServiceConfigs: map[string]kobject.ServiceConfig{ + "app": service, + }, + } + + k := Kubernetes{} + + objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 1}) + if err != nil { + t.Error(errors.Wrap(err, "k.Transform failed")) + } + + for _, obj := range objects { + t.Log(obj) + if configMap, ok := obj.(*api.ConfigMap); ok { + fileContent := configMap.Data["config.yaml"] + if fileContent != content { + t.Errorf("Config map content not equal") + } + } + if deployment, ok := obj.(*appsv1.Deployment); ok { + spec := deployment.Spec.Template.Spec + if spec.Containers[0].VolumeMounts[0].MountPath != target { + t.Errorf("Config map mountPath not found") + } + } + } +} + +func TestCreateServiceWithConfigShortSyntax(t *testing.T) { + content := "setting: true" + source := "configmap" + target := "/" + source + + // An example service + service := kobject.ServiceConfig{ + ContainerName: "name", + Image: "image", + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Command: []string{"cmd"}, + Configs: []types.ServiceConfigObjConfig{{Source: source}}, + ConfigsMetaData: map[string]types.ConfigObjConfig{source: {Content: content}}, + } + + komposeObject := kobject.KomposeObject{ + ServiceConfigs: map[string]kobject.ServiceConfig{ + "app": service, + }, + } + + k := Kubernetes{} + + objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 1}) + if err != nil { + t.Error(errors.Wrap(err, "k.Transform failed")) + } + + for _, obj := range objects { + t.Log(obj) + if configMap, ok := obj.(*api.ConfigMap); ok { + fileContent := configMap.Data[source] + if fileContent != content { + t.Errorf("Config map content not equal") + } + } + if deployment, ok := obj.(*appsv1.Deployment); ok { + spec := deployment.Spec.Template.Spec + if spec.Containers[0].VolumeMounts[0].MountPath != target { + t.Errorf("Config map mountPath not found") + } + } + } +} + func TestTransformWithPid(t *testing.T) { // An example service service := kobject.ServiceConfig{ diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index 4feb191d5..a1fecbc5d 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -332,6 +332,24 @@ func initConfigMapData(configMap *api.ConfigMap, data map[string]string) { configMap.BinaryData = binData } +// InitConfigMapFromContent initializes a ConfigMap object +func (k *Kubernetes) InitConfigMapFromContent(name string, service kobject.ServiceConfig, content string, currentConfigName string, target string) *api.ConfigMap { + configMap := &api.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: currentConfigName, + Labels: transformer.ConfigLabels(name), + }, + } + filename := GetFileName(target) + data := map[string]string{filename: content} + initConfigMapData(configMap, data) + return configMap +} + // InitConfigMapFromFile initializes a ConfigMap object func (k *Kubernetes) InitConfigMapFromFile(name string, service kobject.ServiceConfig, fileName string) *api.ConfigMap { content, err := GetContentFromFile(fileName) @@ -1325,12 +1343,26 @@ func (k *Kubernetes) createConfigMapFromComposeConfig(name string, service kobje for _, config := range service.Configs { currentConfigName := config.Source currentConfigObj := service.ConfigsMetaData[currentConfigName] + if config.Target == "" { + config.Target = currentConfigName + } if currentConfigObj.External { continue } - currentFileName := currentConfigObj.File - configMap := k.InitConfigMapFromFile(name, service, currentFileName) - objects = append(objects, configMap) + if currentConfigObj.File != "" { + currentFileName := currentConfigObj.File + configMap := k.InitConfigMapFromFile(name, service, currentFileName) + objects = append(objects, configMap) + } else if currentConfigObj.Content != "" { + content := currentConfigObj.Content + configMap := k.InitConfigMapFromContent(name, service, content, currentConfigName, config.Target) + objects = append(objects, configMap) + } else if currentConfigObj.Environment != "" { + // TODO: Add support for environment variables in configmaps + log.Warnf("Environment variables in configmaps are not supported yet") + } else { + log.Warnf("Configmap %s is empty", currentConfigName) + } } return objects }