Added node details page to the plugin
Added details page files to the plugin. Change-Id: I17e4c749038dfa9f4a8423796186c133d248fba0 Co-Authored-By: Peter Piela <ppiela@cray.com>
This commit is contained in:
parent
5f8fc8b7a0
commit
f230e96da5
11
ironic_ui/content/ironic/templates/ironic/node_detail.html
Normal file
11
ironic_ui/content/ironic/templates/ironic/node_detail.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Node Details" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
<hz-page-header header="{% trans "Node Details" %}"></hz-page-header>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<ng-include src="'{{ STATIC_URL }}dashboard/admin/ironic/node-details/node-details.html'"></ng-include>
|
||||||
|
{% endblock %}
|
@ -110,7 +110,7 @@
|
|||||||
|
|
||||||
function putNodeInMaintenanceMode(uuid, reason) {
|
function putNodeInMaintenanceMode(uuid, reason) {
|
||||||
var data = {
|
var data = {
|
||||||
maint_reason: (reason ? reason : gettext('No maintenance reason given.'))
|
maint_reason: (reason ? reason : gettext("No maintenance reason given."))
|
||||||
};
|
};
|
||||||
return apiService.patch('/api/ironic/nodes/' + uuid + '/maintenance', data).error(function() {
|
return apiService.patch('/api/ironic/nodes/' + uuid + '/maintenance', data).error(function() {
|
||||||
toastService.add('error',
|
toastService.add('error',
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||||
|
* 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')
|
||||||
|
.controller('horizon.dashboard.admin.ironic.NodeDetailsController',
|
||||||
|
IronicNodeDetailsController);
|
||||||
|
|
||||||
|
IronicNodeDetailsController.$inject = [
|
||||||
|
'$location',
|
||||||
|
'horizon.app.core.openstack-service-api.ironic',
|
||||||
|
'horizon.dashboard.admin.ironic.actions',
|
||||||
|
'horizon.dashboard.admin.basePath'
|
||||||
|
];
|
||||||
|
|
||||||
|
function IronicNodeDetailsController($location, ironic, actions, basePath) {
|
||||||
|
var ctrl = this;
|
||||||
|
var path = basePath + 'ironic/node-details/sections/';
|
||||||
|
|
||||||
|
ctrl.actions = actions;
|
||||||
|
|
||||||
|
ctrl.sections = [
|
||||||
|
{
|
||||||
|
heading: gettext('Overview'),
|
||||||
|
templateUrl: path + 'overview.html'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: gettext('Configuration'),
|
||||||
|
templateUrl: path + 'configuration.html'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
ctrl.basePath = basePath;
|
||||||
|
ctrl.init = init;
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
// Fetch the Node ID from the URL.
|
||||||
|
var pattern = /(.*\/admin\/ironic\/)(.+)\/(detail)?/;
|
||||||
|
var uuid = $location.absUrl().match(pattern)[2];
|
||||||
|
|
||||||
|
retrieveNode(uuid).then(function () {
|
||||||
|
retrievePorts(uuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function retrieveNode(uuid) {
|
||||||
|
return ironic.getNode(uuid).then(function (response) {
|
||||||
|
var node = response.data;
|
||||||
|
ctrl.node = node;
|
||||||
|
if (node['target_power_state']) {
|
||||||
|
actions.updateNode(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function retrievePorts(node_id) {
|
||||||
|
ironic.getPortsWithNode(node_id).then(function (response) {
|
||||||
|
ctrl.ports = response.data.items;
|
||||||
|
// Ensure that the vif_port_id property exists for all ports
|
||||||
|
angular.forEach(ctrl.ports,
|
||||||
|
function(port, key) {
|
||||||
|
if (angular.isUndefined(port.extra.vif_port_id)) {
|
||||||
|
port.extra.vif_port_id = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Hewlett Packard Enterprise Development Company LP
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
describe('horizon.dashboard.admin.ironic.node-details', function () {
|
||||||
|
var ctrl, $q;
|
||||||
|
var nodeUuid = "0123abcd-0123-4567-abcd-0123456789ab";
|
||||||
|
var nodeName = "herp";
|
||||||
|
var numPorts = 2;
|
||||||
|
|
||||||
|
function portUuid(nodeUuid, index) {
|
||||||
|
return '' + index + index + nodeUuid.substring(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPort(nodeUuid, index, extra) {
|
||||||
|
return {uuid: portUuid(nodeUuid, index), extra: extra};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNode(name, uuid) {
|
||||||
|
return {name: name, uuid: uuid};
|
||||||
|
}
|
||||||
|
|
||||||
|
var ironicAPI = {
|
||||||
|
getNode: function (uuid) {
|
||||||
|
var node = createNode(nodeName, uuid);
|
||||||
|
return $q.when({data: node});
|
||||||
|
},
|
||||||
|
|
||||||
|
getPortsWithNode: function (uuid) {
|
||||||
|
var ports = [];
|
||||||
|
for (var i = 0; i < numPorts; i++) {
|
||||||
|
ports.push(createPort(uuid, i, {}));
|
||||||
|
}
|
||||||
|
return $q.when({data: {items: ports}});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(module('horizon.dashboard.admin.ironic'));
|
||||||
|
|
||||||
|
beforeEach(module('horizon.app.core.openstack-service-api', function($provide) {
|
||||||
|
$provide.value('horizon.app.core.openstack-service-api.ironic', ironicAPI);
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(inject(function ($injector, _$rootScope_, _$location_) {
|
||||||
|
var scope = _$rootScope_.$new();
|
||||||
|
$q = $injector.get('$q');
|
||||||
|
var controller = $injector.get('$controller');
|
||||||
|
var $location = _$location_;
|
||||||
|
$location.path('/admin/ironic/' + nodeUuid + '/');
|
||||||
|
|
||||||
|
ctrl = controller('horizon.dashboard.admin.ironic.NodeDetailsController', {
|
||||||
|
$scope: scope,
|
||||||
|
$location: $location,
|
||||||
|
'horizon.dashboard.admin.ironic.actions': {},
|
||||||
|
'horizon.dashboard.admin.basePath': '/static'});
|
||||||
|
ctrl.init();
|
||||||
|
|
||||||
|
scope.$apply();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should be defined', function () {
|
||||||
|
expect(ctrl).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a basePath', function () {
|
||||||
|
expect(ctrl.basePath).toBeDefined();
|
||||||
|
expect(ctrl.basePath).toEqual('/static');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a node', function () {
|
||||||
|
expect(ctrl.node).toBeDefined();
|
||||||
|
expect(ctrl.node).toEqual(createNode(nodeName, nodeUuid))
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have ports', function () {
|
||||||
|
expect(ctrl.ports).toBeDefined();
|
||||||
|
expect(ctrl.ports.length).toEqual(numPorts);
|
||||||
|
|
||||||
|
var ports = [];
|
||||||
|
for (var i = 0; i < ctrl.ports.length; i++) {
|
||||||
|
ports.push(createPort(ctrl.node.uuid, i, {vif_port_id: ''}));
|
||||||
|
}
|
||||||
|
expect(ctrl.ports).toEqual(ports);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,45 @@
|
|||||||
|
<div class="detail-page"
|
||||||
|
ng-controller="horizon.dashboard.admin.ironic.NodeDetailsController as ctrl"
|
||||||
|
ng-init="ctrl.init()">
|
||||||
|
|
||||||
|
<div class="pull-right">
|
||||||
|
<action-list dropdown>
|
||||||
|
<action button-type="split-button"
|
||||||
|
action-classes="'btn btn-default btn-sm'"
|
||||||
|
callback="ctrl.actions.powerOn"
|
||||||
|
item="ctrl.node"
|
||||||
|
disabled="ctrl.node['power_state']!=='power off'">
|
||||||
|
{$ 'Power on' | translate $}
|
||||||
|
</action>
|
||||||
|
<menu>
|
||||||
|
<action button-type="menu-item"
|
||||||
|
callback="ctrl.actions.powerOff"
|
||||||
|
item="ctrl.node"
|
||||||
|
disabled="ctrl.node['power_state']!=='power on'">
|
||||||
|
{$ 'Power off' | translate $}
|
||||||
|
</action>
|
||||||
|
<action button-type="menu-item"
|
||||||
|
callback="ctrl.actions.promptForPutNodeInMaintenanceMode"
|
||||||
|
item="ctrl.node"
|
||||||
|
disabled="ctrl.node['maintenance']">
|
||||||
|
{$ 'Maintenance on' | translate $}
|
||||||
|
</action>
|
||||||
|
<action button-type="menu-item"
|
||||||
|
callback="ctrl.actions.removeNodeFromMaintenanceMode"
|
||||||
|
item="ctrl.node"
|
||||||
|
disabled="!ctrl.node['maintenance']">
|
||||||
|
{$ 'Maintenance off' | translate $}
|
||||||
|
</action>
|
||||||
|
</menu>
|
||||||
|
</action-list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
<tabset>
|
||||||
|
<tab ng-repeat="section in ctrl.sections"
|
||||||
|
heading="{$ section.heading $}">
|
||||||
|
<ng-include src="section.templateUrl"></ng-include>
|
||||||
|
</tab>
|
||||||
|
</tabset>
|
||||||
|
</div>
|
@ -0,0 +1,120 @@
|
|||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<!-- General -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>General</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt translate>Node ID</dt>
|
||||||
|
<dd>{$ ctrl.node['uuid'] $}</dd>
|
||||||
|
<dt translate>Chassis ID</dt>
|
||||||
|
<dd>{$ ctrl.node['chassis_uuid'] $}</dd>
|
||||||
|
<dt translate>Created At</dt>
|
||||||
|
<dd>{$ ctrl.node['created_at'] $}</dd>
|
||||||
|
<dt translate>Extra</dt>
|
||||||
|
<dd>{$ ctrl.node['extra'] $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Ports -->
|
||||||
|
<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="port.extra.vif_port_id">
|
||||||
|
<a href="/admin/networks/ports/{$ port.extra.vif_port_id $}/detail">
|
||||||
|
{$ port.address $}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
<dd ng-if="!port.extra.vif_port_id">
|
||||||
|
{$ port.address $}
|
||||||
|
</dd>
|
||||||
|
<p ng-repeat-end></p>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Properties -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>Properties</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt translate>Memory</dt>
|
||||||
|
<dd>{$ ctrl.node['properties']['memory_mb'] + ' MB' $}</dd>
|
||||||
|
<dt translate>CPU Arch</dt>
|
||||||
|
<dd>{$ ctrl.node['properties']['cpu_arch'] $}</dd>
|
||||||
|
<dt translate>Local GB</dt>
|
||||||
|
<dd>{$ ctrl.node['properties']['local_gb'] $}</dd>
|
||||||
|
<dt translate>CPUs</dt>
|
||||||
|
<dd>{$ ctrl.node['properties']['cpus'] $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Driver Info -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>Driver Info</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<div ng-switch="ctrl.node['driver']">
|
||||||
|
<dl ng-switch-when="pxe_ssh" class="dl-horizontal">
|
||||||
|
<dt translate>Driver</dt>
|
||||||
|
<dd>{$ ctrl.node['driver'] $}</dd>
|
||||||
|
<dt translate>SSH Port</dt>
|
||||||
|
<dd>{$ ctrl.node['driver_info']['ssh_port'] $}</dd>
|
||||||
|
<dt translate>SSH Username</dt>
|
||||||
|
<dd>{$ ctrl.node['driver_info']['ssh_username'] $}</dd>
|
||||||
|
<dt translate>Deploy Kernel</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="/admin/images/{$ ctrl.node['driver_info']['deploy_kernel'] $}/detail">
|
||||||
|
{$ ctrl.node['driver_info']['deploy_kernel'] $}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
<dt translate>Deploy Ramdisk</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="/admin/images/{$ ctrl.node['driver_info']['deploy_ramdisk'] $}/detail">
|
||||||
|
{$ ctrl.node['driver_info']['deploy_ramdisk'] $}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<dl ng-switch-default class="dl-horizontal">
|
||||||
|
<dt ng-repeat-start="(id, value) in ctrl.node['driver_info']">{$ id $}</dt>
|
||||||
|
<dd ng-repeat-end>{$ value $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Capabilities -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>Capabilities</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dd>{$ ctrl.node['capabilities'] $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Instance Info -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>Instance Info</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt translate>Instance Name</dt>
|
||||||
|
<dd>{$ ctrl.node['instance_info']['display_name'] $}</dd>
|
||||||
|
<dt translate>Ramdisk</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="/admin/images/{$ ctrl.node['instance_info']['ramdisk'] $}/detail">
|
||||||
|
{$ ctrl.node['instance_info']['ramdisk'] $}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
<dt translate>Kernel</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="/admin/images/{$ ctrl.node['instance_info']['kernel'] $}/detail">
|
||||||
|
{$ ctrl.node['instance_info']['kernel'] $}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,50 @@
|
|||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<!-- General -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>General</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt translate>Name</dt>
|
||||||
|
<dd>{$ ctrl.node['name'] $}</dd>
|
||||||
|
<dt translate>Maintenance</dt>
|
||||||
|
<dd>{$ ctrl.node['maintenance'] ? 'True' : 'False' $}</dd>
|
||||||
|
<dt translate>Maintenance Reason</dt>
|
||||||
|
<dd>{$ ctrl.node['maintenance_reason'] $}</dd>
|
||||||
|
<dt translate>Inspection Started At</dt>
|
||||||
|
<dd>{$ ctrl.node['inspection_started_at'] $}</dd>
|
||||||
|
<dt translate>Inspection Finished At</dt>
|
||||||
|
<dd>{$ ctrl.node['inspection_finished_at'] $}</dd>
|
||||||
|
<dt translate>Reservation</dt>
|
||||||
|
<dd>{$ ctrl.node['reservation'] $}</dd>
|
||||||
|
<dt translate>Console Enabled</dt>
|
||||||
|
<dd>{$ ctrl.node['console_enabled'] ? 'True' : 'False' $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Provisioning Status -->
|
||||||
|
<div class="col-md-6 status detail">
|
||||||
|
<h4 translate>Provisioning Status</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt translate>Instance ID</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="/admin/instances/{$ ctrl.node['instance_uuid'] $}/detail">
|
||||||
|
{$ ctrl.node['instance_uuid'] $}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
<dt translate>Power State</dt>
|
||||||
|
<dd ng-class="{'running': ctrl.node['target_power_state']}">{$ ctrl.node['power_state'] $}</dd>
|
||||||
|
<dt translate>Target Power State</dt>
|
||||||
|
<dd>{$ ctrl.node['target_power_state'] $}</dd>
|
||||||
|
<dt translate>Provision State</dt>
|
||||||
|
<dd>{$ ctrl.node['provision_state'] $}</dd>
|
||||||
|
<dt translate>Target Provision State</dt>
|
||||||
|
<dd>{$ ctrl.node['target_provision_state'] $}</dd>
|
||||||
|
<dt translate>Last Error</dt>
|
||||||
|
<dd>{$ ctrl.node['last_error'] $}</dd>
|
||||||
|
<dt translate>Updated At</dt>
|
||||||
|
<dd>{$ ctrl.node['updated_at'] $}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
x
Reference in New Issue
Block a user