diff --git a/docs/conversion.md b/docs/conversion.md index bbbaf36..5ff7659 100644 --- a/docs/conversion.md +++ b/docs/conversion.md @@ -144,16 +144,23 @@ spec: - secretRef: # `$name(-$refSlug)-env` name: "myapp-feat-foo-env" - # To reference a value in a Secret you need to use a special syntax in `services.$name.environment`: - # If an environment value starts with a literal '$_ref_:', it is interpreted as a Secret reference. - # Example which would generate the secretRef shown below: - # `DATABASE_PASSWORD=$_ref_:database-credentials-secret:password` env: - - DATABASE_PASSWORD + # To reference a value in a Secret you need to use a special syntax in `services.$name.environment`: + # If an environment value starts with a literal '$_secretRef_:', it is interpreted as a Secret reference. + # Example which would generate the secretRef shown below: + # `DATABASE_PASSWORD=$_secretRef_:database-credentials-secret:password` + - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: database-credentials-secret key: password + # To reference a pod field, use `$_fieldRef_:` instead + # Example which would generate the fieldRef shown below: + # `MY_POD_IP=$_fieldRef_:status.podIP` + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP # List of the target port values from `services.$name.ports` ports: - containerPort: 8000 @@ -267,16 +274,23 @@ spec: - secretRef: # `$name(-$refSlug)-env` name: "myapp-feat-foo-env" - # To reference a value in a Secret you need to use a special syntax in `services.$name.environment`: - # If an environment value starts with a literal '$_ref_:', it is interpreted as a Secret reference. - # Example which would generate the secretRef shown below: - # `DATABASE_PASSWORD=$_ref_:database-credentials-secret:password` env: - - DATABASE_PASSWORD + # To reference a value in a Secret you need to use a special syntax in `services.$name.environment`: + # If an environment value starts with a literal '$_secretRef_:', it is interpreted as a Secret reference. + # Example which would generate the secretRef shown below: + # `DATABASE_PASSWORD=$_secretRef_:database-credentials-secret:password` + - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: database-credentials-secret key: password + # To reference a pod field, use `$_fieldRef_:` instead + # Example which would generate the fieldRef shown below: + # `MY_POD_IP=$_fieldRef_:status.podIP` + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP # List of the target port values from `services.$name.ports` ports: - containerPort: 8000 diff --git a/main.go b/main.go index a48f46d..5ab6602 100644 --- a/main.go +++ b/main.go @@ -82,11 +82,15 @@ func Main(args []string) int { } } env := util.GetEnv() - if _, ok := env["_ref_"]; ok { - logrus.Error("The environment variable '_ref_' must not be defined as it is needed for internal purposes") - return 1 + for _, key := range []string{"_ref_", "_secretRef_", "_fieldRef_"} { + if _, ok := env[key]; ok { + logrus.Errorf("The environment variable '%s' must not be defined as it is needed for internal purposes", key) + return 1 + } } env["_ref_"] = converter.SecretRefMagic + env["_secretRef_"] = converter.SecretRefMagic + env["_fieldRef_"] = converter.FieldRefMagic configDetails := composeTypes.ConfigDetails{ ConfigFiles: composeConfigFiles, Environment: env, diff --git a/pkg/converter/converter.go b/pkg/converter/converter.go index 46f74c5..7cddd8d 100644 --- a/pkg/converter/converter.go +++ b/pkg/converter/converter.go @@ -27,7 +27,11 @@ import ( ) var ( - SecretRefMagic = "ylkBUFN0o29yr4yLCTUZqzgIT6qCIbyj" // magic string to indicate that what follows isn't a value but a reference to a secret + // magic string to indicate that what follows isn't a value but a reference to a secret + SecretRefMagic = "ylkBUFN0o29yr4yLCTUZqzgIT6qCIbyj" + + // magic string to indicate that what follows isn't a value but a fieldRef + FieldRefMagic = "VtF2ZSrJBKSEJCiUVkGCyUawAfGBCwou" ) func composeServiceVolumesToK8s( @@ -121,11 +125,17 @@ func composeServicePortsToK8sContainerPorts(workload *ir.Service) []core.Contain return containerPorts } +func isReference(value *string) bool { + return value != nil && (strings.HasPrefix(*value, SecretRefMagic+":") || strings.HasPrefix(*value, FieldRefMagic+":")) +} + func composeServiceToSecret(workload *ir.Service, refSlug string, labels map[string]string) *core.Secret { stringData := make(map[string]string) for key, value := range workload.AsCompose().Environment { - if value != nil && strings.HasPrefix(*value, SecretRefMagic+":") { - // we've encountered a reference to another secret (starting with "$_ref_:" in the compose file), ignore + if isReference(value) { + // we've encountered a reference to another secret or a field ref + // (starting with "$_secretRef_:" or "$_fieldRef_:" in the compose file), + // ignore continue } if value == nil { @@ -365,14 +375,22 @@ func composeServiceToContainer( for _, key := range keys { value := workload.AsCompose().Environment[key] if value != nil && strings.HasPrefix(*value, SecretRefMagic+":") { - // we've encountered a reference to another secret (starting with "$_ref_:" in the compose file) + // we've encountered a reference to another secret (starting with "$_secretRef_:" in the compose file) refValue := (*value)[len(SecretRefMagic)+1:] refStrings := strings.SplitN(refValue, ":", 2) if len(refStrings) != 2 { - logrus.Warnf("Secret reference '$_ref_:%s' has invalid format, should be '$_ref_:SECRETNAME:KEY'. Ignoring.", refValue) + logrus.Warnf("Secret reference '$_secretRef_:%s' has invalid format, should be '$_secretRef_:SECRETNAME:KEY'. Ignoring.", refValue) continue } env = append(env, core.EnvVar{Name: key, ValueFrom: &core.EnvVarSource{SecretKeyRef: &core.SecretKeySelector{LocalObjectReference: core.LocalObjectReference{Name: refStrings[0]}, Key: refStrings[1]}}}) + } else if value != nil && strings.HasPrefix(*value, FieldRefMagic+":") { + // we've encountered a fieldRef + refValue := (*value)[len(FieldRefMagic)+1:] + if strings.Contains(refValue, ":") { + logrus.Warnf("FieldRef '$_fieldRef_:%s' has invalid format, should be '$_fieldRef_:PATH'. Ignoring.", refValue) + continue + } + env = append(env, core.EnvVar{Name: key, ValueFrom: &core.EnvVarSource{FieldRef: &core.ObjectFieldSelector{FieldPath: refValue}}}) } } diff --git a/tests/golden/env-vars/compose.yml b/tests/golden/env-vars/compose.yml index 26fee60..c08d913 100644 --- a/tests/golden/env-vars/compose.yml +++ b/tests/golden/env-vars/compose.yml @@ -5,6 +5,7 @@ services: - FOO - BAR=${BAR} - something_else=${BAZ} - - "PASSWORD=$_ref_:mongodb-secret:password" - - "FOOREF=$_ref_:foo:fooooooo" - - "BARREF=$_ref_:bar:baaaaaar" + - "PASSWORD=$_secretRef_:mongodb-secret:password" + - "FOOREF=$_secretRef_:foo:fooooooo" + - "BARREF=$_secretRef_:bar:baaaaaar" + - "MY_IP=$_fieldRef_:status.podIP" diff --git a/tests/golden/env-vars/manifests/fooBar-oasp-deployment.yaml b/tests/golden/env-vars/manifests/fooBar-oasp-deployment.yaml index 51ceb89..701e411 100644 --- a/tests/golden/env-vars/manifests/fooBar-oasp-deployment.yaml +++ b/tests/golden/env-vars/manifests/fooBar-oasp-deployment.yaml @@ -42,6 +42,10 @@ spec: secretKeyRef: key: fooooooo name: foo + - name: MY_IP + valueFrom: + fieldRef: + fieldPath: status.podIP - name: PASSWORD valueFrom: secretKeyRef: