Merge "Extend support for the Ironic state machine"

This commit is contained in:
Jenkins 2016-12-30 10:13:34 +00:00 committed by Gerrit Code Review
commit b7a3844479
7 changed files with 164 additions and 87 deletions

View File

@ -18,41 +18,6 @@
(function () {
'use strict';
var provisionStateTransitionMatrix = {
enroll: {
manageable: 'manage'
},
manageable: {
active: 'adopt',
available: 'provide'
},
active: {
available: 'deleted'
},
available: {
active: 'active',
manageable: 'manage'
},
'adopt failed': {
manageable: 'manage',
active: 'adopt'
},
'inspect failed': {
manageable: 'manage'
},
'clean failed': {
manageable: 'manage'
},
'deploy failed': {
active: 'active',
manageable: 'deleted'
},
error: {
active: 'rebuild',
manageable: 'deleted'
}
};
angular
.module('horizon.app.core.openstack-service-api')
.factory('horizon.app.core.openstack-service-api.ironic', ironicAPI);
@ -82,7 +47,6 @@
getNode: getNode,
getNodes: getNodes,
getPortsWithNode: getPortsWithNode,
getProvisionStateTransitionVerb: getProvisionStateTransitionVerb,
powerOffNode: powerOffNode,
powerOnNode: powerOnNode,
putNodeInMaintenanceMode: putNodeInMaintenanceMode,
@ -447,25 +411,6 @@
toastService.add('error', interpolate(msg, [reason], false));
});
}
/**
* @description Get the verb used to transition a node from a source
* provision-state to a target provision-state
*
* @param {string} sourceState source state
* @param {string} targetState target state
* @return {string} Verb used to transition from source to target state.
* null if the requested transition is not allowed.
*/
function getProvisionStateTransitionVerb(sourceState, targetState) {
var verb = null;
if (angular.isDefined(provisionStateTransitionMatrix[sourceState]) &&
angular.isDefined(
provisionStateTransitionMatrix[sourceState][targetState])) {
verb = provisionStateTransitionMatrix[sourceState][targetState];
}
return verb;
}
}
}());

View File

@ -75,7 +75,6 @@
deleteNodes: deleteNodes,
deletePort: deletePort,
deletePorts: deletePorts,
getProvisionStateTransitionVerb: getProvisionStateTransitionVerb,
powerOn: powerOn,
powerOff: powerOff,
powerOnAll: powerOnNodes,
@ -207,10 +206,6 @@
ironic.setNodeProvisionState(args.node.uuid, args.verb);
}
function getProvisionStateTransitionVerb(sourceState, targetState) {
return ironic.getProvisionStateTransitionVerb(sourceState, targetState);
}
function createPort(node) {
return createPortService.modal(node);
}

View File

