Add support for starting/stopping/accessing the serial console

- The action menu in the node-details panel has a new item
Enable|Disable console.
- The node-details/overview panel has a new "Console info." item
in the "General" section. The value of this field is dependent on
the console type. For "shellinabox" the value is an anchor with
the URL of the console and title "shellinabox". For others, the
value is a string representation of the console_info object
returned by the get_console api call.

Closes-Bug: #1655690
Change-Id: Ibfa687f50d2251987276367d743ffb2a88e52796
This commit is contained in:
Peter Piela 2017-02-23 10:01:49 -05:00
parent 327aa2022f
commit 6193569103
7 changed files with 149 additions and 6 deletions

View File

@ -27,7 +27,6 @@ from openstack_dashboard.api import base
DEFAULT_IRONIC_API_VERSION = '1.20'
DEFAULT_INSECURE = False
DEFAULT_CACERT = None
IRONIC_CLIENT_CLASS_NAME = 'baremetal'
@ -117,6 +116,31 @@ def node_set_provision_state(request, node_id, state, cleansteps=None):
cleansteps=cleansteps)
def node_set_console_mode(request, node_id, enabled):
"""Start or stop the serial console for a given node.
:param request: HTTP request.
:param node_id: The UUID or name of the node.
:param enabled: True to start the console, False to stop it
:return: node.
http://docs.openstack.org/developer/python-ironicclient/api/ironicclient.v1.node.html#ironicclient.v1.node.NodeManager.set_console_mode
"""
return ironicclient(request).node.set_console_mode(node_id, enabled)
def node_get_console(request, node_id):
"""Get connection information for a node's console.
:param request: HTTP request.
:param node_id: The UUID or name of the node.
:return: Console connection information
http://docs.openstack.org/developer/python-ironicclient/api/ironicclient.v1.node.html#ironicclient.v1.node.NodeManager.get_console
"""
return ironicclient(request).node.get_console(node_id)
def node_set_maintenance(request, node_id, state, maint_reason=None):
"""Set the maintenance mode on a given node.
@ -194,7 +218,7 @@ def node_get_boot_device(request, node_id):
"""Get the boot device for a specified node.
:param request: HTTP request.
:param node_id: The id of the node.
:param node_id: The UUID or name of the node.
:return: Dictionary with keys "boot_device" and "persistent"
http://docs.openstack.org/developer/python-ironicclient/api/ironicclient.v1.node.html#ironicclient.v1.node.NodeManager.get_boot_device
@ -250,16 +274,16 @@ def port_delete(request, port_uuid):
return ironicclient(request).port.delete(port_uuid)
def port_update(request, port_id, patch):
def port_update(request, port_uuid, patch):
"""Update a specified port.
:param request: HTTP request.
:param node_id: The uuid of the port.
:param port_id: The UUID of the port.
:param patch: Sequence of update operations
:return: port.
:return: Port.
http://docs.openstack.org/developer/python-ironicclient/api/ironicclient.v1.port.html#ironicclient.v1.port.PortManager.update
"""
port = ironicclient(request).port.update(port_id, patch)
port = ironicclient(request).port.update(port_uuid, patch)
return dict([(f, getattr(port, f, ''))
for f in res_fields.PORT_DETAILED_RESOURCE.fields])

View File

@ -177,6 +177,34 @@ class StatesProvision(generic.View):
clean_steps)
@urls.register
class StatesConsole(generic.View):
url_regex = r'ironic/nodes/(?P<node_uuid>[0-9a-f-]+)/states/console$'
@rest_utils.ajax()
def get(self, request, node_uuid):
"""Get connection information for the node's console
:param request: HTTP request.
:param node_id: Node uuid
:return: Connection information
"""
return ironic.node_get_console(request, node_uuid)
@rest_utils.ajax(data_required=True)
def put(self, request, node_uuid):
"""Start or stop the serial console.
:param request: HTTP request.
:param node_id: Node uuid
:return: Return code
"""
return ironic.node_set_console_mode(request,
node_uuid,
request.DATA.get('enabled'))
@urls.register
class Maintenance(generic.View):

View File

