Skip to content

Commit c57ae23

Browse files
committed
Refs #41 -- add client to INSTALLED_APPS, "make flake8" code cleanup.
1 parent cb9906d commit c57ae23

18 files changed

Lines changed: 161 additions & 141 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ db:
66
python manage.py migrate
77

88
test:
9-
python manage.py test api celerytasks web
9+
python manage.py test api celerytasks client web
1010

1111
coverage:
12-
coverage run manage.py test api celerytasks web
12+
coverage run manage.py test api celerytasks client web
1313
coverage html
1414

1515
flake8:

api/models.py

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,31 @@
3030

3131

3232
def import_tasks(provider_type):
33-
"""Return Celery tasks for a given provider type"""
33+
"""Return the celerytasks module for a given provider.
34+
35+
:param provider_type: type of cloud provider **currently only "ec2"**
36+
:type provider_type: string
37+
:rtype: celerytasks module for the provider
38+
:raises: :py:class:`ImportError` if the provider isn't recognized
39+
"""
3440
try:
35-
tasks = importlib.import_module('celerytasks.'+provider_type)
36-
except ImportError as e:
37-
raise e
41+
tasks = importlib.import_module('celerytasks.' + provider_type)
42+
except ImportError:
43+
raise
3844
return tasks
3945

4046

4147
class AuditedModel(models.Model):
4248