@ -33,6 +33,7 @@
'horizon.dashboard.admin.ironic.basePath',
'horizon.dashboard.admin.ironic.edit-node.service',
'horizon.dashboard.admin.ironic.maintenance.service',
'horizon.dashboard.admin.ironic.node-state-transition.service',
'horizon.dashboard.admin.ironic.validUuidPattern'
];
@ -46,6 +47,7 @@
basePath,
editNodeService,
maintenanceService,
nodeStateTransitionService,
validUuidPattern) {
var ctrl = this;
var path = basePath + '/node-details/sections/';
@ -67,6 +69,7 @@
ctrl.node = null;
ctrl.nodeValidation = {};
ctrl.nodeStateTransitions = [];
ctrl.ports = [];
ctrl.portsSrc = [];
ctrl.basePath = basePath;
@ -121,6 +124,8 @@
var uuid = $location.absUrl().match(pattern)[2];
retrieveNode(uuid).then(function () {
ctrl.nodeStateTransitions =
nodeStateTransitionService.getTransitions(ctrl.node.provision_state);
retrievePorts(uuid);
ironic.validateNode(uuid).then(function(response) {
ctrl.nodeValidation = response.data;

View File

@ -32,18 +32,17 @@
disabled="!ctrl.node.maintenance">
{$ 'Maintenance off' | translate $}
</action>
<action ng-repeat="targetState in ['manageable', 'available', 'active']"
button-type="menu-item"
callback="ctrl.actions.setProvisionState"
item="{node: ctrl.node,
verb: ctrl.actions.getProvisionStateTransitionVerb(
ctrl.node.provision_state,
targetState)}"
disabled="ctrl.actions.getProvisionStateTransitionVerb(
ctrl.node.provision_state,
targetState) === null">
{$ ('Move to ' | translate) + targetState $}
</action>
<li role="presentation"
ng-repeat="transition in ctrl.nodeStateTransitions">
<a role="menuitem"
ng-click="ctrl.actions.setProvisionState({
node: ctrl.node,
verb: transition.verb});
$event.stopPropagation();
$event.preventDefault()">
<span>{$ transition.label $}</span>
</a>
</li>
<action button-type="menu-item"
callback="ctrl.editNode">
{$ 'Edit' | translate $}

View File

@ -31,7 +31,8 @@
'horizon.dashboard.admin.ironic.actions',
'horizon.dashboard.admin.ironic.maintenance.service',
'horizon.dashboard.admin.ironic.enroll-node.service',
'horizon.dashboard.admin.ironic.edit-node.service'
'horizon.dashboard.admin.ironic.edit-node.service',
'horizon.dashboard.admin.ironic.node-state-transition.service'
];
function IronicNodeListController($scope,
@ -43,7 +44,8 @@
actions,
maintenanceService,
enrollNodeService,
editNodeService) {
editNodeService,
nodeStateTransitionService) {
var ctrl = this;
ctrl.nodes = [];
@ -57,6 +59,7 @@
ctrl.enrollNode = enrollNode;
ctrl.editNode = editNode;
ctrl.refresh = refresh;
ctrl.getNodeStateTransitions = getNodeStateTransitions;
/**
* Filtering - client-side MagicSearch
@ -188,6 +191,10 @@
function refresh() {
init();
}
function getNodeStateTransitions(node) {
return nodeStateTransitionService.getTransitions(node.provision_state);
}
}
})();

View File

@ -172,19 +172,17 @@
item="node">
{$ 'Create port' | translate $}
</action>
<action ng-repeat="targetState in
['manageable', 'available', 'active']"
button-type="menu-item"
callback="table.actions.setProvisionState"
item="{node: node,
verb: table.actions.getProvisionStateTransitionVerb(
node.provision_state,
targetState)}"
disabled="table.actions.getProvisionStateTransitionVerb(
node.provision_state,
targetState) === null">
{$ ('Move to ' | translate) + targetState $}
</action>
<li role="presentation"
ng-repeat="transition in table.getNodeStateTransitions(node)">
<a role="menuitem"
ng-click="table.actions.setProvisionState({
node: node,
verb: transition.verb});
$event.stopPropagation();
$event.preventDefault()">
<span>{$ transition.label $}</span>
</a>
</li>
<action button-type="menu-item"
callback="table.editNode"
item="node">

View File

@ -0,0 +1,128 @@
/*
* © Copyright 2016 Cray Inc.
*
* 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';
angular
.module('horizon.dashboard.admin.ironic')
.service('horizon.dashboard.admin.ironic.node-state-transition.service',
nodeStateTransitionService);
nodeStateTransitionService.$inject = [];
/**
* @description Utility service for working with the node state machine
* @return {void}
*/
function nodeStateTransitionService() {
// Dictionary of NodeState objects indexed by state name
var states = {};
// Create node state objects
angular.forEach(['enroll',
'manageable',
'active',
'available',
'adopt failed',
'clean failed',
'inspect failed',
'clean wait',
'deploy failed',
'error'],
function(state) {
states[state] = new NodeState(state);
});
// Add state transitions
states.enroll.addTransition('manageable', 'manage');
states.manageable.addTransition('active', 'adopt');
states.manageable.addTransition('available', 'provide');
states.active.addTransition('available', 'deleted');
states.available.addTransition('active', 'active');
states.available.addTransition('manageable', 'manage');
states['adopt failed'].addTransition('manageable', 'manage');
states['adopt failed'].addTransition('active', 'adopt');
states['inspect failed'].addTransition('manageable', 'manage');
states['clean failed'].addTransition('manageable', 'manage');
states['deploy failed'].addTransition('active', 'active');
states['deploy failed'].addTransition('manageable', 'deleted');
states.error.addTransition('active', 'rebuild');
states.error.addTransition('manageable', 'deleted');
/**
* @description Class constructor for NodeState object.
* A NodeState maintains a set of transitions to other states.
*
* @param {name} name Name of state
* @return {void}
*/
function NodeState(name) {
this.name = name;
this.transitions = {};
/**
* @description Add a transition to a specified target state.
*
* @param {string} target Name of target state
* @param {string} verb Verb used to accomplish transition
* @param {string} label Description of the transition. Optional.
* @return {void}
*/
this.addTransition = function(target, verb, label) {
this.transitions[target] =
{source: this.name,
target: target,
verb: verb,
label: angular.isDefined(label)
? label : gettext("Move to") + " " + target};
};
/**
* @description Get the transition object associated with a
* specified target state.
*
* @param {string} targetState Name of target state
* @return {object} Transition object. A value of null
* is returned if a transition does not exist.
*/
this.getTransition = function(targetState) {
return this.transitions.hasOwnProperty(targetState)
? this.transitions[targetState] : null;
};
}
this.getTransitions = function(sourceState) {
var transitions = [];
if (states.hasOwnProperty(sourceState)) {
angular.forEach(states[sourceState].transitions,
function(transition) {
transitions.push(transition);
});
}
return transitions;
};
}
}());