Merge ~ltrager/maas:lp1650396 into maas:master

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: fa3a3006598c6fedb68ac6e7fcf957a5e9fd36da
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:lp1650396
Merge into: maas:master
Diff against target: 441 lines (+61/-79)
5 files modified
src/maasserver/api/interfaces.py (+6/-14)
src/maasserver/api/tests/test_interfaces.py (+29/-16)
src/maasserver/static/js/angular/controllers/node_details_networking.js (+7/-30)
src/maasserver/static/js/angular/controllers/tests/test_node_details_networking.js (+8/-8)
src/maasserver/static/partials/node-details.html (+11/-11)
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Needs Information
Данило Шеган (community) Approve
Review via email: mp+326332@code.launchpad.net

Commit message

Allow editing of network settings while a machine is in an allocated state.

This fixes LP:1650396

To post a comment you must log in.
Revision history for this message
Данило Шеган (danilo) wrote :

Looks good, but I do have a question about dropping isLimitedEditingAllowed removal: it seems to be about "Deployed" status, so I think we still want to keep that. Did I miss something there (the bug only talks about allowing editing in allocated state)?

I also ain't too happy about how we create multiple test scenarios with a for loop over 3 different node statuses, but you didn't introduce this originally, so no need to fix it either, though I have to rant a bit about it :-)

review: Needs Fixing
~ltrager/maas:lp1650396 updated
a75bb01... by Lee Trager

Merge branch 'master' into lp1650396

bcf2525... by Lee Trager

Squashed commit of the following:

commit a4f9627af7727bb96f4aad276c7f4a8d88b06d6a
Author: Lee Trager <email address hidden>
Date: Tue Jun 27 19:31:06 2017 +0000

    Remove link-junk from Makefile

    make lint ran link-junk which checks for bzr files accidentally committed.
    MAAS is no longer in bzr so this check is no longer needed and keeping it
    causes bzr to complain its not being run from a bzr branch.

0e05b6c... by Lee Trager

danilo fixes

d5b995b... by Lee Trager

danilo fixes

Revision history for this message
Lee Trager (ltrager) wrote :

Thanks for the review. I missed that MAAS allows editing of an interface name and MAC while deployed. I've brought back isLimitedEditingAllowed to restore this functionality. Now all this should change is allowing interfaces to be edited while the node is allocated.

Revision history for this message
Данило Шеган (danilo) wrote :

Looks good, thanks. It seems there's one change from isLimited... to isAllNetworking... that you missed to revert. Not blocking on it, though.

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

this needs a backport to 2.2

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

I have a comment inline

review: Needs Information
~ltrager/maas:lp1650396 updated
2cece51... by Lee Trager

Danillo fixes

fa3a300... by Lee Trager

