Added support for creating/deleting network ports
Network ports can be created in both the node list and node detail pages. Network ports can be deleted from the the node detail page. Change-Id: I3047a0adef9df58aaabd0f2d99a09351233fa06b
This commit is contained in:
parent
f43592f456
commit
04973a788d
@ -166,3 +166,24 @@ def driver_properties(request, driver_name):
|
||||
:return: Property list
|
||||
"""
|
||||
return ironicclient(request).driver.properties(driver_name)
|
||||
|
||||
|
||||
def port_create(request, params):
|
||||
"""Create network port
|
||||
|
||||
:param request: HTTP request
|
||||
:param params: Port creation parameters
|
||||
:return: Port
|
||||
"""
|
||||
port_manager = ironicclient(request).port
|
||||
return port_manager.create(**params)
|
||||
|
||||
|
||||
def port_delete(request, port_uuid):
|
||||
"""Delete a network port
|
||||
|
||||
:param request: HTTP request
|
||||
:param port_uuid: Port uuid
|
||||
:return: Port
|
||||
"""
|
||||
return ironicclient(request).port.delete(port_uuid)
|
||||
|
@ -93,6 +93,25 @@ class Ports(generic.View):
|
||||
'items': [i.to_dict() for i in items],
|
||||
}
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def post(self, request):
|
||||
"""Create a network port
|
||||
|
||||
:param request: HTTP request
|
||||
:return: Port
|
||||
"""
|
||||
port = request.DATA.get('port')
|
||||
return ironic.port_create(request, port).to_dict()
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def delete(self, request):
|
||||
"""Delete a network port
|
||||
|
||||
:param request: HTTP request
|
||||
"""
|
||||
params = request.DATA.get('port_uuid')
|
||||
return ironic.port_delete(request, params)
|
||||
|
||||
|
||||
@urls.register
|
||||
class StatesPower(generic.View):
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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')
|
||||
.directive('autoFocus', AutoFocus);
|
||||
|
||||
AutoFocus.$inject = ['$timeout'];
|
||||
|
||||
function AutoFocus($timeout) {
|
||||
return {
|
||||
restrict: 'AC',
|
||||
link: function(scope, elem) {
|
||||
$timeout(function() {
|
||||
elem[0].focus();
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 create a network port on a specified node
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.admin.ironic')
|
||||
.controller('CreatePortController', CreatePortController);
|
||||
|
||||
CreatePortController.$inject = [
|
||||
'$rootScope',
|
||||
'$modalInstance',
|
||||
'horizon.app.core.openstack-service-api.ironic',
|
||||
'horizon.dashboard.admin.ironic.events',
|
||||
'$log',
|
||||
'node'
|
||||
];
|
||||
|
||||
function CreatePortController($rootScope,
|
||||
$modalInstance,
|
||||
ironic,
|
||||
ironicEvents,
|
||||
$log,
|
||||
node) {
|
||||
var ctrl = this;
|
||||
|
||||
// Paramater object that defines the port to be created
|
||||
ctrl.port = {
|
||||
node_uuid: node.id,
|
||||
address: null,
|
||||
extra: {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel the port creation process
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
ctrl.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the defined port
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
ctrl.createPort = function() {
|
||||
ironic.createPort(ctrl.port).then(
|
||||
function() {
|
||||
$modalInstance.close();
|
||||
$rootScope.$emit(ironicEvents.CREATE_PORT_SUCCESS);
|
||||
},
|
||||
function() {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a port metadata property
|
||||
*
|
||||
* @param {string} propertyName - Name of the property
|
||||
* @return {void}
|
||||
*/
|
||||
ctrl.deleteExtra = function(propertyName) {
|
||||
delete ctrl.port.extra[propertyName];
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether the specified port 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.port.extra);
|
||||
};
|
||||
}
|
||||
})();
|
@ -0,0 +1,90 @@
|
||||
<div class="modal-header" modal-draggable>
|
||||
<button type="button"
|
||||
class="close"
|
||||
ng-click="$dismiss()"
|
||||
aria-hidden="true"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true" class="fa fa-times"></span>
|
||||
</button>
|
||||
<h3 class="modal-title" translate>Create Port</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="CreatePortForm" name="CreatePortForm">
|
||||
<div class="form-group"
|
||||
ng-class="{'has-error': CreatePortForm.macAddress.$invalid &&
|
||||
CreatePortForm.macAddress.$dirty}">
|
||||
<label for="macAddress"
|
||||
class="control-label"
|
||||
translate>MAC address</label>
|
||||
<div>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
ng-model="ctrl.port.address"
|
||||
id="macAddress"
|
||||
name="macAddress"
|
||||
ng-required="true"
|
||||
ng-pattern="'([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})'"
|
||||
auto-focus
|
||||
placeholder="{$ 'MAC address for this port. Required.' | translate $}"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form id="AddExtraForm" name="AddExtraForm" style="margin-bottom:10px;">
|
||||
<label for="extras" class="control-label" translate>Extras</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon"
|
||||
style="width:25%;text-align:right">
|
||||
Add Extra:</span>
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
ng-model="extraName"
|
||||
validate-unique="ctrl.checkExtraUnique"
|
||||
placeholder="{$ 'Property Name' | translate $}"/>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary"
|
||||
type="button"
|
||||
ng-disabled="!extraName || AddExtraForm.$invalid"
|
||||
ng-click="ctrl.port.extra[extraName] = null;
|
||||
extraName = null">
|
||||
<span class="fa fa-plus"> </span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="form-horizontal" id="ExtraForm" name="ExtraForm">
|
||||
<div class="input-group input-group-sm"
|
||||
ng-repeat="(propertyName, propertyValue) in ctrl.port.extra">
|
||||
<span class="input-group-addon"
|
||||
style="width:25%;text-align:right">
|
||||
{$ propertyName $}
|
||||
</span>
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
name="{$ propertyName $}"
|
||||
ng-model="ctrl.port.extra[propertyName]"
|
||||
ng-required="true"/>
|
||||
<div class="input-group-btn">
|
||||
<a class="btn btn-default"
|
||||
ng-click="ctrl.deleteExtra(propertyName)">
|
||||
<span class="fa fa-minus"> </span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!--modal footer-->
|
||||
<div class="modal-footer ng-scope">
|
||||
<button class="btn btn-default" ng-click="ctrl.cancel()">
|
||||
<span class="fa fa-close"></span>
|
||||
<span class="ng-scope" translate>Cancel</span>
|
||||
</button>
|
||||
<button type="submit"
|
||||
ng-disabled="CreatePortForm.$invalid || ExtraForm.$invalid"
|
||||
ng-click="ctrl.createPort()"
|
||||
class="btn btn-primary"
|
||||
translate>
|
||||
Create Port
|
||||
</button>
|
||||
</div>
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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')
|
||||
.factory('horizon.dashboard.admin.ironic.create-port.service',
|
||||
createPortService);
|
||||
|
||||
createPortService.$inject = [
|
||||
'$modal',
|
||||
'horizon.dashboard.admin.basePath'
|
||||
];
|
||||
|
||||
function createPortService($modal, basePath) {
|
||||
var service = {
|
||||
modal: modal
|
||||
};
|
||||
return service;
|
||||
|
||||
function modal(node) {
|
||||
var options = {
|
||||
controller: 'CreatePortController as ctrl',
|
||||
backdrop: 'static',
|
||||
resolve: {
|
||||
node: function() {
|
||||
return node;
|
||||
}
|
||||
},
|
||||
templateUrl: basePath + '/ironic/create-port/create-port.html'
|
||||
};
|
||||
return $modal.open(options);
|
||||
}
|
||||
}
|
||||
})();
|
@ -27,6 +27,7 @@
|
||||
'$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',
|
||||
@ -36,6 +37,7 @@
|
||||
function EnrollNodeController($rootScope,
|
||||
$modalInstance,
|
||||
ironic,
|
||||
ironicEvents,
|
||||
glance,
|
||||
enrollNodeService,
|
||||
validHostNamePattern,
|
||||
@ -276,7 +278,7 @@
|
||||
ironic.createNode(ctrl.node).then(
|
||||
function() {
|
||||
$modalInstance.close();
|
||||
$rootScope.$emit('ironic-ui:new-node');
|
||||
$rootScope.$emit(ironicEvents.ENROLL_NODE_SUCCESS);
|
||||
},
|
||||
function() {
|
||||
// No additional error processing for now
|
||||
|
@ -31,6 +31,16 @@
|
||||
'^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$') // eslint-disable-line max-len
|
||||
|
||||
.constant('horizon.dashboard.admin.ironic.validUuidPattern',
|
||||
'^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'); // eslint-disable-line max-len
|
||||
'^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$') // eslint-disable-line max-len
|
||||
.constant('horizon.dashboard.admin.ironic.events', events());
|
||||
|
||||
function events() {
|
||||
return {
|
||||
ENROLL_NODE_SUCCESS:'horizon.dashboard.admin.ironic.ENROLL_NODE_SUCCESS',
|
||||
DELETE_NODE_SUCCESS:'horizon.dashboard.admin.ironic.DELETE_NODE_SUCCESS',
|
||||
CREATE_PORT_SUCCESS:'horizon.dashboard.admin.ironic.CREATE_PORT_SUCCESS',
|
||||
DELETE_PORT_SUCCESS:'horizon.dashboard.admin.ironic.DELETE_PORT_SUCCESS'
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -28,7 +28,7 @@
|
||||
];
|
||||
|
||||
/**
|
||||
* Service that provides access to the Ironic client API
|
||||
* @description Service that provides access to the Ironic client API
|
||||
*
|
||||
* @param {object} apiService - HTTP service
|
||||
* @param {object} toastService - User message service
|
||||
@ -37,7 +37,9 @@
|
||||
function ironicAPI(apiService, toastService) {
|
||||
var service = {
|
||||
createNode: createNode,
|
||||
createPort: createPort,
|
||||
deleteNode: deleteNode,
|
||||
deletePort: deletePort,
|
||||
getDrivers: getDrivers,
|
||||
getDriverProperties: getDriverProperties,
|
||||
getNode: getNode,
|
||||
@ -52,7 +54,7 @@
|
||||
return service;
|
||||
|
||||
/**
|
||||
* Retrieve a list of nodes
|
||||
* @description Retrieve a list of nodes
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#get--v1-nodes
|
||||
*
|
||||
* @return {promise} Node collection in JSON
|
||||
@ -67,7 +69,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve information about the given node.
|
||||
* @description Retrieve information about the given node.
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#get--v1-
|
||||
* nodes-(node_ident)
|
||||
@ -84,7 +86,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of ports associated with a node.
|
||||
* @description Retrieve a list of ports associated with a node.
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#get--v1-ports
|
||||
*
|
||||
@ -106,7 +108,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the node in maintenance mode.
|
||||
* @description Put the node in maintenance mode.
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#
|
||||
* put--v1-nodes-(node_ident)-maintenance
|
||||
@ -130,7 +132,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the node from maintenance mode.
|
||||
* @description Remove the node from maintenance mode.
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#
|
||||
* delete--v1-nodes-(node_ident)-maintenance
|
||||
@ -148,7 +150,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the power state of the node.
|
||||
* @description Set the power state of the node.
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#
|
||||
* put--v1-nodes-(node_ident)-states-power
|
||||
@ -173,7 +175,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the power state of the node.
|
||||
* @description Set the power state of the node.
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#
|
||||
* put--v1-nodes-(node_ident)-states-power
|
||||
@ -198,7 +200,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Ironic node
|
||||
* @description Create an Ironic node
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#post--v1-nodes
|
||||
*
|
||||
@ -220,7 +222,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specified node from inventory
|
||||
* @description Delete the specified node from inventory
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#
|
||||
* delete--v1-nodes
|
||||
@ -244,7 +246,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of Ironic drivers
|
||||
* @description Retrieve the list of Ironic drivers
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#get--v1-drivers
|
||||
*
|
||||
@ -259,7 +261,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve properities of a specified driver
|
||||
* @description Retrieve properities of a specified driver
|
||||
*
|
||||
* http://docs.openstack.org/developer/ironic/webapi/v1.html#
|
||||
* get--v1-drivers-properties
|
||||
@ -276,6 +278,47 @@
|
||||
toastService.add('error', interpolate(msg, [reason], false));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Create a network port
|
||||
*
|
||||
* @param {object} port – Object containing parameters that define
|
||||
* the port to be created
|
||||
* @return {promise} Promise
|
||||
*/
|
||||
function createPort(port) {
|
||||
var data = {
|
||||
port: port
|
||||
};
|
||||
return apiService.post('/api/ironic/ports/', data)
|
||||
.success(function() {
|
||||
toastService.add('success',
|
||||
gettext('Port successfully created'));
|
||||
})
|
||||
.error(function(reason) {
|
||||
var msg = gettext('Unable to create port: %s');
|
||||
toastService.add('error', interpolate(msg, [reason], false));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Delete a network port
|
||||
*
|
||||
* @param {string} portUuid – UUID of the port to be deleted
|
||||
* @return {promise} Promise
|
||||
*/
|
||||
function deletePort(portUuid) {
|
||||
var data = {
|
||||
port_uuid: portUuid
|
||||
};
|
||||
return apiService.delete('/api/ironic/ports/', data)
|
||||
.success(function() {
|
||||
})
|
||||
.error(function(reason) {
|
||||
var msg = gettext('Unable to delete port: %s');
|
||||
toastService.add('error', interpolate(msg, [reason], false));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}());
|
||||
|
@ -34,6 +34,20 @@
|
||||
var DELETE_NODES_SUCCESS = gettext('Successfully deleted nodes "%s"');
|
||||
var DELETE_NODES_ERROR = gettext('Error deleting nodes "%s"');
|
||||
|
||||
var DELETE_PORT_TITLE = gettext("Delete Port");
|
||||
var DELETE_PORT_MSG =
|
||||
gettext('Are you sure you want to delete port "%s"? ' +
|
||||
'This action cannot be undone.');
|
||||
var DELETE_PORT_SUCCESS = gettext('Successfully deleted port "%s"');
|
||||
var DELETE_PORT_ERROR = gettext('Unable to delete port "%s"');
|
||||
|
||||
var DELETE_PORTS_TITLE = gettext("Delete Ports");
|
||||
var DELETE_PORTS_MSG =
|
||||
gettext('Are you sure you want to delete ports "%s"? ' +
|
||||
'This action cannot be undone.');
|
||||
var DELETE_PORTS_SUCCESS = gettext('Successfully deleted ports "%s"');
|
||||
var DELETE_PORTS_ERROR = gettext('Error deleting ports "%s"');
|
||||
|
||||
angular
|
||||
.module('horizon.dashboard.admin.ironic')
|
||||
.factory('horizon.dashboard.admin.ironic.actions', actions);
|
||||
@ -41,15 +55,26 @@
|
||||
actions.$inject = [
|
||||
'horizon.app.core.openstack-service-api.ironic',
|
||||
'horizon.framework.widgets.toast.service',
|
||||
'horizon.dashboard.admin.ironic.events',
|
||||
'horizon.framework.widgets.modal.deleteModalService',
|
||||
'horizon.dashboard.admin.ironic.create-port.service',
|
||||
'$q',
|
||||
'$rootScope'
|
||||
];
|
||||
|
||||
function actions(ironic, toastService, deleteModalService, $q, $rootScope) {
|
||||
function actions(ironic,
|
||||
toastService,
|
||||
ironicEvents,
|
||||
deleteModalService,
|
||||
createPortService,
|
||||
$q,
|
||||
$rootScope) {
|
||||
var service = {
|
||||
createPort: createPort,
|
||||
deleteNode: deleteNode,
|
||||
deleteNodes: deleteNodes,
|
||||
deletePort: deletePort,
|
||||
deletePorts: deletePorts,
|
||||
powerOn: powerOn,
|
||||
powerOff: powerOff,
|
||||
powerOnAll: powerOnNodes,
|
||||
@ -73,7 +98,7 @@
|
||||
var context = {
|
||||
labels: labels,
|
||||
deleteEntity: ironic.deleteNode,
|
||||
successEvent: "ironic-ui:delete-node-success"
|
||||
successEvent: ironicEvents.DELETE_NODE_SUCCESS
|
||||
};
|
||||
return deleteModalService.open($rootScope, [node], context);
|
||||
}
|
||||
@ -89,7 +114,7 @@
|
||||
var context = {
|
||||
labels: labels,
|
||||
deleteEntity: ironic.deleteNode,
|
||||
successEvent: "ironic-ui:delete-node-success"
|
||||
successEvent: ironicEvents.DELETE_NODE_SUCCESS
|
||||
};
|
||||
return deleteModalService.open($rootScope, nodes, context);
|
||||
}
|
||||
@ -166,6 +191,42 @@
|
||||
return applyFuncToNodes(removeFromMaintenanceMode, nodes);
|
||||
}
|
||||
|
||||
function createPort(node) {
|
||||
return createPortService.modal(node);
|
||||
}
|
||||
|
||||
function deletePort(port) {
|
||||
var labels = {
|
||||
title: DELETE_PORT_TITLE,
|
||||
message: DELETE_PORT_MSG,
|
||||
submit: DELETE_PORT_TITLE,
|
||||
success: DELETE_PORT_SUCCESS,
|
||||
error: DELETE_PORT_ERROR
|
||||
};
|
||||
var context = {
|
||||
labels: labels,
|
||||
deleteEntity: ironic.deletePort,
|
||||
successEvent: ironicEvents.DELETE_PORT_SUCCESS
|
||||
};
|
||||
return deleteModalService.open($rootScope, [port], context);
|
||||
}
|
||||
|
||||
function deletePorts(ports) {
|
||||
var labels = {
|
||||
title: DELETE_PORTS_TITLE,
|
||||
message: DELETE_PORTS_MSG,
|
||||
submit: DELETE_PORTS_TITLE,
|
||||
success: DELETE_PORTS_SUCCESS,
|
||||
error: DELETE_PORTS_ERROR
|
||||
};
|
||||
var context = {
|
||||
labels: labels,
|
||||
deleteEntity: ironic.deletePort,
|
||||
successEvent: ironicEvents.DELETE_PORT_SUCCESS
|
||||
};
|
||||
return deleteModalService.open($rootScope, ports, context);
|
||||
}
|
||||
|
||||
/*
|
||||
* @name horizon.dashboard.admin.ironic.actions.applyFuncToNodes
|
||||
* @description Apply a specified function to each member of a
|
||||
|
@ -23,21 +23,31 @@
|
||||
IronicNodeDetailsController);
|
||||
|
||||
IronicNodeDetailsController.$inject = [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
'$location',
|
||||
'horizon.app.core.openstack-service-api.ironic',
|
||||
'horizon.dashboard.admin.ironic.events',
|
||||
'horizon.dashboard.admin.ironic.actions',
|
||||
'horizon.dashboard.admin.basePath',
|
||||
'horizon.dashboard.admin.ironic.maintenance.service'
|
||||
'horizon.dashboard.admin.ironic.maintenance.service',
|
||||
'horizon.dashboard.admin.ironic.validUuidPattern'
|
||||
];
|
||||
|
||||
function IronicNodeDetailsController($location,
|
||||
function IronicNodeDetailsController($scope,
|
||||
$rootScope,
|
||||
$location,
|
||||
ironic,
|
||||
ironicEvents,
|
||||
actions,
|
||||
basePath,
|
||||
maintenanceService) {
|
||||
maintenanceService,
|
||||
validUuidPattern) {
|
||||
var ctrl = this;
|
||||
var path = basePath + 'ironic/node-details/sections/';
|
||||
|
||||
ctrl.noPortsText = gettext('No network ports have been defined');
|
||||
|
||||
ctrl.actions = actions;
|
||||
|
||||
ctrl.sections = [
|
||||
@ -51,18 +61,42 @@
|
||||
}
|
||||
];
|
||||
|
||||
ctrl.ports = [];
|
||||
ctrl.portsSrc = [];
|
||||
ctrl.basePath = basePath;
|
||||
ctrl.re_uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
|
||||
ctrl.re_uuid = new RegExp(validUuidPattern);
|
||||
ctrl.isUuid = isUuid;
|
||||
ctrl.getVifPortId = getVifPortId;
|
||||
ctrl.putNodeInMaintenanceMode = putNodeInMaintenanceMode;
|
||||
ctrl.removeNodeFromMaintenanceMode = removeNodeFromMaintenanceMode;
|
||||
ctrl.createPort = createPort;
|
||||
ctrl.deletePort = deletePort;
|
||||
ctrl.deletePorts = deletePorts;
|
||||
|
||||
var createPortHandler =
|
||||
$rootScope.$on(ironicEvents.CREATE_PORT_SUCCESS,
|
||||
function() {
|
||||
init();
|
||||
});
|
||||
|
||||
var deletePortHandler =
|
||||
$rootScope.$on(ironicEvents.DELETE_PORT_SUCCESS,
|
||||
function() {
|
||||
init();
|
||||
$scope.$broadcast('hzTable:clearSelected');
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
createPortHandler();
|
||||
deletePortHandler();
|
||||
});
|
||||
|
||||
init();
|
||||
|
||||
/**
|
||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.init
|
||||
* @description Initialize the controller instance based on the current page url.
|
||||
* @description Initialize the controller instance based on the
|
||||
* current page url.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
@ -87,20 +121,24 @@
|
||||
function retrieveNode(uuid) {
|
||||
return ironic.getNode(uuid).then(function (response) {
|
||||
ctrl.node = response.data;
|
||||
ctrl.node.id = uuid;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.retrievePorts
|
||||
* @description Retrieve the ports associated with a specified node, and store
|
||||
* them in the controller instance.
|
||||
* @description Retrieve the ports associated with a specified node,
|
||||
* and store them in the controller instance.
|
||||
*
|
||||
* @param {string} nodeId – Node name or UUID
|
||||
* @return {void}
|
||||
*/
|
||||
function retrievePorts(nodeId) {
|
||||
ironic.getPortsWithNode(nodeId).then(function (response) {
|
||||
ctrl.ports = response.data.items;
|
||||
ctrl.portsSrc = response.data.items;
|
||||
ctrl.portsSrc.forEach(function(port) {
|
||||
port.id = port.uuid;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -109,7 +147,8 @@
|
||||
* @description Test whether a string is an OpenStack UUID
|
||||
*
|
||||
* @param {string} str – string
|
||||
* @return {boolean} True if the string is an OpenStack UUID, otherwise false
|
||||
* @return {boolean} True if the string is an OpenStack UUID,
|
||||
* otherwise false
|
||||
*/
|
||||
function isUuid(str) {
|
||||
return !!str.match(ctrl.re_uuid);
|
||||
@ -120,7 +159,8 @@
|
||||
* @description Get the vif_port_id property of a specified port
|
||||
*
|
||||
* @param {object} port – instance of port
|
||||
* @return {string} Value of vif_port_id property or "" if the property does not exist
|
||||
* @return {string} Value of vif_port_id property or
|
||||
* "" if the property does not exist
|
||||
*/
|
||||
function getVifPortId(port) {
|
||||
return angular.isDefined(port.extra) &&
|
||||
@ -135,5 +175,42 @@
|
||||
function removeNodeFromMaintenanceMode() {
|
||||
maintenanceService.removeNodeFromMaintenanceMode(ctrl.node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.createPort
|
||||
* @description Initiate creation of a newtwork port for the current
|
||||
* node
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function createPort() {
|
||||
ctrl.actions.createPort(ctrl.node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.deletePort
|
||||
* @description Delete a specified port
|
||||
*
|
||||
* @param {port []} port – port to be deleted
|
||||
* @return {void}
|
||||
*/
|
||||
function deletePort(port) {
|
||||
ctrl.actions.deletePort({id: port.uuid, name: port.address});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name horizon.dashboard.admin.ironic.NodeDetailsController.deletePorts
|
||||
* @description Delete a specified list of ports
|
||||
*
|
||||
* @param {port []} ports – list of ports to be deleted
|
||||
* @return {void}
|
||||
*/
|
||||
function deletePorts(ports) {
|
||||
var selectedPorts = [];
|
||||
angular.forEach(ports, function(port) {
|
||||
selectedPorts.push({id: port.uuid, name: port.address});
|
||||
});
|
||||
ctrl.actions.deletePorts(selectedPorts);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
@ -8,9 +8,9 @@
|
||||
<dt translate>Node ID</dt>
|
||||
<dd>{$ ctrl.node.uuid $}</dd>
|
||||
<dt translate>Chassis ID</dt>
|
||||
<dd>{$ ctrl.node.chassis_uuid $}</dd>
|
||||
<dd>{$ ctrl.node.chassis_uuid | noValue $}</dd>
|
||||
<dt translate>Created At</dt>
|
||||
<dd>{$ ctrl.node.created_at $}</dd>
|
||||
<dd>{$ ctrl.node.created_at | date:'medium' $}</dd>
|
||||
<dt translate>Extra</dt>
|
||||
<dd>{$ ctrl.node.extra $}</dd>
|
||||
</dl>
|
||||
@ -20,19 +20,89 @@
|
||||
<div class="col-md-6 status detail">
|
||||
<h4 translate>Ports</h4>
|
||||
<hr class="header_rule">
|
||||
<dl class="dl-horizontal">
|
||||
<dt ng-repeat-start="port in ctrl.ports">
|
||||
{$ 'MAC ' + (1 + $index) $}</dt>
|
||||
<dd ng-if="vif_port_id = ctrl.getVifPortId(port)">
|
||||
<a href="/dashboard/admin/networks/ports/{$ vif_port_id $}/detail">
|
||||
{$ port.address $}
|
||||
</a>
|
||||
</dd>
|
||||
<dd ng-if="!vif_port_id">
|
||||
{$ port.address $}
|
||||
</dd>
|
||||
<p ng-repeat-end></p>
|
||||
</dl>
|
||||
<table hz-table ng-cloak
|
||||
st-table="ctrl.ports"
|
||||
st-safe-src="ctrl.portsSrc"
|
||||
class="table table-striped table-rsp table-detail">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="4" class="action-col">
|
||||
<action-list dropdown class="pull-right">
|
||||
<action button-type="split-button"
|
||||
action-classes="'btn btn-default btn-sm'"
|
||||
callback="ctrl.createPort">
|
||||
{$ 'Create port' | translate $}
|
||||
</action>
|
||||
<menu>
|
||||
<action button-type="menu-item"
|
||||
callback="ctrl.deletePorts"
|
||||
item="tCtrl.selected"
|
||||
disabled="tCtrl.selected.length === 0">
|
||||
<span class="fa fa-trash"></span>
|
||||
{$ 'Delete ports' | translate $}
|
||||
</action>
|
||||
</menu>
|
||||
</action-list>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="multi_select_column">
|
||||
<input type="checkbox"
|
||||
hz-select-all="ctrl.ports"/>
|
||||
</th>
|
||||
<th translate class="rsp-p1" style="white-space:nowrap">
|
||||
MAC Address
|
||||
</th>
|
||||
<th translate class="rsp-p2" style="width:100%;">
|
||||
Extra
|
||||
</th>
|
||||
<th translate class="actions_column">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="port in ctrl.ports">
|
||||
<td class="multi_select_column">
|
||||
<input type="checkbox"
|
||||
hz-select="port"
|
||||
ng-model="tCtrl.selections[port.id].checked"/>
|
||||
<td ng-if="vif_port_id = ctrl.getVifPortId(port)"
|
||||
class="rsp-p1">
|
||||
<a href="/dashboard/admin/networks/ports/{$ vif_port_id $}/detail">
|
||||
{$ port.address $}
|
||||
</a>
|
||||
</td>
|
||||
<td ng-if="!vif_port_id" class="rsp-p1">
|
||||
{$ port.address $}
|
||||
</td>
|
||||
<td>
|
||||
<dl class="dl-horizontal">
|
||||
<dt style="width:auto;" ng-repeat-start="(id, value) in port.extra">
|
||||
{$ id $}
|
||||
</dt>
|
||||
<dd>
|
||||
{$ value $}
|
||||
</dd>
|
||||
<p ng-repeat-end></p>
|
||||
</dl>
|
||||
</td>
|
||||
<td class="actions_column">
|
||||
<action-list>
|
||||
<action action-classes="'btn btn-default btn-sm'"
|
||||
callback="ctrl.deletePort"
|
||||
item="port">
|
||||
<span class="fa fa-trash"></span>
|
||||
</action>
|
||||
</action-list>
|
||||
</td>
|
||||
</tr>
|
||||
<tr hz-no-items
|
||||
items="ctrl.ports"
|
||||
message="ctrl.noPortsText">
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
IronicNodeListController.$inject = [
|
||||
'$rootScope',
|
||||
'horizon.app.core.openstack-service-api.ironic',
|
||||
'horizon.dashboard.admin.ironic.events',
|
||||
'horizon.dashboard.admin.ironic.actions',
|
||||
'horizon.dashboard.admin.basePath',
|
||||
'horizon.dashboard.admin.ironic.maintenance.service',
|
||||
@ -32,6 +33,7 @@
|
||||
|
||||
function IronicNodeListController($rootScope,
|
||||
ironic,
|
||||
ironicEvents,
|
||||
actions,
|
||||
basePath,
|
||||
maintenanceService,
|
||||
@ -87,11 +89,19 @@
|
||||
];
|
||||
|
||||
// Listen for the creation of new nodes, and update the node list
|
||||
$rootScope.$on('ironic-ui:new-node', function() {
|
||||
$rootScope.$on(ironicEvents.ENROLL_NODE_SUCCESS, function() {
|
||||
init();
|
||||
});
|
||||
|
||||
$rootScope.$on('ironic-ui:delete-node-success', function() {
|
||||
$rootScope.$on(ironicEvents.DELETE_NODE_SUCCESS, function() {
|
||||
init();
|
||||
});
|
||||
|
||||
$rootScope.$on(ironicEvents.CREATE_PORT_SUCCESS, function() {
|
||||
init();
|
||||
});
|
||||
|
||||
$rootScope.$on(ironicEvents.DELETE_PORT_SUCCESS, function() {
|
||||
init();
|
||||
});
|
||||
|
||||
|
@ -122,7 +122,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="rsp-p2">{$ node.provision_state $}</td>
|
||||
<td class="rsp-p2">{$ node.maintenance $}</td>
|
||||
<td class="rsp-p2">{$ node.maintenance | yesno $}</td>
|
||||
<td class="rsp-p2">{$ node.ports.length $}</td>
|
||||
<td class="rsp-p2">{$ node.driver $}</td>
|
||||
<td class="actions_column">
|
||||
@ -160,6 +160,11 @@
|
||||
<span class="fa fa-trash"></span>
|
||||
{$ 'Delete node' | translate $}
|
||||
</action>
|
||||
<action button-type="menu-item"
|
||||
callback="table.actions.createPort"
|
||||
item="node">
|
||||
{$ 'Create port' | translate $}
|
||||
</action>
|
||||
</menu>
|
||||
</action-list>
|
||||
</td>
|
||||
|
Loading…
Reference in New Issue
Block a user