Merge lp:~trapnine/maas/fix-1501982 into lp:~maas-committers/maas/trunk

Proposed by Jeffrey C Jones
Status: Merged
Approved by: Jeffrey C Jones
Approved revision: no longer in the source branch.
Merged at revision: 4416
Proposed branch: lp:~trapnine/maas/fix-1501982
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 252 lines (+144/-11)
5 files modified
src/maasserver/static/js/angular/factories/nodes.js (+3/-1)
src/maasserver/static/js/angular/factories/tests/test_nodes.js (+2/-1)
src/maasserver/static/partials/nodes-list.html (+26/-6)
src/maasserver/websockets/handlers/node.py (+31/-1)
src/maasserver/websockets/handlers/tests/test_node.py (+82/-2)
To merge this branch: bzr merge lp:~trapnine/maas/fix-1501982
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Andres Rodriguez (community) Approve
Ricardo Bánffy (community) Approve
Review via email: mp+275617@code.launchpad.net

Commit message

Replaced node list page 'Networks' filter with 'Subnets' and added new 'Fabrics' and 'Spaces' filters.

To post a comment you must log in.
Revision history for this message
Ricardo Bánffy (rbanffy) wrote :

LGTM. Just add docstrings for the new methods. Remember you'll eventually forget what you did here (this you can find out by re-reading the code) and, most important, why it is the way it is (something code doesn't say most of the time).

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good. But missing 3 unit tests. You have unit tests on the overall generated result, but you should unit test each of those new methods explicitly.

review: Needs Fixing
Revision history for this message
Jeffrey C Jones (trapnine) wrote :

> Looks good. But missing 3 unit tests. You have unit tests on the overall
> generated result, but you should unit test each of those new methods
> explicitly.

added, thanks for review.

Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm!

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (1000.4 KiB)

