Allow selecting interfaces while enrolling nodes
Adds support for selecting from the enabled interfaces for the underlying driver while creating nodes. A new tab is added in the enroll node modal. Also enhanced "package.json" and "karma.conf.js" to widen the range of accepted versions and jasmine capabilities. Change-Id: Ie1b24cbf147b849a1d57fcdcbd735429ea7c9e34 Partial-Bug: #1672729
This commit is contained in:
parent
dfbe630ab2
commit
c73492c877
@ -25,7 +25,7 @@ from horizon.utils.memoized import memoized # noqa
|
|||||||
from openstack_dashboard.api import base
|
from openstack_dashboard.api import base
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_IRONIC_API_VERSION = '1.31'
|
DEFAULT_IRONIC_API_VERSION = '1.34'
|
||||||
DEFAULT_INSECURE = False
|
DEFAULT_INSECURE = False
|
||||||
DEFAULT_CACERT = None
|
DEFAULT_CACERT = None
|
||||||
IRONIC_CLIENT_CLASS_NAME = 'baremetal'
|
IRONIC_CLIENT_CLASS_NAME = 'baremetal'
|
||||||
@ -282,6 +282,19 @@ def driver_properties(request, driver_name):
|
|||||||
return ironicclient(request).driver.properties(driver_name)
|
return ironicclient(request).driver.properties(driver_name)
|
||||||
|
|
||||||
|
|
||||||
|
def driver_details(request, driver_name):
|
||||||
|
"""Retrieve the details of a specified driver
|
||||||
|
|
||||||
|
:param request: HTTP request
|
||||||
|
:param driver_name: Name of the driver
|
||||||
|
:return: dictionary of driver details
|
||||||
|
|
||||||
|
https://docs.openstack.org/python-ironicclient/latest/cli/osc/v1/index.html#baremetal-driver-show
|
||||||
|
"""
|
||||||
|
details = ironicclient(request).driver.get(driver_name)
|
||||||
|
return details.to_dict()
|
||||||
|
|
||||||
|
|
||||||
def port_create(request, params):
|
def port_create(request, params):
|
||||||
"""Create network port
|
"""Create network port
|
||||||
|
|
||||||
|
@ -450,3 +450,20 @@ class RaidConfig(generic.View):
|
|||||||
request,
|
request,
|
||||||
node_id,
|
node_id,
|
||||||
request.DATA.get('target_raid_config'))
|
request.DATA.get('target_raid_config'))
|
||||||
|
|
||||||
|
|
||||||
|
@urls.register
|
||||||
|
class DriverDetails(generic.View):
|
||||||
|
|
||||||
|
url_regex = r'ironic/drivers/(?P<driver_name>[0-9a-zA-Z_-]+)$'. \
|
||||||
|
format(LOGICAL_NAME_PATTERN)
|
||||||
|
|
||||||
|
@rest_utils.ajax()
|
||||||
|
def get(self, request, driver_name):
|
||||||
|
"""Get the details of a specified driver
|
||||||
|
|
||||||
|
:param request: HTTP request
|
||||||
|
:param driver_name: Driver name
|
||||||
|
:return: Dictionary of details
|
||||||
|
"""
|
||||||
|
return ironic.driver_details(request, driver_name)
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
* Django or via jasmine template.
|
* Django or via jasmine template.
|
||||||
*/
|
*/
|
||||||
'../test-shim.js',
|
'../test-shim.js',
|
||||||
|
'../node_modules/string.prototype.endswith/*.js',
|
||||||
|
|
||||||
// from jasmine.html
|
// from jasmine.html
|
||||||
toxPath + 'xstatic/pkg/jquery/data/jquery.js',
|
toxPath + 'xstatic/pkg/jquery/data/jquery.js',
|
||||||
@ -113,9 +114,9 @@
|
|||||||
|
|
||||||
autoWatch: true,
|
autoWatch: true,
|
||||||
|
|
||||||
frameworks: ['jasmine'],
|
frameworks: ['jasmine', 'jasmine-matchers'],
|
||||||
|
|
||||||
browsers: ['Chrome'],
|
browsers: ['Chrome', 'PhantomJS'],
|
||||||
|
|
||||||
browserNoActivityTimeout: 60000,
|
browserNoActivityTimeout: 60000,
|
||||||
|
|
||||||
@ -129,7 +130,9 @@
|
|||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
'karma-chrome-launcher',
|
'karma-chrome-launcher',
|
||||||
|
'karma-phantomjs-launcher',
|
||||||
'karma-jasmine',
|
'karma-jasmine',
|
||||||
|
'karma-jasmine-matchers',
|
||||||
'karma-ng-html2js-preprocessor',
|
'karma-ng-html2js-preprocessor',
|
||||||
'karma-coverage',
|
'karma-coverage',
|
||||||
'karma-threshold-reporter'
|
'karma-threshold-reporter'
|
||||||
|
@ -27,31 +27,41 @@
|
|||||||
'$uibModalInstance',
|
'$uibModalInstance',
|
||||||
'horizon.app.core.openstack-service-api.ironic',
|
'horizon.app.core.openstack-service-api.ironic',
|
||||||
'horizon.app.core.openstack-service-api.glance',
|
'horizon.app.core.openstack-service-api.glance',
|
||||||
|
'horizon.dashboard.admin.ironic.form-field.service',
|
||||||
'horizon.dashboard.admin.ironic.base-node.service',
|
'horizon.dashboard.admin.ironic.base-node.service',
|
||||||
'horizon.dashboard.admin.ironic.driver-property.service',
|
'horizon.dashboard.admin.ironic.driver-property.service',
|
||||||
'horizon.dashboard.admin.ironic.graph.service',
|
'horizon.dashboard.admin.ironic.graph.service',
|
||||||
'horizon.dashboard.admin.ironic.validHostNamePattern',
|
'horizon.dashboard.admin.ironic.validHostNamePattern',
|
||||||
|
'horizon.dashboard.admin.ironic.driverInterfaces',
|
||||||
'$log',
|
'$log',
|
||||||
|
'$q',
|
||||||
'ctrl'
|
'ctrl'
|
||||||
];
|
];
|
||||||
|
|
||||||
function BaseNodeController($uibModalInstance,
|
function BaseNodeController($uibModalInstance,
|
||||||
ironic,
|
ironic,
|
||||||
glance,
|
glance,
|
||||||
|
formFieldService,
|
||||||
baseNodeService,
|
baseNodeService,
|
||||||
driverPropertyService,
|
driverPropertyService,
|
||||||
graphService,
|
graphService,
|
||||||
validHostNamePattern,
|
validHostNamePattern,
|
||||||
|
driverInterfaces,
|
||||||
$log,
|
$log,
|
||||||
|
$q,
|
||||||
ctrl) {
|
ctrl) {
|
||||||
ctrl.validHostNameRegex = new RegExp(validHostNamePattern);
|
ctrl.validHostNameRegex = new RegExp(validHostNamePattern);
|
||||||
ctrl.drivers = null;
|
ctrl.drivers = null;
|
||||||
ctrl.images = null;
|
ctrl.images = null;
|
||||||
ctrl.loadingDriverProperties = false;
|
ctrl.loadingDriverProperties = false;
|
||||||
|
ctrl.driverType = null;
|
||||||
// Object containing the set of properties associated with the currently
|
// Object containing the set of properties associated with the currently
|
||||||
// selected driver
|
// selected driver
|
||||||
ctrl.driverProperties = null;
|
ctrl.driverProperties = null;
|
||||||
ctrl.driverPropertyGroups = null;
|
ctrl.driverPropertyGroups = null;
|
||||||
|
// Dictionary of form-fields for supported interfaces indexed by interface
|
||||||
|
// name for the currently selected driver
|
||||||
|
ctrl.driverInterfaceFields = {};
|
||||||
|
|
||||||
ctrl.modalTitle = gettext("Node");
|
ctrl.modalTitle = gettext("Node");
|
||||||
ctrl.submitButtonTitle = gettext("Submit");
|
ctrl.submitButtonTitle = gettext("Submit");
|
||||||
@ -91,10 +101,14 @@
|
|||||||
name: null,
|
name: null,
|
||||||
driver: null,
|
driver: null,
|
||||||
driver_info: {},
|
driver_info: {},
|
||||||
network_interface: null,
|
|
||||||
resource_class: null
|
resource_class: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initialize hardware interfaces
|
||||||
|
angular.forEach(driverInterfaces, function(interfaceName) {
|
||||||
|
ctrl.node[interfaceName + '_interface'] = null;
|
||||||
|
});
|
||||||
|
|
||||||
angular.forEach(ctrl.propertyCollections, function(collection) {
|
angular.forEach(ctrl.propertyCollections, function(collection) {
|
||||||
ctrl.node[collection.id] = {};
|
ctrl.node[collection.id] = {};
|
||||||
});
|
});
|
||||||
@ -189,8 +203,8 @@
|
|||||||
* @param {string} driverName - Name of driver
|
* @param {string} driverName - Name of driver
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
ctrl.loadDriverProperties = function(driverName) {
|
ctrl._loadDriverProperties = function(driverName) {
|
||||||
ctrl.node.driver = driverName;
|
ctrl.node.driver = null;
|
||||||
ctrl.node.driver_info = {};
|
ctrl.node.driver_info = {};
|
||||||
|
|
||||||
ctrl.loadingDriverProperties = true;
|
ctrl.loadingDriverProperties = true;
|
||||||
@ -198,6 +212,7 @@
|
|||||||
ctrl.driverPropertyGroups = null;
|
ctrl.driverPropertyGroups = null;
|
||||||
|
|
||||||
return ironic.getDriverProperties(driverName).then(function(properties) {
|
return ironic.getDriverProperties(driverName).then(function(properties) {
|
||||||
|
ctrl.node.driver = driverName;
|
||||||
ctrl.driverProperties = {};
|
ctrl.driverProperties = {};
|
||||||
angular.forEach(properties, function(desc, property) {
|
angular.forEach(properties, function(desc, property) {
|
||||||
ctrl.driverProperties[property] =
|
ctrl.driverProperties[property] =
|
||||||
@ -275,5 +290,58 @@
|
|||||||
}
|
}
|
||||||
return ready;
|
return ready;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Load details for a specified driver.
|
||||||
|
* Includes driver type and supported interfaces.
|
||||||
|
*
|
||||||
|
* @param {string} driverName - driver name
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
ctrl._loadDriverDetails = function(driverName) {
|
||||||
|
// Re-initialize driver related properties
|
||||||
|
ctrl.driverType = null;
|
||||||
|
angular.forEach(driverInterfaces, function(interfaceName) {
|
||||||
|
ctrl.node[interfaceName + '_interface'] = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
ctrl.driverInterfaceFields = {};
|
||||||
|
return ironic.getDriverDetails(driverName).then(function(details) {
|
||||||
|
ctrl.driverType = details.type;
|
||||||
|
|
||||||
|
// Extract interface information for dynamic drivers
|
||||||
|
angular.forEach(driverInterfaces, function(interfaceName) {
|
||||||
|
var enabled = 'enabled_' + interfaceName + '_interfaces';
|
||||||
|
if (angular.isDefined(details[enabled]) && details[enabled] !== null) {
|
||||||
|
var options = [];
|
||||||
|
angular.forEach(details[enabled], function(value) {
|
||||||
|
options.push({label: value, value: value});
|
||||||
|
});
|
||||||
|
|
||||||
|
ctrl.driverInterfaceFields[interfaceName] =
|
||||||
|
new formFieldService.FormField(
|
||||||
|
{type: 'radio',
|
||||||
|
id: interfaceName,
|
||||||
|
title: interfaceName,
|
||||||
|
options: options,
|
||||||
|
value: details['default_' + interfaceName + '_interface']});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Load a specified driver.
|
||||||
|
*
|
||||||
|
* @param {string} driverName - driver name
|
||||||
|
* @return {promise} Promise that completes
|
||||||
|
* when both properties and details are loaded.
|
||||||
|
*/
|
||||||
|
ctrl.loadDriver = function(driverName) {
|
||||||
|
var promises = [];
|
||||||
|
promises.push(ctrl._loadDriverProperties(driverName));
|
||||||
|
promises.push(ctrl._loadDriverDetails(driverName));
|
||||||
|
return $q.all(promises);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
describe('horizon.dashboard.admin.ironic.base-node', function () {
|
describe('horizon.dashboard.admin.ironic.base-node', function () {
|
||||||
var ironicBackendMockService, uibModalInstance;
|
var ironicBackendMockService, uibModalInstance, driverInterfaces;
|
||||||
var ctrl = {};
|
var ctrl = {};
|
||||||
|
|
||||||
beforeEach(module('horizon.dashboard.admin.ironic'));
|
beforeEach(module('horizon.dashboard.admin.ironic'));
|
||||||
@ -51,6 +51,11 @@
|
|||||||
controller('BaseNodeController', {ctrl: ctrl});
|
controller('BaseNodeController', {ctrl: ctrl});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
beforeEach(inject(function($injector) {
|
||||||
|
driverInterfaces =
|
||||||
|
$injector.get('horizon.dashboard.admin.ironic.driverInterfaces');
|
||||||
|
}));
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
ironicBackendMockService.postTest();
|
ironicBackendMockService.postTest();
|
||||||
});
|
});
|
||||||
@ -64,6 +69,7 @@
|
|||||||
expect(ctrl.images).toBeNull();
|
expect(ctrl.images).toBeNull();
|
||||||
expect(ctrl.loadingDriverProperties).toBe(false);
|
expect(ctrl.loadingDriverProperties).toBe(false);
|
||||||
expect(ctrl.driverProperties).toBeNull();
|
expect(ctrl.driverProperties).toBeNull();
|
||||||
|
expect(ctrl.driverInterfaceFields).toEqual({});
|
||||||
expect(ctrl.driverPropertyGroups).toBeNull();
|
expect(ctrl.driverPropertyGroups).toBeNull();
|
||||||
expect(ctrl.modalTitle).toBeDefined();
|
expect(ctrl.modalTitle).toBeDefined();
|
||||||
angular.forEach(ctrl.propertyCollections, function(collection) {
|
angular.forEach(ctrl.propertyCollections, function(collection) {
|
||||||
@ -74,14 +80,17 @@
|
|||||||
.toContain(jasmine.objectContaining({id: "properties"}));
|
.toContain(jasmine.objectContaining({id: "properties"}));
|
||||||
expect(ctrl.propertyCollections)
|
expect(ctrl.propertyCollections)
|
||||||
.toContain(jasmine.objectContaining({id: "extra"}));
|
.toContain(jasmine.objectContaining({id: "extra"}));
|
||||||
expect(ctrl.node).toEqual({
|
var node = {
|
||||||
name: null,
|
name: null,
|
||||||
driver: null,
|
driver: null,
|
||||||
driver_info: {},
|
driver_info: {},
|
||||||
properties: {},
|
properties: {},
|
||||||
extra: {},
|
extra: {},
|
||||||
network_interface: null,
|
resource_class: null};
|
||||||
resource_class: null});
|
angular.forEach(driverInterfaces, function(interfaceName) {
|
||||||
|
node[interfaceName + '_interface'] = null;
|
||||||
|
});
|
||||||
|
expect(ctrl.node).toEqual(node);
|
||||||
expect(Object.getOwnPropertyNames(ctrl).sort()).toEqual(
|
expect(Object.getOwnPropertyNames(ctrl).sort()).toEqual(
|
||||||
BASE_NODE_CONTROLLER_PROPERTIES.sort());
|
BASE_NODE_CONTROLLER_PROPERTIES.sort());
|
||||||
});
|
});
|
||||||
@ -89,7 +98,7 @@
|
|||||||
it('_loadDrivers', function () {
|
it('_loadDrivers', function () {
|
||||||
ctrl._loadDrivers();
|
ctrl._loadDrivers();
|
||||||
ironicBackendMockService.flush();
|
ironicBackendMockService.flush();
|
||||||
expect(ctrl.drivers).toEqual(ironicBackendMockService.getDrivers());
|
expect(ctrl.drivers).toEqual(ironicBackendMockService.getBaseDrivers());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('_getImages', function () {
|
it('_getImages', function () {
|
||||||
@ -103,5 +112,24 @@
|
|||||||
expect(uibModalInstance.dismiss).toHaveBeenCalledWith('cancel');
|
expect(uibModalInstance.dismiss).toHaveBeenCalledWith('cancel');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('_loadDriverProperties', function() {
|
||||||
|
var driverName = "ipmi";
|
||||||
|
ctrl._loadDriverProperties(driverName);
|
||||||
|
var drivers = ironicBackendMockService.getDrivers();
|
||||||
|
ironicBackendMockService.flush();
|
||||||
|
|
||||||
|
expect(ctrl.node.driver).toEqual(driverName);
|
||||||
|
expect(ctrl.node.driver).toEqual(drivers[driverName].details.name);
|
||||||
|
expect(ctrl.node.driver_info).toEqual({});
|
||||||
|
expect(ctrl.driverPropertyGroups).toBeNonEmptyArray();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('_loadDriverDetails', function() {
|
||||||
|
var driverName = "ipmi";
|
||||||
|
ctrl._loadDriverDetails(driverName);
|
||||||
|
ironicBackendMockService.flush();
|
||||||
|
var drivers = ironicBackendMockService.getDrivers();
|
||||||
|
expect(ctrl.driverType).toEqual(drivers[driverName].details.type);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -26,6 +26,15 @@
|
|||||||
data-target="#driverDetails"
|
data-target="#driverDetails"
|
||||||
data-toggle="tab"
|
data-toggle="tab"
|
||||||
translate>Driver Details</a></li>
|
translate>Driver Details</a></li>
|
||||||
|
<li ng-if="ctrl.driverType === 'classic' || !ctrl.driverProperties"
|
||||||
|
class="disabled">
|
||||||
|
<a data-target="#driverInterfaces"
|
||||||
|
translation>Driver Interfaces</a></li>
|
||||||
|
<li ng-if="ctrl.driverType === 'dynamic' && ctrl.driverProperties">
|
||||||
|
<a href=""
|
||||||
|
data-target="#driverInterfaces"
|
||||||
|
data-toggle="tab"
|
||||||
|
translate>Driver Interfaces</a><li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!--base node form-->
|
<!--base node form-->
|
||||||
@ -69,7 +78,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--network interface-->
|
<!--network interface-->
|
||||||
<div class="form-group">
|
<div ng-if="ctrl.driverType === 'classic'" class="form-group">
|
||||||
<label for="network_interface"
|
<label for="network_interface"
|
||||||
class="control-label"
|
class="control-label"
|
||||||
translate>
|
translate>
|
||||||
@ -91,6 +100,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!--storage interface-->
|
||||||
|
<div ng-if="ctrl.driverType === 'classic'" class="form-group">
|
||||||
|
<label for="storage_interface"
|
||||||
|
class="control-label"
|
||||||
|
translate>
|
||||||
|
Storage Interface
|
||||||
|
</label>
|
||||||
|
<span class="help-icon"
|
||||||
|
data-container="body"
|
||||||
|
title=""
|
||||||
|
data-toggle="tooltip"
|
||||||
|
data-original-title="{$ ::'Interface used for attaching and detaching volumes on this node.' | translate $}">
|
||||||
|
<span class="fa fa-question-circle"></span>
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<label class="btn btn-default"
|
||||||
|
ng-repeat="opt in ['noop', 'cinder']"
|
||||||
|
ng-model="ctrl.node.storage_interface"
|
||||||
|
uib-btn-radio="opt">{$ opt $}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!--node driver-->
|
<!--node driver-->
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<label for="driver"
|
<label for="driver"
|
||||||
@ -102,7 +134,7 @@
|
|||||||
class="form-control"
|
class="form-control"
|
||||||
ng-options="driver as driver.name for driver in ctrl.drivers"
|
ng-options="driver as driver.name for driver in ctrl.drivers"
|
||||||
ng-model="ctrl.selectedDriver"
|
ng-model="ctrl.selectedDriver"
|
||||||
ng-change="ctrl.loadDriverProperties(ctrl.selectedDriver.name)">
|
ng-change="ctrl.loadDriver(ctrl.selectedDriver.name)">
|
||||||
<option value="" disabled selected translate>Select a Driver</option>
|
<option value="" disabled selected translate>Select a Driver</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -253,6 +285,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end driver details tab-->
|
<!--end driver details tab-->
|
||||||
|
|
||||||
|
<!-- start of driver interfaces tab -->
|
||||||
|
<div class="tab-pane", id="driverInterfaces">
|
||||||
|
<p class="text-center"
|
||||||
|
ng-if="ctrl.loadingDriverProperties">
|
||||||
|
<small><em><i class="fa fa-spin fa-refresh"></i></em></small>
|
||||||
|
</p>
|
||||||
|
<form id="DriverInterfacesForm", name="DriverInterfacesForm">
|
||||||
|
<div ng-repeat="field in ctrl.driverInterfaceFields"
|
||||||
|
class="form-group">
|
||||||
|
<form-field field="field" form="DriverInterfacesForm"></form-field>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--end tabbed content-->
|
<!--end tabbed content-->
|
||||||
</form>
|
</form>
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
'horizon.framework.widgets.toast.service',
|
'horizon.framework.widgets.toast.service',
|
||||||
'horizon.app.core.openstack-service-api.ironic',
|
'horizon.app.core.openstack-service-api.ironic',
|
||||||
'horizon.dashboard.admin.ironic.events',
|
'horizon.dashboard.admin.ironic.events',
|
||||||
|
'horizon.dashboard.admin.ironic.driverInterfaces',
|
||||||
'horizon.dashboard.admin.ironic.edit-node.service',
|
'horizon.dashboard.admin.ironic.edit-node.service',
|
||||||
'horizon.dashboard.admin.ironic.update-patch.service',
|
'horizon.dashboard.admin.ironic.update-patch.service',
|
||||||
'$log',
|
'$log',
|
||||||
@ -42,6 +43,7 @@
|
|||||||
toastService,
|
toastService,
|
||||||
ironic,
|
ironic,
|
||||||
ironicEvents,
|
ironicEvents,
|
||||||
|
driverInterfaces,
|
||||||
editNodeService,
|
editNodeService,
|
||||||
updatePatchService,
|
updatePatchService,
|
||||||
$log,
|
$log,
|
||||||
@ -67,8 +69,6 @@
|
|||||||
|
|
||||||
ctrl.node[instanceInfoId] = {};
|
ctrl.node[instanceInfoId] = {};
|
||||||
|
|
||||||
ctrl.node[instanceInfoId] = {};
|
|
||||||
|
|
||||||
init(node);
|
init(node);
|
||||||
|
|
||||||
function init(node) {
|
function init(node) {
|
||||||
@ -80,11 +80,9 @@
|
|||||||
|
|
||||||
function _loadNodeData(nodeId) {
|
function _loadNodeData(nodeId) {
|
||||||
ironic.getNode(nodeId).then(function(node) {
|
ironic.getNode(nodeId).then(function(node) {
|
||||||
ctrl.baseNode = node;
|
ctrl.baseNode = angular.copy(node);
|
||||||
|
|
||||||
ctrl.node.name = node.name;
|
ctrl.node.name = node.name;
|
||||||
ctrl.node.resource_class = node.resource_class;
|
ctrl.node.resource_class = node.resource_class;
|
||||||
ctrl.node.network_interface = node.network_interface;
|
|
||||||
for (var i = 0; i < ctrl.drivers.length; i++) {
|
for (var i = 0; i < ctrl.drivers.length; i++) {
|
||||||
if (ctrl.drivers[i].name === node.driver) {
|
if (ctrl.drivers[i].name === node.driver) {
|
||||||
ctrl.selectedDriver = ctrl.drivers[i];
|
ctrl.selectedDriver = ctrl.drivers[i];
|
||||||
@ -92,12 +90,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl.loadDriverProperties(node.driver).then(function() {
|
ctrl.loadDriver(node.driver).then(function() {
|
||||||
angular.forEach(node.driver_info, function(value, property) {
|
angular.forEach(node.driver_info, function(value, property) {
|
||||||
if (angular.isDefined(ctrl.driverProperties[property])) {
|
if (angular.isDefined(ctrl.driverProperties[property])) {
|
||||||
ctrl.driverProperties[property].inputValue = value;
|
ctrl.driverProperties[property].inputValue = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (ctrl.driverType === 'classic') {
|
||||||
|
ctrl.node.network_interface = node.network_interface;
|
||||||
|
ctrl.node.storage_interface = node.storage_interface;
|
||||||
|
} else {
|
||||||
|
angular.forEach(
|
||||||
|
ctrl.driverInterfaceFields,
|
||||||
|
function(field, interfaceName) {
|
||||||
|
field.value = ctrl.baseNode[interfaceName + '_interface'];
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ctrl.node.properties = angular.copy(node.properties);
|
ctrl.node.properties = angular.copy(node.properties);
|
||||||
@ -121,9 +130,9 @@
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
};
|
};
|
||||||
|
|
||||||
angular.forEach([new PatchItem("name", "/name"),
|
angular.forEach([new PatchItem("name", "/name"),
|
||||||
new PatchItem("resource_class", "/resource_class"),
|
new PatchItem("resource_class", "/resource_class"),
|
||||||
new PatchItem("network_interface", "/network_interface"),
|
|
||||||
new PatchItem("driver", "/driver"),
|
new PatchItem("driver", "/driver"),
|
||||||
new PatchItem("properties", "/properties"),
|
new PatchItem("properties", "/properties"),
|
||||||
new PatchItem("extra", "/extra"),
|
new PatchItem("extra", "/extra"),
|
||||||
@ -135,6 +144,15 @@
|
|||||||
item.path);
|
item.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
angular.forEach(driverInterfaces, function(interfaceName) {
|
||||||
|
var propName = interfaceName + '_interface';
|
||||||
|
if (angular.isDefined(sourceNode[propName])) {
|
||||||
|
patcher.buildPatch(sourceNode[propName],
|
||||||
|
targetNode[propName],
|
||||||
|
'/' + propName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return patcher.getPatch();
|
return patcher.getPatch();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,6 +172,10 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
angular.forEach(ctrl.driverInterfaceFields, function(field, interfaceName) {
|
||||||
|
ctrl.node[interfaceName + '_interface'] = field.value;
|
||||||
|
});
|
||||||
|
|
||||||
$log.info("Updating node " + JSON.stringify(ctrl.baseNode));
|
$log.info("Updating node " + JSON.stringify(ctrl.baseNode));
|
||||||
$log.info("to " + JSON.stringify(ctrl.node));
|
$log.info("to " + JSON.stringify(ctrl.node));
|
||||||
|
|
||||||
|
@ -78,7 +78,11 @@
|
|||||||
});
|
});
|
||||||
expect(ctrl.node.name).toEqual(editNode.name);
|
expect(ctrl.node.name).toEqual(editNode.name);
|
||||||
expect(ctrl.node.resource_class).toEqual(editNode.resource_class);
|
expect(ctrl.node.resource_class).toEqual(editNode.resource_class);
|
||||||
|
if (ctrl.driverType === 'classic') {
|
||||||
expect(ctrl.node.network_interface).toEqual(editNode.network_interface);
|
expect(ctrl.node.network_interface).toEqual(editNode.network_interface);
|
||||||
|
} else {
|
||||||
|
expect(ctrl.node.network_interface).toBeNull();
|
||||||
|
}
|
||||||
expect(ctrl.node.properties).toEqual(editNode.properties);
|
expect(ctrl.node.properties).toEqual(editNode.properties);
|
||||||
expect(ctrl.node.extra).toEqual(editNode.extra);
|
expect(ctrl.node.extra).toEqual(editNode.extra);
|
||||||
expect(ctrl.node.instance_info).toEqual(editNode.instance_info);
|
expect(ctrl.node.instance_info).toEqual(editNode.instance_info);
|
||||||
|
@ -71,6 +71,10 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
angular.forEach(ctrl.driverInterfaceFields, function(field, interfaceName) {
|
||||||
|
ctrl.node[interfaceName + '_interface'] = field.value;
|
||||||
|
});
|
||||||
|
|
||||||
ironic.createNode(ctrl.node).then(
|
ironic.createNode(ctrl.node).then(
|
||||||
function(response) {
|
function(response) {
|
||||||
$log.info("create node response = " + JSON.stringify(response));
|
$log.info("create node response = " + JSON.stringify(response));
|
||||||
|
@ -30,12 +30,14 @@
|
|||||||
ironicBackendMockService.$inject = [
|
ironicBackendMockService.$inject = [
|
||||||
'$httpBackend',
|
'$httpBackend',
|
||||||
'horizon.framework.util.uuid.service',
|
'horizon.framework.util.uuid.service',
|
||||||
'horizon.dashboard.admin.ironic.validMacAddressPattern'
|
'horizon.dashboard.admin.ironic.validMacAddressPattern',
|
||||||
|
'horizon.dashboard.admin.ironic.driverInterfaces'
|
||||||
];
|
];
|
||||||
|
|
||||||
function ironicBackendMockService($httpBackend,
|
function ironicBackendMockService($httpBackend,
|
||||||
uuidService,
|
uuidService,
|
||||||
validMacAddressPattern) {
|
validMacAddressPattern,
|
||||||
|
driverInterfaces) {
|
||||||
// Default node object.
|
// Default node object.
|
||||||
var defaultNode = {
|
var defaultNode = {
|
||||||
chassis_uuid: null,
|
chassis_uuid: null,
|
||||||
@ -106,6 +108,38 @@
|
|||||||
uuid: undefined
|
uuid: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var drivers = {
|
||||||
|
ipmi: {
|
||||||
|
details: {
|
||||||
|
default_boot_interface: "pxe",
|
||||||
|
default_console_interface: "no-console",
|
||||||
|
default_deploy_interface: "iscsi",
|
||||||
|
default_inspect_interface: "no-inspect",
|
||||||
|
default_management_interface: "ipmitool",
|
||||||
|
default_network_interface: "flat",
|
||||||
|
default_power_interface: "ipmitool",
|
||||||
|
default_raid_interface: "no-raid",
|
||||||
|
default_vendor_interface: "ipmitool",
|
||||||
|
enabled_boot_interfaces: ["pxe"],
|
||||||
|
enabled_console_interfaces: ["no-console"],
|
||||||
|
enabled_deploy_interfaces: ["iscsi", "direct"],
|
||||||
|
enabled_inspect_interfaces: ["no-inspect"],
|
||||||
|
enabled_management_interfaces: ["ipmitool"],
|
||||||
|
enabled_network_interfaces: ["flat", "noop"],
|
||||||
|
enabled_power_interfaces: ["ipmitool"],
|
||||||
|
enabled_raid_interfaces: ["no-raid", "agent"],
|
||||||
|
enabled_vendor_interfaces: ["ipmitool", "no-vendor"],
|
||||||
|
hosts: ["testhost"],
|
||||||
|
name: "ipmi",
|
||||||
|
type: "dynamic"
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
deploy_kernel: "UUID (from Glance)",
|
||||||
|
deploy_ramdisk: "UUID (from Glance)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Value of the next available system port
|
// Value of the next available system port
|
||||||
var nextAvailableSystemPort = 1024;
|
var nextAvailableSystemPort = 1024;
|
||||||
|
|
||||||
@ -114,13 +148,10 @@
|
|||||||
// Console info
|
// Console info
|
||||||
consoleType: "shellinabox",
|
consoleType: "shellinabox",
|
||||||
consoleUrl: "http://localhost:",
|
consoleUrl: "http://localhost:",
|
||||||
defaultDriver: "agent_ipmitool",
|
defaultDriver: "ipmi",
|
||||||
supportedBootDevices: ["pxe", "bios", "safe"]
|
supportedBootDevices: ["pxe", "bios", "safe"]
|
||||||
};
|
};
|
||||||
|
|
||||||
// List of supported drivers
|
|
||||||
var drivers = [{name: params.defaultDriver}];
|
|
||||||
|
|
||||||
// List of images
|
// List of images
|
||||||
var images = [];
|
var images = [];
|
||||||
|
|
||||||
@ -142,6 +173,7 @@
|
|||||||
getNodeBootDevice: getNodeBootDevice,
|
getNodeBootDevice: getNodeBootDevice,
|
||||||
getNodeSupportedBootDevices: getNodeSupportedBootDevices,
|
getNodeSupportedBootDevices: getNodeSupportedBootDevices,
|
||||||
nodeGetConsoleUrl: nodeGetConsoleUrl,
|
nodeGetConsoleUrl: nodeGetConsoleUrl,
|
||||||
|
getBaseDrivers: getBaseDrivers,
|
||||||
getDrivers: getDrivers,
|
getDrivers: getDrivers,
|
||||||
getImages: getImages,
|
getImages: getImages,
|
||||||
getPort: getPort,
|
getPort: getPort,
|
||||||
@ -189,8 +221,22 @@
|
|||||||
function createNode(params) {
|
function createNode(params) {
|
||||||
var node = null;
|
var node = null;
|
||||||
|
|
||||||
if (angular.isDefined(params.driver)) {
|
if (angular.isDefined(params.driver) &&
|
||||||
|
angular.isDefined(drivers[params.driver])) {
|
||||||
node = angular.copy(defaultNode);
|
node = angular.copy(defaultNode);
|
||||||
|
|
||||||
|
// For dynamic drivers, initialize interfaces based on
|
||||||
|
// default values
|
||||||
|
var details = drivers[params.driver].details;
|
||||||
|
if (details.type === 'dynamic') {
|
||||||
|
angular.forEach(driverInterfaces, function(interfaceName) {
|
||||||
|
var defaultInterface = 'default_' + interfaceName + '_interface';
|
||||||
|
if (angular.isDefined(details[defaultInterface])) {
|
||||||
|
node[interfaceName + '_interface'] = details[defaultInterface];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
angular.forEach(params, function(value, key) {
|
angular.forEach(params, function(value, key) {
|
||||||
node[key] = value;
|
node[key] = value;
|
||||||
});
|
});
|
||||||
@ -624,13 +670,28 @@
|
|||||||
|
|
||||||
// Get the currently available drivers
|
// Get the currently available drivers
|
||||||
$httpBackend.whenGET(/\/api\/ironic\/drivers\/$/)
|
$httpBackend.whenGET(/\/api\/ironic\/drivers\/$/)
|
||||||
.respond(responseCode.SUCCESS, {drivers: drivers});
|
.respond(function() {
|
||||||
|
return [responseCode.SUCCESS,
|
||||||
|
{drivers: service.getBaseDrivers()}];
|
||||||
|
});
|
||||||
|
|
||||||
// Get driver properties
|
// Get driver properties
|
||||||
$httpBackend.whenGET(/\/api\/ironic\/drivers\/([^\/]+)\/properties$/,
|
$httpBackend.whenGET(/\/api\/ironic\/drivers\/([^\/]+)\/properties$/,
|
||||||
undefined,
|
undefined,
|
||||||
['driverName'])
|
['driverName'])
|
||||||
.respond(responseCode.SUCCESS, []);
|
.respond(function(method, url, data, headers, params) {
|
||||||
|
return [responseCode.SUCCESS,
|
||||||
|
drivers[params.driverName].properties];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get driver details
|
||||||
|
$httpBackend.whenGET(/\/api\/ironic\/drivers\/([^\/]+)$/,
|
||||||
|
undefined,
|
||||||
|
['driverName'])
|
||||||
|
.respond(function(method, url, data, headers, params) {
|
||||||
|
return [responseCode.SUCCESS,
|
||||||
|
drivers[params.driverName].details];
|
||||||
|
});
|
||||||
|
|
||||||
// Get glance images
|
// Get glance images
|
||||||
$httpBackend.whenGET(/\/api\/glance\/images/)
|
$httpBackend.whenGET(/\/api\/glance\/images/)
|
||||||
@ -768,14 +829,29 @@
|
|||||||
} // init()
|
} // init()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Get the list of supported drivers
|
* @description Get the map of supported drivers
|
||||||
*
|
*
|
||||||
* @return {[]} Array of driver objects
|
* @return {Object} Dictionary of driver objects
|
||||||
*/
|
*/
|
||||||
function getDrivers() {
|
function getDrivers() {
|
||||||
return drivers;
|
return drivers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get list of available drivers
|
||||||
|
*
|
||||||
|
* @return {[]} List of drivers. Each driver contains name
|
||||||
|
* and type properties.
|
||||||
|
*/
|
||||||
|
function getBaseDrivers() {
|
||||||
|
var driverList = [];
|
||||||
|
angular.forEach(drivers, function(driver) {
|
||||||
|
driverList.push({name: driver.details.name,
|
||||||
|
type: driver.details.type});
|
||||||
|
});
|
||||||
|
return driverList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Get the list of images
|
* @description Get the list of images
|
||||||
*
|
*
|
||||||
|
@ -56,5 +56,17 @@
|
|||||||
EDIT_PORT_SUCCESS:'horizon.dashboard.admin.ironic.EDIT_PORT_SUCCESS'
|
EDIT_PORT_SUCCESS:'horizon.dashboard.admin.ironic.EDIT_PORT_SUCCESS'
|
||||||
};
|
};
|
||||||
$provide.constant('horizon.dashboard.admin.ironic.events', events);
|
$provide.constant('horizon.dashboard.admin.ironic.events', events);
|
||||||
|
|
||||||
|
$provide.constant('horizon.dashboard.admin.ironic.driverInterfaces',
|
||||||
|
['boot',
|
||||||
|
'console',
|
||||||
|
'deploy',
|
||||||
|
'inspect',
|
||||||
|
'management',
|
||||||
|
'network',
|
||||||
|
'power',
|
||||||
|
'raid',
|
||||||
|
'storage',
|
||||||
|
'vendor']);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
deleteNode: deleteNode,
|
deleteNode: deleteNode,
|
||||||
deletePort: deletePort,
|
deletePort: deletePort,
|
||||||
getDrivers: getDrivers,
|
getDrivers: getDrivers,
|
||||||
|
getDriverDetails: getDriverDetails,
|
||||||
getDriverProperties: getDriverProperties,
|
getDriverProperties: getDriverProperties,
|
||||||
getNode: getNode,
|
getNode: getNode,
|
||||||
getNodes: getNodes,
|
getNodes: getNodes,
|
||||||
@ -71,6 +72,19 @@
|
|||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get details of a specified driver
|
||||||
|
*
|
||||||
|
* @param {string} driverName - Name of the driver.
|
||||||
|
* @return {promise} Promise containing driver details.
|
||||||
|
*/
|
||||||
|
function getDriverDetails(driverName) {
|
||||||
|
return apiService.get('/api/ironic/drivers/' + driverName)
|
||||||
|
.then(function(response) {
|
||||||
|
return response.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Retrieve a list of nodes
|
* @description Retrieve a list of nodes
|
||||||
* http://developer.openstack.org/api-ref/baremetal/?
|
* http://developer.openstack.org/api-ref/baremetal/?
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
'deletePort',
|
'deletePort',
|
||||||
'deletePortgroup',
|
'deletePortgroup',
|
||||||
'getDrivers',
|
'getDrivers',
|
||||||
|
'getDriverDetails',
|
||||||
'getDriverProperties',
|
'getDriverProperties',
|
||||||
'getNode',
|
'getNode',
|
||||||
'getNodes',
|
'getNodes',
|
||||||
@ -120,10 +121,31 @@
|
|||||||
it('getDrivers', function() {
|
it('getDrivers', function() {
|
||||||
ironicAPI.getDrivers()
|
ironicAPI.getDrivers()
|
||||||
.then(function(drivers) {
|
.then(function(drivers) {
|
||||||
expect(drivers.length).toBeGreaterThan(0);
|
expect(drivers).toEqual(ironicBackendMockService.getBaseDrivers());
|
||||||
angular.forEach(drivers, function(driver) {
|
})
|
||||||
expect(driver.name).toBeDefined();
|
.catch(failTest);
|
||||||
|
|
||||||
|
ironicBackendMockService.flush();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getDriverDetails', function() {
|
||||||
|
var driver = ironicBackendMockService.params.defaultDriver;
|
||||||
|
ironicAPI.getDriverDetails(driver)
|
||||||
|
.then(function(details) {
|
||||||
|
var drivers = ironicBackendMockService.getDrivers();
|
||||||
|
expect(details).toEqual(drivers[driver].details);
|
||||||
|
})
|
||||||
|
.catch(failTest);
|
||||||
|
|
||||||
|
ironicBackendMockService.flush();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getDriverProperties', function() {
|
||||||
|
var driver = ironicBackendMockService.params.defaultDriver;
|
||||||
|
ironicAPI.getDriverProperties(driver)
|
||||||
|
.then(function(properties) {
|
||||||
|
var drivers = ironicBackendMockService.getDrivers();
|
||||||
|
expect(properties).toEqual(drivers[driver].properties);
|
||||||
})
|
})
|
||||||
.catch(failTest);
|
.catch(failTest);
|
||||||
|
|
||||||
@ -639,6 +661,7 @@
|
|||||||
|
|
||||||
ironicBackendMockService.flush();
|
ironicBackendMockService.flush();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -83,8 +83,8 @@
|
|||||||
ctrl.portgroupDetailsTemplateUrl = path + "portgroup-details.html";
|
ctrl.portgroupDetailsTemplateUrl = path + "portgroup-details.html";
|
||||||
|
|
||||||
ctrl.node = null;
|
ctrl.node = null;
|
||||||
ctrl.nodeValidation = [];
|
ctrl.nodeValidation = []; // List of validation results
|
||||||
ctrl.nodeValidationMap = {}; // Indexed by interface
|
ctrl.nodeValidationMap = {}; // Validation results indexed by interface
|
||||||
ctrl.nodeStateTransitions = [];
|
ctrl.nodeStateTransitions = [];
|
||||||
ctrl.nodePowerTransitions = [];
|
ctrl.nodePowerTransitions = [];
|
||||||
ctrl.ports = [];
|
ctrl.ports = [];
|
||||||
@ -155,19 +155,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.nodeGetInterface
|
|
||||||
* @description Retrieve the current underlying interface for specified interface
|
|
||||||
* type.
|
|
||||||
*
|
|
||||||
* @param {string} interfacename - Name of interface, e.g. power, boot, etc.
|
|
||||||
* @return {string} current name of interface for the requested interface type.
|
|
||||||
*/
|
|
||||||
function nodeGetInterface(interfacename) {
|
|
||||||
return ctrl.node[interfacename + '_interface'] === null ? 'None'
|
|
||||||
: ctrl.node[interfacename + '_interface'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.retrievePorts
|
* @name horizon.dashboard.admin.ironic.NodeDetailsController.retrievePorts
|
||||||
* @description Retrieve the ports associated with the current node,
|
* @description Retrieve the ports associated with the current node,
|
||||||
@ -227,7 +214,7 @@
|
|||||||
angular.forEach(response.data, function(interfaceStatus) {
|
angular.forEach(response.data, function(interfaceStatus) {
|
||||||
interfaceStatus.id = interfaceStatus.interface;
|
interfaceStatus.id = interfaceStatus.interface;
|
||||||
ctrl.nodeValidationMap[interfaceStatus.interface] = interfaceStatus;
|
ctrl.nodeValidationMap[interfaceStatus.interface] = interfaceStatus;
|
||||||
interfaceStatus.hw_interface = nodeGetInterface(interfaceStatus.interface);
|
interfaceStatus.hw_interface = ctrl.node[interfaceStatus.interface + '_interface'];
|
||||||
nodeValidation.push(interfaceStatus);
|
nodeValidation.push(interfaceStatus);
|
||||||
});
|
});
|
||||||
ctrl.nodeValidation = nodeValidation;
|
ctrl.nodeValidation = nodeValidation;
|
||||||
|
@ -338,7 +338,7 @@
|
|||||||
<span ng-switch-default class="fa fa-minus"></span>
|
<span ng-switch-default class="fa fa-minus"></span>
|
||||||
</td>
|
</td>
|
||||||
<td class="rsp-p1">
|
<td class="rsp-p1">
|
||||||
<span ng-if="item.result">
|
<span>
|
||||||
{$ item.hw_interface $}</span>
|
{$ item.hw_interface $}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="rsp-p2">
|
<td class="rsp-p2">
|
||||||
|
@ -27,19 +27,23 @@ var BASE_NODE_CONTROLLER_PROPERTIES = [
|
|||||||
'cancel',
|
'cancel',
|
||||||
'collectionCheckPropertyUnique',
|
'collectionCheckPropertyUnique',
|
||||||
'collectionDeleteProperty',
|
'collectionDeleteProperty',
|
||||||
|
'driverInterfaceFields',
|
||||||
'driverProperties',
|
'driverProperties',
|
||||||
'driverPropertyGroups',
|
'driverPropertyGroups',
|
||||||
'drivers',
|
'drivers',
|
||||||
'images',
|
'images',
|
||||||
'isDriverPropertyActive',
|
'isDriverPropertyActive',
|
||||||
'loadDriverProperties',
|
'loadDriver',
|
||||||
|
'_loadDriverDetails',
|
||||||
|
'_loadDriverProperties',
|
||||||
'loadingDriverProperties',
|
'loadingDriverProperties',
|
||||||
'modalTitle',
|
'modalTitle',
|
||||||
'node',
|
'node',
|
||||||
'propertyCollections',
|
'propertyCollections',
|
||||||
'readyToSubmit',
|
'readyToSubmit',
|
||||||
'submitButtonTitle',
|
'submitButtonTitle',
|
||||||
'validHostNameRegex'];
|
'validHostNameRegex',
|
||||||
|
'driverType'];
|
||||||
|
|
||||||
/* exported BASE_PORT_CONTROLLER_PROPERTIES */
|
/* exported BASE_PORT_CONTROLLER_PROPERTIES */
|
||||||
|
|
||||||
|
@ -82,9 +82,9 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Add instructions to the patch for processing a
|
* @description Add instructions to the patch for processing a
|
||||||
* specified item
|
* specified property or collection
|
||||||
*
|
*
|
||||||
* @param {object} item - item to be added
|
* @param {object} item - value of the item to be added
|
||||||
* @param {string} path - Path to the item being added
|
* @param {string} path - Path to the item being added
|
||||||
* @param {string} op - add or remove
|
* @param {string} op - add or remove
|
||||||
* @return {void}
|
* @return {void}
|
||||||
@ -92,9 +92,14 @@
|
|||||||
UpdatePatch.prototype._processItem = function(item, path, op) {
|
UpdatePatch.prototype._processItem = function(item, path, op) {
|
||||||
$log.info("UpdatePatch._processItem: " + path + " " + op);
|
$log.info("UpdatePatch._processItem: " + path + " " + op);
|
||||||
if (isProperty(item)) {
|
if (isProperty(item)) {
|
||||||
|
if (op === 'remove') {
|
||||||
|
this.patch.push({op: op, path: path});
|
||||||
|
} else {
|
||||||
this.patch.push({op: op, path: path, value: item});
|
this.patch.push({op: op, path: path, value: item});
|
||||||
|
}
|
||||||
} else if (isCollection(item)) {
|
} else if (isCollection(item)) {
|
||||||
angular.forEach(item, function(partName, part) {
|
$log.info("Processing collection " + path);
|
||||||
|
angular.forEach(item, function(part, partName) {
|
||||||
this._processItem(part, path + "/" + partName, op);
|
this._processItem(part, path + "/" + partName, op);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
20
package.json
20
package.json
@ -12,14 +12,16 @@
|
|||||||
"eslint": "1.10.3",
|
"eslint": "1.10.3",
|
||||||
"eslint-config-openstack": "1.2.4",
|
"eslint-config-openstack": "1.2.4",
|
||||||
"eslint-plugin-angular": "1.0.1",
|
"eslint-plugin-angular": "1.0.1",
|
||||||
"jasmine-core": "2.4.1",
|
"jasmine-core": "^2.4.1",
|
||||||
"karma": "1.1.2",
|
"karma": "^1.1.2",
|
||||||
"karma-chrome-launcher": "1.0.1",
|
"karma-chrome-launcher": "^1.0.1",
|
||||||
"karma-cli": "1.0.1",
|
"karma-cli": "1.0.1",
|
||||||
"karma-coverage": "1.1.1",
|
"karma-coverage": "^1.1.1",
|
||||||
"karma-jasmine": "1.0.2",
|
"karma-jasmine": "^1.0.2",
|
||||||
"karma-ng-html2js-preprocessor": "1.0.0",
|
"karma-jasmine-matchers": "^3.7.0",
|
||||||
"karma-threshold-reporter": "0.1.15"
|
"karma-ng-html2js-preprocessor": "^1.0.0",
|
||||||
|
"karma-phantomjs-launcher": "^1.0.4",
|
||||||
|
"karma-threshold-reporter": "^0.1.15"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "if [ ! -d .tox ] || [ ! -d .tox/py27 ]; then tox -epy27 --notest; fi",
|
"postinstall": "if [ ! -d .tox ] || [ ! -d .tox/py27 ]; then tox -epy27 --notest; fi",
|
||||||
@ -27,5 +29,7 @@
|
|||||||
"lint": "eslint --no-color ironic_ui/static",
|
"lint": "eslint --no-color ironic_ui/static",
|
||||||
"lintq": "eslint --quiet ironic_ui/static"
|
"lintq": "eslint --quiet ironic_ui/static"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {
|
||||||
|
"string.prototype.endswith": "^0.2.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support for selecting driver interfaces for dynamic drivers
|
||||||
|
while creating nodes. The support for driver interfaces is not compatible
|
||||||
|
with classic drivers. This feature is supported with Pike and further
|
||||||
|
versions of ironic.
|
Loading…
Reference in New Issue
Block a user