Skip to content

Commit ddc643c

Browse files
committed
ref(scheduler): create base k8s resources on app creation and update them during deploy
This modifies things so that k8s resources are created during app creation, allowing Domains and other resources to be added on at any point, even before a deploy. Changes the world a little bit around if a scale vs deploy internally is called on first deploy (as it was before) Technically this change brings in the ability to change the target port based on a deploy but that's just a by product Fixes #420
1 parent 916fe94 commit ddc643c

7 files changed

Lines changed: 137 additions & 102 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ SHELL_SCRIPTS = $(wildcard rootfs/bin/*) $(shell find "rootfs" -name '*.sh') $(w
88

99
# Get the component informtation to a tmp location and get replica count
1010
$(shell kubectl get rc deis-$(COMPONENT) --namespace deis -o yaml > /tmp/deis-$(COMPONENT))
11-
DESIRED_REPLICAS=$(shell kubectl get -o template rc/deis-$(COMPONENT) --template={{.status.replicas}})
11+
DESIRED_REPLICAS=$(shell kubectl get -o template rc/deis-$(COMPONENT) --template={{.status.replicas}} --namespace deis)
1212

1313
info:
1414
@echo "Build tag: ${VERSION}"

rootfs/api/models/app.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,17 @@ def create(self, *args, **kwargs):
123123
config = Config.objects.create(owner=self.owner, app=self)
124124
Release.objects.create(version=1, owner=self.owner, app=self, config=config, build=None)
125125

126+
# create required minimum resources in k8s for the application
127+
self._scheduler.create(self.id)
128+
129+
# Attach the platform specific application sub domain to the k8s service
130+
Domain(owner=self.owner, app=self, domain=self.id).save()
131+
126132
def delete(self, *args, **kwargs):
127133
"""Delete this application including all containers"""
128134
try:
129135
# attempt to remove containers from the scheduler
136+
self._scheduler.destroy(self.id)
130137
self._destroy_containers([c for c in self.container_set.exclude(type='run')])
131138
except RuntimeError:
132139
pass
@@ -323,12 +330,6 @@ def _scale_containers(self, scale_types, to_remove):
323330
command=command,
324331
**kwargs
325332
)
326-
327-
# Attach the platform specific application sub domain
328-
# scheduler.scale creates the required service on apps:create
329-
if not Domain.objects.filter(owner=self.owner, app=self, domain=self).exists():
330-
Domain(owner=self.owner, app=self, domain=str(self)).save()
331-
332333
except Exception as e:
333334
err = '{} (scale): {}'.format(job_id, e)
334335
log_event(self, err, logging.ERROR)
@@ -375,14 +376,19 @@ def _destroy_containers(self, to_destroy):
375376
"""Destroys containers via the scheduler"""
376377
if not to_destroy:
377378
return
378-
destroy_threads = [Thread(target=c.destroy) for c in to_destroy]
379-
[t.start() for t in destroy_threads]
380-
[t.join() for t in destroy_threads]
381-
[c.delete() for c in to_destroy if c.state == 'destroyed']
382-
if any(c.state != 'destroyed' for c in to_destroy):
383-
err = 'aborting, failed to destroy some containers'
384-
log_event(self, err, logging.ERROR)
385-
raise RuntimeError(err)
379+
380+
# for mock scheduler
381+
if "scale" not in dir(self._scheduler):
382+
destroy_threads = [Thread(target=c.destroy) for c in to_destroy]
383+
[t.start() for t in destroy_threads]
384+
[t.join() for t in destroy_threads]
385+
[c.delete() for c in to_destroy if c.state == 'destroyed']
386+
if any(c.state != 'destroyed' for c in to_destroy):
387+
err = 'aborting, failed to destroy some containers'
388+
log_event(self, err, logging.ERROR)
389+
raise RuntimeError(err)
390+
else:
391+
[c.delete() for c in to_destroy]
386392

387393
def deploy(self, user, release):
388394
"""Deploy a new release to this application"""
@@ -418,7 +424,7 @@ def _deploy_app(self, scale_types, release, existing):
418424
'cpu': release.config.cpu,
419425
'tags': release.config.tags,
420426
'envs': release.config.values,
421-
'num': 0,
427+
'num': 0, # Scaling up happens in a separate operation
422428
'version': version,
423429
'app_type': scale_type,
424430
'build_type': build_type,
@@ -458,7 +464,16 @@ def _default_scale(self, user, release):
458464
else:
459465
structure = {'web': 1}
460466

461-
self.scale(user, structure)
467+
if "scale" in dir(self._scheduler):
468+
self._deploy_app(structure, release, [])
469+
else:
470+
for key, num in structure.items():
471+
c = Container.objects.create(owner=self.owner,
472+
app=self,
473+
release=release,
474+
type=key,
475+
num=num)
476+
self._start_containers([c])
462477

463478
def logs(self, log_lines=str(settings.LOG_LINES)):
464479
"""Return aggregated log data for this application."""

rootfs/api/tests/test_domain.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def test_manage_domain(self):
8787
content_type='application/json',
8888
HTTP_AUTHORIZATION='token {}'.format(self.token)
8989
)
90-
result = response.data['results'][0]
91-
self.assertEqual(domain, result['domain'], msg)
90+
expected = [data['domain'] for data in response.data['results']]
91+
self.assertEqual([self.app_id, domain], expected, msg)
9292

9393
# Delete
9494
url = '/v2/apps/{app_id}/domains/{hostname}'.format(hostname=domain,
@@ -107,7 +107,11 @@ def test_manage_domain(self):
107107
content_type='application/json',
108108
HTTP_AUTHORIZATION='token {}'.format(self.token)
109109
)
110-
self.assertEqual(0, response.data['count'], msg)
110+
self.assertEqual(1, response.data['count'], msg)
111+
112+
# verify only app domain is left
113+
expected = [data['domain'] for data in response.data['results']]
114+
self.assertEqual([self.app_id], expected, msg)
111115

112116
def test_delete_domain_does_not_exist(self):
113117
"""Remove a domain that does not exist"""
@@ -146,7 +150,7 @@ def test_delete_domain_does_not_remove_latest(self):
146150
def test_delete_domain_does_not_remove_others(self):
147151
"""https://github.com/deis/deis/issues/3475"""
148152
self.test_delete_domain_does_not_remove_latest()
149-
self.assertEqual(Domain.objects.all().count(), 1)
153+
self.assertEqual(Domain.objects.all().count(), 2)
150154

151155
def test_manage_domain_invalid_app(self):
152156
# Create domain

0 commit comments

Comments
 (0)