The attempt to merge lp:~trapnine/maas/fix-1501982 into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com trusty-security InRelease [64.4 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://nova.clouds.archive.ubuntu.com trusty-updates InRelease [64.4 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:3 http://security.ubuntu.com trusty-security/main Sources [97.7 kB]
Get:4 http://security.ubuntu.com trusty-security/universe Sources [31.0 kB]
Get:5 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [241 kB]
Get:6 http://security.ubuntu.com trusty-security/main amd64 Packages [356 kB]
Get:7 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [140 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [117 kB]
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [636 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [324 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 2,071 kB in 3s (527 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm pep8 phantomjs postgresql pyflakes python-apt python-bson python-bzrlib python-convoy python-coverage python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lxml python-mock python-netaddr python-netifaces python-nose python-oauth python-openssl python-paramiko python-pexpect python-pip python-pocket-lint python-psycopg2 python-pyinotify python-pyparsing python-seamicroclient python-simplejson python-simplestreams python-sphinx python-subunit python-tempita python-testresources python-testscenarios python-testt...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/static/js/angular/factories/nodes.js'
2--- src/maasserver/static/js/angular/factories/nodes.js 2015-10-23 04:03:23 +0000
3+++ src/maasserver/static/js/angular/factories/nodes.js 2015-10-27 02:33:24 +0000
4@@ -26,7 +26,9 @@
5 "zone": function(node) {
6 return node.zone.name;
7 },
8- "networks": null,
9+ "subnets": null,
10+ "fabrics": null,
11+ "spaces": null,
12 "storage_tags": null
13 };
14
15
16=== modified file 'src/maasserver/static/js/angular/factories/tests/test_nodes.js'
17--- src/maasserver/static/js/angular/factories/tests/test_nodes.js 2015-10-23 16:34:24 +0000
18+++ src/maasserver/static/js/angular/factories/tests/test_nodes.js 2015-10-27 02:33:24 +0000
19@@ -47,7 +47,8 @@
20 expect(NodesManager._pk).toBe("system_id");
21 expect(NodesManager._handler).toBe("node");
22 expect(Object.keys(NodesManager._metadataAttributes)).toEqual(
23- ["status", "owner", "tags", "zone", "networks", "storage_tags"]);
24+ ["status", "owner", "tags", "zone", "subnets", "fabrics",
25+ "spaces", "storage_tags"]);
26 });
27
28 describe("create", function() {
29
30=== modified file 'src/maasserver/static/partials/nodes-list.html'
31--- src/maasserver/static/partials/nodes-list.html 2015-10-13 09:38:21 +0000
32+++ src/maasserver/static/partials/nodes-list.html 2015-10-27 02:33:24 +0000
33@@ -447,12 +447,32 @@
34 </ul>
35 </div>
36 </div>
37- <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.networks.length">
38- <h4 class="accordion__tab-title maas-accordion-tab">Networks</h4>
39- <div class="accordion__tab-content">
40- <ul class="accordion__tab-list">
41- <li class="accordion__tab-item" data-ng-repeat="network in tabs.nodes.metadata.networks | orderBy:['name', '-count']" data-ng-class="{ active: isFilterActive('networks', network.name, 'nodes') }">
42- <a class="accordion__tab-link" href="" data-ng-click="toggleFilter('networks', network.name, 'nodes')">{$ network.name $} ({$ network.count $})</a>
43+ <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.subnets.length">
44+ <h4 class="accordion__tab-title maas-accordion-tab">Subnets</h4>
45+ <div class="accordion__tab-content">
46+ <ul class="accordion__tab-list">
47+ <li class="accordion__tab-item" data-ng-repeat="subnet in tabs.nodes.metadata.subnets | orderBy:['name', '-count']" data-ng-class="{ active: isFilterActive('subnets', subnet.name, 'nodes') }">
48+ <a class="accordion__tab-link" href="" data-ng-click="toggleFilter('subnets', subnet.name, 'nodes')">{$ subnet.name $} ({$ subnet.count $})</a>
49+ </li>
50+ </ul>
51+ </div>
52+ </div>
53+ <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.fabrics.length">
54+ <h4 class="accordion__tab-title maas-accordion-tab">Fabrics</h4>
55+ <div class="accordion__tab-content">
56+ <ul class="accordion__tab-list">
57+ <li class="accordion__tab-item" data-ng-repeat="fabric in tabs.nodes.metadata.fabrics | orderBy:['name', '-count']" data-ng-class="{ active: isFilterActive('fabrics', fabric.name, 'nodes') }">
58+ <a class="accordion__tab-link" href="" data-ng-click="toggleFilter('fabrics', fabric.name, 'nodes')">{$ fabric.name $} ({$ fabric.count $})</a>
59+ </li>
60+ </ul>
61+ </div>
62+ </div>
63+ <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.spaces.length">
64+ <h4 class="accordion__tab-title maas-accordion-tab">Spaces</h4>
65+ <div class="accordion__tab-content">
66+ <ul class="accordion__tab-list">
67+ <li class="accordion__tab-item" data-ng-repeat="space in tabs.nodes.metadata.spaces | orderBy:['name', '-count']" data-ng-class="{ active: isFilterActive('spaces', space.name, 'nodes') }">
68+ <a class="accordion__tab-link" href="" data-ng-click="toggleFilter('spaces', space.name, 'nodes')">{$ space.name $} ({$ space.count $})</a>
69 </li>
70 </ul>
71 </div>
72
73=== modified file 'src/maasserver/websockets/handlers/node.py'
74--- src/maasserver/websockets/handlers/node.py 2015-10-23 04:03:23 +0000
75+++ src/maasserver/websockets/handlers/node.py 2015-10-27 02:33:24 +0000
76@@ -115,8 +115,11 @@
77 queryset = (
78 Node.nodes.filter(installable=True)
79 .select_related('nodegroup', 'pxe_mac', 'owner')
80- .prefetch_related('interface_set__ip_addresses__subnet__vlan')
81+ .prefetch_related(
82+ 'interface_set__ip_addresses__subnet__vlan__fabric')
83+ .prefetch_related('interface_set__ip_addresses__subnet__space')
84 .prefetch_related('nodegroup__nodegroupinterface_set__subnet')
85+ .prefetch_related('interface_set__vlan__fabric')
86 .prefetch_related('zone')
87 .prefetch_related('tags')
88 .prefetch_related('blockdevice_set__physicalblockdevice')
89@@ -260,6 +263,11 @@
90 ]) / (1000 ** 3))
91 data["storage_tags"] = self.get_all_storage_tags(blockdevices)
92
93+ subnets = self.get_all_subnets(obj)
94+ data["subnets"] = [subnet.name for subnet in subnets]
95+ data["fabrics"] = self.get_all_fabric_names(obj, subnets)
96+ data["spaces"] = self.get_all_space_names(subnets)
97+
98 data["tags"] = [
99 tag.name
100 for tag in obj.tags.all()
101@@ -577,6 +585,28 @@
102 tags = tags.union(blockdevice.tags)
103 return list(tags)
104
105+ def get_all_subnets(self, obj):
106+ subnets = set()
107+ for interface in obj.interface_set.all():
108+ for ip_address in interface.ip_addresses.all():
109+ if ip_address.subnet is not None:
110+ subnets.add(ip_address.subnet)
111+ return list(subnets)
112+
113+ def get_all_fabric_names(self, obj, subnets):
114+ fabric_names = set()
115+ for interface in obj.interface_set.all():
116+ fabric_names.add(interface.vlan.fabric.name)
117+ for subnet in subnets:
118+ fabric_names.add(subnet.vlan.fabric.name)
119+ return list(fabric_names)
120+
121+ def get_all_space_names(self, subnets):
122+ space_names = set()
123+ for subnet in subnets:
124+ space_names.add(subnet.space.name)
125+ return list(space_names)
126+
127 def get_blockdevices_for(self, obj):
128 """Return only `BlockDevice`s using the prefetched query."""
129 return [
130
131=== modified file 'src/maasserver/websockets/handlers/tests/test_node.py'
132--- src/maasserver/websockets/handlers/tests/test_node.py 2015-10-23 18:39:01 +0000
133+++ src/maasserver/websockets/handlers/tests/test_node.py 2015-10-27 02:33:24 +0000
134@@ -134,6 +134,7 @@
135 for cache_set in CacheSet.objects.get_cache_sets_for_node(node)
136 ]
137 disks = sorted(disks, key=itemgetter("name"))
138+ subnets = handler.get_all_subnets(node)
139 data = {
140 "actions": compile_node_actions(node, handler.user).keys(),
141 "architecture": node.architecture,
142@@ -201,6 +202,9 @@
143 for blockdevice in node.physicalblockdevice_set.all()
144 ]) / (1000 ** 3)),
145 "storage_tags": handler.get_all_storage_tags(blockdevices),
146+ "subnets": [subnet.name for subnet in subnets],
147+ "fabrics": handler.get_all_fabric_names(node, subnets),
148+ "spaces": handler.get_all_space_names(subnets),
149 "swap_size": node.swap_size,
150 "system_id": node.system_id,
151 "tags": [
152@@ -223,7 +227,9 @@
153 "pxe_mac_vendor",
154 "extra_macs",
155 "tags",
156- "networks",
157+ "subnets",
158+ "fabrics",
159+ "spaces",
160 "physical_disk_count",
161 "storage",
162 "storage_tags",
163@@ -660,6 +666,80 @@
164 factory.make_Event(node=node, type=event_type)
165 self.assertEquals([], handler.dehydrate_events(node))
166
167+ def make_node_with_subnets(self):
168+ user = factory.make_User()
169+ handler = NodeHandler(user, {})
170+ space1 = factory.make_Space()
171+ fabric1 = factory.make_Fabric(name=factory.make_name("fabric"))
172+ vlan1 = factory.make_VLAN(fabric=fabric1)
173+ subnet1 = factory.make_Subnet(space=space1, vlan=vlan1)
174+ node = factory.make_Node_with_Interface_on_Subnet(
175+ subnet=subnet1, vlan=vlan1)
176+ node.save()
177+
178+ # Bond interface with a VLAN on top. With the bond set to STATIC
179+ # and the VLAN set to AUTO.
180+ fabric2 = factory.make_Fabric(name=factory.make_name("fabric"))
181+ vlan2 = factory.make_VLAN(fabric=fabric2)
182+ space2 = factory.make_Space()
183+ bond_subnet = factory.make_Subnet(space=space1, vlan=vlan1)
184+ vlan_subnet = factory.make_Subnet(space=space2, vlan=vlan2)
185+ nic1 = factory.make_Interface(
186+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan1)
187+ nic2 = factory.make_Interface(
188+ INTERFACE_TYPE.PHYSICAL, node=node, vlan=vlan2)
189+ bond = factory.make_Interface(
190+ INTERFACE_TYPE.BOND, parents=[nic1, nic2], vlan=vlan1)
191+ vlan_int = factory.make_Interface(
192+ INTERFACE_TYPE.VLAN, vlan=vlan2, parents=[bond])
193+ factory.make_StaticIPAddress(
194+ alloc_type=IPADDRESS_TYPE.STICKY,
195+ ip=factory.pick_ip_in_network(bond_subnet.get_ipnetwork()),
196+ subnet=bond_subnet, interface=bond)
197+ factory.make_StaticIPAddress(
198+ alloc_type=IPADDRESS_TYPE.STICKY, ip="",
199+ subnet=vlan_subnet, interface=vlan_int)
200+
201+ # LINK_UP interface with no subnet.
202+ fabric3 = factory.make_Fabric(name=factory.make_name("fabric"))
203+ vlan3 = factory.make_VLAN(fabric=fabric3)
204+ nic3 = factory.make_Interface(
205+ INTERFACE_TYPE.PHYSICAL, vlan=vlan3, node=node)
206+ nic3_ip = factory.make_StaticIPAddress(
207+ alloc_type=IPADDRESS_TYPE.STICKY, ip="",
208+ subnet=None, interface=nic3)
209+ nic3_ip.subnet = None
210+ nic3_ip.save()
211+
212+ self.patch_autospec(interface_module, "update_host_maps")
213+ boot_interface = node.get_boot_interface()
214+ boot_interface.claim_static_ips()
215+ node.boot_interface = boot_interface
216+ node.save()
217+
218+ subnets = [subnet1, bond_subnet, vlan_subnet]
219+ fabrics = [fabric1, fabric2, fabric3]
220+ spaces = [space1, space2]
221+ return (handler, node, subnets, fabrics, spaces)
222+
223+ def test_get_all_subnets(self):
224+ (handler, node, subnets, _, _) = self.make_node_with_subnets()
225+ self.assertItemsEqual(subnets, handler.get_all_subnets(node))
226+
227+ def test_get_all_fabric_names(self):
228+ (handler, node, _, fabrics, _) = self.make_node_with_subnets()
229+ fabric_names = [fabric.name for fabric in fabrics]
230+ node_subnets = handler.get_all_subnets(node)
231+ self.assertItemsEqual(
232+ fabric_names, handler.get_all_fabric_names(node, node_subnets))
233+
234+ def test_get_all_space_names(self):
235+ (handler, node, _, _, spaces) = self.make_node_with_subnets()
236+ space_names = [space.name for space in spaces]
237+ node_subnets = handler.get_all_subnets(node)
238+ self.assertItemsEqual(
239+ space_names, handler.get_all_space_names(node_subnets))
240+
241 def test_get(self):
242 user = factory.make_User()
243 handler = NodeHandler(user, {})
244@@ -757,7 +837,7 @@
245 # number means regiond has to do more work slowing down its process
246 # and slowing down the client waiting for the response.
247 self.assertEquals(
248- query_10_count, 9,
249+ query_10_count, 11,
250 "Number of queries has changed; make sure this is expected.")
251 self.assertEquals(
252 query_10_count, query_20_count,