Merge lp:~jameinel/maas/arch_constraint into lp:~maas-committers/maas/trunk

Proposed by John A Meinel
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 1060
Proposed branch: lp:~jameinel/maas/arch_constraint
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 141 lines (+53/-18)
4 files modified
src/maasserver/api.py (+4/-5)
src/maasserver/models/node.py (+5/-0)
src/maasserver/tests/test_api.py (+21/-11)
src/maasserver/tests/test_node.py (+23/-2)
To merge this branch: bzr merge lp:~jameinel/maas/arch_constraint
Reviewer Review Type Date Requested Status
John A Meinel (community) Approve
Review via email: mp+125979@code.launchpad.net

Commit message

Expose 'arch' as a constraint that can be used to select nodes in get_available_node_for_acquisition.

Description of the change

Ignore this branch, it is just one of ~gz's approved branches that needed a trivial merge-conflict fix.

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

Self approving because https://code.launchpad.net/~gz/maas/arch_constraint/+merge/123789 is already approved.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api.py'
2--- src/maasserver/api.py 2012-09-21 16:36:27 +0000
3+++ src/maasserver/api.py 2012-09-24 11:28:20 +0000
4@@ -645,11 +645,10 @@
5 :return: A mapping of applicable constraint names to their values.
6 :rtype: :class:`dict`
7 """
8- name = request_params.get('name', None)
9- if name is None:
10- return {}
11- else:
12- return {'name': name}
13+ supported_constraints = ('name', 'arch')
14+ return {constraint: request_params[constraint]
15+ for constraint in supported_constraints
16+ if constraint in request_params}
17
18
19 @api_operations
20
21=== modified file 'src/maasserver/models/node.py'
22--- src/maasserver/models/node.py 2012-09-24 09:00:41 +0000
23+++ src/maasserver/models/node.py 2012-09-24 11:28:20 +0000
24@@ -253,6 +253,11 @@
25 if constraints.get('name'):
26 available_nodes = available_nodes.filter(
27 hostname=constraints['name'])
28+ if constraints.get('arch'):
29+ # GZ 2012-09-11: This only supports an exact match on arch type,
30+ # using an i386 image on amd64 hardware will wait.
31+ available_nodes = available_nodes.filter(
32+ architecture=constraints['arch'])
33
34 return get_first(available_nodes)
35
36
37=== modified file 'src/maasserver/tests/test_api.py'
38--- src/maasserver/tests/test_api.py 2012-09-21 16:36:27 +0000
39+++ src/maasserver/tests/test_api.py 2012-09-24 11:28:20 +0000
40@@ -1663,17 +1663,6 @@
41 self.assertEqual(
42 node.hostname, json.loads(response.content)['hostname'])
43
44- def test_POST_acquire_constrains_by_name(self):
45- # Negative test for name constraint.
46- # If a name constraint is given, "acquire" will only consider a
47- # node with that name.
48- factory.make_node(status=NODE_STATUS.READY, owner=None)
49- response = self.client.post(self.get_uri('nodes/'), {
50- 'op': 'acquire',
51- 'name': factory.getRandomString(),
52- })
53- self.assertEqual(httplib.CONFLICT, response.status_code)
54-
55 def test_POST_acquire_treats_unknown_name_as_resource_conflict(self):
56 # A name constraint naming an unknown node produces a resource
57 # conflict: most likely the node existed but has changed or
58@@ -1687,6 +1676,27 @@
59 })
60 self.assertEqual(httplib.CONFLICT, response.status_code)
61
62+ def test_POST_acquire_allocates_node_by_arch(self):
63+ # Asking for a particular arch acquires a node with that arch.
64+ node = factory.make_node(
65+ status=NODE_STATUS.READY, architecture=ARCHITECTURE.i386)
66+ response = self.client.post(self.get_uri('nodes/'), {
67+ 'op': 'acquire',
68+ 'arch': 'i386',
69+ })
70+ self.assertEqual(httplib.OK, response.status_code)
71+ response_json = json.loads(response.content)
72+ self.assertEqual(node.architecture, response_json['architecture'])
73+
74+ def test_POST_acquire_treats_unknown_arch_as_resource_conflict(self):
75+ # Asking for an unknown arch returns an HTTP conflict
76+ factory.make_node(status=NODE_STATUS.READY)
77+ response = self.client.post(self.get_uri('nodes/'), {
78+ 'op': 'acquire',
79+ 'arch': 'sparc',
80+ })
81+ self.assertEqual(httplib.CONFLICT, response.status_code)
82+
83 def test_POST_acquire_sets_a_token(self):
84 # "acquire" should set the Token being used in the request on
85 # the Node that is allocated.
86
87=== modified file 'src/maasserver/tests/test_node.py'
88--- src/maasserver/tests/test_node.py 2012-09-24 09:00:41 +0000
89+++ src/maasserver/tests/test_node.py 2012-09-24 11:28:20 +0000
90@@ -20,6 +20,7 @@
91 ValidationError,
92 )
93 from maasserver.enum import (
94+ ARCHITECTURE,
95 DISTRO_SERIES,
96 NODE_PERMISSION,
97 NODE_STATUS,
98@@ -635,7 +636,8 @@
99 Node.objects.get_available_node_for_acquisition(
100 user, {'name': node.system_id}))
101
102- def test_get_available_node_constrains_by_name(self):
103+ def test_get_available_node_with_name(self):
104+ """A single available node can be selected using its hostname"""
105 user = factory.make_user()
106 nodes = [self.make_node() for counter in range(3)]
107 self.assertEqual(
108@@ -643,13 +645,32 @@
109 Node.objects.get_available_node_for_acquisition(
110 user, {'name': nodes[1].hostname}))
111
112- def test_get_available_node_returns_None_if_name_is_unknown(self):
113+ def test_get_available_node_with_unknown_name(self):
114+ """None is returned if there is no node with a given name"""
115 user = factory.make_user()
116 self.assertEqual(
117 None,
118 Node.objects.get_available_node_for_acquisition(
119 user, {'name': factory.getRandomString()}))
120
121+ def test_get_available_node_with_arch(self):
122+ """An available node can be selected of a given architecture"""
123+ user = factory.make_user()
124+ nodes = [self.make_node(architecture=s)
125+ for s in (ARCHITECTURE.amd64, ARCHITECTURE.i386)]
126+ available_node = Node.objects.get_available_node_for_acquisition(
127+ user, {'arch': "i386"})
128+ self.assertEqual(ARCHITECTURE.i386, available_node.architecture)
129+ self.assertEqual(nodes[1], available_node)
130+
131+ def test_get_available_node_with_unknown_arch(self):
132+ """None is returned if an arch not used by MaaS is given"""
133+ user = factory.make_user()
134+ self.assertEqual(
135+ None,
136+ Node.objects.get_available_node_for_acquisition(
137+ user, {'arch': "sparc"}))
138+
139 def test_stop_nodes_stops_nodes(self):
140 # We don't actually want to fire off power events, but we'll go
141 # through the motions right up to the point where we'd normally