Merge ~mpontillo/maas:preseed-per-interface-routes--bug-1758919--2.3 into maas:master
- Git
- lp:~mpontillo/maas
- preseed-per-interface-routes--bug-1758919--2.3
- Merge into master
Status: | Superseded |
---|---|
Proposed branch: | ~mpontillo/maas:preseed-per-interface-routes--bug-1758919--2.3 |
Merge into: | maas:master |
Diff against target: |
1785 lines (+1501/-2) (has conflicts) 17 files modified
debian/changelog (+10/-0) snap/snapcraft.yaml (+9/-0) src/maasserver/bootsources.py (+3/-0) src/maasserver/models/tests/test_userprofile.py (+3/-0) src/maasserver/rpc/boot.py (+5/-0) src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js (+17/-0) src/maasserver/static/partials/ipranges.html (+17/-0) src/maasserver/static/partials/node-details.html (+134/-0) src/maasserver/static/partials/nodes-list.html (+1017/-0) src/maasserver/static/partials/script-results-list.html (+76/-0) src/maasserver/tests/test_bootsources.py (+3/-0) src/maasserver/triggers/tests/test_websocket_listener.py (+5/-0) src/provisioningserver/import_images/boot_resources.py (+61/-0) src/provisioningserver/import_images/tests/test_boot_resources.py (+92/-0) src/provisioningserver/import_images/tests/test_download_resources.py (+35/-0) src/provisioningserver/utils/tests/test_network.py (+3/-0) utilities/release-build (+11/-2) Conflict in debian/changelog Conflict in snap/snapcraft.yaml Conflict in src/maasserver/bootsources.py Conflict in src/maasserver/models/tests/test_userprofile.py Conflict in src/maasserver/rpc/boot.py Conflict in src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js Conflict in src/maasserver/static/partials/ipranges.html Conflict in src/maasserver/static/partials/node-details.html Conflict in src/maasserver/static/partials/nodes-list.html Conflict in src/maasserver/static/partials/script-results-list.html Conflict in src/maasserver/tests/test_bootsources.py Conflict in src/maasserver/triggers/tests/test_websocket_listener.py Conflict in src/provisioningserver/import_images/boot_resources.py Conflict in src/provisioningserver/import_images/tests/test_boot_resources.py Conflict in src/provisioningserver/import_images/tests/test_download_resources.py Conflict in src/provisioningserver/utils/tests/test_network.py Conflict in utilities/release-build |
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Maintainers | Pending | ||
Review via email: mp+342242@code.launchpad.net |
Commit message
LP: #1758919 - Move routes to interface context within preseed.
Backports: 9fbf7eb682c3c3f
Description of the change
Unmerged commits
- 434ff94... by Mike Pontillo
-
LP: #1758919 - Move routes to interface context within preseed.
Backports: 9fbf7eb682c3c3f
f1de08b33bb967f ffdf4a61bf - b830483... by Newell Jensen
-
Backport of 611eaccf792a388
fc7b5d8e2420502 28a6bc0e57 LP: #1753874 -- Fix typo in virsh pod driver for get_pod_
pool_size_ map. - a318f7c... by Newell Jensen
-
Backport 476dcf44f137062
5d5c5637d3b459c dd6511db0c Convert number to exponential representation in RSD Pod driver.
- b3b05a9... by Andres Rodriguez
-
Update to reflect 2.3.1 release
- 036d646... by Andres Rodriguez
-
Clean-up build scripts
- 8289431... by Andres Rodriguez
-
debian/changelog: Update in preparation for 2.3.1 release.
- d5c58de... by Lee Trager
-
LP: #1751946 - Only cleanup ScriptSets of the same type.
Backport 1f9751aec9041dc
079b83db4e9e814 85cd188ef6 from master - 5a7cb12... by Newell Jensen
-
Backport of c5a810187578776
c9dacf386d2628f 23678a6aa2 LP: #1741165 -- Remove --delete-snapshots flag to workaround volumes not being deleted for node decomposition.
- 8442748... by Andres Rodriguez
-
LP: #1711203 - Use grub instead of shim to workaround issues with Secure Boot deployment
Backport 1223c03c6ae2396
7561ec7218344da af3a95698d from master - d5bd3b1... by Lee Trager
-
Backport 02b1bf4 - LP: #1750160 - Confirm running tests on deployed hardware in the UI.
Preview Diff
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index 09263b4..ab17966 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,3 +1,4 @@ |
6 | +<<<<<<< debian/changelog |
7 | maas (2.4.0~beta1-0ubuntu1) UNRELEASED; urgency=medium |
8 | |
9 | * UNRELEASED |
10 | @@ -28,6 +29,15 @@ maas (2.4.0~alpha1-6573-g12ee2331b-0ubuntu1) bionic; urgency=medium |
11 | -- Andres Rodriguez <andreserl@ubuntu.com> Fri, 09 Feb 2018 18:50:10 -0500 |
12 | |
13 | maas (2.3.0-6434-gd354690-0ubuntu1) bionic; urgency=medium |
14 | +======= |
15 | +maas (2.3.1-6470-g036d646-0ubuntu1) artful; urgency=medium |
16 | + |
17 | + * New upstream release, MAAS 2.3.1 |
18 | + |
19 | + -- Andres Rodriguez <andreserl@ubuntu.com> Mon, 05 Mar 2018 10:25:44 -0500 |
20 | + |
21 | +maas (2.3.0-6434-gd354690-0ubuntu1) artful; urgency=medium |
22 | +>>>>>>> debian/changelog |
23 | |
24 | * New upstream release, MAAS 2.3.0: |
25 | - Add support for CentOS & Windows networking. |
26 | diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml |
27 | index 4c39956..3b31301 100644 |
28 | --- a/snap/snapcraft.yaml |
29 | +++ b/snap/snapcraft.yaml |
30 | @@ -133,6 +133,15 @@ parts: |
31 | source: src/maasserver/static |
32 | organize: |
33 | '*': usr/share/maas/web/static/ |
34 | +<<<<<<< snap/snapcraft.yaml |
35 | +======= |
36 | + twisted-plugins: |
37 | + plugin: dump |
38 | + source: twisted/plugins |
39 | + organize: |
40 | + maasrackd.py: usr/lib/python3/dist-packages/twisted/plugins/maasrackd.py |
41 | + maasregiond.py: usr/lib/python3/dist-packages/twisted/plugins/maasregiond.py |
42 | +>>>>>>> snap/snapcraft.yaml |
43 | snap: |
44 | plugin: dump |
45 | source: snap |
46 | diff --git a/src/maasserver/bootsources.py b/src/maasserver/bootsources.py |
47 | index f71040f..1e11784 100644 |
48 | --- a/src/maasserver/bootsources.py |
49 | +++ b/src/maasserver/bootsources.py |
50 | @@ -26,7 +26,10 @@ from maasserver.models import ( |
51 | Config, |
52 | Notification, |
53 | ) |
54 | +<<<<<<< src/maasserver/bootsources.py |
55 | from maasserver.models.timestampedmodel import now |
56 | +======= |
57 | +>>>>>>> src/maasserver/bootsources.py |
58 | from maasserver.utils import get_maas_user_agent |
59 | from maasserver.utils.orm import transactional |
60 | from maasserver.utils.threads import deferToDatabase |
61 | diff --git a/src/maasserver/models/tests/test_userprofile.py b/src/maasserver/models/tests/test_userprofile.py |
62 | index 8a0efac..4bf4730 100644 |
63 | --- a/src/maasserver/models/tests/test_userprofile.py |
64 | +++ b/src/maasserver/models/tests/test_userprofile.py |
65 | @@ -139,6 +139,7 @@ class UserProfileTest(MAASServerTestCase): |
66 | self.assertEqual(reload_object(node).owner, new_user) |
67 | self.assertEqual(reload_object(ipaddress).user, new_user) |
68 | self.assertEqual(reload_object(iprange).user, new_user) |
69 | +<<<<<<< src/maasserver/models/tests/test_userprofile.py |
70 | |
71 | def test_transfer_resources_missing_target_access(self): |
72 | user = factory.make_User() |
73 | @@ -153,6 +154,8 @@ class UserProfileTest(MAASServerTestCase): |
74 | " resource pool(s)") |
75 | # owner didn't change |
76 | self.assertEqual(reload_object(node).owner, user) |
77 | +======= |
78 | +>>>>>>> src/maasserver/models/tests/test_userprofile.py |
79 | |
80 | def test_manager_all_users(self): |
81 | users = set(factory.make_User() for _ in range(3)) |
82 | diff --git a/src/maasserver/rpc/boot.py b/src/maasserver/rpc/boot.py |
83 | index 5b5f1de..9a51bf3 100644 |
84 | --- a/src/maasserver/rpc/boot.py |
85 | +++ b/src/maasserver/rpc/boot.py |
86 | @@ -280,10 +280,15 @@ def get_config( |
87 | osystem = configs['commissioning_osystem'] |
88 | series = configs['commissioning_distro_series'] |
89 | else: |
90 | +<<<<<<< src/maasserver/rpc/boot.py |
91 | osystem = machine.get_osystem( |
92 | default=configs['default_osystem']) |
93 | series = machine.get_distro_series( |
94 | default=configs['default_distro_series']) |
95 | +======= |
96 | + osystem = machine.get_osystem() |
97 | + series = machine.get_distro_series() |
98 | +>>>>>>> src/maasserver/rpc/boot.py |
99 | # XXX: roaksoax LP: #1739761 - Since the switch to squashfs (and |
100 | # drop of iscsi), precise is no longer deployable. To address a |
101 | # squashfs image is made available allowing it to be deployed in |
102 | diff --git a/src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js b/src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js |
103 | index 0a48138..8f8743a 100644 |
104 | --- a/src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js |
105 | +++ b/src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js |
106 | @@ -1580,6 +1580,7 @@ describe("NodesListController", function() { |
107 | it("sets showing_confirmation with testOptions", |
108 | function() { |
109 | var controller = makeController(); |
110 | +<<<<<<< src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js |
111 | var object = makeObject("machines"); |
112 | object.status_code = 6; |
113 | var spy = spyOn( |
114 | @@ -1594,6 +1595,22 @@ describe("NodesListController", function() { |
115 | true); |
116 | expect($scope.tabs[ |
117 | "machines"].actionProgress.affected_nodes).toBe(1); |
118 | +======= |
119 | + var object = makeObject("nodes"); |
120 | + object.status_code = 6; |
121 | + var spy = spyOn( |
122 | + $scope.tabs.nodes.manager, |
123 | + "performAction").and.returnValue( |
124 | + $q.defer().promise); |
125 | + $scope.tabs.nodes.actionOption = { name: "test" }; |
126 | + $scope.tabs.nodes.selectedItems = [object]; |
127 | + $scope.actionGo("nodes"); |
128 | + expect($scope.tabs[ |
129 | + "nodes"].actionProgress.showing_confirmation).toBe( |
130 | + true); |
131 | + expect($scope.tabs[ |
132 | + "nodes"].actionProgress.affected_nodes).toBe(1); |
133 | +>>>>>>> src/maasserver/static/js/angular/controllers/tests/test_nodes_list.js |
134 | expect(spy).not.toHaveBeenCalled(); |
135 | }); |
136 | |
137 | diff --git a/src/maasserver/static/partials/ipranges.html b/src/maasserver/static/partials/ipranges.html |
138 | index 897d959..3d48a68 100755 |
139 | --- a/src/maasserver/static/partials/ipranges.html |
140 | +++ b/src/maasserver/static/partials/ipranges.html |
141 | @@ -15,6 +15,7 @@ |
142 | <tbody> |
143 | <tr data-ng-repeat="iprange in (subnetIPRanges = ipranges | filterBySubnetOrVlan:subnet:vlan) | orderBy:ipRangeSort" |
144 | data-ng-class="{ 'is-active': isIPRangeInEditMode(iprange) || isIPRangeInDeleteMode(iprange)}"> |
145 | +<<<<<<< src/maasserver/static/partials/ipranges.html |
146 | <td class="col-2" aria-label="Start IP Address">{$ iprange.start_ip $}</td> |
147 | <td class="col-2" aria-label="End IP Address">{$ iprange.end_ip $}</td> |
148 | <td class="col-1" aria-label="Owner">{$ iprange.type == "dynamic" ? "MAAS" : iprange.user $}</td> |
149 | @@ -26,6 +27,22 @@ |
150 | data-ng-click="toggleMenu(); ipRangeToggleEditMode(iprange)">Edit</button> |
151 | <button class="table__controls-action u-text--error" aria-label="Remove range" |
152 | data-ng-click="toggleMenu(); ipRangeEnterDeleteMode(iprange)">Remove</button> |
153 | +======= |
154 | + <div class="table__data table-col--20" aria-label="Start IP Address">{$ iprange.start_ip $}</div> |
155 | + <div class="table__data table-col--20" aria-label="End IP Address">{$ iprange.end_ip $}</div> |
156 | + <div class="table__data table-col--10" aria-label="Owner">{$ iprange.type == "dynamic" ? "MAAS" : iprange.user $}</div> |
157 | + <div class="table__data table-col--10" aria-label="Type">{$ iprange.type == "dynamic" ? "Dynamic" : "Reserved" $}</div> |
158 | + <div class="table__data table-col--31" aria-label="Comment">{$ iprange.type == "dynamic" ? "Dynamic" : iprange.comment $}</div> |
159 | + <div class="table__data table-col--9 table--mobile-controls"> |
160 | + <div class="table__controls" toggle-ctrl data-ng-if="ipRangeCanBeModified(iprange)"> |
161 | + <button class="table__controls-toggle" data-ng-click="toggleMenu()">View actions</button> |
162 | + <div class="table__controls-menu" role="menu" data-ng-show="isToggled"> |
163 | + <button class="table__controls-action" aria-label="Edit row" |
164 | + data-ng-click="toggleMenu(); ipRangeToggleEditMode(iprange)">Edit reserved range</button> |
165 | + <button class="table__controls-action u-text--error" aria-label="Remove" |
166 | + data-ng-click="toggleMenu(); ipRangeEnterDeleteMode(iprange)">Remove range</button> |
167 | + </div> |
168 | +>>>>>>> src/maasserver/static/partials/ipranges.html |
169 | </div> |
170 | </td> |
171 | <td class="is-active p-table-expanding__panel col-12" col-span="6" data-ng-if="isIPRangeInDeleteMode(iprange)"> |
172 | diff --git a/src/maasserver/static/partials/node-details.html b/src/maasserver/static/partials/node-details.html |
173 | index 33688a5..6f4de0f 100755 |
174 | --- a/src/maasserver/static/partials/node-details.html |
175 | +++ b/src/maasserver/static/partials/node-details.html |
176 | @@ -98,6 +98,7 @@ |
177 | </ul> |
178 | </div> |
179 | |
180 | +<<<<<<< src/maasserver/static/partials/node-details.html |
181 | <div class="col-8" data-ng-show="action.option.name === 'deploy' || action.option.name === 'release'"> |
182 | <div class="ng-hide" data-ng-show="action.option.name === 'deploy'"> |
183 | <div class="p-form__group"> |
184 | @@ -236,6 +237,139 @@ |
185 | </div> |
186 | </div> |
187 | </div> |
188 | +======= |
189 | + <!-- XXX blake_r 2015-02-19 - Need to add e2e test. --> |
190 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': action.option }"> |
191 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-if="!isDevice && !node.dhcp_on"> |
192 | + <p class="page-header__message page-header__message--warning">MAAS is not providing DHCP.</p> |
193 | + </div> |
194 | + |
195 | + <!-- XXX blake_r 2015-02-19 - Need to add e2e test. --> |
196 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-hide="isActionError() || isDeployError() || isSSHKeyError() || hasActionPowerError(action.option.name)"> |
197 | + <form class="form form--inline u-display--inline"> |
198 | + <fieldset class="form__fieldset ng-hide" data-ng-show="action.option.name === 'commission' || action.option.name === 'test'"> |
199 | + <div class="form__group"> |
200 | + <input class="checkbox" id="enableSSH" type="checkbox" |
201 | + data-ng-model="commissionOptions.enableSSH"> |
202 | + <label for="enableSSH">Allow SSH access and prevent machine from powering off</label> |
203 | + </div> |
204 | + </fieldset> |
205 | + <fieldset class="form__fieldset ng-hide" data-ng-show="action.option.name === 'commission'"> |
206 | + <div class="form__group"> |
207 | + <input class="checkbox" id="skipNetworking" type="checkbox" |
208 | + data-ng-model="commissionOptions.skipNetworking"> |
209 | + <label for="skipNetworking">Retain network configuration</label> |
210 | + </div> |
211 | + <div class="form__group"> |
212 | + <input class="checkbox" id="skipStorage" type="checkbox" |
213 | + data-ng-model="commissionOptions.skipStorage"> |
214 | + <label for="skipStorage">Retain storage configuration</label> |
215 | + </div> |
216 | + </fieldset> |
217 | + <fieldset class="form__fieldset ng-hide" data-ng-show="action.option.name === 'deploy'"> |
218 | + <div class="form__group"> |
219 | + <label class="form__group-label">Choose your image</label> |
220 | + <div class="form__group-input" data-maas-os-select="osinfo" data-ng-model="osSelection"></div> |
221 | + </div> |
222 | + </fieldset> |
223 | + <fieldset class="form__fieldset" data-ng-if="action.option.name === 'release'"> |
224 | + <div class="form__group"> |
225 | + <div data-maas-release-options="releaseOptions"></div> |
226 | + </div> |
227 | + </fieldset> |
228 | + <div class="page-header__controls" data-ng-if="action.option.name !== 'commission' && action.option.name !== 'test'"> |
229 | + <button class="button--base button--inline" data-ng-click="actionCancel()">Cancel</button> |
230 | + <button class="button--inline" data-ng-class="action.option.name === 'delete' ? 'button--destructive' : 'button--positive'" data-ng-click="actionGo('nodes')" data-ng-hide="hasActionsFailed('nodes')"> |
231 | + <span data-ng-if="action.option.name === 'acquire'">Acquire {$ type_name $}</span> |
232 | + <span data-ng-if="action.option.name === 'deploy'">Deploy {$ type_name $}</span> |
233 | + <span data-ng-if="action.option.name === 'release'">Release {$ type_name $}</span> |
234 | + <span data-ng-if="action.option.name === 'set-zone'">Set zone for {$ type_name $}</span> |
235 | + <span data-ng-if="action.option.name === 'on'">Power on {$ type_name $}</span> |
236 | + <span data-ng-if="action.option.name === 'off'">Power off {$ type_name $}</span> |
237 | + <span data-ng-if="action.option.name === 'abort'">Abort action on {$ type_name $}</span> |
238 | + <span data-ng-if="action.option.name === 'rescue-mode'">Rescue {$ type_name $}</span> |
239 | + <span data-ng-if="action.option.name === 'exit-rescue-mode'">Exit rescue mode</span> |
240 | + <span data-ng-if="action.option.name === 'mark-broken'">Mark {$ type_name $}</span> |
241 | + <span data-ng-if="action.option.name === 'mark-fixed'">Mark {$ type_name $}</span> |
242 | + <span data-ng-if="action.option.name === 'override-failed-testing'">Override failed testing</span> |
243 | + <span data-ng-if="action.option.name === 'delete'">Delete {$ type_name $}</span> |
244 | + <span data-ng-if="action.option.name === 'import-images'">Import images</span> |
245 | + </button> |
246 | + </div> |
247 | + </form> |
248 | + </div> |
249 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-hide="isActionError() || isDeployError() || isSSHKeyError() || hasActionPowerError(action.option.name) || action.option.name !== 'commission'" data-ng-if="hasCustomCommissioningScripts()"> |
250 | + <form class="form form--stack"> |
251 | + <fieldset class="form__fieldset eight-col u-margin--bottom-small"> |
252 | + <div class="form__group"> |
253 | + <label for="commissioning-scripts">Additional commissioning scripts</label> |
254 | + <span id="commissioning-scripts" data-maas-script-select="script" data-script-type="0" data-ng-model="commissioningSelection" class="tags--inline"></span> |
255 | + </div> |
256 | + </fieldset> |
257 | + </form> |
258 | + </div> |
259 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-hide="isActionError() || isDeployError() || isSSHKeyError() || hasActionPowerError(action.option.name) || (action.option.name !== 'commission' && action.option.name !== 'test')"> |
260 | + <form class="form form--stack"> |
261 | + <fieldset class="form__fieldset eight-col u-margin--bottom-small"> |
262 | + <div class="form__group"> |
263 | + <label>Hardware tests</label> |
264 | + <span id="testing-scripts" data-maas-script-select="script" data-script-type="2" data-ng-model="testSelection" class="tags--inline"></span> |
265 | + </div> |
266 | + </fieldset> |
267 | + </form> |
268 | + </div> |
269 | + <div class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="isActionError() || isDeployError() || isSSHKeyError() || hasActionPowerError(action.option.name)" data-ng-if="action.option.name === 'commission' || action.option.name === 'test'"> |
270 | + <form class="form form--inline"> |
271 | + <div class="page-header__controls"> |
272 | + <button class="button--base button--inline" data-ng-click="actionCancel()">Cancel</button> |
273 | + <button class="button--inline" data-ng-class="action.option.name === 'delete' ? 'button--destructive' : 'button--positive'" data-ng-click="actionGo('nodes')" data-ng-hide="hasActionsFailed('nodes')"> |
274 | + <span data-ng-if="action.option.name === 'commission'">Commission {$ type_name $}</span> |
275 | + <span data-ng-if="action.option.name === 'test'">Test {$ type_name $}</span> |
276 | + </button> |
277 | + </div> |
278 | + </form> |
279 | + </div> |
280 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="action.showing_confirmation && action.option.name === 'test'"> |
281 | + <p class="page-header__message page-header__message--warning"> |
282 | + Node is currently deployed. Are you sure you want to continue to test hardware? |
283 | + </p> |
284 | + <div class="page-header__controls"> |
285 | + <button class="button--base button--inline" data-ng-click="actionCancel()">No</button> |
286 | + <button class="button--secondary button--inline" data-ng-click="actionGo()">Yes</button> |
287 | + </div> |
288 | + </div> |
289 | + <!-- XXX blake_r 2015-02-19 - Need to add e2e test. --> |
290 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="isActionError()"> |
291 | + <p class="page-header__message page-header__message--error"> |
292 | + Node failed to be {$ action.option.sentence $}, because of the following error: {$ action.error $} |
293 | + </p> |
294 | + <div class="page-header__controls"> |
295 | + <button class="button--base button--inline" data-ng-click="actionCancel()">Cancel</button> |
296 | + <button class="button--secondary button--inline" data-ng-click="actionGo()">Retry</button> |
297 | + </div> |
298 | + </div> |
299 | + |
300 | + <!-- XXX blake_r 2015-02-19 - Need to add e2e test. --> |
301 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="isDeployError()"> |
302 | + <p class="page-header__message page-header__message--error"> |
303 | + Node cannot be {$ action.option.sentence $}, because the required boot images have not been imported. To import boot images, visit the <a href="images/">images page</a>. |
304 | + </p> |
305 | + <div class="page-header__controls"> |
306 | + <button class="button--base button--inline" data-ng-click="actionCancel()">Cancel</button> |
307 | + </div> |
308 | + </div> |
309 | + |
310 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="hasActionPowerError(action.option.name)"> |
311 | + <p class="page-header__message page-header__message--error"> |
312 | + Node cannot be {$ action.option.sentence $}, because power control software for the |
313 | + node is missing from its rack controller. To proceed, install the |
314 | + {$ getPowerErrors() $} on the rack controller. |
315 | + </p> |
316 | + <div class="page-header__controls"> |
317 | + <button class="button--base button--inline" data-ng-click="actionCancel()">Cancel</button> |
318 | + </div> |
319 | + </div> |
320 | +>>>>>>> src/maasserver/static/partials/node-details.html |
321 | |
322 | <nav class="p-tabs"> |
323 | <ul class="p-tabs__list" role="tablist" data-ng-class="{ 'u-hide': action.option }"> |
324 | diff --git a/src/maasserver/static/partials/nodes-list.html b/src/maasserver/static/partials/nodes-list.html |
325 | index 8952e21..71f4b64 100644 |
326 | --- a/src/maasserver/static/partials/nodes-list.html |
327 | +++ b/src/maasserver/static/partials/nodes-list.html |
328 | @@ -1,3 +1,4 @@ |
329 | +<<<<<<< src/maasserver/static/partials/nodes-list.html |
330 | <header class="p-strip--light is-shallow is-bordered page-header" media-query="min-width: 769px"> |
331 | <div class="row"> |
332 | <div class="col-8"> |
333 | @@ -1047,3 +1048,1019 @@ sudo maas-rack register --url {$ tabs.controllers.registerUrl $} --secret {$ tab |
334 | on-check-all="toggleCheckAll('switches')" on-check="toggleChecked($switch_, 'switches')"></maas-switches-table> |
335 | </div> |
336 | </div> |
337 | +======= |
338 | +<header class="page-header u-margin--bottom-none" sticky media-query="min-width: 769px"> |
339 | + <div class="wrapper--inner"> |
340 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
341 | + <h1 class="page-header__title">Nodes</h1> |
342 | + |
343 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
344 | + <p class="page-header__status" data-ng-show="loading"><span class="u-text--loading"><i class="icon icon--loading u-animation--spin"></i> Loading...</span></p> |
345 | + |
346 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
347 | + <div class="page-header__controls u-float--right ng-hide" data-ng-show="currentpage === 'nodes'"> |
348 | + <div data-ng-hide="tabs.nodes.selectedItems.length"> |
349 | + <div data-maas-cta="addHardwareOptions" |
350 | + data-ng-model="addHardwareOption" |
351 | + data-ng-change="addHardwareOptionChanged()" data-default-title="Add hardware"> |
352 | + </div> |
353 | + </div> |
354 | + <div class="ng-hide" data-ng-show="tabs.nodes.selectedItems.length"> |
355 | + <a class="u-display--inline u-margin--right" data-ng-click="showSelected('nodes')">{$ tabs.nodes.selectedItems.length $} Selected</a> |
356 | + <div data-maas-cta="tabs.nodes.takeActionOptions" |
357 | + data-ng-model="tabs.nodes.actionOption" |
358 | + data-ng-change="actionOptionSelected('nodes')"> |
359 | + </div> |
360 | + </div> |
361 | + </div> |
362 | + |
363 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
364 | + <div class="page-header__controls u-float--rightng-hide" data-ng-show="currentpage === 'devices'"> |
365 | + <div data-ng-hide="tabs.devices.selectedItems.length"> |
366 | + <button class="button--secondary button--inline" |
367 | + data-ng-click="addDevice()" |
368 | + data-ng-hide="addDeviceScope.viewable">Add device</button> |
369 | + <button class="button--secondary button--inline ng-hide" |
370 | + data-ng-click="cancelAddDevice()" |
371 | + data-ng-show="addDeviceScope.viewable">Cancel add device</button> |
372 | + </div> |
373 | + <div data-ng-show="tabs.devices.selectedItems.length"> |
374 | + <a class="u-display--inline u-margin--right" data-ng-click="showSelected('devices')">{$ tabs.devices.selectedItems.length $} Selected</a> |
375 | + <div data-maas-cta="tabs.devices.takeActionOptions" |
376 | + data-ng-model="tabs.devices.actionOption" |
377 | + data-ng-change="actionOptionSelected('devices')"> |
378 | + </div> |
379 | + </div> |
380 | + </div> |
381 | + |
382 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
383 | + <div class="page-header__controls u-float--rightng-hide" data-ng-show="currentpage === 'controllers'"> |
384 | + <div data-ng-if="!tabs.controllers.selectedItems.length"> |
385 | + <button class="button--secondary button--inline" |
386 | + data-ng-click="tabs.controllers.addController = true" |
387 | + data-ng-hide="tabs.controllers.addController">Add rack controller</button> |
388 | + <button class="button--secondary button--inline ng-hide" |
389 | + data-ng-click="tabs.controllers.addController = false" |
390 | + data-ng-show="tabs.controllers.addController">Close add rack controller</button> |
391 | + </div> |
392 | + <div data-ng-show="tabs.controllers.selectedItems.length"> |
393 | + <a class="u-display--inline u-margin--right" data-ng-click="showSelected('controllers')">{$ tabs.controllers.selectedItems.length $} Selected</a> |
394 | + <div data-maas-cta="tabs.controllers.takeActionOptions" |
395 | + data-ng-model="tabs.controllers.actionOption" |
396 | + data-ng-change="actionOptionSelected('controllers')"> |
397 | + </div> |
398 | + </div> |
399 | + </div> |
400 | + |
401 | + <div class="page-header__controls u-float--right ng-hide" data-ng-show="currentpage === 'switches'"> |
402 | + <div class="ng-hide" data-ng-show="tabs.switches.selectedItems.length"> |
403 | + <a class="u-display--inline u-margin--right" data-ng-click="showSelected('switches')">{$ tabs.switches.selectedItems.length $} Selected</a> |
404 | + <div data-maas-cta="tabs.switches.takeActionOptions" |
405 | + data-ng-model="tabs.switches.actionOption" |
406 | + data-ng-change="actionOptionSelected('switches')"> |
407 | + </div> |
408 | + </div> |
409 | + </div> |
410 | + |
411 | + <div data-ng-repeat="tab in ['nodes', 'switches']" data-ng-show="currentpage == tab"> |
412 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
413 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': tabs[tab].actionOption }"> |
414 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
415 | + <section class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="isActionError(tab) || hasActionsInProgress(tab)"> |
416 | + <form class="form form--inline u-display--inline"> |
417 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs[tab].actionOption.name === 'commission' || tabs[tab].actionOption.name === 'test'"> |
418 | + <div class="form__group"> |
419 | + <input class="form__group-label" id="{$ tab $}-enableSSH" type="checkbox" |
420 | + data-ng-model="tabs[tab].commissionOptions.enableSSH"> |
421 | + <label class="checkbox-label" for="{$ tab $}-enableSSH">Allow SSH access and prevent machine from powering off</label> |
422 | + </div> |
423 | + </fieldset> |
424 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs[tab].actionOption.name === 'commission'"> |
425 | + <div class="form__group"> |
426 | + <input class="form__group-label" id="{$ tab $}-skipNetworking" type="checkbox" |
427 | + data-ng-model="tabs[tab].commissionOptions.skipNetworking"> |
428 | + <label class="checkbox-label" for="{$ tab $}-skipNetworking">Retain network configuration</label> |
429 | + </div> |
430 | + <div class="form__group"> |
431 | + <input class="form__group-label" id="{$ tab $}-skipStorage" type="checkbox" |
432 | + data-ng-model="tabs[tab].commissionOptions.skipStorage"> |
433 | + <label class="checkbox-label" for="{$ tab $}-skipStorage">Retain storage configuration</label> |
434 | + </div> |
435 | + </fieldset> |
436 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs[tab].actionOption.name === 'deploy'"> |
437 | + <div class="form__group"> |
438 | + <label for="image" class="form__group-label">Choose your image</label> |
439 | + <div class="form__group-input" data-maas-os-select="osinfo" data-ng-model="tabs[tab].osSelection"></div> |
440 | + </div> |
441 | + </fieldset> |
442 | + <fieldset class="form__fieldset" data-ng-if="tabs[tab].actionOption.name === 'release'"> |
443 | + <div class="form__group"> |
444 | + <div data-maas-release-options="tabs[tab].releaseOptions"></div> |
445 | + </div> |
446 | + </fieldset> |
447 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs[tab].actionOption.name === 'set-zone'"> |
448 | + <div class="form__group"> |
449 | + <label for="{$ tab $}-zone3" class="form__group-label">Select Zone</label> |
450 | + <div class="form__group-input"> |
451 | + <select name="zone" id="{$ tab $}-zone3" |
452 | + data-ng-model="tabs[tab].zoneSelection" |
453 | + data-ng-options="zone as zone.name for zone in zones"> |
454 | + <option value="" disabled="disabled">Choose a zone</option> |
455 | + </select> |
456 | + </div> |
457 | + </div> |
458 | + </fieldset> |
459 | + </form> |
460 | + <div class="page-header__controls" data-ng-if="tabs[tab].actionOption.name !== 'commission' && tabs[tab].actionOption.name !== 'test'"> |
461 | + <button class="button--base button--inline" data-ng-click="actionCancel(tab)">Cancel</button> |
462 | + <button class="button--inline" data-ng-class="tabs[tab].actionOption.name === 'delete' ? 'button--destructive' : 'button--positive'" data-ng-click="actionGo(tab)" data-ng-hide="hasActionsFailed(tab)"> |
463 | + <span data-ng-if="tabs[tab].actionOption.name === 'acquire'">Acquire {$ tabs[tab].selectedItems.length $} |
464 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
465 | + </span> |
466 | + <span data-ng-if="tabs[tab].actionOption.name === 'deploy'">Deploy {$ tabs[tab].selectedItems.length $} |
467 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
468 | + </span> |
469 | + <span data-ng-if="tabs[tab].actionOption.name === 'release'">Release {$ tabs[tab].selectedItems.length $} |
470 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
471 | + </span> |
472 | + <span data-ng-if="tabs[tab].actionOption.name === 'set-zone'">Set zone for {$ tabs[tab].selectedItems.length $} |
473 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
474 | + </span> |
475 | + <span data-ng-if="tabs[tab].actionOption.name === 'on'">Power on {$ tabs[tab].selectedItems.length $} |
476 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
477 | + </span> |
478 | + <span data-ng-if="tabs[tab].actionOption.name === 'off'">Power off {$ tabs[tab].selectedItems.length $} |
479 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
480 | + </span> |
481 | + <span data-ng-if="tabs[tab].actionOption.name === 'abort'">Abort action for {$ tabs[tab].selectedItems.length $} |
482 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
483 | + </span> |
484 | + <span data-ng-if="tabs[tab].actionOption.name === 'rescue-mode'">Set rescue mode for {$ tabs[tab].selectedItems.length $} |
485 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
486 | + </span> |
487 | + <span data-ng-if="tabs[tab].actionOption.name === 'exit-rescue-mode'">Exit rescue mode for {$ tabs[tab].selectedItems.length $} |
488 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
489 | + </span> |
490 | + <span data-ng-if="tabs[tab].actionOption.name === 'mark-broken'">Mark {$ tabs[tab].selectedItems.length $} |
491 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> as broken |
492 | + </span> |
493 | + <span data-ng-if="tabs[tab].actionOption.name === 'mark-fixed'">Mark {$ tabs[tab].selectedItems.length $} |
494 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> as fixed |
495 | + </span> |
496 | + <span data-ng-if="tabs[tab].actionOption.name === 'override-failed-testing'">Override failed testing on {$ tabs[tab].selectedItems.length $} |
497 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
498 | + </span> |
499 | + <span data-ng-if="tabs[tab].actionOption.name === 'delete'">Delete {$ tabs[tab].selectedItems.length $} |
500 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
501 | + </span> |
502 | + </button> |
503 | + <button class="button--secondary button--inline" data-ng-click="actionGo(tab)" data-ng-show="hasActionsFailed(tab)">Retry</button> |
504 | + </div> |
505 | + </section> |
506 | + <section class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="isActionError(tab) || hasActionsInProgress(tab)" data-ng-if="tabs[tab].actionOption.name === 'commission' && hasCustomCommissioningScripts()"> |
507 | + <form class="form form--stack"> |
508 | + <fieldset class="form__fieldset eight-col u-margin--bottom-small"> |
509 | + <div class="form__group"> |
510 | + <label for="{$ tab $}-commissiong-scripts">Additional commissioning Scripts</label> |
511 | + <span id="{$ tab $}-commissioning-scripts" data-maas-script-select="script" data-script-type="0" data-ng-model="tabs[tab].commissioningSelection" class="tags--inline"></span> |
512 | + </div> |
513 | + </fieldset> |
514 | + </form> |
515 | + </section> |
516 | + <section class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="isActionError(tab) || hasActionsInProgress(tab)" data-ng-if="tabs[tab].actionOption.name === 'commission' || tabs[tab].actionOption.name ==='test'"> |
517 | + <form class="form form--stack"> |
518 | + <fieldset class="form__fieldset eight-col u-margin--bottom-small"> |
519 | + <div class="form__group"> |
520 | + <label for="{$ tab $}-testing-scripts">Hardware Tests</label> |
521 | + <span id="{$ tab $}-testing-scripts" data-maas-script-select="script" data-script-type="2" data-ng-model="tabs[tab].testSelection" class="tags--inline"></span> |
522 | + </div> |
523 | + </fieldset> |
524 | + </form> |
525 | + </section> |
526 | + <section class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="isActionError(tab) || hasActionsInProgress(tab)" data-ng-if="tabs[tab].actionOption.name === 'commission' || tabs[tab].actionOption.name === 'test'"> |
527 | + <div class="page-header__controls"> |
528 | + <button class="button--base button--inline" data-ng-click="actionCancel(tab)">Cancel</button> |
529 | + <button class="button--inline" data-ng-class="tabs[tab].actionOption.name === 'delete' ? 'button--destructive' : 'button--positive'" data-ng-click="actionGo(tab)" data-ng-hide="hasActionsFailed(tab)"> |
530 | + <span data-ng-if="tabs[tab].actionOption.name === 'commission'">Commission {$ tabs[tab].selectedItems.length $} |
531 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
532 | + </span> |
533 | + <span data-ng-if="tabs[tab].actionOption.name === 'test'">Test {$ tabs[tab].selectedItems.length $} |
534 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'machine', 'other': 'machines'}"></span> |
535 | + </span> |
536 | + </button> |
537 | + <button class="button--secondary button--inline" data-ng-click="actionGo(tab)" data-ng-show="hasActionsFailed(tab)">Retry</button> |
538 | + </div> |
539 | + </section> |
540 | + |
541 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
542 | + <section class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="isActionError(tab)"> |
543 | + <p data-ng-hide="isDeployError(tab) || isSSHKeyError(tab)" |
544 | + class="page-header__message page-header__message--error ng-hide"> |
545 | + {$ tabs[tab].actionErrorCount $} |
546 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'node', 'other': 'nodes'}"></span> |
547 | + cannot be {$ tabs[tab].actionOption.sentence $}. To proceed, update your selection. |
548 | + </p> |
549 | + <p class="page-header__message page-header__message--error ng-hide" data-ng-show="isDeployError(tab)"> |
550 | + {$ tabs[tab].selectedItems.length $} |
551 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'node', 'other': 'nodes'}"></span> |
552 | + cannot be {$ tabs[tab].actionOption.sentence $}, because the required boot images have not been imported. To import boot images, visit the <a href="#/images">images page</a>. |
553 | + </p> |
554 | + <p class="page-header__message page-header__message--error ng-hide" data-ng-show="isSSHKeyError(tab)"> |
555 | + {$ tabs[tab].selectedItems.length $} |
556 | + <span data-ng-pluralize count="tabs[tab].selectedItems.length" when="{'one': 'node', 'other': 'nodes'}"></span> |
557 | + cannot be {$ tabs[tab].actionOption.sentence $}, because an SSH key has not been added to your account. To add an SSH key, visit <a href="account/prefs/">your account page</a>. |
558 | + </p> |
559 | + </section> |
560 | + <section class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="tabs[tab].actionProgress.showing_confirmation"> |
561 | + <p class="page-header__message page-header__message--warning"> |
562 | + {$ tabs[tab].actionProgress.affected_nodes $} of {$ tabs[tab].selectedItems.length $} are in a deployed state. Are you sure you want to continue to test hardware? |
563 | + </p> |
564 | + <div class="page-header__controls"> |
565 | + <button class="button--base button--inline" data-ng-click="actionCancel(tab)">No</button> |
566 | + <button class="button--secondary button--inline" data-ng-click="actionGo(tab)">Yes</button> |
567 | + </div> |
568 | + </section> |
569 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
570 | + <section class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="hasActionsInProgress(tab) || hasActionsFailed(tab)"> |
571 | + <p class="page-header__message" data-ng-show="hasActionsInProgress(tab)"> |
572 | + <i class="icon icon--loading u-animation--spin"></i> |
573 | + {$ tabs[tab].actionProgress.completed $} of {$ tabs[tab].actionProgress.total $} |
574 | + nodes are transitioning to {$ tabs[tab].actionOption.sentence $}. |
575 | + </p> |
576 | + <p class="page-header__message page-header__message--error" |
577 | + data-ng-repeat="(error, nodes) in tabs[tab].actionProgress.errors"> |
578 | + The {$ tabs[tab].actionOption.title.toLowerCase() $} action for {$ nodes.length $} |
579 | + <span data-ng-pluralize count="nodes.length" when="{'one': 'node', 'other': 'nodes'}"></span> |
580 | + failed with error: {$ error $} |
581 | + </p> |
582 | + </section> |
583 | + </div> |
584 | + |
585 | + </div> |
586 | + |
587 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
588 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': addHardwareScope.viewable }" data-ng-controller="AddHardwareController"> |
589 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
590 | + <section class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="showMachine()"> |
591 | + <h3 class="page-header__dropdown-title">Add machine</h3> |
592 | + <form class="form form--stack"> |
593 | + <fieldset class="form__fieldset six-col"> |
594 | + <div class="form__group"> |
595 | + <label for="machine-name" class="form__label two-col">Machine name</label> |
596 | + <div class="form__group-input three-col"> |
597 | + <input type="text" id="machine-name" placeholder="Choose a machine name (optional)" |
598 | + data-ng-model="machine.name"> |
599 | + </div> |
600 | + </div> |
601 | + <div class="form__group"> |
602 | + <label for="domain" class="form__group-label two-col">Domain</label> |
603 | + <div class="form__group-input three-col"> |
604 | + <select name="domain" id="domain" |
605 | + data-ng-model="machine.domain" |
606 | + data-ng-options="domain as domain.name for domain in domains"> |
607 | + <option value="" disabled>Choose a domain</option> |
608 | + </select> |
609 | + </div> |
610 | + </div> |
611 | + <div class="form__group"> |
612 | + <label for="architecture" class="form__group-label two-col">Architecture</label> |
613 | + <div class="form__group-input three-col"> |
614 | + <select name="architecture" id="architecture" |
615 | + data-ng-model="machine.architecture" |
616 | + data-ng-options="arch for arch in architectures"> |
617 | + <option value="" disabled>Choose an architecture</option> |
618 | + </select> |
619 | + </div> |
620 | + </div> |
621 | + <div class="form__group"> |
622 | + <label for="min_hwe_kernel" class="form__group-label two-col">Minimum Kernel</label> |
623 | + <div class="form__group-input three-col"> |
624 | + <select name="min_hwe_kernel" id="min_hwe_kernel" |
625 | + data-ng-model="machine.min_hwe_kernel" |
626 | + data-ng-options="hwe_kernel[0] as hwe_kernel[1] for hwe_kernel in hwe_kernels"> |
627 | + <option value="">No minimum kernel</option> |
628 | + </select> |
629 | + </div> |
630 | + </div> |
631 | + <div class="form__group"> |
632 | + <label for="zone4" class="form__group-label two-col">Zone</label> |
633 | + <select name="zone" id="zone4" class="three-col" |
634 | + data-ng-model="machine.zone" |
635 | + data-ng-options="zone as zone.name for zone in zones"> |
636 | + </select> |
637 | + </div> |
638 | + <div class="form__group" data-ng-repeat="mac in machine.macs"> |
639 | + <label for="mac-address" class="form__group-label two-col"><span data-ng-hide="mac !== machine.macs[0]">MAC Address</span> </label> |
640 | + <div class="form__group-input three-col"> |
641 | + <input type="text" id="mac-address" placeholder="00:00:00:00:00:00" |
642 | + maxlength="17" |
643 | + data-ng-class="{ 'has-error': mac.error }" |
644 | + data-ng-model="mac.mac" |
645 | + data-ng-pattern="macAddressRegex" |
646 | + data-ng-change="validateMac(mac)" |
647 | + mac-address> |
648 | + <span class="form__group-remove" title="Delete MAC" |
649 | + data-ng-hide="mac === machine.macs[0]" data-ng-click="removeMac(mac)"></span> |
650 | + </div> |
651 | + </div> |
652 | + <div class="form__group"> |
653 | + <div class="five-col"> |
654 | + <button class="button--secondary button--inline u-float--right" data-ng-click="addMac()">+ Add MAC Address</a> |
655 | + </div> |
656 | + </div> |
657 | + </fieldset> |
658 | + <fieldset class="form__fieldset six-col last-col" |
659 | + data-maas-power-parameters="power_types" |
660 | + data-ng-model="machine.power"> |
661 | + </fieldset> |
662 | + </form> |
663 | + </section> |
664 | + <section class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="showChassis()"> |
665 | + <h3 class="page-header__dropdown-title">Add chassis</h3> |
666 | + <form action="post" class="form form--stack"> |
667 | + <fieldset class="form__fieldset six-col" |
668 | + data-maas-power-parameters="chassisPowerTypes" |
669 | + data-ng-model="chassis.power"> |
670 | + </fieldset> |
671 | + <fieldset class="form__fieldset six-col last-col"> |
672 | + <div class="form__group"> |
673 | + <label for="domain2" class="form__group-label two-col">Domain</label> |
674 | + <div class="form__group-input three-col"> |
675 | + <select name="domain" id="domain2" |
676 | + data-ng-model="chassis.domain" |
677 | + data-ng-options="domain as domain.name for domain in domains"> |
678 | + </select> |
679 | + </div> |
680 | + </div> |
681 | + </fieldset> |
682 | + </form> |
683 | + </section> |
684 | + |
685 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
686 | + <section class="page-header__section twelve-col u-margin--bottom-none" data-ng-show="showMachine()"> |
687 | + <p class="page-header__message page-header__message--error ng-hide" data-ng-show="error">{$ error $}</p> |
688 | + <div class="page-header__controls"> |
689 | + <button class="button--base button--inline" data-ng-click="cancel()">Cancel</button> |
690 | + <button class="button--secondary button--inline" |
691 | + data-ng-disabled="machineHasError()" |
692 | + data-ng-click="saveMachine(true)">Save and add another</button> |
693 | + <button class="button--positive button--inline" |
694 | + data-ng-disabled="machineHasError()" |
695 | + data-ng-click="saveMachine(false)">Save machine</button> |
696 | + </div> |
697 | + </section> |
698 | + |
699 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
700 | + <section class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="showChassis()"> |
701 | + <p class="page-header__message page-header__message--error ng-hide" data-ng-show="error">{$ error $}</p> |
702 | + <div class="page-header__controls"> |
703 | + <button class="button--base button--inline" data-ng-click="cancel()">Cancel</button> |
704 | + <button class="button--secondary button--inline" |
705 | + data-ng-disabled="chassisHasErrors()" |
706 | + data-ng-click="saveChassis(true)">Save and add another</button> |
707 | + <button class="button--positive button--inline" |
708 | + data-ng-disabled="chassisHasErrors()" |
709 | + data-ng-click="saveChassis(false)">Save chassis</button> |
710 | + </div> |
711 | + </section> |
712 | + |
713 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
714 | + <section class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="architectures.length"> |
715 | + <p class="page-header__message page-header__message--error"> |
716 | + Cannot add {$ mode $} until boot images have been imported. To fix, visit the <a href="#/images">images page</a>. |
717 | + </p> |
718 | + </section> |
719 | + </div> |
720 | + |
721 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
722 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': tabs.devices.actionOption }"> |
723 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
724 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-hide="isActionError('devices') || hasActionsInProgress('devices')"> |
725 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
726 | + <form class="form form--inline u-display--inline"> |
727 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs.devices.actionOption.name === 'set-zone'"> |
728 | + <div class="form__group"> |
729 | + <label class="form__group-label" for="zone1">Set zone</label> |
730 | + <select name="zone" id="zone1" |
731 | + data-ng-model="tabs.devices.zoneSelection" |
732 | + data-ng-options="zone as zone.name for zone in zones"> |
733 | + <option value="" disabled="disabled">Choose a zone</option> |
734 | + </select> |
735 | + </div> |
736 | + </fieldset> |
737 | + <div class="page-header__controls"> |
738 | + <button class="button--base button--inline" data-ng-click="actionCancel('devices')">Cancel</button> |
739 | + <button class="button--positive button--inline" data-ng-click="actionGo('devices')"> |
740 | + <span data-ng-if="tabs.devices.actionOption.name === 'set-zone'">Set zone for {$ tabs.devices.selectedItems.length $} |
741 | + <span data-ng-pluralize count="tabs.devices.selectedItems.length" when="{'one': 'device', 'other': 'devices'}"></span> |
742 | + </span> |
743 | + <span data-ng-if="tabs.devices.actionOption.name === 'delete'">Delete {$ tabs.devices.selectedItems.length $} |
744 | + <span data-ng-pluralize count="tabs.devices.selectedItems.length" when="{'one': 'device', 'other': 'devices'}"></span> |
745 | + </span> |
746 | + </button> |
747 | + </div> |
748 | + </form> |
749 | + </div> |
750 | + |
751 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
752 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="isActionError('devices')"> |
753 | + <p class="page-header__message page-header__message--error"> |
754 | + {$ tabs.devices.actionErrorCount $} |
755 | + <span data-ng-pluralize count="tabs.devices.selectedItems.length" when="{'one': 'device', 'other': 'devices'}"></span> |
756 | + cannot be {$ tabs.devices.actionOption.sentence $}. To proceed, update your selection. |
757 | + </p> |
758 | + </div> |
759 | + |
760 | + <!-- XXX blake_r 2015-05-07 - Need to add e2e test. --> |
761 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="hasActionsInProgress('devices') || hasActionsFailed('devices')"> |
762 | + <p class="page-header__message" data-ng-show="hasActionsInProgress('devices')"> |
763 | + <i class="icon icon--loading u-animation--spin"></i> |
764 | + {$ tabs.devices.actionProgress.completed $} of {$ tabs.devices.actionProgress.total $} |
765 | + devices have been {$ tabs.devices.actionOption.sentence $}. |
766 | + </p> |
767 | + <p class="page-header__message page-header__message--error" |
768 | + data-ng-repeat="(error, devices) in tabs.devices.actionProgress.errors"> |
769 | + The {$ tabs.devices.actionOption.title.toLowerCase() $} action for {$ devices.length $} |
770 | + <span data-ng-pluralize count="devices.length" when="{'one': 'device', 'other': 'devices'}"></span> |
771 | + failed with error: {$ error $} |
772 | + </p> |
773 | + </div> |
774 | + </div> |
775 | + |
776 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
777 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': addDeviceScope.viewable }" data-ng-controller="AddDeviceController"> |
778 | + <section class="page-header__section twelve-col u-margin--bottom-none"> |
779 | + <h3 class="page-header__dropdown-title">Add device</h3> |
780 | + <form class="form form--stack"> |
781 | + <fieldset class="form__fieldset six-col"> |
782 | + <div class="form__group"> |
783 | + <label for="device-name" class="form__group-label two-col">Name</label> |
784 | + <div class="form__group-input three-col"> |
785 | + <input type="text" id="device-name" placeholder="Name your device" |
786 | + data-ng-model="device.name" |
787 | + data-ng-class="{ 'has-error': nameHasError() }"> |
788 | + </div> |
789 | + |
790 | + </div> |
791 | + <div class="form__group"> |
792 | + <label for="domain3" class="form__group-label two-col">Domain</label> |
793 | + <div class="form__group-input three-col"> |
794 | + <select name="domain" id="domain3" |
795 | + data-ng-model="device.domain" |
796 | + data-ng-options="domain as domain.name for domain in domains"> |
797 | + </select> |
798 | + </div> |
799 | + </div> |
800 | + </fieldset> |
801 | + </form> |
802 | + <table> |
803 | + <thead> |
804 | + <tr> |
805 | + <th class="table-col--20">MAC address</th> |
806 | + <th class="table-col--20">IP assignment</th> |
807 | + <th class="table-col--20">Subnet</th> |
808 | + <th class="table-col--35">IP address</th> |
809 | + <th class="table-col--5"></th> |
810 | + </tr> |
811 | + </thead> |
812 | + <tbody vs-repeat vs-scroll-parent="window"> |
813 | + <tr data-ng-repeat="interface in device.interfaces"> |
814 | + <td class="table-col--20" aria-label="MAC address"> |
815 | + <input type="text" id="mac-address1" placeholder="00:00:00:00:00:00" |
816 | + data-ng-model="interface.mac" |
817 | + data-ng-class="{ 'has-error': macHasError(interface) }"> |
818 | + </td> |
819 | + <td class="table-col--20" aria-label="IP assignment"> |
820 | + <select name="ip-assignment" id="ip-assignment" |
821 | + data-ng-model="interface.ipAssignment" |
822 | + data-ng-options="assigment.title for assigment in ipAssignments"> |
823 | + <option value="" disabled selected>Select IP assignment</option> |
824 | + </select> |
825 | + </td> |
826 | + <td class="table-col--20" aria-label="Subnet"> |
827 | + <select name="subnet" id="subnet" |
828 | + data-ng-model="interface.subnetId" |
829 | + data-ng-options="subnet.id as subnet.name for subnet in subnets" |
830 | + data-ng-show="interface.ipAssignment.name === 'static'"> |
831 | + <option value="" disabled selected>Select subnet</option> |
832 | + </select> |
833 | + </td> |
834 | + <td class="table-col--35" aria-label="IP address"> |
835 | + <input type="text" id="ip-address" placeholder="000.000.000.000" |
836 | + data-ng-model="interface.ipAddress" |
837 | + data-ng-class="{ 'has-error': ipHasError(interface) }" |
838 | + data-ng-show="interface.ipAssignment.name === 'external'"> |
839 | + <input type="text" id="ip-address" |
840 | + data-ng-model="interface.ipAddress" |
841 | + data-ng-class="{ 'has-error': ipHasError(interface) }" |
842 | + data-ng-show="interface.ipAssignment.name === 'static'"> |
843 | + </td> |
844 | + <td class="table-col--5 u-u-align---right table--mobile-controls"> |
845 | + <!-- space needed to set correct height --> |
846 | + <span data-ng-show="isPrimaryInterface(interface)"> </span> |
847 | + <a title="Delete" class="icon icon--remove u-display--desktop" |
848 | + data-ng-click="deleteInterface(interface)" |
849 | + data-ng-hide="isPrimaryInterface(interface)">delete</a> |
850 | + <button class="button--secondary u-display--mobile" |
851 | + data-ng-click="deleteInterface(interface)" |
852 | + data-ng-hide="isPrimaryInterface(interface)">delete</a> |
853 | + </td> |
854 | + </tr> |
855 | + </tbody> |
856 | + </table> |
857 | + <button class="button--secondary button--inline" data-ng-click="addInterface()">+ Add another interface</button> |
858 | + </section> |
859 | + <section class="page-header__section twelve-col u-margin--bottom-none twelve-col u-margin--bottom-none"> |
860 | + <form class="form form--inline"> |
861 | + <p class="page-header__message page-header__message--error ng-hide" data-ng-show="error">{$ error $}</p> |
862 | + <div class="page-header__controls"> |
863 | + <button class="button--base button--inline" data-ng-click="cancel()">Cancel</button> |
864 | + <button class="button--secondary button--inline" |
865 | + data-ng-class="{ disabled: deviceHasError() }" |
866 | + data-ng-click="save(true)">Save and add another</button> |
867 | + <button class="button--positive button--inline" |
868 | + data-ng-class="{ disabled: deviceHasError() }" |
869 | + data-ng-click="save(false)">Save device</button> |
870 | + </div> |
871 | + </form> |
872 | + </section> |
873 | + </div> |
874 | + |
875 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
876 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': tabs.controllers.actionOption }"> |
877 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
878 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-hide="isActionError('controllers') || hasActionsInProgress('controllers')"> |
879 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
880 | + <form class="form form--inline u-display--inline"> |
881 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs.controllers.actionOption.name === 'set-zone'"> |
882 | + <div class="form__group"> |
883 | + <label for="zone2" class="form__group-label">Select Zone</label> |
884 | + <div class="form__group-input"> |
885 | + <select name="zone" id="zone2" |
886 | + data-ng-model="tabs.controllers.zoneSelection" |
887 | + data-ng-options="zone as zone.name for zone in zones"> |
888 | + <option value="" disabled="disabled">Choose a zone</option> |
889 | + </select> |
890 | + </div> |
891 | + </div> |
892 | + </fieldset> |
893 | + <fieldset class="form__fieldset ng-hide" data-ng-show="tabs.controllers.actionOption.name === 'test'"> |
894 | + <div class="form__group"> |
895 | + <input class="form__group-label" id="enable_SSH" type="checkbox" |
896 | + data-ng-model="tabs.controllers.commissionOptions.enableSSH"> |
897 | + <label class="checkbox-label" for="enable_SSH">Allow SSH access and prevent machine from powering off</label> |
898 | + </div> |
899 | + </fieldset> |
900 | + </form> |
901 | + <div class="page-header__controls" data-ng-if="tabs.controllers.actionOption.name !== 'test'"> |
902 | + <button class="button--base button--inline" data-ng-click="actionCancel('controllers')">Cancel</button> |
903 | + <button class="button--positive button--inline" data-ng-click="actionGo('controllers')"> |
904 | + <span data-ng-if="tabs.controllers.actionOption.name === 'set-zone'">Set zone for {$ tabs.controllers.selectedItems.length $} |
905 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
906 | + </span> |
907 | + <span data-ng-if="tabs.controllers.actionOption.name === 'on'">Power on {$ tabs.controllers.selectedItems.length $} |
908 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
909 | + </span> |
910 | + <span data-ng-if="tabs.controllers.actionOption.name === 'off'">Power off {$ tabs.controllers.selectedItems.length $} |
911 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
912 | + </span> |
913 | + <span data-ng-if="tabs.controllers.actionOption.name === 'delete'">Delete {$ tabs.controllers.selectedItems.length $} |
914 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
915 | + </span> |
916 | + <span data-ng-if="tabs.controllers.actionOption.name === 'import-images'">Import images for {$ tabs.controllers.selectedItems.length $} |
917 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
918 | + </span> |
919 | + </button> |
920 | + </div> |
921 | + </div> |
922 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-hide="isActionError('controllers') || hasActionsInProgress('controllers')" data-ng-if="tabs.controllers.actionOption.name === 'test'"> |
923 | + <form class="form form--stack"> |
924 | + <fieldset class="form__fieldset eight-col u-margin--bottom-small"> |
925 | + <div class="form__group"> |
926 | + <label for="testing-scripts">Hardware Tests</label> |
927 | + <span id="testing-scripts" data-maas-script-select="script" data-script-type="2" data-ng-model="tabs.nodes.testSelection" class="tags--inline"></span> |
928 | + </div> |
929 | + </fieldset> |
930 | + </form> |
931 | + </div> |
932 | + <div class="page-header__section twelve-col u-margin--bottom-none" data-ng-hide="isActionError('controllers') || hasActionsInProgress('controllers')" data-ng-if="tabs.controllers.actionOption.name === 'test'"> |
933 | + <div class="page-header__controls"> |
934 | + <button class="button--base button--inline" data-ng-click="actionCancel('controllers')">Cancel</button> |
935 | + <button class="button--positive button--inline" data-ng-click="actionGo('controllers')"> |
936 | + <span>Test {$ tabs.controllers.selectedItems.length $} |
937 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
938 | + </span> |
939 | + </button> |
940 | + </div> |
941 | + </div> |
942 | + |
943 | + <!-- XXX blake_r 2015-04-02 - Need to add e2e test. --> |
944 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="isActionError('controllers')"> |
945 | + <form class="form form--inline"> |
946 | + <p class="page-header__message page-header__message--error"> |
947 | + {$ tabs.controllers.actionErrorCount $} |
948 | + <span data-ng-pluralize count="tabs.controllers.selectedItems.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
949 | + cannot be {$ tabs.controllers.actionOption.sentence $}. To proceed, update your selection. |
950 | + </p> |
951 | + </form> |
952 | + </div> |
953 | + |
954 | + <!-- XXX blake_r 2015-05-07 - Need to add e2e test. --> |
955 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="hasActionsInProgress('controllers') || hasActionsFailed('controllers')"> |
956 | + <form class="form form--inline"> |
957 | + <p class="page-header__message" data-ng-show="hasActionsInProgress('controllers')"> |
958 | + <i class="icon icon--loading u-animation--spin u-margin--right-small"></i> |
959 | + {$ tabs.controllers.actionProgress.completed $} of {$ tabs.controllers.actionProgress.total $} |
960 | + controllers have been {$ tabs.controllers.actionOption.sentence $}. |
961 | + </p> |
962 | + <p class="page-header__message page-header__message--error" |
963 | + data-ng-repeat="(error, controllers) in tabs.controllers.actionProgress.errors"> |
964 | + The {$ tabs.controllers.actionOption.title.toLowerCase() $} action for {$ controllers.length $} |
965 | + <span data-ng-pluralize count="controllers.length" when="{'one': 'controller', 'other': 'controllers'}"></span> |
966 | + failed with error: {$ error $} |
967 | + </p> |
968 | + </form> |
969 | + </div> |
970 | + </div> |
971 | + |
972 | + <div class="page-header__dropdown" data-ng-class="{ 'is-open': tabs.controllers.addController }"> |
973 | + <!-- XXX blake_r 2015-05-07 - Need to add e2e test. --> |
974 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="tabs.controllers.addController"> |
975 | + <h3 class="page-header__dropdown-title">Add rack controller</h3> |
976 | + <pre class="u-margin--none"> |
977 | + <code># To add a new rack controller, SSH into the rack controller. |
978 | +# Install the maas-rack-controller package. |
979 | +sudo apt install maas-rack-controller |
980 | +# Register the rack controller with this MAAS. If the rack controller (and machines) |
981 | +# don't have access to the URL, use a different IP address to allow connection. |
982 | +sudo maas-rack register --url {$ tabs.controllers.registerUrl $} --secret {$ tabs.controllers.registerSecret $}</code> |
983 | + </pre> |
984 | + </div> |
985 | + <div class="page-header__section twelve-col u-margin--bottom-none ng-hide" data-ng-show="tabs.controllers.addController"> |
986 | + <form class="form form--inline"> |
987 | + <div class="page-header__controls"> |
988 | + <button class="button--secondary button--inline" |
989 | + data-ng-click="tabs.controllers.addController = false">Close</button> |
990 | + </div> |
991 | + </form> |
992 | + </div> |
993 | + </div> |
994 | + </div> |
995 | +</header> |
996 | +<div sticky media-query="min-width: 769px" offset="89" class="page-navigation" data-ng-class="{ 'u-visibility--hidden': tabs.nodes.actionOption || addHardwareScope.viewable || tabs.devices.actionOption || addDeviceScope.viewable || tabs.controllers.actionOption || tabs.controllers.addController }"> |
997 | + <div class="wrapper--inner"> |
998 | + <nav class="page-navigation__links"> |
999 | + <button class="page-navigation__link tooltip tooltip--right" |
1000 | + aria-label="A deployable node managed by MAAS." |
1001 | + data-ng-class="{ 'is-active': currentpage === 'nodes'}" |
1002 | + data-ng-click="toggleTab('nodes')">{$ nodes.length $} <ng-pluralize count="nodes.length" when="{'one': 'Machine', 'other': 'Machines'}"></ng-pluralize></button> |
1003 | + <button class="page-navigation__link tooltip" |
1004 | + aria-label="A node known to MAAS, but is not deployable." |
1005 | + data-ng-class="{ 'is-active': currentpage === 'devices'}" |
1006 | + data-ng-click="toggleTab('devices')">{$ devices.length $} <ng-pluralize count="devices.length" when="{'one': 'Device', 'other': 'Devices'}"></ng-pluralize></button> |
1007 | + <button class="page-navigation__link tooltip" |
1008 | + data-ng-if="isSuperUser()" |
1009 | + aria-label="A node that provides MAAS services." |
1010 | + data-ng-class="{ 'is-active': currentpage === 'controllers'}" |
1011 | + data-ng-click="toggleTab('controllers')">{$ controllers.length $} <ng-pluralize count="controllers.length" when="{'one': 'Controller', 'other': 'Controllers'}"></ng-pluralize></button> |
1012 | + <button class="page-navigation__link tooltip" |
1013 | + data-ng-if="showswitches" |
1014 | + aria-label="A node that is a network switch." |
1015 | + data-ng-class="{ 'is-active': currentpage === 'switches'}" |
1016 | + data-ng-click="toggleTab('switches')">{$ switches.length $} <ng-pluralize count="switches.length" when="{'one': 'Switch', 'other': 'Switches'}"></ng-pluralize></button> |
1017 | + </nav> |
1018 | + </div> |
1019 | +</div> |
1020 | +<div class="u-padding--top row"> |
1021 | + <div class="wrapper--inner"> |
1022 | + <maas-notifications></maas-notifications> |
1023 | + <aside class="three-col"> |
1024 | + <div class="accordion maas-accordion ng-hide" data-ng-show="currentpage === 'nodes'" |
1025 | + data-ng-class="{ 'is-disabled': tabs.nodes.actionOption }"> |
1026 | + <h3 class="accordion__title" |
1027 | + data-ng-class="{'is-active': isActive}" |
1028 | + data-ng-init="isActive = false" |
1029 | + data-ng-click="isActive = !isActive">Filter by</h3> |
1030 | + <div class="accordion__content"> |
1031 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
1032 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.status.length"> |
1033 | + <button class="accordion__tab-title maas-accordion-tab is-active">Status</button> |
1034 | + <div class="accordion__tab-content"> |
1035 | + <ul class="accordion__tab-list"> |
1036 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
1037 | + <li class="accordion__tab-item" data-ng-repeat="status in tabs.nodes.metadata.status | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('status', status.name, 'nodes') }"> |
1038 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('status', status.name, 'nodes')">{$ status.name $} ({$ status.count $})</button> |
1039 | + </li> |
1040 | + </ul> |
1041 | + </div> |
1042 | + </div> |
1043 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.owner.length"> |
1044 | + <button class="accordion__tab-title maas-accordion-tab">Owner</button> |
1045 | + <div class="accordion__tab-content"> |
1046 | + <ul class="accordion__tab-list"> |
1047 | + <li class="accordion__tab-item" data-ng-repeat="owner in tabs.nodes.metadata.owner | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('owner', owner.name, 'nodes') }"> |
1048 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('owner', owner.name, 'nodes')">{$ owner.name $} ({$ owner.count $})</button> |
1049 | + </li> |
1050 | + </ul> |
1051 | + </div> |
1052 | + </div> |
1053 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.architecture.length"> |
1054 | + <button class="accordion__tab-title maas-accordion-tab">Architectures</button> |
1055 | + <div class="accordion__tab-content"> |
1056 | + <ul class="accordion__tab-list"> |
1057 | + <li class="accordion__tab-item" data-ng-repeat="architecture in tabs.nodes.metadata.architecture | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('architecture', architecture.name, 'nodes') }"> |
1058 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('architecture', architecture.name, 'nodes')"><span data-maas-release-name="architecture.name"></span> ({$ architecture.count $})</button> |
1059 | + </li> |
1060 | + </ul> |
1061 | + </div> |
1062 | + </div> |
1063 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.release.length"> |
1064 | + <button class="accordion__tab-title maas-accordion-tab">OS/Release</button> |
1065 | + <div class="accordion__tab-content"> |
1066 | + <ul class="accordion__tab-list"> |
1067 | + <li class="accordion__tab-item" data-ng-repeat="release in tabs.nodes.metadata.release | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('release', release.name, 'nodes') }"> |
1068 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('release', release.name, 'nodes')"><span data-maas-release-name="release.name"></span> ({$ release.count $})</button> |
1069 | + </li> |
1070 | + </ul> |
1071 | + </div> |
1072 | + </div> |
1073 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.tags.length"> |
1074 | + <button class="accordion__tab-title maas-accordion-tab">Tags</button> |
1075 | + <div class="accordion__tab-content"> |
1076 | + <ul class="accordion__tab-list"> |
1077 | + <li class="accordion__tab-item" data-ng-repeat="tag in tabs.nodes.metadata.tags | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('tags', tag.name, 'nodes') }"> |
1078 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('tags', tag.name, 'nodes')">{$ tag.name $} ({$ tag.count $})</button> |
1079 | + </li> |
1080 | + </ul> |
1081 | + </div> |
1082 | + </div> |
1083 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.storage_tags.length"> |
1084 | + <button class="accordion__tab-title maas-accordion-tab">Storage Tags</button> |
1085 | + <div class="accordion__tab-content"> |
1086 | + <ul class="accordion__tab-list"> |
1087 | + <li class="accordion__tab-item" data-ng-repeat="tag in tabs.nodes.metadata.storage_tags | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('storage_tags', tag.name, 'nodes') }"> |
1088 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('storage_tags', tag.name, 'nodes')">{$ tag.name $} ({$ tag.count $})</button> |
1089 | + </li> |
1090 | + </ul> |
1091 | + </div> |
1092 | + </div> |
1093 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.subnets.length"> |
1094 | + <button class="accordion__tab-title maas-accordion-tab">Subnets</button> |
1095 | + <div class="accordion__tab-content"> |
1096 | + <ul class="accordion__tab-list"> |
1097 | + <li class="accordion__tab-item" data-ng-repeat="subnet in tabs.nodes.metadata.subnets | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('subnets', subnet.name, 'nodes') }"> |
1098 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('subnets', subnet.name, 'nodes')">{$ subnet.name $} ({$ subnet.count $})</button> |
1099 | + </li> |
1100 | + </ul> |
1101 | + </div> |
1102 | + </div> |
1103 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.fabrics.length"> |
1104 | + <button class="accordion__tab-title maas-accordion-tab">Fabrics</button> |
1105 | + <div class="accordion__tab-content"> |
1106 | + <ul class="accordion__tab-list"> |
1107 | + <li class="accordion__tab-item" data-ng-repeat="fabric in tabs.nodes.metadata.fabrics | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('fabrics', fabric.name, 'nodes') }"> |
1108 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('fabrics', fabric.name, 'nodes')">{$ fabric.name $} ({$ fabric.count $})</button> |
1109 | + </li> |
1110 | + </ul> |
1111 | + </div> |
1112 | + </div> |
1113 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.spaces.length"> |
1114 | + <button class="accordion__tab-title maas-accordion-tab">Spaces</button> |
1115 | + <div class="accordion__tab-content"> |
1116 | + <ul class="accordion__tab-list"> |
1117 | + <li class="accordion__tab-item" data-ng-repeat="space in tabs.nodes.metadata.spaces | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('spaces', space.name, 'nodes') }"> |
1118 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('spaces', space.name, 'nodes')">{$ space.name $} ({$ space.count $})</button> |
1119 | + </li> |
1120 | + </ul> |
1121 | + </div> |
1122 | + </div> |
1123 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.nodes.metadata.zone.length"> |
1124 | + <button class="accordion__tab-title maas-accordion-tab">Zones</button> |
1125 | + <div class="accordion__tab-content"> |
1126 | + <ul class="accordion__tab-list"> |
1127 | + <li class="accordion__tab-item" data-ng-repeat="zone in tabs.nodes.metadata.zone | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('zone', zone.name, 'nodes') }"> |
1128 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('zone', zone.name, 'nodes')">{$ zone.name $} ({$ zone.count $})</button> |
1129 | + </li> |
1130 | + </ul> |
1131 | + </div> |
1132 | + </div> |
1133 | + </div> |
1134 | + </div> |
1135 | + <div class="accordion three-col maas-accordion ng-hide" data-ng-show="currentpage === 'devices'" |
1136 | + data-ng-class="{ 'is-disabled': tabs.devices.actionOption }"> |
1137 | + <h3 class="accordion__title">Filter by</h3> |
1138 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1139 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.devices.metadata.owner.length"> |
1140 | + <button class="accordion__tab-title maas-accordion-tab active">Owner</button> |
1141 | + <div class="accordion__tab-content"> |
1142 | + <ul class="accordion__tab-list"> |
1143 | + <li class="accordion__tab-item" data-ng-repeat="owner in tabs.devices.metadata.owner | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('owner', owner.name, 'devices') }"> |
1144 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('owner', owner.name, 'devices')">{$ owner.name $} ({$ owner.count $})</button> |
1145 | + </li> |
1146 | + </ul> |
1147 | + </div> |
1148 | + </div> |
1149 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.devices.metadata.tags.length"> |
1150 | + <button class="accordion__tab-title maas-accordion-tab">Tags</button> |
1151 | + <div class="accordion__tab-content"> |
1152 | + <ul class="accordion__tab-list"> |
1153 | + <li class="accordion__tab-item" data-ng-repeat="tag in tabs.devices.metadata.tags | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('tags', tag.name, 'devices') }"> |
1154 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('tags', tag.name, 'devices')">{$ tag.name $} ({$ tag.count $})</button> |
1155 | + </li> |
1156 | + </ul> |
1157 | + </div> |
1158 | + </div> |
1159 | + <div class="ng-hide accordion__tab" data-ng-show="tabs.devices.metadata.zone.length"> |
1160 | + <button class="accordion__tab-title maas-accordion-tab">Zones</button> |
1161 | + <div class="accordion__tab-content"> |
1162 | + <ul class="accordion__tab-list"> |
1163 | + <li class="accordion__tab-item" data-ng-repeat="zone in tabs.devices.metadata.zone | orderBy:['name', '-count']" data-ng-class="{ 'is-active': isFilterActive('zone', zone.name, 'devices') }"> |
1164 | + <button class="accordion__tab-link" data-ng-click="toggleFilter('zone', zone.name, 'devices')">{$ zone.name $} ({$ zone.count $})</button> |
1165 | + </li> |
1166 | + </ul> |
1167 | + </div> |
1168 | + </div> |
1169 | + </div> |
1170 | + </aside> |
1171 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
1172 | + <div class="nine-col last-col ng-hide" data-ng-show="currentpage === 'nodes'"> |
1173 | + <form> |
1174 | + <div id="search-bar" class="search nine-col"> |
1175 | + <!-- XXX ricgard 2016-06-16 - Need to add e2e test. --> |
1176 | + <input |
1177 | + type="search" placeholder="Search nodes" class="search__input" |
1178 | + data-ng-model="tabs.nodes.search" data-ng-change="updateFilters('nodes')" |
1179 | + data-ng-class="{ error: !tabs.nodes.searchValid }" |
1180 | + data-ng-disabled="tabs.nodes.actionOption" /> |
1181 | + <input type="reset" class="search__submit" |
1182 | + data-ng-class="{ 'search__submit--close': tabs.nodes.search.length > 0 }" |
1183 | + data-ng-click="clearSearch('nodes')" /> |
1184 | + </div> |
1185 | + <maas-machines-table id="nodes-listing" search="tabs.nodes.search" ng-disabled="hasActionsInProgress('nodes')" |
1186 | + machine-has-error="!supportsAction($machine, 'nodes')" on-listing-change="onNodeListingChanged($machines, 'nodes')" |
1187 | + on-check-all="toggleCheckAll('nodes')" on-check="toggleChecked($machine, 'nodes')"></maas-machines-table> |
1188 | + </form> |
1189 | + </div> |
1190 | + <div class="nine-col last-col" class="ng-hide" data-ng-show="currentpage === 'devices'"> |
1191 | + <div class="search nine-col"> |
1192 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1193 | + <input |
1194 | + type="search" placeholder="Search devices" class="search__input" |
1195 | + data-ng-model="tabs.devices.search" data-ng-change="updateFilters('devices')" |
1196 | + data-ng-class="{ error: !tabs.devices.searchValid }" |
1197 | + data-ng-disabled="tabs.devices.actionOption" /> |
1198 | + <input type="reset" class="search__submit" |
1199 | + data-ng-class="{ 'search__submit--close': tabs.devices.search.length > 0 }" |
1200 | + data-ng-click="clearSearch('devices')" /> |
1201 | + </div> |
1202 | + <table> |
1203 | + <thead> |
1204 | + <tr> |
1205 | + <th class="table-col--3"> |
1206 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1207 | + <input type="checkbox" class="checkbox" data-ng-click="toggleCheckAll('devices')" data-ng-checked="tabs.devices.allViewableChecked" id="check-all-devices" data-ng-disabled="hasActionsInProgress('devices')" /> |
1208 | + <label for="check-all-devices" class="checkbox-label"></label> |
1209 | + </th> |
1210 | + <th class="table-col--24"> |
1211 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1212 | + <a href="" data-ng-click="sortTable('fqdn', 'devices')" data-ng-class="{'is-sorted': tabs.devices.predicate === 'fqdn', 'sort-asc': tabs.devices.reverse === false, 'sort-desc': tabs.devices.reverse === true}"> |
1213 | + <span title="Fully Qualified Domain Name">FQDN</span> |
1214 | + </a> |
1215 | + </th> |
1216 | + <th class="table-col--25"> |
1217 | + <a href="" data-ng-click="sortTable('primary_mac', 'devices')" data-ng-class="{'is-sorted': tabs.devices.predicate === 'primary_mac', 'sort-asc': tabs.devices.reverse === false, 'sort-desc': tabs.devices.reverse === true}"> |
1218 | + <span title="Media Access Control addresses">MAC</span> |
1219 | + </a> |
1220 | + </th> |
1221 | + <th class="table-col--15"> |
1222 | + <a href="" data-ng-click="sortTable('ip_assignment', 'devices')" data-ng-class="{'is-sorted': tabs.devices.predicate === 'ip_assignment', 'sort-asc': tabs.devices.reverse === false, 'sort-desc': tabs.devices.reverse === true}">IP Assignment</a> |
1223 | + </th> |
1224 | + <th class="table-col--20"> |
1225 | + <a href="" data-ng-click="sortTable('ip_address', 'devices')" data-ng-class="{'is-sorted': tabs.devices.predicate === 'ip_address', 'sort-asc': tabs.devices.reverse === false, 'sort-desc': tabs.devices.reverse === true}">IP Address</a> |
1226 | + </th> |
1227 | + <th class="table-col--12"> |
1228 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1229 | + <a href="" data-ng-click="sortTable('owner', 'devices')" data-ng-class="{'is-sorted': tabs.devices.predicate === 'owner', 'sort-asc': tabs.devices.reverse === false, 'sort-desc': tabs.devices.reverse === true}">Owner</a> |
1230 | + </th> |
1231 | + </tr> |
1232 | + </thead> |
1233 | + <tbody vs-repeat vs-scroll-parent="window"> |
1234 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. This really needs lots of tests. --> |
1235 | + <tr |
1236 | + data-ng-repeat="device in tabs.devices.filtered_items = (devices | nodesFilter:tabs.devices.search | orderBy:tabs.devices.predicate:tabs.devices.reverse) track by device.system_id" |
1237 | + data-ng-class="{ 'table--error': !supportsAction(device, 'devices'), selected: device.$selected }"> |
1238 | + <td class="table-col--3" aria-label="Select device"> |
1239 | + <input type="checkbox" class="checkbox" data-ng-click="toggleChecked(device, 'devices')" data-ng-checked="device.$selected" id="{$ device.fqdn $}" data-ng-disabled="hasActionsInProgress('devices')"/> |
1240 | + <label for="{$ device.fqdn $}" class="checkbox-label"></label> |
1241 | + </td> |
1242 | + <td class="table-col--24" aria-label="FQDN"> |
1243 | + <a href="#/node/device/{$ device.system_id $}">{$ device.fqdn $}</a> |
1244 | + </td> |
1245 | + <td class="table-col--25" aria-label="MAC"> |
1246 | + {$ device.primary_mac $} |
1247 | + <span class="extra-macs" data-ng-show="device.extra_macs.length">(+{$ device.extra_macs.length $})</span> |
1248 | + </td> |
1249 | + <td class="table-col--15" aria-label="IP Assignment">{$ getDeviceIPAssignment(device.ip_assignment) $}</td> |
1250 | + <td class="table-col--20" aria-label="IP Address">{$ device.ip_address $}</td> |
1251 | + <td class="table-col--12" aria-label="Owner">{$ device.owner $}</td> |
1252 | + </tr> |
1253 | + </tbody> |
1254 | + </table> |
1255 | + </div> |
1256 | + <div class="twelve-col last-col" class="ng-hide" data-ng-show="currentpage === 'controllers'"> |
1257 | + <div class="search twelve-col"> |
1258 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1259 | + <input |
1260 | + type="search" placeholder="Search controllers" class="search__input" |
1261 | + data-ng-model="tabs.controllers.search" data-ng-change="updateFilters('controllers')" |
1262 | + data-ng-class="{ error: !tabs.controllers.searchValid }" |
1263 | + data-ng-disabled="tabs.controllers.actionOption" /> |
1264 | + <input type="submit" class="search__submit" |
1265 | + data-ng-class="{ 'search__submit--close': tabs.controllers.search.length > 0 }" |
1266 | + data-ng-click="clearSearch('controllers')" /> |
1267 | + </div> |
1268 | + <table> |
1269 | + <thead> |
1270 | + <tr> |
1271 | + <th class="table-col--2"> |
1272 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1273 | + <input type="checkbox" class="checkbox" data-ng-click="toggleCheckAll('controllers')" data-ng-checked="tabs.controllers.allViewableChecked" id="check-all-controllers" data-ng-disabled="hasActionsInProgress('controllers')" /> |
1274 | + <label for="check-all-controllers" class="checkbox-label"></label> |
1275 | + </th> |
1276 | + <th class="table-col--19"> |
1277 | + <a href="" data-ng-click="sortTable('fqdn', 'controllers')" data-ng-class="{'is-sorted': tabs.controllers.predicate === 'fqdn', 'sort-asc': tabs.controllers.reverse === false, 'sort-desc': tabs.controllers.reverse === true}"> |
1278 | + <span title="Fully Qualified Domain Name">Name</span> |
1279 | + </a> |
1280 | + </th> |
1281 | + <th class="table-col--4 u-align--center"> |
1282 | + <span title="Status">Status</span> |
1283 | + </th> |
1284 | + <th class="table-col--15"> |
1285 | + <a href="" data-ng-click="sortTable('node_type_display', 'controllers')" data-ng-class="{'is-sorted': tabs.controllers.predicate === 'node_type_display', 'sort-asc': tabs.controllers.reverse === false, 'sort-desc': tabs.controllers.reverse === true}"> |
1286 | + <span title="Controller Type">Type</span> |
1287 | + </a> |
1288 | + </th> |
1289 | + <th class="table-col--10"> |
1290 | + <a href="" data-ng-click="sortTable('node_type_display', 'controllers')" data-ng-class="{'is-sorted': tabs.controllers.predicate === 'version', 'sort-asc': tabs.controllers.reverse === false, 'sort-desc': tabs.controllers.reverse === true}"> |
1291 | + <span title="Version">Version</span> |
1292 | + </a> |
1293 | + </th> |
1294 | + <th class="table-col--15"> |
1295 | + <a href="" data-ng-click="sortTable('updated', 'controllers')" data-ng-class="{'is-sorted': tabs.controllers.predicate === 'updated', 'sort-asc': tabs.controllers.reverse === false, 'sort-desc': tabs.controllers.reverse === true}">Last Image Sync</a> |
1296 | + </th> |
1297 | + <th class="table-col--15"> |
1298 | + <a href="" data-ng-click="sortTable('updated', 'controllers')" data-ng-class="{'is-sorted': tabs.controllers.predicate === 'updated', 'sort-asc': tabs.controllers.reverse === false, 'sort-desc': tabs.controllers.reverse === true}">Images Status</a> |
1299 | + </th> |
1300 | + </tr> |
1301 | + </thead> |
1302 | + <tbody vs-repeat vs-scroll-parent="window"> |
1303 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. This really needs lots of tests. --> |
1304 | + <tr |
1305 | + data-ng-repeat="controller in tabs.controllers.filtered_items = (controllers | nodesFilter:tabs.controllers.search | orderBy:tabs.controllers.predicate:tabs.controllers.reverse) track by controller.system_id" |
1306 | + data-ng-class="{ 'table--error': !supportsAction(controller, 'controllers'), selected: controller.$selected }"> |
1307 | + <td class="table-col--2" aria-label="Select controller"> |
1308 | + <input type="checkbox" class="checkbox" data-ng-click="toggleChecked(controller, 'controllers')" data-ng-checked="controller.$selected" id="{$ controller.fqdn $}" data-ng-disabled="hasActionsInProgress('controllers')"/> |
1309 | + <label for="{$ controller.fqdn $}" class="checkbox-label"></label> |
1310 | + </td> |
1311 | + <td class="table-col--19" aria-label="FQDN"> |
1312 | + <a href="#/node/controller/{$ controller.system_id $}">{$ controller.fqdn $}</a> |
1313 | + </td> |
1314 | + <td class="table-col--4 u-align--center" data-maas-controller-status="controller" data-maas-services="services" aria-label="Status"></td> |
1315 | + <td class="table-col--15" aria-label="Type">{$ controller.node_type_display $}</td> |
1316 | + <td class="table-col--10" aria-label="Version"> |
1317 | + <div data-ng-show="controller.version"> |
1318 | + {$ controller.version__short $} |
1319 | + </div> |
1320 | + <div data-ng-show="!controller.version" class="u-text--subtle"> |
1321 | + Unknown |
1322 | + <i class="icon icon--info u-margin--left-tiny tooltip" |
1323 | + aria-label="Less than 2.3.0"></i> |
1324 | + </div> |
1325 | + </td> |
1326 | + <td class="table-col--15" aria-label="Last image sync">{$ controller.last_image_sync || 'Never' $}</td> |
1327 | + <td class="table-col--15" aria-label="Image status"> |
1328 | + <maas-controller-image-status system-id="controller.system_id"></maas-controller-image-status> |
1329 | + </td> |
1330 | + </tr> |
1331 | + </tbody> |
1332 | + </table> |
1333 | + </div> |
1334 | + <div class="twelve-col last-col" class="ng-hide" data-ng-show="currentpage === 'switches'"> |
1335 | + <div class="search twelve-col"> |
1336 | + <!-- XXX rvba 2015-02-25 - Need to add e2e test. --> |
1337 | + <input |
1338 | + type="search" placeholder="Search switches" class="search__input" |
1339 | + data-ng-model="tabs.switches.search" data-ng-change="updateFilters('switches')" |
1340 | + data-ng-class="{ error: !tabs.switches.searchValid }" |
1341 | + data-ng-disabled="tabs.switches.actionOption" /> |
1342 | + <input type="submit" class="search__submit" |
1343 | + data-ng-class="{ 'search__submit--close': tabs.switches.search.length > 0 }" |
1344 | + data-ng-click="clearSearch('switches')" /> |
1345 | + </div> |
1346 | + <maas-switches-table id="switches-listing" search="tabs.switches.search" ng-disabled="hasActionsInProgress('switches')" |
1347 | + switch-has-error="!supportsAction($switch_, 'switches')" on-listing-change="onNodeListingChanged($switches, 'switches')" |
1348 | + on-check-all="toggleCheckAll('switches')" on-check="toggleChecked($switch_, 'switches')"></maas-switches-table> |
1349 | + </div> |
1350 | + </div> |
1351 | +</div> |
1352 | +>>>>>>> src/maasserver/static/partials/nodes-list.html |
1353 | diff --git a/src/maasserver/static/partials/script-results-list.html b/src/maasserver/static/partials/script-results-list.html |
1354 | index bfadd34..60ad83a 100644 |
1355 | --- a/src/maasserver/static/partials/script-results-list.html |
1356 | +++ b/src/maasserver/static/partials/script-results-list.html |
1357 | @@ -4,6 +4,7 @@ |
1358 | <p class="u-text--loading"><i class="p-icon--spinner u-animation--spin"></i> Loading...</p> |
1359 | </div> |
1360 | </div> |
1361 | +<<<<<<< src/maasserver/static/partials/script-results-list.html |
1362 | <div class="row"> |
1363 | <div data-ng-repeat="hardware_type in results"> |
1364 | <div data-ng-if="resultsLoaded && (hardware_type.results | json) != '{}'"> |
1365 | @@ -47,12 +48,59 @@ |
1366 | <button class="p-contextual-menu__link" aria-label="View previous {$ result.result_section $}" data-ng-if="!result.showing_history" data-ng-click="toggleMenu(); loadHistory(result)">View previous {$ result.result_section $}</button> |
1367 | <button class="p-contextual-menu__link" aria-label="Hide previous {$ result.result_section $}" data-ng-if="result.showing_history" data-ng-click="toggleMenu(); result.showing_results = false; result.showing_history = false">Hide previous {$ result.result_section $}</button> |
1368 | </div> |
1369 | +======= |
1370 | + <div data-ng-repeat="hardware_type in results"> |
1371 | + <div data-ng-if="resultsLoaded && (hardware_type.results | json) != '{}'"> |
1372 | + <h2 data-ng-if="hardware_type.title !== 'null'">{$ hardware_type.title $}</h2> |
1373 | + <div data-ng-repeat="(title, results) in hardware_type.results"> |
1374 | + <h3 data-ng-if="title !== 'null'">{$ title $}</h3> |
1375 | + <section class="table u-margin--bottom"> |
1376 | + <header class="table__head"> |
1377 | + <div class="table__row"> |
1378 | + <div class="table__header table-col--2 u-padding--left-none"></div> |
1379 | + <div class="table__header table-col--24">Name</div> |
1380 | + <div class="table__header table-col--22">Tags</div> |
1381 | + <div class="table__header table-col--15">Runtime</div> |
1382 | + <div class="table__header table-col--20">Date</div> |
1383 | + <div class="table__header table-col--12">Result</div> |
1384 | + <div class="table__header table-col--5 u-align--right">Actions</div> |
1385 | + </div> |
1386 | + </header> |
1387 | + <main class="table__body"> |
1388 | + <div data-ng-repeat="result in results"> |
1389 | + <div class="table__row" data-ng-class="{'is-active': result.showing_results || result.showing_history}"> |
1390 | + <div class="table__data table-col--2 u-padding--left-none" aria-label="Status"> |
1391 | + <span data-maas-script-status="script-status" data-script-status="result.status"></span> |
1392 | + </div> |
1393 | + <div class="table__data table-col--24" data-ng-click="result.showing_results = !result.showing_results" aria-label="Name"> |
1394 | + {$ result.name $} |
1395 | + <button class="icon u-margin--top-tiny u-float--right" data-ng-class="{'icon--open': !result.showing_results, 'icon--close': result.showing_results}" data-ng-if="!result.showing_history"></button> |
1396 | + </div> |
1397 | + <div class="table__data table-col--22" aria-label="Tags"><span data-ng-hide="result.showing_history">{$ result.tags $}</span></div> |
1398 | + <div class="table__data table-col--15" aria-label="Runtime"><span data-ng-hide="result.showing_history" data-maas-script-run-time="script-runtime" data-start-time="result.starttime" data-run-time="{{result.runtime}}" data-estimated-run-time="{{result.estimated_runtime}}" data-script-status="result.status"></span></div> |
1399 | + <div class="table__data table-col--20" aria-label="Date"><span data-ng-hide="result.showing_history">{$ result.updated $}</span></div> |
1400 | + <div class="table__data table-col--12" aria-label="Status"> |
1401 | + <span data-ng-hide="result.showing_history"> |
1402 | + <!-- Only link to the testing result when we've received it. This is indicated with status 2(passed), 3(failed), 4(timedout), 6(degraded), 8(failed installing)--> |
1403 | + {$ result.status_name $} <a data-ng-if="result.status === 2 || result.status === 3 || result.status === 4 || result.status === 6 || result.status === 8" href="#/node/{$ type_name $}/{$ node.system_id $}/{$ section.area $}/{$ result.id $}">View log</a> |
1404 | + </span> |
1405 | + </div> |
1406 | + <div class="table__data table-col--5 table--mobile-controls"> |
1407 | + <div class="table__controls u-align--right" toggle-ctrl> |
1408 | + <button class="table__controls-toggle" data-ng-click="toggleMenu()">View actions</button> |
1409 | + <div class="table__controls-menu ng-hide" role="menu" data-ng-show="isToggled"> |
1410 | + <button class="table__controls-action" aria-label="View metrics" data-ng-if="!result.showing_results" data-ng-click="toggleMenu(); result.showing_history = false; result.showing_results = true">View metrics</button> |
1411 | + <button class="table__controls-action" aria-label="Hide metrics" data-ng-if="result.showing_results" data-ng-click="toggleMenu(); result.showing_history = false; result.showing_results = false">Hide metrics</button> |
1412 | + <button class="table__controls-action" aria-label="View previous {$ result.result_section $}" data-ng-if="!result.showing_history" data-ng-click="toggleMenu(); result.showing_results = false; result.showing_history = true">View previous {$ result.result_section $}</button> |
1413 | + <button class="table__controls-action" aria-label="Hide previous {$ result.result_section $}" data-ng-if="result.showing_history" data-ng-click="toggleMenu(); result.showing_results = false; result.showing_history = false">Hide previous {$ result.result_section $}</button> |
1414 | +>>>>>>> src/maasserver/static/partials/script-results-list.html |
1415 | </div> |
1416 | </td> |
1417 | <td class="p-table-expanding__panel col-12" aria-label="results" data-ng-if="result.showing_results && !result.showing_history"> |
1418 | <div class="row"> |
1419 | <div class="col-12" data-ng-if="result.results.length === 0">No metrics provided</div> |
1420 | </div> |
1421 | +<<<<<<< src/maasserver/static/partials/script-results-list.html |
1422 | <div class="row" data-ng-if="result.results"> |
1423 | <dl data-ng-repeat="item in result.results"> |
1424 | <dt class="p-tooltip p-tooltip--top-center"> |
1425 | @@ -66,6 +114,34 @@ |
1426 | <td class="p-table-expanding__panel col-12" aria-label="loading history" data-ng-if="result.loading_history"> |
1427 | <div class="col-12"> |
1428 | <p class="u-text--loading"><i class="p-icon--spinner u-animation--spin"></i> Loading...</p> |
1429 | +======= |
1430 | + </div> |
1431 | + </div> |
1432 | + |
1433 | + <div class="table__dropdown" aria-label="history" data-ng-if="result.showing_history"> |
1434 | + <div class="table__row is-active"> |
1435 | + <div class="table__data table-col--100"> |
1436 | + <section class="table u-margin--bottom"> |
1437 | + <main class="table__body"> |
1438 | + <div class="table__row is-active u-border--none" data-ng-repeat="item in result.history_list"> |
1439 | + <div class="table__data table-col--2 u-padding--left-none" aria-label="Status"> |
1440 | + <span data-maas-script-status="script-status" data-script-status="item.status"></span> |
1441 | + </div> |
1442 | + <div class="table__data table-col--24" aria-label="Name">{$ result.name $}</div> |
1443 | + <div class="table__data table-col--24" aria-label="Tags">{$ result.tags $}</div> |
1444 | + <div class="table__data table-col--15" aria-label="Runtime"><span data-maas-script-run-time="script-runtime" data-start-time="item.starttime" data-run-time="{{item.runtime}}" data-estimated-run-time="{{item.estimated_runtime}}" data-script-status="item.status"></span></div> |
1445 | + <div class="table__data table-col--20" aria-label="Date">{$ item.updated $}</div> |
1446 | + <div class="table__data table-col--10" aria-label="Status"> |
1447 | + <!-- Only link to the testing result when we've received it. This is indicated with status 2(passed), 3(failed), 4(timedout), 6(degraded), 8(failed installing)--> |
1448 | + {$ item.status_name $} <a data-ng-if="item.status === 2 || item.status === 3 || item.status === 4 || item.status === 6 || item.status === 8" href="#/node/{$ type_name $}/{$ node.system_id $}/{$ section.area $}/{$ item.id $}">View log</a> |
1449 | + </div> |
1450 | + </div> |
1451 | + </main> |
1452 | + </section> |
1453 | + <p class="u-align--center u-margin--bottom"> |
1454 | + <button class="button--secondary button--inline" data-ng-click="result.showing_history = false">Hide previous {$ result.result_section $}</button> |
1455 | + </p> |
1456 | +>>>>>>> src/maasserver/static/partials/script-results-list.html |
1457 | </div> |
1458 | </div> |
1459 | <td class="p-table-expanding__panel col-12" aria-label="history" data-ng-if="result.showing_history"> |
1460 | diff --git a/src/maasserver/tests/test_bootsources.py b/src/maasserver/tests/test_bootsources.py |
1461 | index a83c9c1..3629529 100644 |
1462 | --- a/src/maasserver/tests/test_bootsources.py |
1463 | +++ b/src/maasserver/tests/test_bootsources.py |
1464 | @@ -44,7 +44,10 @@ from maasserver.testing.testcase import ( |
1465 | ) |
1466 | from maasserver.tests.test_bootresources import SimplestreamsEnvFixture |
1467 | from maasserver.utils import get_maas_user_agent |
1468 | +<<<<<<< src/maasserver/tests/test_bootsources.py |
1469 | from maastesting.djangotestcase import count_queries |
1470 | +======= |
1471 | +>>>>>>> src/maasserver/tests/test_bootsources.py |
1472 | from maastesting.matchers import MockCalledOnceWith |
1473 | from provisioningserver.config import DEFAULT_IMAGES_URL |
1474 | from provisioningserver.import_images import ( |
1475 | diff --git a/src/maasserver/triggers/tests/test_websocket_listener.py b/src/maasserver/triggers/tests/test_websocket_listener.py |
1476 | index 6297f0e..5ba464b 100644 |
1477 | --- a/src/maasserver/triggers/tests/test_websocket_listener.py |
1478 | +++ b/src/maasserver/triggers/tests/test_websocket_listener.py |
1479 | @@ -1714,8 +1714,13 @@ class TestIPRangeListener( |
1480 | self.create_subnet, {'cidr': str(network)}) |
1481 | params = { |
1482 | 'subnet': subnet, |
1483 | +<<<<<<< src/maasserver/triggers/tests/test_websocket_listener.py |
1484 | 'start_ip': IPAddress(network.first + 2), |
1485 | 'end_ip': IPAddress(network.last - 1)} |
1486 | +======= |
1487 | + 'start_ip': str(IPAddress(network.first + 2)), |
1488 | + 'end_ip': str(IPAddress(network.last - 1))} |
1489 | +>>>>>>> src/maasserver/triggers/tests/test_websocket_listener.py |
1490 | yield listener.startService() |
1491 | try: |
1492 | iprange = yield deferToDatabase( |
1493 | diff --git a/src/provisioningserver/import_images/boot_resources.py b/src/provisioningserver/import_images/boot_resources.py |
1494 | index f985df6..0a5b3c2 100644 |
1495 | --- a/src/provisioningserver/import_images/boot_resources.py |
1496 | +++ b/src/provisioningserver/import_images/boot_resources.py |
1497 | @@ -9,6 +9,7 @@ __all__ = [ |
1498 | ] |
1499 | |
1500 | from argparse import ArgumentParser |
1501 | +import copy |
1502 | import errno |
1503 | from io import StringIO |
1504 | import os |
1505 | @@ -41,6 +42,18 @@ from provisioningserver.utils.fs import ( |
1506 | read_text_file, |
1507 | tempdir, |
1508 | ) |
1509 | +<<<<<<< src/provisioningserver/import_images/boot_resources.py |
1510 | +======= |
1511 | +from provisioningserver.utils.service_monitor import ServiceActionError |
1512 | +from provisioningserver.utils.shell import ( |
1513 | + call_and_check, |
1514 | + ExternalProcessError, |
1515 | +) |
1516 | +from provisioningserver.utils.snappy import ( |
1517 | + get_snap_data_path, |
1518 | + running_in_snap, |
1519 | +) |
1520 | +>>>>>>> src/provisioningserver/import_images/boot_resources.py |
1521 | from twisted.internet.defer import inlineCallbacks |
1522 | from twisted.python.filepath import FilePath |
1523 | |
1524 | @@ -109,6 +122,54 @@ def write_snapshot_metadata(snapshot, meta_file_content): |
1525 | atomic_write(meta_file_content.encode("ascii"), meta_file, mode=0o644) |
1526 | |
1527 | |
1528 | +<<<<<<< src/provisioningserver/import_images/boot_resources.py |
1529 | +======= |
1530 | +def write_targets_conf(snapshot): |
1531 | + """Write "maas.tgt" file.""" |
1532 | + targets_conf = os.path.join(snapshot, 'maas.tgt') |
1533 | + targets_conf_content = compose_targets_conf(snapshot) |
1534 | + atomic_write(targets_conf_content, targets_conf, mode=0o644) |
1535 | + |
1536 | + |
1537 | +def update_targets_conf(snapshot): |
1538 | + """Runs tgt-admin to update the new targets from "maas.tgt".""" |
1539 | + # Ensure that tgt is running before tgt-admin is used. |
1540 | + try: |
1541 | + service_monitor.ensureService("tgt").wait(30) |
1542 | + except ServiceActionError: |
1543 | + msg = "Unable to start tgt" |
1544 | + try_send_rack_event(EVENT_TYPES.RACK_IMPORT_WARNING, msg) |
1545 | + maaslog.warning(msg) |
1546 | + return |
1547 | + |
1548 | + # Update the tgt config. |
1549 | + targets_conf = os.path.join(snapshot, 'maas.tgt') |
1550 | + |
1551 | + # The targets_conf may not exist in the event the BootSource is broken |
1552 | + # and images havn't been imported yet. This fixes LP:1655721 |
1553 | + if not os.path.exists(targets_conf): |
1554 | + return |
1555 | + |
1556 | + try: |
1557 | + env = copy.deepcopy(os.environ) |
1558 | + # LP:1718706 - When TGT is run in a snap the socket is stored in the |
1559 | + # SNAP_DATA path. Define it before calling tgt-admin otherwise the |
1560 | + # standard path is used and the call will fail. |
1561 | + if running_in_snap(): |
1562 | + env['TGT_IPC_SOCKET'] = os.path.join( |
1563 | + get_snap_data_path(), 'tgtd-socket') |
1564 | + call_and_check(sudo([ |
1565 | + get_path('/usr/sbin/tgt-admin'), |
1566 | + '--conf', targets_conf, |
1567 | + '--update', 'ALL', |
1568 | + ]), env=env) |
1569 | + except ExternalProcessError as e: |
1570 | + msg = "Unable to update TGT config: %s" % e |
1571 | + try_send_rack_event(EVENT_TYPES.RACK_IMPORT_WARNING, msg) |
1572 | + maaslog.warning(msg) |
1573 | + |
1574 | + |
1575 | +>>>>>>> src/provisioningserver/import_images/boot_resources.py |
1576 | def read_sources(sources_yaml): |
1577 | """Read boot resources config file. |
1578 | |
1579 | diff --git a/src/provisioningserver/import_images/tests/test_boot_resources.py b/src/provisioningserver/import_images/tests/test_boot_resources.py |
1580 | index 28635e7..31fa955 100644 |
1581 | --- a/src/provisioningserver/import_images/tests/test_boot_resources.py |
1582 | +++ b/src/provisioningserver/import_images/tests/test_boot_resources.py |
1583 | @@ -43,7 +43,18 @@ from provisioningserver.testing.config import ( |
1584 | BootSourcesFixture, |
1585 | ClusterConfigurationFixture, |
1586 | ) |
1587 | +<<<<<<< src/provisioningserver/import_images/tests/test_boot_resources.py |
1588 | from provisioningserver.utils.fs import write_text_file |
1589 | +======= |
1590 | +from provisioningserver.utils.fs import ( |
1591 | + tempdir, |
1592 | + write_text_file, |
1593 | +) |
1594 | +from provisioningserver.utils.service_monitor import ServiceActionError |
1595 | +from provisioningserver.utils.shell import ExternalProcessError |
1596 | +from testtools.content import Content |
1597 | +from testtools.content_type import UTF8_TEXT |
1598 | +>>>>>>> src/provisioningserver/import_images/tests/test_boot_resources.py |
1599 | from testtools.matchers import ( |
1600 | DirExists, |
1601 | FileExists, |
1602 | @@ -477,6 +488,87 @@ class TestMain(MAASTestCase): |
1603 | boot_resources.NoConfigFile, |
1604 | boot_resources.main, self.make_args(sources="", sources_file="")) |
1605 | |
1606 | +<<<<<<< src/provisioningserver/import_images/tests/test_boot_resources.py |
1607 | +======= |
1608 | + def test_update_targets_conf_ensures_tgt_service(self): |
1609 | + mock_ensureService = self.patch( |
1610 | + boot_resources.service_monitor, "ensureService") |
1611 | + self.patch(boot_resources, "call_and_check") |
1612 | + boot_resources.update_targets_conf(factory.make_name("snapshot")) |
1613 | + self.assertThat(mock_ensureService, MockCalledOnceWith("tgt")) |
1614 | + |
1615 | + def test_update_targets_conf_logs_tgt_service_check_error(self): |
1616 | + # Regression test for LP:1735025 |
1617 | + mock_ensureService = self.patch( |
1618 | + boot_resources.service_monitor, "ensureService") |
1619 | + mock_ensureService.side_effect = ServiceActionError() |
1620 | + mock_try_send_rack_event = self.patch( |
1621 | + boot_resources, 'try_send_rack_event') |
1622 | + mock_maaslog = self.patch(boot_resources.maaslog, 'warning') |
1623 | + boot_resources.update_targets_conf(factory.make_name("snapshot")) |
1624 | + self.assertThat(mock_try_send_rack_event, MockCalledOnce()) |
1625 | + self.assertThat(mock_maaslog, MockCalledOnce()) |
1626 | + |
1627 | + def test_update_targets_conf_logs_error(self): |
1628 | + self.patch(boot_resources.service_monitor, "ensureService") |
1629 | + mock_try_send_rack_event = self.patch( |
1630 | + boot_resources, 'try_send_rack_event') |
1631 | + mock_maaslog = self.patch(boot_resources.maaslog, 'warning') |
1632 | + self.patch(boot_resources.os.path, 'exists').return_value = True |
1633 | + self.patch(boot_resources, 'call_and_check').side_effect = ( |
1634 | + ExternalProcessError( |
1635 | + returncode=2, cmd=('tgt-admin',), output='error')) |
1636 | + snapshot = factory.make_name("snapshot") |
1637 | + boot_resources.update_targets_conf(snapshot) |
1638 | + self.assertThat(mock_try_send_rack_event, MockCalledOnce()) |
1639 | + self.assertThat(mock_maaslog, MockCalledOnce()) |
1640 | + self.assertThat( |
1641 | + boot_resources.call_and_check, |
1642 | + MockCalledOnceWith([ |
1643 | + 'sudo', '-n', '/usr/sbin/tgt-admin', |
1644 | + '--conf', os.path.join(snapshot, 'maas.tgt'), |
1645 | + '--update', 'ALL'], env=os.environ)) |
1646 | + |
1647 | + def test_update_targets_only_runs_when_conf_exists(self): |
1648 | + # Regression test for LP:1655721 |
1649 | + temp_dir = self.useFixture(TempDirectory()).path |
1650 | + self.useFixture(ClusterConfigurationFixture(tftp_root=temp_dir)) |
1651 | + mock_ensureService = self.patch( |
1652 | + boot_resources.service_monitor, "ensureService") |
1653 | + mock_call_and_check = self.patch(boot_resources, "call_and_check") |
1654 | + mock_path_exists = self.patch(boot_resources.os.path, 'exists') |
1655 | + mock_path_exists.return_value = False |
1656 | + boot_resources.update_targets_conf(temp_dir) |
1657 | + self.assertThat(mock_ensureService, MockCalledOnceWith("tgt")) |
1658 | + self.assertThat( |
1659 | + mock_path_exists, |
1660 | + MockCalledOnceWith(os.path.join(temp_dir, 'maas.tgt'))) |
1661 | + self.assertThat(mock_call_and_check, MockNotCalled()) |
1662 | + |
1663 | + def test_update_targets_conf_sets_env_var_in_snap(self): |
1664 | + # Regression test for LP:1718706 |
1665 | + self.patch(boot_resources.service_monitor, "ensureService") |
1666 | + self.patch(boot_resources.os.path, 'exists').return_value = True |
1667 | + self.patch(boot_resources, 'call_and_check') |
1668 | + self.patch(boot_resources, 'running_in_snap').return_value = True |
1669 | + snap_data_path = factory.make_name('snap_data_path') |
1670 | + self.patch(boot_resources, 'get_snap_data_path').return_value = ( |
1671 | + snap_data_path) |
1672 | + snapshot = factory.make_name("snapshot") |
1673 | + boot_resources.update_targets_conf(snapshot) |
1674 | + self.assertThat( |
1675 | + boot_resources.call_and_check, |
1676 | + MockCalledOnceWith([ |
1677 | + 'sudo', '-n', '/usr/sbin/tgt-admin', |
1678 | + '--conf', os.path.join(snapshot, 'maas.tgt'), |
1679 | + '--update', 'ALL' |
1680 | + ], env={ |
1681 | + 'TGT_IPC_SOCKET': os.path.join( |
1682 | + snap_data_path, 'tgtd-socket'), |
1683 | + **os.environ, |
1684 | + })) |
1685 | + |
1686 | +>>>>>>> src/provisioningserver/import_images/tests/test_boot_resources.py |
1687 | |
1688 | class TestMetaContains(MAASTestCase): |
1689 | """Tests for the `meta_contains` function.""" |
1690 | diff --git a/src/provisioningserver/import_images/tests/test_download_resources.py b/src/provisioningserver/import_images/tests/test_download_resources.py |
1691 | index 9f40e29..81bc3c1 100644 |
1692 | --- a/src/provisioningserver/import_images/tests/test_download_resources.py |
1693 | +++ b/src/provisioningserver/import_images/tests/test_download_resources.py |
1694 | @@ -359,6 +359,41 @@ class TestRepoWriter(MAASTestCase): |
1695 | label=product['label'], subarches={'ga-16.04', 'generic'}, |
1696 | bootloader_type=None)) |
1697 | |
1698 | +<<<<<<< src/provisioningserver/import_images/tests/test_download_resources.py |
1699 | + def test_inserts_no_generic_link_for_generic_non_ga_kflavor(self): |
1700 | + # Regression test for LP:1749246 |
1701 | +======= |
1702 | + def test_inserts_generic_link_for_generic_ga_kflavor(self): |
1703 | +>>>>>>> src/provisioningserver/import_images/tests/test_download_resources.py |
1704 | + product_mapping = ProductMapping() |
1705 | + product = self.make_product(subarch='hwe-16.04', kflavor='generic') |
1706 | + product_mapping.add(product, 'hwe-16.04') |
1707 | + repo_writer = download_resources.RepoWriter( |
1708 | + None, None, product_mapping) |
1709 | + self.patch( |
1710 | + download_resources, 'products_exdata').return_value = product |
1711 | + # Prevent MAAS from trying to actually write the file. |
1712 | + mock_insert_file = self.patch(download_resources, 'insert_file') |
1713 | + mock_link_resources = self.patch(download_resources, 'link_resources') |
1714 | + # We only need to provide the product as the other fields are only used |
1715 | + # when writing the actual files to disk. |
1716 | + repo_writer.insert_item(product, None, None, None, None) |
1717 | + # None is used for the store and the content source as we're not |
1718 | + # writing anything to disk. |
1719 | + self.assertThat( |
1720 | + mock_insert_file, |
1721 | + MockCalledOnceWith( |
1722 | + None, os.path.basename(product['path']), product['sha256'], |
1723 | + {'sha256': product['sha256']}, product['size'], None)) |
1724 | + # links are mocked out by the mock_insert_file above. |
1725 | + self.assertThat( |
1726 | + mock_link_resources, |
1727 | + MockCalledOnceWith( |
1728 | + snapshot_path=None, links=mock.ANY, osystem=product['os'], |
1729 | + arch=product['arch'], release=product['release'], |
1730 | + label=product['label'], subarches={'hwe-16.04'}, |
1731 | + bootloader_type=None)) |
1732 | + |
1733 | def test_inserts_no_generic_link_for_generic_non_ga_kflavor(self): |
1734 | # Regression test for LP:1749246 |
1735 | product_mapping = ProductMapping() |
1736 | diff --git a/src/provisioningserver/utils/tests/test_network.py b/src/provisioningserver/utils/tests/test_network.py |
1737 | index bda51e1..3b3c6b0 100644 |
1738 | --- a/src/provisioningserver/utils/tests/test_network.py |
1739 | +++ b/src/provisioningserver/utils/tests/test_network.py |
1740 | @@ -83,7 +83,10 @@ from provisioningserver.utils.network import ( |
1741 | resolves_to_loopback_address, |
1742 | reverseResolve, |
1743 | ) |
1744 | +<<<<<<< src/provisioningserver/utils/tests/test_network.py |
1745 | from provisioningserver.utils.shell import get_env_with_locale |
1746 | +======= |
1747 | +>>>>>>> src/provisioningserver/utils/tests/test_network.py |
1748 | from testtools import ExpectedException |
1749 | from testtools.matchers import ( |
1750 | Contains, |
1751 | diff --git a/utilities/release-build b/utilities/release-build |
1752 | index 3c0a5af..49f32cc 100755 |
1753 | --- a/utilities/release-build |
1754 | +++ b/utilities/release-build |
1755 | @@ -15,7 +15,7 @@ usage () { |
1756 | exit 1 |
1757 | } |
1758 | |
1759 | -DEFAULT_DISTROS="$(ubuntu-distro-info --supported | grep -v trusty)" |
1760 | +DEFAULT_DISTROS="$(ubuntu-distro-info --supported | grep -v trusty | grep -v bionic)" |
1761 | PACKAGE_DISTROS="" |
1762 | KEEP_CHANGELOG=0 |
1763 | |
1764 | @@ -61,7 +61,7 @@ dch -a "" --release-heuristic log --nomultimaint |
1765 | PKG=$(head -n1 debian/changelog | awk '{print $1}') |
1766 | MAJOR_VER=$(head -n 1 debian/changelog | sed 's/^.*(//' | sed 's/).*//' | sed 's/-.*//') |
1767 | REV_COUNT=$(git rev-list --count $COMMIT) |
1768 | -REV_SHORT=$(git rev-parse --short $COMMIT) |
1769 | +REV_SHORT=$(git rev-parse --short=7 $COMMIT) |
1770 | FULL_VER="$MAJOR_VER-$REV_COUNT-g$REV_SHORT" |
1771 | TARBALL="maas_$FULL_VER.orig.tar.gz" |
1772 | |
1773 | @@ -89,3 +89,12 @@ if echo "$PACKAGE_DISTROS" | grep -q "bionic"; then |
1774 | sed -i "s/) UNRELEASED;/~18.04.1) bionic;/i" debian/changelog |
1775 | debuild -S -sa |
1776 | fi |
1777 | +<<<<<<< utilities/release-build |
1778 | +======= |
1779 | + |
1780 | +if echo "$PACKAGE_DISTROS" | grep -q "artful"; then |
1781 | + cp $ROOTDIR/debian/changelog debian/changelog |
1782 | + sed -i "s/) UNRELEASED;/~17.10.1) artful;/" debian/changelog |
1783 | + debuild -S |
1784 | +fi |
1785 | +>>>>>>> utilities/release-build |