Skip to content

Commit 368fb3c

Browse files
committed
ref(scheduler): generate secrets manifest for create and update secrets
Move to the same model as Pod building. Also moves update secret to generate a whole new object to overwrite the previous one instead of just updating the data element Unifies the base64 encoding and how labels are applied
1 parent d4415c9 commit 368fb3c

2 files changed

Lines changed: 49 additions & 50 deletions

File tree

rootfs/api/models/certificate.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,27 +173,27 @@ def attach_in_kubernetes(self, domain):
173173
# only create if it exists - We raise an exception when a secret doesn't exist
174174
try:
175175
name = '%s-cert' % self.name
176-
app = domain.app
176+
namespace = domain.app.id
177177
data = {
178178
'tls.crt': self.certificate,
179179
'tls.key': self.key
180180
}
181181

182-
secret = self._scheduler.get_secret(app, name).json()['data']
182+
secret = self._scheduler.get_secret(namespace, name).json()['data']
183183
except KubeException:
184-
self._scheduler.create_secret(app, name, data)
184+
self._scheduler.create_secret(namespace, name, data)
185185
else:
186186
# update cert secret to the TLS Ingress format if required
187187
if secret != data:
188188
try:
189-
self._scheduler.update_secret(app, name, data)
189+
self._scheduler.update_secret(namespace, name, data)
190190
except KubeException as e:
191191
msg = 'There was a problem updating the certificate secret ' \
192-
'{} for {}'.format(name, app)
192+
'{} for {}'.format(name, namespace)
193193
raise ServiceUnavailable(msg) from e
194194

195195
# get config for the service
196-
config = self._load_service_config(app, 'router')
196+
config = self._load_service_config(namespace, 'router')
197197

198198
# See if certificates are available
199199
if 'certificates' not in config:
@@ -206,7 +206,7 @@ def attach_in_kubernetes(self, domain):
206206
certificates.append(cert)
207207
config['certificates'] = ','.join(certificates)
208208

209-
self._save_service_config(app, 'router', config)
209+
self._save_service_config(namespace, 'router', config)
210210

211211
def detach(self, *args, **kwargs):
212212
# remove the certificate from the domain
@@ -215,19 +215,19 @@ def detach(self, *args, **kwargs):
215215
domain.save()
216216

217217
name = '%s-cert' % self.name
218-
app = domain.app
218+
namespace = domain.app.id
219219

220220
# only delete if it exists and if no other domains depend on secret
221221
if len(self.domains) == 0:
222222
try:
223223
# We raise an exception when a secret doesn't exist
224-
self._scheduler.get_secret(app, name)
225-
self._scheduler.delete_secret(app, name)
224+
self._scheduler.get_secret(namespace, name)
225+
self._scheduler.delete_secret(namespace, name)
226226
except KubeException as e:
227-
raise ServiceUnavailable("Could not delete certificate secret {} for application {}".format(name, app)) from e # noqa
227+
raise ServiceUnavailable("Could not delete certificate secret {} for application {}".format(name, namespace)) from e # noqa
228228

229229
# get config for the service
230-
config = self._load_service_config(app, 'router')
230+
config = self._load_service_config(namespace, 'router')
231231

232232
# See if certificates are available
233233
if 'certificates' not in config:
@@ -240,4 +240,4 @@ def detach(self, *args, **kwargs):
240240
certificates.remove(cert)
241241
config['certificates'] = ','.join(certificates)
242242

243-
self._save_service_config(app, 'router', config)
243+
self._save_service_config(namespace, 'router', config)