Merge branch 'lp1650396' of git+ssh://git.launchpad.net/~ltrager/maas into lp1650396

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/api/interfaces.py b/src/maasserver/api/interfaces.py
2index bd55ef6..5e96ff4 100644
3--- a/src/maasserver/api/interfaces.py
4+++ b/src/maasserver/api/interfaces.py
5@@ -1,4 +1,4 @@
6-# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
7+# Copyright 2015-2017 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 """API handlers: `Interface`."""
11@@ -92,7 +92,7 @@ INTERFACES_PREFETCH = [
12 'children_relationships__child__vlan'),
13 ]
14
15-ALLOWED_STATES = (NODE_STATUS.READY, NODE_STATUS.BROKEN)
16+ALLOWED_STATES = (NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN)
17
18
19 def raise_error_for_invalid_state_on_allocated_operations(
20@@ -112,8 +112,8 @@ def raise_error_for_invalid_state_on_allocated_operations(
21 allowed.extend(extra_states)
22 if node.status not in allowed:
23 raise NodeStateViolation(
24- "Cannot %s interface because the machine is not Ready or "
25- "Broken." % operation)
26+ "Cannot %s interface because the machine is not Ready, Allocated, "
27+ "or Broken." % operation)
28
29
30 def raise_error_if_controller(node, operation):
31@@ -327,16 +327,8 @@ class InterfacesHandler(OperationsHandler):
32 """
33 machine = Machine.objects.get_node_or_404(
34 system_id, request.user, NODE_PERMISSION.EDIT)
35- if machine.status not in (
36- NODE_STATUS.READY, NODE_STATUS.BROKEN, NODE_STATUS.ALLOCATED):
37- raise NodeStateViolation(
38- "Cannot create bridge interface because the machine is not "
39- "Ready, Broken, or Allocated.")
40- if (not request.user.is_superuser and
41- machine.status in ALLOWED_STATES):
42- raise NodeStateViolation(
43- "Machine must be alloacted to '%s' to allow bridge "
44- "creation." % request.user.username)
45+ raise_error_for_invalid_state_on_allocated_operations(
46+ machine, request.user, "create bridge")
47 # Cast parent to parents to make it easier on the user and to make it
48 # work with the form.
49 request.data = request.data.copy()
50diff --git a/src/maasserver/api/tests/test_interfaces.py b/src/maasserver/api/tests/test_interfaces.py
51index 6fb1b9f..e6c91a1 100644
52--- a/src/maasserver/api/tests/test_interfaces.py
53+++ b/src/maasserver/api/tests/test_interfaces.py
54@@ -1,4 +1,4 @@
55-# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
56+# Copyright 2015-2017 Canonical Ltd. This software is licensed under the
57 # GNU Affero General Public License version 3 (see the file LICENSE).
58
59 """Tests for NodeInterfaces API."""
60@@ -43,7 +43,6 @@ STATUSES = (
61 NODE_STATUS.FAILED_COMMISSIONING,
62 NODE_STATUS.MISSING,
63 NODE_STATUS.RESERVED,
64- NODE_STATUS.ALLOCATED,
65 NODE_STATUS.DEPLOYING,
66 NODE_STATUS.DEPLOYED,
67 NODE_STATUS.RETIRED,
68@@ -241,7 +240,8 @@ class TestInterfacesAPI(APITestCase.ForUser):
69
70 def test_create_physical_disabled(self):
71 self.become_admin()
72- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
73+ for status in (
74+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
75 node = factory.make_Node(status=status)
76 mac = factory.make_mac_address()
77 name = factory.make_name("eth")
78@@ -342,7 +342,8 @@ class TestInterfacesAPI(APITestCase.ForUser):
79
80 def test_create_bond(self):
81 self.become_admin()
82- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
83+ for status in (
84+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
85 node = factory.make_Node(status=status)
86 vlan = factory.make_VLAN()
87 parent_1_iface = factory.make_Interface(
88@@ -931,7 +932,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
89
90 def test_update_physical_interface(self):
91 self.become_admin()
92- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
93+ for status in (
94+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
95 node = factory.make_Node(status=status)
96 interface = factory.make_Interface(
97 INTERFACE_TYPE.PHYSICAL, node=node)
98@@ -969,7 +971,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
99
100 def test_update_bond_interface(self):
101 self.become_admin()
102- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
103+ for status in (
104+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
105 node = factory.make_Node(status=status)
106 bond, [nic_0, nic_1], [vlan_10, vlan_11] = make_complex_interface(
107 node)
108@@ -984,7 +987,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
109
110 def test_update_vlan_interface(self):
111 self.become_admin()
112- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
113+ for status in (
114+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
115 node = factory.make_Node(status=status)
116 bond, [nic_0, nic_1], [vlan_10, vlan_11] = make_complex_interface(
117 node)
118@@ -1031,7 +1035,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
119
120 def test_delete_deletes_interface(self):
121 self.become_admin()
122- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
123+ for status in (
124+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
125 node = factory.make_Node(interface=True, status=status)
126 interface = node.get_boot_interface()
127 uri = get_interface_uri(interface)
128@@ -1086,7 +1091,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
129 # This just tests that the form is saved and the updated interface
130 # is returned.
131 self.become_admin()
132- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
133+ for status in (
134+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
135 node = factory.make_Node(interface=True, status=status)
136 interface = node.get_boot_interface()
137 uri = get_interface_uri(interface)
138@@ -1324,7 +1330,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
139
140 def test_link_subnet_raises_error(self):
141 self.become_admin()
142- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
143+ for status in (
144+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
145 node = factory.make_Node(interface=True, status=status)
146 interface = node.get_boot_interface()
147 uri = get_interface_uri(interface)
148@@ -1366,7 +1373,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
149 # This just tests that the form is saved and the updated interface
150 # is returned.
151 self.become_admin()
152- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
153+ for status in (
154+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
155 node = factory.make_Node(interface=True, status=status)
156 interface = node.get_boot_interface()
157 subnet = factory.make_Subnet()
158@@ -1403,7 +1411,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
159
160 def test_unlink_subnet_raises_error(self):
161 self.become_admin()
162- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
163+ for status in (
164+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
165 node = factory.make_Node(interface=True, status=status)
166 interface = node.get_boot_interface()
167 uri = get_interface_uri(interface)
168@@ -1444,7 +1453,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
169 # This just tests that the form is saved and the updated interface
170 # is returned.
171 self.become_admin()
172- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
173+ for status in (
174+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
175 node = factory.make_Node(interface=True, status=status)
176 interface = node.get_boot_interface()
177 subnet = factory.make_Subnet()
178@@ -1486,7 +1496,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
179 # The form that is used is fully tested in test_forms_interface_link.
180 # This just tests that the form is saved and the node link is created.
181 self.become_admin()
182- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
183+ for status in (
184+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
185 node = factory.make_Node(interface=True, status=status)
186 interface = node.get_boot_interface()
187 network = factory.make_ipv4_network()
188@@ -1508,7 +1519,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
189 # The form that is used is fully tested in test_forms_interface_link.
190 # This just tests that the form is saved and the node link is created.
191 self.become_admin()
192- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
193+ for status in (
194+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
195 node = factory.make_Node(interface=True, status=status)
196 interface = node.get_boot_interface()
197 network = factory.make_ipv6_network()
198@@ -1528,7 +1540,8 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
199
200 def test_set_default_gateway_raises_error(self):
201 self.become_admin()
202- for status in (NODE_STATUS.READY, NODE_STATUS.BROKEN):
203+ for status in (
204+ NODE_STATUS.READY, NODE_STATUS.ALLOCATED, NODE_STATUS.BROKEN):
205 node = factory.make_Node(interface=True, status=status)
206 interface = node.get_boot_interface()
207 uri = get_interface_uri(interface)
208diff --git a/src/maasserver/static/js/angular/controllers/node_details_networking.js b/src/maasserver/static/js/angular/controllers/node_details_networking.js
209index 84b7739..4067dab 100644
210--- a/src/maasserver/static/js/angular/controllers/node_details_networking.js
211+++ b/src/maasserver/static/js/angular/controllers/node_details_networking.js
212@@ -1,4 +1,4 @@
213-/* Copyright 2015-2016 Canonical Ltd. This software is licensed under the
214+/* Copyright 2015-2017 Canonical Ltd. This software is licensed under the
215 * GNU Affero General Public License version 3 (see the file LICENSE).
216 *
217 * MAAS Node Networking Controller
218@@ -568,30 +568,6 @@ angular.module('MAAS').controller('NodeNetworkingController', [
219 updateLoaded();
220 };
221
222- // Return true if the Node is Ready (or Broken)
223- $scope.isNodeEditingAllowed = function() {
224- if (!$scope.isSuperUser()) {
225- // If the user is not the superuser, pretend it's not Ready.
226- return false;
227- }
228- if ($scope.$parent.isDevice) {
229- // Devices are always Ready, for our purposes, for now.
230- return true;
231- }
232- if ($scope.$parent.isController) {
233- // Controllers are always Ready, for our purposes.
234- return true;
235- }
236- if (angular.isObject($scope.node) &&
237- ["Ready", "Broken"].indexOf($scope.node.status) === -1) {
238- // If a non-controller node is not Ready or Broken, then no
239- // editing networking.
240- return false;
241- }
242- // All is well, let them edit.
243- return true;
244- };
245-
246 // Return true if only the name or mac address of an interface can
247 // be edited.
248 $scope.isLimitedEditingAllowed = function(nic) {
249@@ -623,9 +599,10 @@ angular.module('MAAS').controller('NodeNetworkingController', [
250 return false;
251 }
252 if (angular.isObject($scope.node) &&
253- ["Ready", "Broken"].indexOf($scope.node.status) === -1) {
254- // If a non-controller node is not ready or broken, disable
255- // networking panel.
256+ ["Ready", "Allocated", "Broken"].indexOf(
257+ $scope.node.status) === -1) {
258+ // If a non-controller node is not ready allocated, or broken,
259+ // disable networking panel.
260 return true;
261 }
262 // User must be a superuser and the node must be
263@@ -1090,7 +1067,7 @@ angular.module('MAAS').controller('NodeNetworkingController', [
264 $scope.canAddAliasOrVLAN = function(nic) {
265 if($scope.$parent.isController) {
266 return false;
267- } else if (!$scope.isNodeEditingAllowed()) {
268+ } else if ($scope.isAllNetworkingDisabled()) {
269 return false;
270 } else {
271 return $scope.canAddAlias(nic) || $scope.canAddVLAN(nic);
272@@ -1148,7 +1125,7 @@ angular.module('MAAS').controller('NodeNetworkingController', [
273 $scope.canBeRemoved = function() {
274 return (
275 !$scope.$parent.isController &&
276- $scope.isNodeEditingAllowed());
277+ !$scope.isAllNetworkingDisabled());
278 };
279
280 // Enter remove mode.
281diff --git a/src/maasserver/static/js/angular/controllers/tests/test_node_details_networking.js b/src/maasserver/static/js/angular/controllers/tests/test_node_details_networking.js
282index a51834c..77967e7 100644
283--- a/src/maasserver/static/js/angular/controllers/tests/test_node_details_networking.js
284+++ b/src/maasserver/static/js/angular/controllers/tests/test_node_details_networking.js
285@@ -1,4 +1,4 @@
286-/* Copyright 2015-2016 Canonical Ltd. This software is licensed under the
287+/* Copyright 2015-2017 Canonical Ltd. This software is licensed under the
288 * GNU Affero General Public License version 3 (see the file LICENSE).
289 *
290 * Unit tests for NodeNetworkingController.
291@@ -2146,7 +2146,7 @@ describe("NodeNetworkingController", function() {
292 it("returns false if isController", function() {
293 var controller = makeController();
294 $parentScope.isController = true;
295- spyOn($scope, "isNodeEditingAllowed").and.returnValue(true);
296+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(false);
297 spyOn($scope, "canAddAlias").and.returnValue(true);
298 spyOn($scope, "canAddVLAN").and.returnValue(true);
299 expect($scope.canAddAliasOrVLAN({})).toBe(false);
300@@ -2155,7 +2155,7 @@ describe("NodeNetworkingController", function() {
301 it("returns false if no node editing", function() {
302 var controller = makeController();
303 $parentScope.isController = false;
304- spyOn($scope, "isNodeEditingAllowed").and.returnValue(false);
305+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(true);
306 spyOn($scope, "canAddAlias").and.returnValue(true);
307 spyOn($scope, "canAddVLAN").and.returnValue(true);
308 expect($scope.canAddAliasOrVLAN({})).toBe(false);
309@@ -2164,7 +2164,7 @@ describe("NodeNetworkingController", function() {
310 it("returns true if can edit alias", function() {
311 var controller = makeController();
312 $parentScope.isController = false;
313- spyOn($scope, "isNodeEditingAllowed").and.returnValue(true);
314+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(false);
315 spyOn($scope, "canAddAlias").and.returnValue(true);
316 spyOn($scope, "canAddVLAN").and.returnValue(false);
317 expect($scope.canAddAliasOrVLAN({})).toBe(true);
318@@ -2173,7 +2173,7 @@ describe("NodeNetworkingController", function() {
319 it("returns true if can edit VLAN", function() {
320 var controller = makeController();
321 $parentScope.isController = false;
322- spyOn($scope, "isNodeEditingAllowed").and.returnValue(true);
323+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(false);
324 spyOn($scope, "canAddAlias").and.returnValue(false);
325 spyOn($scope, "canAddVLAN").and.returnValue(true);
326 expect($scope.canAddAliasOrVLAN({})).toBe(true);
327@@ -2523,21 +2523,21 @@ describe("NodeNetworkingController", function() {
328 it("false if isController", function() {
329 var controller = makeController();
330 $parentScope.isController = true;
331- spyOn($scope, "isNodeEditingAllowed").and.returnValue(true);
332+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(false);
333 expect($scope.canBeRemoved()).toBe(false);
334 });
335
336 it("false if no node editing", function() {
337 var controller = makeController();
338 $parentScope.isController = false;
339- spyOn($scope, "isNodeEditingAllowed").and.returnValue(false);
340+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(true);
341 expect($scope.canBeRemoved()).toBe(false);
342 });
343
344 it("true if node can be edited", function() {
345 var controller = makeController();
346 $parentScope.isController = false;
347- spyOn($scope, "isNodeEditingAllowed").and.returnValue(true);
348+ spyOn($scope, "isAllNetworkingDisabled").and.returnValue(false);
349 expect($scope.canBeRemoved()).toBe(true);
350 });
351 });
352diff --git a/src/maasserver/static/partials/node-details.html b/src/maasserver/static/partials/node-details.html
353index 0066e2b..62d379a 100755
354--- a/src/maasserver/static/partials/node-details.html
355+++ b/src/maasserver/static/partials/node-details.html
356@@ -656,7 +656,7 @@
357 <div class="p-notification" data-ng-if="!isController && isAllNetworkingDisabled() && isSuperUser()">
358 <p class="p-notification__response">Interface
359 configuration cannot be modified unless the
360- node is Ready or Broken.</p>
361+ node is Ready, Allocated, or Broken.</p>
362 </div>
363 <div class="p-notification--warning" data-ng-if="!isController && isCustomOS()">
364 <p class="p-notification__response">
365@@ -698,15 +698,15 @@
366 </header>
367 <div class="table__body" data-selected-rows>
368 <div class="table__row"
369- data-ng-class="{ disabled: isDisabled(), 'is-active': isInterfaceSelected(interface) && (isNodeEditingAllowed() || isLimitedEditingAllowed(interface)), noEdit: cannotEditInterface(interface) }"
370- data-ng-repeat="interface in interfaces | removeInterfaceParents:newBondInterface:!isNodeEditingAllowed() | removeInterfaceParents:newBridgeInterface:!isNodeEditingAllowed()">
371+ data-ng-class="{ disabled: isDisabled(), 'is-active': isInterfaceSelected(interface) && (!isAllNetworkingDisabled() || isLimitedEditingAllowed(interface)), noEdit: cannotEditInterface(interface) }"
372+ data-ng-repeat="interface in interfaces | removeInterfaceParents:newBondInterface:isAllNetworkingDisabled() | removeInterfaceParents:newBridgeInterface:isAllNetworkingDisabled()">
373 <div class="table__data table-col--3" data-ng-if="!isDevice" aria-label="Select">
374 <input type="checkbox" class="checkbox" id="{$ getUniqueKey(interface) $}"
375 data-ng-hide="isAllNetworkingDisabled()"
376 data-ng-checked="isInterfaceSelected(interface)"
377 data-ng-click="toggleInterfaceSelect(interface)"
378 data-ng-disabled="isDisabled()"
379- data-ng-if="!isController && isNodeEditingAllowed()">
380+ data-ng-if="!isController && !isAllNetworkingDisabled()">
381 <label for="{$ getUniqueKey(interface) $}"></label>
382 </div>
383 <div class="table__data table-col--12" aria-label="Name" data-ng-if="!isDevice" data-ng-show="tableInfo.column == 'name'">
384@@ -755,7 +755,7 @@
385 </span>
386 </div>
387 <div class="table__data table--mobile-controls table-col--8">
388- <div class="table__controls" toggle-ctrl data-ng-if="isNodeEditingAllowed() || isLimitedEditingAllowed(interface)">
389+ <div class="table__controls" toggle-ctrl data-ng-if="!isAllNetworkingDisabled() || isLimitedEditingAllowed(interface)">
390 <button class="table__controls-toggle" data-ng-click="toggleMenu()">View actions</button>
391 <div class="table__controls-menu" role="menu" data-ng-show="isToggled">
392 <button class="table__controls-action"
393@@ -787,7 +787,7 @@
394 </div>
395 </div>
396 </div>
397- <div data-ng-if="isNodeEditingAllowed() || isLimitedEditingAllowed(interface)">
398+ <div data-ng-if="!isAllNetworkingDisabled() || isLimitedEditingAllowed(interface)">
399 <div class="table__dropdown" tabindex="0" data-ng-if="isShowingAdd() || isEditing(interface) || isShowingDeleteConfirm() || isShowingAdd() && !newInterface.saving">
400 <div class="table__dropdown-title">
401 <h2 data-ng-click="cancel()" class="u-float--left">
402@@ -888,10 +888,10 @@
403 input-class="table__input u-margin--none" placeholder="00:00:00:00:00:00"></maas-obj-field>
404 <maas-obj-field type="tags" key="tags" label="Tags" label-width="two" input-width="three"
405 placeholder="Add a tag"
406- data-ng-if="!isLimitedEditingAllowed(interface) && interface.type !== 'alias'"
407+ data-ng-if="!isAllNetworkingDisabled(interface) && interface.type !== 'alias'"
408 disable-label="false" input-class="table__input u-margin--none"></maas-obj-field>
409 </fieldset>
410- <fieldset class="form__fieldset six-col last-col" data-ng-if="!isLimitedEditingAllowed(interface)">
411+ <fieldset class="form__fieldset six-col last-col" data-ng-if="!isAllNetworkingDisabled(interface)">
412 <maas-obj-field type="options" key="fabric" label="Fabric" label-width="two" input-width="three"
413 disable-label="false" input-class="table__input u-margin--none"
414 data-ng-if="!isDevice"
415@@ -976,7 +976,7 @@
416 </div>
417 </div>
418 </div>
419- <div class="table__row is-active" tabindex="0" data-ng-if="isShowingCreateBond() && isNodeEditingAllowed()">
420+ <div class="table__row is-active" tabindex="0" data-ng-if="isShowingCreateBond() && !isAllNetworkingDisabled()">
421 <div class="table__data table-col--3">
422 <input type="checkbox" class="checkbox" name="bond-create" disabled="disabled" checked />
423 <label for="bond-create"></label>
424@@ -1077,7 +1077,7 @@
425 </div>
426 </div>
427 </div>
428- <div class="table__row is-active" tabindex="0" data-ng-if="isShowingCreateBridge() && isNodeEditingAllowed()">
429+ <div class="table__row is-active" tabindex="0" data-ng-if="isShowingCreateBridge() && !isAllNetworkingDisabled()">
430 <div class="table__data table-col--3">
431 <input type="checkbox" class="checkbox" id="bond-create" disabled="disabled" checked />
432 <label for="bridge-create"></label>
433@@ -1262,7 +1262,7 @@
434 data-ng-class="{ 'has-error': isMACAddressInvalid(newInterface.mac_address, true) }">
435 </div>
436 </fieldset>
437- <fieldset class="form__fieldset six-col last-col" data-ng-if="!isLimitedEditingAllowed(interface)">
438+ <fieldset class="form__fieldset six-col last-col" data-ng-if="!isAllNetworkingDisabled(interface)">
439 <div class="form__group">
440 <label for="ip-assignment" class="two-col">IP Assignment</label>
441 <select name="ip-assignment" class="three-col"

Subscribers

People subscribed via source and target branches