Files
ironic-ui/ironic_ui/static/dashboard/admin/ironic/enroll-node/enroll-node.controller.js
Elizabeth Elwell e476fe9344 Updated to ironic API v1.11 and added manageable state
Newly registered nodes begin in the enroll provision state by default
instead of available.

Actions added to the current dropdown on node view to enable move to
manageable, available and active states. Actions are enabled and
disabled in view as the current state permits.

All necessary fields required to move a node to available state are
still required on the enroll node modal. This will be changed to only
the necessary fields to move a node to enroll state once the
functionality for editing a node is ready.

Change-Id: I349a293a1069ad01fd782d1828bad607f9b9d6b0
Co-Authored-By: Peter Piela <ppiela@cray.com>
2016-09-19 15:24:50 +01:00

350 lines
11 KiB
JavaScript

/*
* 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';
/**
* Controller used to enroll a node in the Ironic database
*/
angular
.module('horizon.dashboard.admin.ironic')
.controller('EnrollNodeController', EnrollNodeController);
EnrollNodeController.$inject = [
'$rootScope',
'$modalInstance',
'horizon.app.core.openstack-service-api.ironic',
'horizon.dashboard.admin.ironic.events',
'horizon.app.core.openstack-service-api.glance',
'horizon.dashboard.admin.ironic.enroll-node.service',
'horizon.dashboard.admin.ironic.validHostNamePattern',
'$log'
];
function EnrollNodeController($rootScope,
$modalInstance,
ironic,
ironicEvents,
glance,
enrollNodeService,
validHostNamePattern,
$log) {
var ctrl = this;
ctrl.validHostNameRegex = new RegExp(validHostNamePattern);
ctrl.drivers = null;
ctrl.images = null;
ctrl.loadingDriverProperties = false;
// Object containing the set of properties associated with the currently
// selected driver
ctrl.driverProperties = null;
ctrl.driverPropertyGroups = null;
ctrl.moveNodeToManageableState = false;
// Parameter object that defines the node to be enrolled
ctrl.node = {
name: null,
driver: null,
driver_info: {},
properties: {},
extra: {}
};
init();
function init() {
loadDrivers();
getImages();
}
/**
* @description Get the list of currently active Ironic drivers
*
* @return {void}
*/
function loadDrivers() {
ironic.getDrivers().then(function(response) {
ctrl.drivers = response.data.items;
});
}
/**
* @description Get the list of images from Glance
*
* @return {void}
*/
function getImages() {
glance.getImages().then(function(response) {
ctrl.images = response.data.items;
});
}
/**
* @description Check whether a group contains required properties
*
* @param {DriverProperty[]} group - Property group
* @return {boolean} Return true if the group contains required
* properties, false otherwise
*/
function driverPropertyGroupHasRequired(group) {
var hasRequired = false;
for (var i = 0; i < group.length; i++) {
if (group[i].required) {
hasRequired = true;
break;
}
}
return hasRequired;
}
/**
* @description Convert array of driver property groups to a string
*
* @param {array[]} groups - Array for driver property groups
* @return {string} Output string
*/
function driverPropertyGroupsToString(groups) {
var output = [];
angular.forEach(groups, function(group) {
var groupStr = [];
angular.forEach(group, function(property) {
groupStr.push(property.name);
});
groupStr = groupStr.join(", ");
output.push(['[', groupStr, ']'].join(""));
});
output = output.join(", ");
return ['[', output, ']'].join("");
}
/**
* @description Comaprison function used to sort driver property groups
*
* @param {DriverProperty[]} group1 - First group
* @param {DriverProperty[]} group2 - Second group
* @return {integer} Return:
* < 0 if group1 should precede group2 in an ascending ordering
* > 0 if group2 should precede group1
* 0 if group1 and group2 are considered equal from ordering perpsective
*/
function compareDriverPropertyGroups(group1, group2) {
var group1HasRequired = driverPropertyGroupHasRequired(group1);
var group2HasRequired = driverPropertyGroupHasRequired(group2);
if (group1HasRequired === group2HasRequired) {
if (group1.length === group2.length) {
return group1[0].name.localeCompare(group2[0].name);
} else {
return group1.length - group2.length;
}
} else {
return group1HasRequired ? -1 : 1;
}
return 0;
}
/**
* @description Order driver properties in the form using the following
* rules:
*
* (1) Properties that are related to one another should occupy adjacent
* locations in the form
*
* (2) Required properties with no dependents should be located at the
* top of the form
*
* @return {void}
*/
ctrl._sortDriverProperties = function() {
// Build dependency graph between driver properties
var graph = new enrollNodeService.Graph();
// Create vertices
angular.forEach(ctrl.driverProperties, function(property, name) {
graph.addVertex(name, property);
});
/* eslint-disable no-unused-vars */
// Create edges
angular.forEach(ctrl.driverProperties,
function(property, name) {
var activators = property.getActivators();
if (activators) {
angular.forEach(activators,
function(unused, activatorName) {
graph.addEdge(name, activatorName);
});
}
});
/* eslint-enable no-unused-vars */
// Perform depth-first-search to find groups of related properties
var groups = [];
graph.dfs(
function(vertexList, components) {
// Sort properties so that those with the largest number of
// immediate dependents are the top of the list
vertexList.sort(function(vertex1, vertex2) {
return vertex2.adjacents.length - vertex1.adjacents.length;
});
// Build component and add to list
var component = new Array(vertexList.length);
angular.forEach(vertexList, function(vertex, index) {
component[index] = vertex.data;
});
components.push(component);
},
groups);
groups.sort(compareDriverPropertyGroups);
$log.debug("Found the following property groups: " +
driverPropertyGroupsToString(groups));
return groups;
};
/**
* @description Get the properties associated with a specified driver
*
* @param {string} driverName - Name of driver
* @return {void}
*/
ctrl.loadDriverProperties = function(driverName) {
ctrl.node.driver = driverName;
ctrl.node.driver_info = {};
ctrl.loadingDriverProperties = true;
ctrl.driverProperties = null;
ctrl.driverPropertyGroups = null;
ironic.getDriverProperties(driverName).then(function(response) {
ctrl.driverProperties = {};
angular.forEach(response.data, function(desc, property) {
ctrl.driverProperties[property] =
new enrollNodeService.DriverProperty(property,
desc,
ctrl.driverProperties);
});
ctrl.driverPropertyGroups = ctrl._sortDriverProperties();
ctrl.loadingDriverProperties = false;
});
};
/**
* @description Cancel the node enrollment process
*
* @return {void}
*/
ctrl.cancel = function() {
$modalInstance.dismiss('cancel');
};
/**
* @description Enroll the defined node
*
* @return {void}
*/
ctrl.enroll = function() {
$log.debug(">> EnrollNodeController.enroll()");
angular.forEach(ctrl.driverProperties, function(property, name) {
$log.debug(name +
", required = " + property.isRequired() +
", active = " + property.isActive() +
", input-value = " + property.getInputValue() +
", default-value = " + property.getDefaultValue());
if (property.isActive() &&
property.getInputValue() &&
property.getInputValue() !== property.getDefaultValue()) {
$log.debug("Setting driver property " + name + " to " +
property.inputValue);
ctrl.node.driver_info[name] = property.inputValue;
}
});
ironic.createNode(ctrl.node).then(
function(response) {
$log.info("create node response = " + JSON.stringify(response));
$modalInstance.close();
$rootScope.$emit(ironicEvents.ENROLL_NODE_SUCCESS);
if (ctrl.moveNodeToManageableState) {
$log.info("Setting node provision state");
ironic.setNodeProvisionState(response.data.uuid, 'manage');
}
},
function() {
// No additional error processing for now
});
$log.debug("<< EnrollNodeController.enroll()");
};
/**
* @desription Delete a node property
*
* @param {string} propertyName - Name of the property
* @return {void}
*/
ctrl.deleteProperty = function(propertyName) {
delete ctrl.node.properties[propertyName];
};
/**
* @description Check whether the specified node property already exists
*
* @param {string} propertyName - Name of the property
* @return {boolean} True if the property already exists,
* otherwise false
*/
ctrl.checkPropertyUnique = function(propertyName) {
return !(propertyName in ctrl.node.properties);
};
/**
* @description Delete a node metadata property
*
* @param {string} propertyName - Name of the property
* @return {void}
*/
ctrl.deleteExtra = function(propertyName) {
delete ctrl.node.extra[propertyName];
};
/**
* @description Check whether the specified node metadata property
* already exists
*
* @param {string} propertyName - Name of the metadata property
* @return {boolean} True if the property already exists,
* otherwise false
*/
ctrl.checkExtraUnique = function(propertyName) {
return !(propertyName in ctrl.node.extra);
};
/**
* @description Check whether a specified driver property is
* currently active
*
* @param {string} property - Driver property
* @return {boolean} True if the property is active, false otherwise
*/
ctrl.isDriverPropertyActive = function(property) {
return property.isActive();
};
}
})();