diff --git a/doc/source/user/proxies/baremetal.rst b/doc/source/user/proxies/baremetal.rst index da35cdcab..0b760a18f 100644 --- a/doc/source/user/proxies/baremetal.rst +++ b/doc/source/user/proxies/baremetal.rst @@ -21,7 +21,8 @@ Node Operations set_node_secure_boot, inject_nmi_to_node, wait_for_nodes_provision_state, set_node_power_state, wait_for_node_power_state, wait_for_node_reservation, validate_node, set_node_maintenance, - unset_node_maintenance, delete_node, list_node_vendor_passthru + unset_node_maintenance, delete_node, list_node_vendor_passthru, + get_node_console, enable_node_console, disable_node_console Node Trait Operations ^^^^^^^^^^^^^^^^^^^^^ diff --git a/openstack/baremetal/v1/_proxy.py b/openstack/baremetal/v1/_proxy.py index 0285fc773..8108939f0 100644 --- a/openstack/baremetal/v1/_proxy.py +++ b/openstack/baremetal/v1/_proxy.py @@ -1103,10 +1103,12 @@ class Proxy(proxy.Proxy): def call_node_vendor_passthru(self, node, verb, method, body=None): """Calls vendor_passthru for a node. - :param session: The session to use for making this request. + :param node: The value can be the name or ID of a node or a + :class:`~openstack.baremetal.v1.node.Node` instance. :param verb: The HTTP verb, one of GET, SET, POST, DELETE. :param method: The method to call using vendor_passthru. :param body: The JSON body in the HTTP call. + :returns: The raw response from the method. """ res = self._get_resource(_node.Node, node) return res.call_vendor_passthru(self, verb, method, body) @@ -1114,11 +1116,43 @@ class Proxy(proxy.Proxy): def list_node_vendor_passthru(self, node): """Lists vendor_passthru for a node. - :param session: The session to use for making this request. + :param node: The value can be the name or ID of a node or a + :class:`~openstack.baremetal.v1.node.Node` instance. + :returns: A list of vendor_passthru methods for the node. """ res = self._get_resource(_node.Node, node) return res.list_vendor_passthru(self) + def get_node_console(self, node): + """Get the console for a node. + + :param node: The value can be the name or ID of a node or a + :class:`~openstack.baremetal.v1.node.Node` instance. + :returns: Connection information for the console. + """ + res = self._get_resource(_node.Node, node) + return res.get_node_console(self) + + def enable_node_console(self, node): + """Enable the console for a node. + + :param node: The value can be the name or ID of a node or a + :class:`~openstack.baremetal.v1.node.Node` instance. + :returns: None + """ + res = self._get_resource(_node.Node, node) + return res.set_console_mode(self, True) + + def disable_node_console(self, node): + """Disable the console for a node. + + :param node: The value can be the name or ID of a node or a + :class:`~openstack.baremetal.v1.node.Node` instance. + :returns: None + """ + res = self._get_resource(_node.Node, node) + return res.set_console_mode(self, False) + def set_node_traits(self, node, traits): """Set traits for a node. diff --git a/openstack/baremetal/v1/node.py b/openstack/baremetal/v1/node.py index 276540abc..8d117b069 100644 --- a/openstack/baremetal/v1/node.py +++ b/openstack/baremetal/v1/node.py @@ -1080,6 +1080,52 @@ class Node(_common.ListMixin, resource.Resource): return response.json() + def get_console(self, session): + session = self._get_session(session) + version = self._get_microversion(session, action='fetch') + request = self._prepare_request(requires_id=True) + request.url = utils.urljoin(request.url, 'states', 'console') + + response = session.get( + request.url, + headers=request.headers, + microversion=version, + retriable_status_codes=_common.RETRIABLE_STATUS_CODES, + ) + + msg = "Failed to get console for node {node}".format( + node=self.id, + ) + exceptions.raise_from_response(response, error_message=msg) + + return response.json() + + def set_console_mode(self, session, enabled): + session = self._get_session(session) + version = self._get_microversion(session, action='commit') + request = self._prepare_request(requires_id=True) + request.url = utils.urljoin(request.url, 'states', 'console') + if not isinstance(enabled, bool): + raise ValueError( + "Invalid enabled %s. It should be True or False " + "corresponding to console enabled or disabled" + % enabled + ) + body = {'enabled': enabled} + + response = session.put( + request.url, + json=body, + headers=request.headers, + microversion=version, + retriable_status_codes=_common.RETRIABLE_STATUS_CODES, + ) + + msg = "Failed to change console mode for {node}".format( + node=self.id, + ) + exceptions.raise_from_response(response, error_message=msg) + def patch(self, session, patch=None, prepend_key=True, has_body=True, retry_on_conflict=None, base_path=None, reset_interfaces=None): diff --git a/openstack/tests/unit/baremetal/v1/test_node.py b/openstack/tests/unit/baremetal/v1/test_node.py index 73386fd3e..a943153d4 100644 --- a/openstack/tests/unit/baremetal/v1/test_node.py +++ b/openstack/tests/unit/baremetal/v1/test_node.py @@ -990,3 +990,43 @@ class TestNodePassthru(object): 'nodes/%s/vendor_passthru/methods' % self.node.id, headers=mock.ANY, microversion='1.37', retriable_status_codes=_common.RETRIABLE_STATUS_CODES) + + +@mock.patch.object(node.Node, 'fetch', lambda self, session: self) +@mock.patch.object(exceptions, 'raise_from_response', mock.Mock()) +class TestNodeConsole(base.TestCase): + + def setUp(self): + super().setUp() + self.node = node.Node(**FAKE) + self.session = mock.Mock( + spec=adapter.Adapter, + default_microversion='1.1', + ) + + def test_get_console(self): + self.node.get_console(self.session) + self.session.get.assert_called_once_with( + 'nodes/%s/states/console' % self.node.id, + headers=mock.ANY, + microversion=mock.ANY, + retriable_status_codes=_common.RETRIABLE_STATUS_CODES, + ) + + def test_set_console_mode(self): + self.node.set_console_mode(self.session, True) + self.session.put.assert_called_once_with( + 'nodes/%s/states/console' % self.node.id, + json={'enabled': True}, + headers=mock.ANY, + microversion=mock.ANY, + retriable_status_codes=_common.RETRIABLE_STATUS_CODES, + ) + + def test_set_console_mode_invalid_enabled(self): + self.assertRaises( + ValueError, + self.node.set_console_mode, + self.session, + 'true', # not a bool + ) diff --git a/releasenotes/notes/node-consoles-63589f22da98a689.yaml b/releasenotes/notes/node-consoles-63589f22da98a689.yaml new file mode 100644 index 000000000..95a2451d8 --- /dev/null +++ b/releasenotes/notes/node-consoles-63589f22da98a689.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Adds ``get_console`` and ``set_console_state`` to + ``openstack.baremetal.v1.Node``. + - | + Adds ``get_node_console``, ``enable_node_console`` and + ``disable_node_console`` to the baremetal Proxy.