Set target raid configuration on a node

Adds menu option to set basic target raid configuration.

Unit tests to be added in a follow-up patch.

Change-Id: I2886e5ca4e5757209ff6da5f9162f874f648e135
Partial-Bug: #1648553
This commit is contained in:
Ramamani Yeleswarapu 2017-07-12 22:53:24 -07:00
parent 791eecc71e
commit 5b9c6f61b7
9 changed files with 325 additions and 0 deletions

View File

@ -384,3 +384,18 @@ def portgroup_get_ports(request, portgroup_id):
http://docs.openstack.org/developer/python-ironicclient/api/ironicclient.v1.portgroup.html#ironicclient.v1.portgroup.PortgroupManager.list_ports
"""
return ironicclient(request).portgroup.list_ports(portgroup_id)
def node_set_raid_config(request, node_id, target_raid_config):
"""Set target raid configuration for a given node.
:param request: HTTP request.
:param node_id: The UUID or name of the node.
:param target_raid_config: Target raid configuration.
:return: Node.
http://docs.openstack.org/developer/python-ironicclient/api/ironicclient.v1.node.html#ironicclient.v1.node.NodeManager.set_target_raid_config
"""
return ironicclient(request).node.set_target_raid_config(
node_id,
target_raid_config)

View File

@ -416,3 +416,23 @@ class PortgroupPorts(generic.View):
return {
'ports': [i.to_dict() for i in ports]
}
@urls.register
class RaidConfig(generic.View):
url_regex = r'ironic/nodes/(?P<node_id>{})/states/raid$'. \
format(LOGICAL_NAME_PATTERN)
@rest_utils.ajax(data_required=True)
def put(self, request, node_id):
"""Set the RAID configuration for a specified node.
:param request: HTTP request.
:param node_id: Node name or node uuid
:return: None
"""
return ironic.node_set_raid_config(
request,
node_id,
request.DATA.get('target_raid_config'))

View File

@ -57,6 +57,7 @@
nodeSetMaintenance: nodeSetMaintenance,
nodeSetBootDevice: nodeSetBootDevice,
nodeSetPowerState: nodeSetPowerState,
nodeSetRaidConfig: nodeSetRaidConfig,
setNodeProvisionState: setNodeProvisionState,
updateNode: updateNode,
updatePort: updatePort,
@ -288,6 +289,31 @@
});
}
/**
* @description Set the target raid configuration of a node
*
* http://developer.openstack.org/api-ref/baremetal/#set-target-raid-config
*
* @param {string} nodeId UUID or logical name of a node.
* @param {string} raidConfig - Target raid configuration.
* @return {promise} Promise
*/
function nodeSetRaidConfig(nodeId, raidConfig) {
return apiService.put('/api/ironic/nodes/' + nodeId + '/states/raid',
{target_raid_config: raidConfig})
.then(function() {
toastService.add('success',
gettext('Refresh page.'));
})
.catch(function(response) {
var msg = interpolate(gettext('Unable to set raid config: %s'),
[response.data],
false);
toastService.add('error', msg);
return $q.reject(msg);
});
}
/**
* @description Set the target provision state of the node.
*

View File

@ -37,6 +37,7 @@
'nodeSetBootDevice',
'nodeSetConsoleMode',
'nodeSetPowerState',
'nodeSetRaidConfig',
'nodeSetMaintenance',
'setNodeProvisionState',
'updateNode',

View File

@ -36,6 +36,7 @@
'horizon.dashboard.admin.ironic.edit-portgroup.service',
'horizon.dashboard.admin.ironic.maintenance.service',
'horizon.dashboard.admin.ironic.bootdevice.service',
'horizon.dashboard.admin.ironic.raidconfig.service',
'horizon.dashboard.admin.ironic.node-state-transition.service',
'horizon.dashboard.admin.ironic.validUuidPattern'
];
@ -53,6 +54,7 @@
editPortgroupService,
maintenanceService,
bootDeviceService,
raidConfigService,
nodeStateTransitionService,
validUuidPattern) {
var ctrl = this;
@ -64,6 +66,7 @@
ctrl.actions = actions;
ctrl.maintenanceService = maintenanceService;
ctrl.bootDeviceService = bootDeviceService;
ctrl.raidConfigService = raidConfigService;
ctrl.sections = [
{

View File

@ -45,6 +45,14 @@
<span>{$ "Set boot device" | translate $}</span>
</a>
</li>
<li role="presentation">
<a role="menuitem"
ng-click="ctrl.raidConfigService.setRaidConfig(ctrl.node);
$event.stopPropagation();
$event.preventDefault()">
<span>{$ "Set RAID configuration" | translate $}</span>
</a>
</li>
<li role="presentation"
ng-repeat="transition in ctrl.nodeStateTransitions">
<a role="menuitem"

View File

@ -0,0 +1,103 @@
/*
* Copyright 2017 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function() {
'use strict';
/**
* @ngdoc controller
* @name horizon.dashboard.admin.ironic:RaidConfigController
* @ngController
*
* @description
* Controller used to prompt the user for information associated with
* setting the target raid configuration of a node
*/
angular
.module('horizon.dashboard.admin.ironic')
.controller('RaidConfigController', RaidConfigController);
RaidConfigController.$inject = [
'$uibModalInstance',
'horizon.dashboard.admin.ironic.form-field.service',
'horizon.app.core.openstack-service-api.ironic',
'node'
];
function RaidConfigController($uibModalInstance,
formFieldService,
ironic,
node) {
var ctrl = this;
ctrl.modalTitle = gettext("Set RAID Configuration");
ctrl.target_raid_config = null;
ctrl.logicalDisks = [];
ctrl.logicalDisksSrc = [];
ironic.getNode(node.uuid).then(function() {
ctrl.logicalDisksSrc = angular.copy(node.raid_config.logical_disks);
});
ctrl.size_gb = new formFieldService.FormField({
id: "size_gb",
title: gettext("Size GB"),
desc: gettext("Specifies logical disk size in GiB. Required."),
pattern: new RegExp('^\\d+$'),
value: null,
required: true,
autoFocus: true
});
ctrl.raid_level = new formFieldService.FormField({
type: "radio",
id: "raid_level",
title: gettext("RAID Level"),
desc: gettext("Specifies RAID Level."),
options: ['JBOD', '0', '1', '2', '5', '6', '1+0', '5+0', '6+0'],
value: '0'});
ctrl.root_volume = new formFieldService.FormField({
type: "radio",
id: "root_volume",
title: gettext("Root Volume."),
desc: gettext(
"Specifies whether root volume or not."),
options: ['True', 'False'],
value: 'False'});
ctrl.addLogicalDisk = function() {
ctrl.logicalDisks.push({raid_level: ctrl.raid_level.value,
size_gb: Number(ctrl.size_gb.value),
is_root_volume: ctrl.root_volume.value === 'True'});
};
ctrl.deleteLogicalDisk = function(disk) {
var index = ctrl.logicalDisks.indexOf(disk);
if (index !== -1) {
ctrl.logicalDisks.splice(index, 1);
}
};
ctrl.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
ctrl.setTargetRaidConfig = function() {
$uibModalInstance.close({target_raid_config: {logical_disks: ctrl.logicalDisks}});
};
}
})();

View File

@ -0,0 +1,81 @@
<div class="modal-header" modal-draggable>
<button type="button"
class="close"
ng-click="$dismiss()"
aria-hidden="true"
aria-label="Close">
<span aria-hidden="true" class="fa fa-times"></span>
</button>
<h3 class="modal-title">{$ ::ctrl.modalTitle $}</h3>
</div>
<div class="modal-body">
<form id="SetTargetRaidConfigForm" name="SetTargetRaidConfigForm" class="well well-sm">
<!-- raid config -->
<form-field field="ctrl.size_gb" form="SetTargetRaidConfigForm"></form-field>
<form-field field="ctrl.raid_level" form="SetTargetRaidConfigForm"></form-field>
<form-field field="ctrl.root_volume"
form="SetTargetRaidConfigForm"></form-field>
<button class="btn btn-primary"
type="button"
ng-click="ctrl.addLogicalDisk()"
ng-disabled="SetTargetRaidConfigForm.$invalid || ctrl.size_gb.value < 1"
translate>
Add Logical Disk
</button>
</form>
<!-- Logical Disks -->
<form id="LogicalDisksForm" name="LogicalDisksForm">
<div>
<table hz-table ng-cloak
st-table="ctrl.logicalDisks"
st-safe-src="ctrl.logicalDisksSrc"
class="table table-rsp table-detail">
<thead>
<tr>
<th translate class="rsp-p1" style="white-space:nowrap">
Size GB
</th>
<th translate class="rsp-p1" style="white-space:nowrap">
RAID Level
</th>
<th translate class="rsp-p1" style="width:100%">
Root Volume
</th>
<th translate class="actions_column">
Action
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="disk in ctrl.logicalDisks">
<td class="rsp-p1">{$ disk.size_gb $}</td>
<td class="rsp-p1">{$ disk.raid_level $}</td>
<td class="rsp-p1">{$ disk.is_root_volume $}</td>
<td>
<a class="btn btn-default"
ng-click="ctrl.deleteLogicalDisk(disk)">
<span class="fa fa-minus"> </span>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
<!--modal footer-->
<div class="modal-footer">
<button class="btn btn-default secondary"
type="button"
ng-click="ctrl.cancel()"
translate>
Cancel
</button>
<button class="btn btn-primary"
type="button"
ng-click="ctrl.setTargetRaidConfig()"
translate>
Set Target RAID Config
</button>
</div>

View File

@ -0,0 +1,68 @@
/*
* Copyright 2017 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function() {
'use strict';
/*
* @ngdoc service
* @name horizon.dashboard.admin.ironic.raidconfig.service
* @description Service for setting the target raid configuration of a node
*/
angular
.module('horizon.dashboard.admin.ironic')
.factory('horizon.dashboard.admin.ironic.raidconfig.service',
raidConfigService);
raidConfigService.$inject = [
'$uibModal',
'horizon.dashboard.admin.ironic.basePath',
'horizon.app.core.openstack-service-api.ironic'
];
function raidConfigService($uibModal, basePath, ironic) {
var service = {
setRaidConfig: setRaidConfig
};
return service;
/*
* @description Set the target raid configuration of a specified node
*
* @param {object} node - node object
* @return {promise}
*/
function setRaidConfig(node) {
var promise;
var options = {
controller: "RaidConfigController as ctrl",
backdrop: 'static',
resolve: {
node: function() {
return node;
}
},
templateUrl: basePath + '/raidconfig/raidconfig.html'
};
promise = $uibModal.open(options).result.then(
function(result) {
return ironic.nodeSetRaidConfig(node.uuid,
result.target_raid_config);
});
return promise;
}
}
})();