@ -50,6 +50,8 @@
getNodes: getNodes,
getPortsWithNode: getPortsWithNode,
getBootDevice: getBootDevice,
nodeGetConsole: nodeGetConsole,
nodeSetConsoleMode: nodeSetConsoleMode,
powerOffNode: powerOffNode,
powerOnNode: powerOnNode,
putNodeInMaintenanceMode: putNodeInMaintenanceMode,
@ -514,6 +516,44 @@
return $q.reject(msg);
});
}
/**
* @description Set the console mode of the node.
*
* http://developer.openstack.org/api-ref/baremetal/?
* expanded=start-stop-console-detail#start-stop-console
*
* @param {string} uuid UUID of a node.
* @param {boolean} enabled true to start the console, false to stop it
* @return {promise} Promise
*/
function nodeSetConsoleMode(uuid, enabled) {
return apiService.put('/api/ironic/nodes/' + uuid + '/states/console',
{enabled: enabled})
.then(function(response) {
var msg = gettext('Refresh page to see updated console details');
toastService.add('success', interpolate(msg, [uuid], false));
return response.data;
})
.catch(function(response) {
var msg = gettext('Unable to set console mode: %s');
toastService.add('error', interpolate(msg, [response.data], false));
return $q.reject(msg);
});
}
function nodeGetConsole(uuid) {
return apiService.get('/api/ironic/nodes/' + uuid + '/states/console')
.then(function(response) {
return response.data; // Object containing console information
})
.catch(function(response) {
var msg = gettext('Unable to get console for node %s: %s');
toastService.add('error',
interpolate(msg, [uuid, response.data], false));
return $q.reject(msg);
});
}
}
}());

View File

@ -72,6 +72,7 @@
ctrl.node = null;
ctrl.nodeValidation = [];
ctrl.nodeValidationMap = {}; // Indexed by interface
ctrl.nodeStateTransitions = [];
ctrl.ports = [];
ctrl.portsSrc = [];
@ -84,11 +85,14 @@
ctrl.deletePort = deletePort;
ctrl.editPort = editPort;
ctrl.refresh = refresh;
ctrl.toggleConsoleMode = toggleConsoleMode;
$scope.emptyObject = function(obj) {
return angular.isUndefined(obj) || Object.keys(obj).length === 0;
};
$scope.isDefined = angular.isDefined;
var editNodeHandler =
$rootScope.$on(ironicEvents.EDIT_NODE_SUCCESS,
function() {
@ -149,6 +153,10 @@
return ironic.getNode(uuid).then(function (node) {
ctrl.node = node;
ctrl.node.id = ctrl.node.uuid;
ironic.nodeGetConsole(uuid).then(function(consoleData) {
ctrl.node.console_enabled = consoleData.console_enabled;
ctrl.node.console_info = consoleData.console_info;
});
});
}
@ -188,9 +196,11 @@
function validateNode() {
ironic.validateNode(ctrl.node.uuid).then(function(response) {
var nodeValidation = [];
ctrl.nodeValidationMap = {};
angular.forEach(response.data, function(status) {
status.id = status.interface;
nodeValidation.push(status);
ctrl.nodeValidationMap[status.interface] = status;
});
ctrl.nodeValidation = nodeValidation;
});
@ -274,5 +284,15 @@
function refresh() {
init();
}
/**
* @name horizon.dashboard.admin.ironic.NodeDetailsController.toggleConsoleMode
* @description Toggle the state of the console for the current node
*
* @return {void}
*/
function toggleConsoleMode() {
ironic.nodeSetConsoleMode(ctrl.node.uuid, !ctrl.node.console_enabled);
}
}
})();

View File

@ -49,6 +49,12 @@
callback="ctrl.editNode">
{$ ::'Edit' | translate $}
</action>
<action button-type="menu-item"
disabled="isDefined(ctrl.nodeValidationMap.console)
&& ctrl.nodeValidationMap.console.result===false"
callback="ctrl.toggleConsoleMode">
{$ ctrl.node.console_enabled ? 'Disable console' : 'Enable console' | translate $}
</action>
</menu>
</action-list>
</div>

View File

@ -21,6 +21,16 @@
<dd>{$ ctrl.node.reservation | noValue $}</dd>
<dt translate>Console Enabled</dt>
<dd>{$ ctrl.node.console_enabled | yesno $}</dd>
<dt translate>Console Info</dt>
<dd ng-if="ctrl.node.console_info.type==='shellinabox'">
<a href="{$ ctrl.node.console_info.url $}"
title="{$ 'Click link to view console' | translate $}">
shellinabox
</a>
</dd>
<dd ng-if="ctrl.node.console_info.type!=='shellinabox'">
{$ ctrl.node.console_info | noValue $}
</dd>
</dl>
</div>

View File

@ -0,0 +1,15 @@
---
features:
- |
Support has been added for starting, stopping, and accessing the
console associated with a node.
- |
The action dropdown menu in the node-details panel has a new item
``Enable|Disable console``.
- |
The node-details/overview panel has a new ``Console info`` item in the
``General`` section. The value of this field is dependent on the console
type. For ``shellinabox`` the value is an anchor with the URL required
to access the web console and title ``shellinabox``. For others, the
value is a string representation of the console_info object returned
by the get_console api call.