Skip to content

Commit 8aeab3c

Browse files
committed
feat(k8s): differential update state to k8s
1 parent a48ae7d commit 8aeab3c

3 files changed

Lines changed: 59 additions & 38 deletions

File tree

rootfs/api/management/commands/load_db_state_to_k8s.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,9 @@ class Command(BaseCommand):
2020
to k8s.
2121
"""
2222

23-
def _deploy(self, app, release):
24-
if release.build is None:
25-
print('WARNING: {} has no build associated with '
26-
'its latest release. Skipping deployment...'.format(app))
27-
return
28-
23+
def _deploy(self, app):
2924
try:
30-
app.deploy(release)
25+
app.state_to_k8s()
3126
except AlreadyExists as error:
3227
logger.debug(error)
3328
print('WARNING: {} has a deployment in progress. '
@@ -50,13 +45,9 @@ def handle(self, *args, **options):
5045
cert.attach_in_kubernetes(domain)
5146

5247
# deploy apps
53-
print("Deploying available applications")
48+
print("Deploying available applications.")
5449
for app in App.objects.all():
55-
release = app.release_set.filter(failed=False).latest()
56-
if release.canary:
57-
self._deploy(app, app.release_set.filter(failed=False, canary=False).latest())
58-
self._deploy(app, release)
59-
50+
self._deploy(app)
6051
print("Done Publishing DB state to kubernetes.")
6152

6253
def save_apps(self):

rootfs/api/models/app.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,33 @@ def image_pull_secret(self, namespace, registry, image):
512512

513513
return name
514514

515+
def state_to_k8s(self):
516+
def _load_procfile_types(canary):
517+
procfile_types = set()
518+
for procfile_type, scale in self.structure.items():
519+
response = self.scheduler().deployment.get(
520+
self.id, self._get_job_id(procfile_type, canary),
521+
ignore_exception=True)
522+
if response.status_code == 404 and scale > 0:
523+
procfile_types.add(procfile_type)
524+
elif response.status_code != 200:
525+
data = response.json()
526+
self.log('get deployment status_code {}, message: {}'.format(
527+
response.status_code, data.get("message", "")), logging.ERROR)
528+
return procfile_types
529+
530+
release = self.release_set.filter(failed=False).latest()
531+
if release.build is None:
532+
self.log('the last release does not have a build, skipping deployment...')
533+
return
534+
procfile_types = _load_procfile_types(False)
535+
if release.canary:
536+
procfile_types = procfile_types.union(_load_procfile_types(canary=True))
537+
if len(procfile_types) == 0:
538+
self.log('the cluster status is the latest, skipping deployment...')
539+
return
540+
self.deploy(release, procfile_types)
541+
515542
def set_application_config(self, release, procfile_type):
516543
"""
517544
Creates the application config as a secret in Kubernetes and

rootfs/scheduler/resources/deployment.py

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Deployment(Resource):
99
api_prefix = 'apis'
1010
api_version = 'apps/v1'
1111

12-
def get(self, namespace, name=None, **kwargs):
12+
def get(self, namespace, name=None, ignore_exception=False, **kwargs):
1313
"""
1414
Fetch a single Deployment or a list
1515
"""
@@ -24,7 +24,7 @@ def get(self, namespace, name=None, **kwargs):
2424

2525
url = self.api(url, *args)
2626
response = self.http_get(url, params=self.query_params(**kwargs))
27-
if self.unhealthy(response.status_code):
27+
if self.unhealthy(response.status_code) and not ignore_exception:
2828
args.reverse() # error msg is in reverse order
2929
raise KubeHTTPException(response, message, *args)
3030

