diff --git a/ironic_ui/static/dashboard/admin/ironic/ironic.service.js b/ironic_ui/static/dashboard/admin/ironic/ironic.service.js index 83eaaf9c..12198724 100755 --- a/ironic_ui/static/dashboard/admin/ironic/ironic.service.js +++ b/ironic_ui/static/dashboard/admin/ironic/ironic.service.js @@ -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; - } } }()); diff --git a/ironic_ui/static/dashboard/admin/ironic/node-actions.service.js b/ironic_ui/static/dashboard/admin/ironic/node-actions.service.js index d90af358..34ad4a3c 100755 --- a/ironic_ui/static/dashboard/admin/ironic/node-actions.service.js +++ b/ironic_ui/static/dashboard/admin/ironic/node-actions.service.js @@ -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); } diff --git a/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.controller.js b/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.controller.js index 00acd79f..d1d3e5ab 100755 --- a/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.controller.js +++ b/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.controller.js @@ -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; diff --git a/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.html b/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.html index 5dcb3b0b..473403ac 100644 --- a/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.html +++ b/ironic_ui/static/dashboard/admin/ironic/node-details/node-details.html @@ -32,18 +32,17 @@ disabled="!ctrl.node.maintenance"> {$ 'Maintenance off' | translate $} - - {$ ('Move to ' | translate) + targetState $} - +
  • + + {$ transition.label $} + +
  • {$ 'Edit' | translate $} diff --git a/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.controller.js b/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.controller.js index 1b522833..a130cc98 100755 --- a/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.controller.js +++ b/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.controller.js @@ -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); + } } })(); diff --git a/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.html b/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.html index 91abbd37..1732a2b5 100644 --- a/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.html +++ b/ironic_ui/static/dashboard/admin/ironic/node-list/node-list.html @@ -172,19 +172,17 @@ item="node"> {$ 'Create port' | translate $} - - {$ ('Move to ' | translate) + targetState $} - +
  • + + {$ transition.label $} + +
  • diff --git a/ironic_ui/static/dashboard/admin/ironic/node-state-transition.service.js b/ironic_ui/static/dashboard/admin/ironic/node-state-transition.service.js new file mode 100644 index 00000000..46ea0e82 --- /dev/null +++ b/ironic_ui/static/dashboard/admin/ironic/node-state-transition.service.js @@ -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; + }; + } +}());