Skip to content

Commit f86f595

Browse files
committed
Merge pull request #587 from helgi/env_as_secrets
feat(scheduler): store env vars as secrets in k8s and map them in the RC
2 parents 3fe88f8 + e82446c commit f86f595

2 files changed

Lines changed: 60 additions & 8 deletions

File tree

rootfs/api/models/app.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ def pod_name(size=5, chars=string.ascii_lowercase + string.digits):
535535
'memory': release.config.memory,
536536
'cpu': release.config.cpu,
537537
'tags': release.config.tags,
538-
'envs': release.config.values
538+
'envs': release.config.values,
539+
'version': "v{}".format(release.version),
539540
}
540541

541542
try:

rootfs/scheduler/__init__.py

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,15 @@ def deploy(self, namespace, name, image, command, **kwargs):
377377
new_rc["metadata"]["name"], desired)
378378
)
379379

380-
# Remove old release
380+
# Remove new release
381381
self._scale_rc(namespace, new_rc["metadata"]["name"], 0)
382382
self._delete_rc(namespace, new_rc["metadata"]["name"])
383+
# remove secret that contains env vars for the release
384+
try:
385+
secret_name = "{}-{}-env".format(namespace, kwargs.get('version'))
386+
self._delete_secret(namespace, secret_name)
387+
except KubeHTTPException:
388+
pass
383389

384390
# Bring back old release if available
385391
if old_rc:
@@ -390,6 +396,12 @@ def deploy(self, namespace, name, image, command, **kwargs):
390396
# New release is live and kicking. Clean up old release
391397
if old_rc:
392398
self._delete_rc(namespace, old_rc["metadata"]["name"])
399+
# remove secret that contains env vars for the release
400+
secret_name = "{}-{}-env".format(namespace, old_rc['metadata']['labels']['version'])
401+
try:
402+
self._delete_secret(namespace, secret_name)
403+
except KubeHTTPException:
404+
pass
393405

394406
# Make sure the application is routable and uses the correct port
395407
# Done after the fact to let initial deploy settle before routing
@@ -520,7 +532,7 @@ def run(self, namespace, name, image, entrypoint, command, **kwargs):
520532
containers['command'] = [entrypoint]
521533
containers['args'] = args
522534

523-
self._set_environment(containers, **kwargs)
535+
self._set_environment(containers, namespace, **kwargs)
524536

525537
url = self._api("/namespaces/{}/pods", namespace)
526538
response = self.session.post(url, json=template)
@@ -564,7 +576,7 @@ def run(self, namespace, name, image, entrypoint, command, **kwargs):
564576

565577
return 0, data
566578

567-
def _set_environment(self, data, **kwargs):
579+
def _set_environment(self, data, namespace, **kwargs):
568580
app_type = kwargs.get('app_type')
569581
mem = kwargs.get('memory', {}).get(app_type)
570582
cpu = kwargs.get('cpu', {}).get(app_type)
@@ -575,10 +587,30 @@ def _set_environment(self, data, **kwargs):
575587
data['env'] = []
576588

577589
if env:
578-
for key, value in env.items():
590+
# env vars are stored in secrets and mapped to env in k8s
591+
try:
592+
# secrets use dns labels for keys, map those properly here
593+
secrets_env = {}
594+
for key, value in env.items():
595+
secrets_env[key.lower().replace('_', '-')] = str(value)
596+
597+
secret_name = "{}-{}-env".format(namespace, kwargs.get('version'))
598+
self._get_secret(namespace, secret_name)
599+
except KubeHTTPException:
600+
self._create_secret(namespace, secret_name, secrets_env)
601+
else:
602+
self._update_secret(namespace, secret_name, secrets_env)
603+
604+
for key in env.keys():
579605
data["env"].append({
580606
"name": key,
581-
"value": str(value)
607+
"valueFrom": {
608+
"secretKeyRef": {
609+
"name": secret_name,
610+
# k8s doesn't allow _ so translate to -, see above
611+
"key": key.lower().replace('_', '-')
612+
}
613+
}
582614
})
583615

584616
# Inject debugging if workflow is in debug mode
@@ -906,7 +938,7 @@ def _create_rc(self, namespace, name, image, command, **kwargs): # noqa
906938
container = template["spec"]["template"]["spec"]["containers"][0]
907939
container['args'] = args
908940

909-
self._set_environment(container, **kwargs)
941+
self._set_environment(container, namespace, **kwargs)
910942

911943
# add in healtchecks
912944
if kwargs.get('healthcheck'):
@@ -1047,7 +1079,26 @@ def _create_secret(self, namespace, name, data):
10471079
url = self._api("/namespaces/{}/secrets", namespace)
10481080
response = self.session.post(url, json=template)
10491081
if unhealthy(response.status_code):
1050-
error(response, 'failed to create secret "{}" in Namespace "{}"', name, namespace)
1082+
error(response, 'failed to create Secret "{}" in Namespace "{}"', name, namespace)
1083+
1084+
return response
1085+
1086+
def _update_secret(self, namespace, name, data):
1087+
template = json.loads(string.Template(SECRET_TEMPLATE).substitute({
1088+
"version": self.apiversion,
1089+
"id": namespace,
1090+
"name": name
1091+
}))
1092+
1093+
for key, value in data.items():
1094+
value = value if isinstance(value, bytes) else bytes(value, 'UTF-8')
1095+
item = base64.b64encode(value).decode()
1096+
template["data"].update({key: item})
1097+
1098+
url = self._api("/namespaces/{}/secrets/{}", namespace, name)
1099+
response = self.session.put(url, json=template)
1100+
if unhealthy(response.status_code):
1101+
error(response, 'failed to update Secret "{}" in Namespace "{}"', name, namespace)
10511102

10521103
return response
10531104

0 commit comments

Comments
 (0)