@@ -115,40 +115,43 @@ def manifest(self, namespace, name, image, command, args, spec_annotations, **kw
115115

116116
return manifest
117117

118-
def create(self, namespace, name, image, command, args, spec_annotations, **kwargs):
118+
def create(self, namespace, name, image, command, args,
119+
spec_annotations, ignore_exception=False, **kwargs):
119120
manifest = self.manifest(namespace, name, image,
120121
command, args, spec_annotations, **kwargs)
121122

122123
url = self.api("/namespaces/{}/deployments", namespace)
123124
response = self.http_post(url, json=manifest)
124125
if self.unhealthy(response.status_code):
125126
self.log(namespace, 'template: {}'.format(json.dumps(manifest, indent=4)), 'DEBUG')
126-
raise KubeHTTPException(
127-
response,
128-
'create Deployment "{}" in Namespace "{}"', name, namespace
129-
)
130-
131-
self.wait_until_updated(namespace, name)
132-
self.wait_until_ready(namespace, name, **kwargs)
133-
127+
if not ignore_exception:
128+
raise KubeHTTPException(
129+
response,
130+
'create Deployment "{}" in Namespace "{}"', name, namespace
131+
)
132+
else:
133+
self.wait_until_updated(namespace, name)
134+
self.wait_until_ready(namespace, name, **kwargs)
134135
return response
135136

136-
def update(self, namespace, name, image, command, args, spec_annotations, **kwargs):
137+
def update(self, namespace, name, image, command, args,
138+
spec_annotations, ignore_exception=False, **kwargs):
137139
manifest = self.manifest(namespace, name, image,
138140
command, args, spec_annotations, **kwargs)
139141

140142
url = self.api("/namespaces/{}/deployments/{}", namespace, name)
141143
response = self.http_put(url, json=manifest)
142144
if self.unhealthy(response.status_code):
143145
self.log(namespace, 'template: {}'.format(json.dumps(manifest, indent=4)), 'DEBUG')
144-
raise KubeHTTPException(response, 'update Deployment "{}"', name)
145-
146-
self.wait_until_updated(namespace, name)
147-
self.wait_until_ready(namespace, name, **kwargs)
148-
146+
if not ignore_exception:
147+
raise KubeHTTPException(response, 'update Deployment "{}"', name)
148+
else:
149+
self.wait_until_updated(namespace, name)
150+
self.wait_until_ready(namespace, name, **kwargs)
149151
return response
150152

151-
def patch(self, namespace, name, image, command, args, spec_annotations, **kwargs):
153+
def patch(self, namespace, name, image, command, args,
154+
spec_annotations, ignore_exception=False, **kwargs):
152155
manifest = self.manifest(namespace, name, image,
153156
command, args, spec_annotations, **kwargs)
154157

@@ -161,11 +164,11 @@ def patch(self, namespace, name, image, command, args, spec_annotations, **kwarg
161164

162165
if self.unhealthy(response.status_code):
163166
self.log(namespace, 'template: {}'.format(json.dumps(manifest, indent=4)), 'DEBUG')
164-
raise KubeHTTPException(response, 'patch Deployment "{}"', name)
165-
166-
self.wait_until_updated(namespace, name)
167-
self.wait_until_ready(namespace, name, **kwargs)
168-
167+
if not ignore_exception:
168+
raise KubeHTTPException(response, 'patch Deployment "{}"', name)
169+
else:
170+
self.wait_until_updated(namespace, name)
171+
self.wait_until_ready(namespace, name, **kwargs)
169172
return response
170173

171174
def delete(self, namespace, name, ignore_exception=False):
@@ -200,7 +203,7 @@ def scale(self, namespace, name, **kwargs):
200203
kwargs['previous_replicas'] = current
201204
self.wait_until_ready(namespace, name, **kwargs)
202205

203-
def restart(self, namespace, name):
206+
def restart(self, namespace, name, ignore_exception=False):
204207
url = self.api(
205208
"/namespaces/{}/deployments/{}?fieldManager=kubectl-rollout&pretty=true",
206209
namespace, name
@@ -221,7 +224,7 @@ def restart(self, namespace, name):
221224
}),
222225
headers={"Content-Type": "application/merge-patch+json"},
223226
)
224-
if self.unhealthy(response.status_code):
227+
if self.unhealthy(response.status_code) and not ignore_exception:
225228
raise KubeHTTPException(
226229
response,
227230
'restart Deployment "{}" in Namespace "{}"', name, namespace

0 commit comments

Comments
 (0)