Skip to content

Commit 22f96eb

Browse files
authored
ref(scheduler): add more Pod tests in scheduler and add create() to Pod resource (#1079)
1 parent 06c7695 commit 22f96eb

6 files changed

Lines changed: 143 additions & 32 deletions

File tree

rootfs/api/models/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,6 @@ def pod_name(size=5, chars=string.ascii_lowercase + string.digits):
681681
return ''.join(random.choice(chars) for _ in range(size))
682682

683683
"""Run a one-off command in an ephemeral app container."""
684-
scale_type = 'run'
685684
release = self.release_set.latest()
686685
if release.build is None:
687686
raise DeisException('No build associated with this release to run this command')
@@ -690,11 +689,12 @@ def pod_name(size=5, chars=string.ascii_lowercase + string.digits):
690689
# use slugrunner image for app if buildpack app otherwise use normal image
691690
image = settings.SLUGRUNNER_IMAGE if release.build.type == 'buildpack' else release.image
692691

693-
data = self._gather_app_settings(release, app_settings, 'run', 1)
692+
data = self._gather_app_settings(release, app_settings, process_type='run', replicas=1)
694693

695694
# create application config and build the pod manifest
696695
self.set_application_config(release)
697696

697+
scale_type = 'run'
698698
name = self._get_job_id(scale_type) + '-' + pod_name()
699699
self.log("{} on {} runs '{}'".format(user.username, name, command))
700700

rootfs/scheduler/__init__.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -304,23 +304,7 @@ def run(self, namespace, name, image, entrypoint, command, **kwargs):
304304
kwargs['command'] = entrypoint
305305
kwargs['args'] = command
306306

307-
manifest = self.pod.manifest(namespace, name, image, **kwargs)
308-
309-
url = self.pods.api("/namespaces/{}/pods", namespace)
310-
response = self.http_post(url, json=manifest)
311-
if self.unhealthy(response.status_code):
312-
raise KubeHTTPException(response, 'create Pod in Namespace "{}"', namespace)
313-
314-
# wait for run pod to start - use the same function as scale
315-
labels = manifest['metadata']['labels']
316-
containers = manifest['spec']['containers']
317-
self.pods.wait_until_ready(
318-
namespace,
319-
containers,
320-
labels,
321-
desired=1,
322-
timeout=kwargs.get('deploy_timeout')
323-
)
307+
self.pod.create(namespace, name, image, **kwargs)
324308

325309
try:
326310
# give pod 20 minutes to execute (after it got into ready state)
@@ -331,8 +315,7 @@ def run(self, namespace, name, image, entrypoint, command, **kwargs):
331315
waited = 0
332316
timeout = 1200 # 20 minutes
333317
while (state == 'up' and waited < timeout):
334-
response = self.pod.get(namespace, name)
335-
pod = response.json()
318+
pod = self.pod.get(namespace, name).json()
336319
state = str(self.pod.state(pod))
337320
# default data
338321
exit_code = 0

rootfs/scheduler/resources/pod.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ def get(self, namespace, name=None, **kwargs):
3232

3333
return response
3434

35+
def create(self, namespace, name, image, **kwargs):
36+
manifest = self.manifest(namespace, name, image, **kwargs)
37+
38+
url = self.api('/namespaces/{}/pods', namespace)
39+
response = self.http_post(url, json=manifest)
40+
if self.unhealthy(response.status_code):
41+
raise KubeHTTPException(response, 'create Pod in Namespace "{}"', namespace)
42+
43+
# wait for all pods to start - use the same function as scale
44+
labels = manifest['metadata']['labels']
45+
containers = manifest['spec']['containers']
46+
self.pods.wait_until_ready(
47+
namespace,
48+
containers,
49+
labels,
50+
desired=kwargs.get('replicas'),
51+
timeout=kwargs.get('deploy_timeout')
52+
)
53+
54+
return response
55+
3556
def state(self, pod):
3657
"""
3758
Resolve Pod state to an internally understandable format and returns a
@@ -315,9 +336,9 @@ def delete(self, namespace, name):
315336

316337
# delete pod
317338
url = self.api("/namespaces/{}/pods/{}", namespace, name)
318-
resp = self.http_delete(url)
319-
if self.unhealthy(resp.status_code):
320-
raise KubeHTTPException(resp, 'delete Pod "{}" in Namespace "{}"', name, namespace)
339+
response = self.http_delete(url)
340+
if self.unhealthy(response.status_code):
341+
raise KubeHTTPException(response, 'delete Pod "{}" in Namespace "{}"', name, namespace)
321342

322343
# Verify the pod has been deleted
323344
# Only wait as long as the grace period is - k8s will eventually GC
@@ -333,6 +354,8 @@ def delete(self, namespace, name):
333354

334355
time.sleep(1)
335356

357+
return response
358+
336359
def logs(self, namespace, name):
337360
url = self.api("/namespaces/{}/pods/{}/log", namespace, name)
338361
response = self.http_get(url)

rootfs/scheduler/tests/test_deployments.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ def create(self, namespace=None, name=generate_random_name(), **kwargs):
2222
'version': kwargs.get('version', 'v99'),
2323
'replicas': kwargs.get('replicas', 4),
2424
'pod_termination_grace_period_seconds': 2,
25+
'image': 'quay.io/fake/image',
26+
'entrypoint': 'sh',
27+
'command': 'start',
2528
}
2629

27-
deployment = self.scheduler.deployment.create(namespace, name, 'quay.io/fake/image',
28-
'sh', 'start', **kwargs)
30+
deployment = self.scheduler.deployment.create(namespace, name, **kwargs)
2931
self.assertEqual(deployment.status_code, 201, deployment.json())
3032
return name
3133

@@ -40,10 +42,12 @@ def update(self, namespace=None, name=generate_random_name(), **kwargs):
4042
'version': kwargs.get('version', 'v99'),
4143
'replicas': kwargs.get('replicas', 4),
4244
'pod_termination_grace_period_seconds': 2,
45+
'image': 'quay.io/fake/image',
46+
'entrypoint': 'sh',
47+
'command': 'start',
4348
}
4449

45-
deployment = self.scheduler.deployment.update(namespace, name, 'quay.io/fake/image',
46-
'sh', 'start', **kwargs)
50+
deployment = self.scheduler.deployment.update(namespace, name, **kwargs)
4751
data = deployment.json()
4852
self.assertEqual(deployment.status_code, 200, data)
4953
return name
@@ -59,9 +63,12 @@ def scale(self, namespace=None, name=generate_random_name(), **kwargs):
5963
'version': kwargs.get('version', 'v99'),
6064
'replicas': kwargs.get('replicas', 4),
6165
'pod_termination_grace_period_seconds': 2,
66+
'image': 'quay.io/fake/image',
67+
'entrypoint': 'sh',
68+
'command': 'start',
6269
}
6370

64-
self.scheduler.scale(namespace, name, 'quay.io/fake/image', 'sh', 'start', **kwargs)
71+
self.scheduler.scale(namespace, name, **kwargs)
6572
return name
6673

6774
def test_create_failure(self):
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
Unit tests for the Deis scheduler module.
3+
4+
Run the tests with './manage.py test scheduler'
5+
"""
6+
from scheduler import KubeHTTPException
7+
from scheduler.tests import TestCase
8+
from scheduler.utils import generate_random_name
9+
10+
11+
class PodsTest(TestCase):
12+
"""Tests scheduler pod calls"""
13+
14+
def create(self, namespace=None, name=generate_random_name(), **kwargs):
15+
"""
16+
Helper function to create and verify a pod on the namespace
17+
"""
18+
namespace = self.namespace if namespace is None else namespace
19+
# these are all required even if it is kwargs...
20+
kwargs = {
21+
'app_type': kwargs.get('app_type', 'web'),
22+
'version': kwargs.get('version', 'v99'),
23+
'replicas': kwargs.get('replicas', 4),
24+
'pod_termination_grace_period_seconds': 2,
25+
'image': 'quay.io/fake/image',
26+
'entrypoint': 'sh',
27+
'command': 'start',
28+
'deploy_timeout': 10,
29+
}
30+
31+
pod = self.scheduler.pod.create(namespace, name, **kwargs)
32+
self.assertEqual(pod.status_code, 201, pod.json())
33+
return name
34+
35+
def test_create_failure(self):
36+
with self.assertRaises(
37+
KubeHTTPException,
38+
msg='failed to create Pod doesnotexist in Namespace {}: 404 Not Found'.format(self.namespace) # noqa
39+
):
40+
self.create('doesnotexist', 'doesnotexist')
41+
42+
def test_create(self):
43+
self.create()
44+
45+
def test_delete_failure(self):
46+
# test failure
47+
with self.assertRaises(
48+
KubeHTTPException,
49+
msg='failed to delete Pod foo in Namespace {}: 404 Not Found'.format(self.namespace) # noqa
50+
):
51+
self.scheduler.pod.delete(self.namespace, 'foo')
52+
53+
def test_delete(self):
54+
# test success
55+
name = self.create()
56+
response = self.scheduler.pod.delete(self.namespace, name)
57+
data = response.json()
58+
self.assertEqual(response.status_code, 200, data)
59+
60+
def test_get_pods(self):
61+
# test success
62+
name = self.create()
63+
response = self.scheduler.pod.get(self.namespace)
64+
data = response.json()
65+
self.assertEqual(response.status_code, 200, data)
66+
self.assertIn('items', data)
67+
self.assertEqual(1, len(data['items']), data['items'])
68+
# simple verify of data
69+
self.assertEqual(data['items'][0]['metadata']['name'], name, data)
70+
71+
def test_get_pod_failure(self):
72+
# test failure
73+
with self.assertRaises(
74+
KubeHTTPException,
75+
msg='failed to get Pod doesnotexist in Namespace {}: 404 Not Found'.format(self.namespace) # noqa
76+
):
77+
self.scheduler.pod.get(self.namespace, 'doesnotexist')
78+
79+
def test_get_pod(self):
80+
# test success
81+
name = self.create()
82+
response = self.scheduler.pod.get(self.namespace, name)
83+
data = response.json()
84+
self.assertEqual(response.status_code, 200, data)
85+
self.assertEqual(data['kind'], 'Pod')
86+
self.assertEqual(data['metadata']['name'], name)
87+
self.assertDictContainsSubset(
88+
{
89+
'app': self.namespace,
90+
'heritage': 'deis'
91+
},
92+
data['metadata']['labels']
93+
)

rootfs/scheduler/tests/test_replicationcontrollers.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ def create(self, namespace=None, name=generate_random_name(), **kwargs):
2222
'version': kwargs.get('version', 'v99'),
2323
'replicas': kwargs.get('replicas', 4),
2424
'pod_termination_grace_period_seconds': 2,
25+
'image': 'quay.io/fake/image',
26+
'entrypoint': 'sh',
27+
'command': 'start',
2528
}
2629

27-
rc = self.scheduler.rc.create(namespace, name, 'quay.io/fake/image',
28-
'sh', 'start', **kwargs)
30+
rc = self.scheduler.rc.create(namespace, name, **kwargs)
2931
data = rc.json()
3032
self.assertEqual(rc.status_code, 201, data)
3133
return name
@@ -42,9 +44,12 @@ def scale_rc(self, namespace=None, name=generate_random_name(), **kwargs):
4244
'replicas': kwargs.get('replicas', 4),
4345
'deploy_timeout': 120,
4446
'pod_termination_grace_period_seconds': 2,
47+
'image': 'quay.io/fake/image',
48+
'entrypoint': 'sh',
49+
'command': 'start',
4550
}
4651

47-
self.scheduler.scale_rc(namespace, name, 'quay.io/fake/image', 'sh', 'start', **kwargs)
52+
self.scheduler.scale_rc(namespace, name, **kwargs)
4853
return name
4954

5055
def test_create_failure(self):

0 commit comments

Comments
 (0)