Files
ironic-ui/ironic_ui/static/dashboard/admin/ironic/base-node/base-node.controller.js
Peter Piela 3fc9f6039a Cleanup code associated with the ironic REST api
- In the ironic_rest_api module use specific names like node, port,
driver for return values. I believe this is more descriptive than
the current approach of using "items" in all function returns. The
use of specific names also reduces the possibility of cut and paste
errors in client code.
- Rethink data returned from functions in the ironic.service. For
example, I believe that a function like getNodes should return a
list of nodes as opposed to a HTTP response as is done today. The
client should receieve the requested data, and be abstracted from
how it was obtained
- Modify controllers to take advantage of the api simplifications

Change-Id: Ica8c9ff8dfa9299cd5ef2893d296e366065bca97
2017-02-28 14:53:31 -05:00

301 lines
9.4 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 support operations on an Ironic node
*/
angular
.module('horizon.dashboard.admin.ironic')
.controller('BaseNodeController', BaseNodeController);
BaseNodeController.$inject = [
'$uibModalInstance',
'horizon.app.core.openstack-service-api.ironic',
'horizon.app.core.openstack-service-api.glance',
'horizon.dashboard.admin.ironic.base-node.service',
'horizon.dashboard.admin.ironic.validHostNamePattern',
'$log',
'ctrl'
];
function BaseNodeController($uibModalInstance,
ironic,
glance,
baseNodeService,
validHostNamePattern,
$log,
ctrl) {
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.modalTitle = gettext("Node");
ctrl.submitButtonTitle = gettext("Submit");
/* A property-collection is a set of properties that will be displayed
in the node view as a minimal browser ui that supports:
- adding new properties
- displaying the list of properties in the set
- changing the value of properties
*/
ctrl.propertyCollections = [
{id: "properties",
title: "Properties",
addPrompt: "Add Property",
placeholder: "Property Name"
},
{id: "extra",
title: "Extras",
addPrompt: "Add Extra",
placeholder: "Extra Property Name"
}];
// Node object suitable for Ironic api
ctrl.node = {
name: null,
driver: null,
driver_info: {},
properties: {},
extra: {}
};
/**
* @description Get the list of currently active Ironic drivers
*
* @return {void}
*/
ctrl._loadDrivers = function() {
return ironic.getDrivers().then(function(drivers) {
ctrl.drivers = drivers;
});
};
/**
* @description Get the list of images from Glance
*
* @return {void}
*/
ctrl._getImages = function() {
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 baseNodeService.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;
return ironic.getDriverProperties(driverName).then(function(properties) {
ctrl.driverProperties = {};
angular.forEach(properties, function(desc, property) {
ctrl.driverProperties[property] =
new baseNodeService.DriverProperty(property,
desc,
ctrl.driverProperties);
});
ctrl.driverPropertyGroups = ctrl._sortDriverProperties();
ctrl.loadingDriverProperties = false;
});
};
/**
* @description Cancel the current node operation
*
* @return {void}
*/
ctrl.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
/**
* @description Check whether the specified property already exists
*
* @param {string} collectionId - Collection ID
* @param {string} propertyName - Name of the property
* @return {boolean} True if the property already exists,
* otherwise false
*/
ctrl.collectionCheckPropertyUnique = function(collectionId, propertyName) {
return !(propertyName in ctrl.node[collectionId]);
};
/**
* @description Delete a node metadata property
*
* @param {string} collectionId - Collection ID
* @param {string} propertyName - Name of the property
* @return {void}
*/
ctrl.collectionDeleteProperty = function(collectionId, propertyName) {
delete ctrl.node[collectionId][propertyName];
};
/**
* @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();
};
}
})();