rootfs/scheduler/__init__.py

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,6 @@
4141
heritage: deis
4242
"""
4343

44-
SECRET_TEMPLATE = """\
45-
kind: Secret
46-
apiVersion: v1
47-
metadata:
48-
name: $name
49-
namespace: $id
50-
labels:
51-
app: $id
52-
heritage: deis
53-
type: $type
54-
data: {}
55-
"""
56-
5744

5845
class KubeException(Exception):
5946
def __init__(self, *args, **kwargs):
@@ -454,6 +441,11 @@ def _set_container(self, namespace, container_name, data, **kwargs): # noqa
454441
if env:
455442
# env vars are stored in secrets and mapped to env in k8s
456443
try:
444+
labels = {
445+
'version': kwargs.get('version'),
446+
'type': 'env'
447+
}
448+
457449
# secrets use dns labels for keys, map those properly here
458450
secrets_env = {}
459451
for key, value in env.items():
@@ -462,13 +454,9 @@ def _set_container(self, namespace, container_name, data, **kwargs): # noqa
462454
secret_name = "{}-{}-env".format(namespace, kwargs.get('version'))
463455
self.get_secret(namespace, secret_name)
464456
except KubeHTTPException:
465-
labels = {
466-
'version': kwargs.get('version'),
467-
'type': 'env'
468-
}
469457
self.create_secret(namespace, secret_name, secrets_env, labels=labels)
470458
else:
471-
self.update_secret(namespace, secret_name, secrets_env)
459+
self.update_secret(namespace, secret_name, secrets_env, labels=labels)
472460

473461
for key in env.keys():
474462
item = {
@@ -562,7 +550,12 @@ def _set_image_secret(self, data, namespace, **kwargs):
562550
secret_type='kubernetes.io/dockerconfigjson'
563551
)
564552
else:
565-
self.update_secret(namespace, secret_name, secret_data)
553+
self.update_secret(
554+
namespace,
555+
secret_name,
556+
secret_data,
557+
secret_type='kubernetes.io/dockerconfigjson'
558+
)
566559

567560
# apply image pull secret to a Pod spec
568561
data['imagePullSecrets'] = [{'name': secret_name}]
@@ -1030,7 +1023,7 @@ def _default_dockerapp_readiness_probe(self, port, delay=5, timeout=5, period_se
10301023
return readinessprobe
10311024

10321025
# SECRETS #
1033-
# http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_secret
1026+
# http://kubernetes.io/docs/api-reference/v1/definitions/#_v1_secret
10341027
def get_secret(self, namespace, name):
10351028
url = self._api("/namespaces/{}/secrets/{}", namespace, name)
10361029
response = self.session.get(url)
@@ -1060,25 +1053,38 @@ def get_secrets(self, namespace, **kwargs):
10601053

10611054
return response
10621055

1063-
def create_secret(self, namespace, name, data, secret_type='Opaque', labels={}):
1056+
def _build_secret_manifest(self, namespace, name, data, secret_type='Opaque', labels={}):
10641057
secret_types = ['Opaque', 'kubernetes.io/dockerconfigjson']
10651058
if secret_type not in secret_types:
10661059
raise KubeException('{} is not a supported secret type. Use one of the following: '.format(secret_type, ', '.join(secret_types))) # noqa
10671060

1068-
manifest = ruamel.yaml.load(string.Template(SECRET_TEMPLATE).substitute({
1069-
"id": namespace,
1070-
"name": name,
1071-
"type": secret_type
1072-
}))
1061+
manifest = {
1062+
'kind': 'Secret',
1063+
'apiVersion': 'v1',
1064+
'metadata': {
1065+
'name': name,
1066+
'namespace': namespace,
1067+
'labels': {
1068+
'app': namespace,
1069+
'heritage': 'deis'
1070+
}
1071+
},
1072+
'type': secret_type,
1073+
'data': {}
1074+
}
10731075

10741076
# add in any additional label info
10751077
manifest['metadata']['labels'].update(labels)
10761078

10771079
for key, value in data.items():
10781080
value = value if isinstance(value, bytes) else bytes(value, 'UTF-8')
10791081
item = base64.b64encode(value).decode(encoding='UTF-8')
1080-
manifest["data"].update({key: item})
1082+
manifest['data'].update({key: item})
1083+
1084+
return manifest
10811085

1086+
def create_secret(self, namespace, name, data, secret_type='Opaque', labels={}):
1087+
manifest = self._build_secret_manifest(namespace, name, data, secret_type, labels)
10821088
url = self._api("/namespaces/{}/secrets", namespace)
10831089
response = self.session.post(url, json=manifest)
10841090
if unhealthy(response.status_code):
@@ -1089,17 +1095,10 @@ def create_secret(self, namespace, name, data, secret_type='Opaque', labels={}):
10891095

10901096
return response
10911097

1092-
def update_secret(self, namespace, name, data):
1093-
# only update the data attribute
1094-
secret = self.get_secret(namespace, name).json()
1095-
1096-
for key, value in data.items():
1097-
value = value if isinstance(value, bytes) else bytes(value, 'UTF-8')
1098-
item = base64.b64encode(value).decode(encoding='UTF-8')
1099-
secret["data"].update({key: item})
1100-
1098+
def update_secret(self, namespace, name, data, secret_type='Opaque', labels={}):
1099+
manifest = self._build_secret_manifest(namespace, name, data, secret_type, labels)
11011100
url = self._api("/namespaces/{}/secrets/{}", namespace, name)
1102-
response = self.session.put(url, json=secret)
1101+
response = self.session.put(url, json=manifest)
11031102
if unhealthy(response.status_code):
11041103
raise KubeHTTPException(
11051104
response,

0 commit comments

Comments
 (0)