Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for "fieldRef" environment variables #150

Merged
merged 2 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions docs/conversion.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,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
Expand Down Expand Up @@ -265,16 +272,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
Expand Down
10 changes: 7 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 23 additions & 5 deletions pkg/converter/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -94,11 +98,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 {
Expand Down Expand Up @@ -331,14 +341,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}}})
}
}

Expand Down
7 changes: 4 additions & 3 deletions tests/golden/env-vars/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
4 changes: 4 additions & 0 deletions tests/golden/env-vars/manifests/fooBar-oasp-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ spec:
secretKeyRef:
key: fooooooo
name: foo
- name: MY_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: PASSWORD
valueFrom:
secretKeyRef:
Expand Down