43-
"""
44-
Adds created and update fields to a model.
49+
"""Adds created and updated fields to a model.
4550
"""
4651

4752
created = models.DateTimeField(auto_now_add=True)
4853
updated = models.DateTimeField(auto_now=True)
4954

5055
class Meta:
5156
"""
52-
Metadata options for AuditedModel, marking this class as abstract.
57+
Metadata options for `AuditedModel`, marking this class as abstract.
5358
"""
5459
abstract = True
5560

@@ -122,7 +127,7 @@ class FlavorManager(models.Manager):
122127
def load_cloud_config_base(self):
123128
# load cloud-config-base yaml_
124129
_cloud_config_path = os.path.abspath(
125-
os.path.join(__file__, '..', 'files', 'cloud-config-base.yml'))
130+
os.path.join(__file__, '..', 'files', 'cloud-config-base.yml'))
126131
with open(_cloud_config_path) as f:
127132
_data = f.read()
128133
return yaml.safe_load(_data)
@@ -199,7 +204,7 @@ def publish(self, **kwargs):
199204
'ssh_keys': {},
200205
'admins': [],
201206
'formations': {}
202-
}
207+
}
203208
# add all ssh keys on the system
204209
for key in Key.objects.all():
205210
key_id = "{0}_{1}".format(key.owner.username, key.id)
@@ -217,9 +222,11 @@ def publish(self, **kwargs):
217222
def next_container_node(self, formation, container_type):
218223
count = []
219224
layer = formation.layer_set.get(id='runtime')
220-
runtime_nodes = list(Node.objects.filter(formation=formation, layer=layer).order_by('created'))
221-
container_map = { n: [] for n in runtime_nodes }
222-
containers = list(Container.objects.filter(formation=formation, type=container_type).order_by('created'))
225+
runtime_nodes = list(Node.objects.filter(
226+
formation=formation, layer=layer).order_by('created'))
227+
container_map = {n: [] for n in runtime_nodes}
228+
containers = list(Container.objects.filter(
229+
formation=formation, type=container_type).order_by('created'))
223230
for c in containers:
224231
container_map[c.node].append(c)
225232
for n in container_map.keys():
@@ -261,13 +268,13 @@ def scale_layers(self, **kwargs):
261268
node = nodes.pop(0)
262269
funcs.append(node.terminate)
263270
diff = requested - len(nodes)
264-
while diff > 0:
271+
while diff > 0:
265272
node = Node.objects.new(self, layer)
266273
nodes.append(node)
267274
funcs.append(node.launch)
268275
diff = requested - len(nodes)
269276
# http://docs.celeryproject.org/en/latest/userguide/canvas.html#groups
270-
job = [func() for func in funcs ]
277+
job = [func() for func in funcs]
271278
# balance containers
272279
containers_balanced = self._balance_containers()
273280
# launch/terminate nodes in parallel
@@ -334,17 +341,17 @@ def balance(self, **kwargs):
334341
def _balance_containers(self, **kwargs):
335342
runtime_nodes = self.node_set.filter(layer__id='runtime').order_by('created')
336343
if len(runtime_nodes) < 2:
337-
return # there's nothing to balance with 1 runtime node
344+
return # there's nothing to balance with 1 runtime node
338345
all_containers = Container.objects.filter(formation=self).order_by('-created')
339346
# get the next container number (e.g. web.19)
340347
container_num = 1 if not all_containers else all_containers[0].num + 1
341348
changed = False
342349
# iterate by unique container type
343350
for container_type in set([c.type for c in all_containers]):
344-
# map node container counts => { 2: [b3, b4], 3: [ b1, b2 ] }
351+
# map node container counts => {2: [b3, b4], 3: [ b1, b2 ]}
345352
n_map = {}
346353
for node in runtime_nodes:
347-
ct = len(node.container_set.filter(type=container_type))
354+
ct = len(node.container_set.filter(type=container_type))
348355
n_map.setdefault(ct, []).append(node)
349356
# loop until diff between min and max is 1 or 0
350357
while max(n_map.keys()) - min(n_map.keys()) > 1:
@@ -421,17 +428,17 @@ def converge(self, databag):
421428
if settings.CHEF_ENABLED:
422429
controller.update_formation.delay(self.id, databag).wait() # @UndefinedVariable
423430
# TODO: batch node converging by layer.level
424-
nodes = [ node for node in self.node_set.all() ]
425-
job = group(*[ n.converge() for n in nodes ])
426-
_results = job.apply_async().join()
431+
nodes = [node for node in self.node_set.all()]
432+
job = group(*[n.converge() for n in nodes])
433+
job.apply_async().join()
427434
return databag
428435

429436
def destroy(self):
430437
node_tasks, layer_tasks, chef_tasks = [], [], []
431438
# create subtasks to terminate all nodes in parallel
432439
all_layers = self.layer_set.all()
433-
node_tasks.extend([ layer.destroy()[0] for layer in all_layers ])
434-
layer_tasks.extend([ layer.destroy()[1] for layer in all_layers ])
440+
node_tasks.extend([layer.destroy()[0] for layer in all_layers])
441+
layer_tasks.extend([layer.destroy()[1] for layer in all_layers])
435442
# call a celery task to update the formation data bag
436443
if settings.CHEF_ENABLED:
437444
chef_tasks.extend([controller.destroy_formation.s(self.id)]) # @UndefinedVariable
@@ -443,23 +450,23 @@ def destroy(self):
443450

444451
@python_2_unicode_compatible
445452
class Layer(UuidAuditedModel):
446-
453+
447454
"""
448455
Layer of nodes used by the formation
449-
456+
450457
All nodes in a layer share the same flavor and configuration
451458
"""
452459

453460
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
454461
id = models.SlugField(max_length=64)
455-
462+
456463
formation = models.ForeignKey('Formation')
457464
flavor = models.ForeignKey('Flavor')
458465
level = models.PositiveIntegerField(default=0)
459466

460467
# chef settings
461468
chef_version = models.CharField(max_length=32, default='11.4.4')
462-
run_list = models.CharField(max_length=512)
469+
run_list = models.CharField(max_length=512)
463470
initial_attributes = fields.JSONField(default='{}', blank=True)
464471
environment = models.CharField(max_length=64, default='_default')
465472
# ssh settings
@@ -484,7 +491,7 @@ def destroy(self):
484491
tasks = import_tasks(self.flavor.provider.type)
485492
subtasks = []
486493
# create subtasks to terminate all nodes in parallel
487-
subtasks.extend([ node.terminate() for node in self.node_set.all() ])
494+
subtasks.extend([node.terminate() for node in self.node_set.all()])
488495
node_tasks = group(*subtasks)
489496
# purge other hosting provider infrastructure
490497
name = "{0}-{1}".format(self.formation.id, self.id)
@@ -526,7 +533,7 @@ class Node(UuidAuditedModel):
526533
formation = models.ForeignKey('Formation')
527534
layer = models.ForeignKey('Layer')
528535
num = models.PositiveIntegerField()
529-
536+
530537
# synchronized with node after creation
531538
provider_id = models.SlugField(max_length=64, blank=True, null=True)
532539
fqdn = models.CharField(max_length=256, blank=True, null=True)
@@ -565,10 +572,10 @@ def _prepare_launch_args(self):
565572
if self.layer.initial_attributes:
566573
chef['initial_attributes'] = self.layer.initial_attributes
567574
# add the formation's ssh pubkey
568-
init.setdefault('ssh_authorized_keys', []).append(
569-
self.layer.ssh_public_key)
575+
init.setdefault(
576+
'ssh_authorized_keys', []).append(self.layer.ssh_public_key)
570577
# add all of the owner's SSH keys
571-
init['ssh_authorized_keys'].extend([k.public for k in self.formation.owner.key_set.all() ])
578+
init['ssh_authorized_keys'].extend([k.public for k in self.formation.owner.key_set.all()])
572579
ssh_username = self.layer.ssh_username
573580
ssh_private_key = self.layer.ssh_private_key
574581
args = (self.uuid, creds, params, init, ssh_username, ssh_private_key)
@@ -744,6 +751,9 @@ def rollback(self):
744751

745752
@receiver(release_signal)
746753
def new_release(sender, **kwargs):
754+
"""Catches a release_signal and creates a new release from the
755+
last release.
756+
"""
747757
formation, user = kwargs['formation'], kwargs['user']
748758
last_release = Release.objects.filter(
749759
formation=formation).order_by('-created')[0]
@@ -759,11 +769,12 @@ def new_release(sender, **kwargs):
759769
if new_values:
760770
# update with current config
761771
new_values.update(config.values)
762-
config = Config.objects.create(version=config.version+1,
763-
owner=user, formation=formation, values=new_values)
772+
config = Config.objects.create(
773+
version=config.version + 1, owner=user,
774+
formation=formation, values=new_values)
764775
# create new release and auto-increment version
765776
new_version = last_release.version + 1
766-
release = Release.objects.create(owner=user, formation=formation,
767-
image=image, config=config, build=build, version=new_version)
777+
release = Release.objects.create(
778+
owner=user, formation=formation, image=image, config=config,
779+
build=build, version=new_version)
768780
return release
769-

api/serializers.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from django.contrib.auth.models import User
99
from rest_framework import serializers
1010

11-
from api import models, utils
11+
from api import models
12+
from api import utils
1213

1314

1415
class UserSerializer(serializers.ModelSerializer):
@@ -125,13 +126,13 @@ class Meta:
125126

126127

127128
class LayerSerializer(serializers.ModelSerializer):
128-
129+
129130
"""Serializes a Layer model."""
130-
131+
131132
owner = serializers.Field(source='owner.username')
132133
formation = serializers.SlugRelatedField(slug_field='id')
133134
flavor = serializers.SlugRelatedField(slug_field='id')
134-
135+
135136
class Meta:
136137
"""Metadata options for a LayerSerializer."""
137138
model = models.Layer

api/tests/auth.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_auth(self):
3939
# try to abuse superuser/staff level perms
4040
'is_superuser': True,
4141
'is_staff': True,
42-
}
42+
}
4343
url = '/api/auth/register'
4444
response = self.client.post(url, json.dumps(submit), content_type='application/json')
4545
self.assertEqual(response.status_code, 201)
@@ -60,4 +60,4 @@ def test_auth(self):
6060
url = '/api/flavors'
6161
response = self.client.get(url)
6262
self.assertEqual(response.status_code, 200)
63-
self.assertEqual(response.data['count'], 8) # 8 regions
63+
self.assertEqual(response.data['count'], 8) # 8 regions

api/tests/formation.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def setUp(self):
2121
self.assertTrue(
2222
self.client.login(username='autotest', password='password'))
2323
url = '/api/providers'
24-
creds = {'secret_key': 'x'*64, 'access_key': 1*20}
24+
creds = {'secret_key': 'x' * 64, 'access_key': 1 * 20}
2525
body = {'id': 'autotest', 'type': 'mock', 'creds': json.dumps(creds)}
2626
response = self.client.post(url, json.dumps(body), content_type='application/json')
2727
self.assertEqual(response.status_code, 201)
@@ -39,7 +39,7 @@ def test_formation(self):
3939
body = {'id': 'autotest'}
4040
response = self.client.post(url, json.dumps(body), content_type='application/json')
4141
self.assertEqual(response.status_code, 201)
42-
formation_id = response.data['id']
42+
formation_id = response.data['id'] # noqa
4343
self.assertIn('layers', response.data)
4444
self.assertIn('containers', response.data)
4545
response = self.client.get('/api/formations')
@@ -56,19 +56,22 @@ def test_formation(self):
5656

5757
def test_formation_auto_id(self):
5858
body = {'id': 'autotest'}
59-
response = self.client.post('/api/formations', json.dumps(body), content_type='application/json')
59+
response = self.client.post('/api/formations', json.dumps(body),
60+
content_type='application/json')
6061
self.assertEqual(response.status_code, 201)
6162
self.assertTrue(response.data['id'])
6263
return response
63-
64+
6465
def test_formation_errors(self):
6566
# test duplicate id
6667
body = {}
67-
response = self.client.post('/api/formations', json.dumps(body), content_type='application/json')
68+
response = self.client.post('/api/formations', json.dumps(body),
69+
content_type='application/json')
6870
self.assertEqual(response.status_code, 201)
6971
self.assertTrue(response.data['id'])
7072
body = {'id': response.data['id']}
71-
response = self.client.post('/api/formations', json.dumps(body), content_type='application/json')
73+
response = self.client.post('/api/formations', json.dumps(body),
74+
content_type='application/json')
7275
self.assertEqual(response.status_code, 400)
7376
self.assertEqual(json.loads(response.content), 'Formation with this Id already exists.')
7477

@@ -77,13 +80,14 @@ def test_formation_scale_errors(self):
7780
body = {'id': 'autotest'}
7881
response = self.client.post(url, json.dumps(body), content_type='application/json')
7982
self.assertEqual(response.status_code, 201)
80-
formation_id = response.data['id']
83+
formation_id = response.data['id'] # noqa
8184
# scaling containers without a runtime layer should throw an error
8285
url = '/api/formations/{formation_id}/scale/containers'.format(**locals())
8386
body = {'web': 1}
8487
response = self.client.post(url, json.dumps(body), content_type='application/json')
8588
self.assertEqual(response.status_code, 400)
86-
self.assertEqual(json.loads(response.content), 'Must create a "runtime" layer to host containers')
89+
self.assertEqual(json.loads(response.content),
90+
'Must create a "runtime" layer to host containers')
8791
# scaling containers without any runtime nodes should throw an error
8892
url = '/api/formations/{formation_id}/layers'.format(**locals())
8993
body = {'id': 'runtime', 'flavor': 'autotest', 'run_list': 'recipe[deis::runtime]'}
@@ -93,14 +97,15 @@ def test_formation_scale_errors(self):
9397
body = {'web': 1}
9498
response = self.client.post(url, json.dumps(body), content_type='application/json')
9599
self.assertEqual(response.status_code, 400)
96-
self.assertEqual(json.loads(response.content), 'Must scale runtime nodes > 0 to host containers')
100+
self.assertEqual(json.loads(response.content),
101+
'Must scale runtime nodes > 0 to host containers')
97102

98103
def test_formation_actions(self):
99104
url = '/api/formations'
100105
body = {'id': 'autotest'}
101106
response = self.client.post(url, json.dumps(body), content_type='application/json')
102107
self.assertEqual(response.status_code, 201)
103-
formation_id = response.data['id']
108+
formation_id = response.data['id'] # noqa
104109
# test calculate
105110
url = '/api/formations/{formation_id}/calculate'.format(**locals())
106111
response = self.client.post(url)

0 commit comments

Comments
 (0)