Merge "Add support for starting/stopping/accessing the serial console"
This commit is contained in:
commit
31d3897a20
@ -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])
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}());
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
15
releasenotes/notes/add-console-support-ccffcedc845ca214.yaml
Normal file
15
releasenotes/notes/add-console-support-ccffcedc845ca214.yaml
Normal 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.
|
Loading…
Reference in New Issue
Block a user