From 2b6b32fa3dd80f0d9d05ddf9130a02464ed5bf2a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 26 Jul 2023 11:14:14 +0100 Subject: [PATCH] baremetal: Decode 'config_drive' argument to 'set_provision_state' ironicclient automatically decoded the base64-encoded byte strings provided to the 'node.set_provision_state' method. We should do the same. Change-Id: Ib4997d11b460078cddf2f422223a67a216cf17df Signed-off-by: Stephen Finucane --- openstack/baremetal/v1/node.py | 8 ++++++++ openstack/tests/unit/baremetal/v1/test_node.py | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/openstack/baremetal/v1/node.py b/openstack/baremetal/v1/node.py index 052358400..524930413 100644 --- a/openstack/baremetal/v1/node.py +++ b/openstack/baremetal/v1/node.py @@ -465,6 +465,14 @@ class Node(_common.Resource): 'Config drive can only be provided with ' '"active" and "rebuild" targets' ) + if isinstance(config_drive, bytes): + try: + config_drive = config_drive.decode('utf-8') + except UnicodeError: + raise ValueError( + 'Config drive must be a dictionary or a base64 ' + 'encoded string' + ) # Not a typo - ironic accepts "configdrive" (without underscore) body['configdrive'] = config_drive diff --git a/openstack/tests/unit/baremetal/v1/test_node.py b/openstack/tests/unit/baremetal/v1/test_node.py index 022f99466..9fb440143 100644 --- a/openstack/tests/unit/baremetal/v1/test_node.py +++ b/openstack/tests/unit/baremetal/v1/test_node.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import base64 from unittest import mock from keystoneauth1 import adapter @@ -338,6 +339,20 @@ class TestNodeSetProvisionState(base.TestCase): retriable_status_codes=_common.RETRIABLE_STATUS_CODES, ) + def test_deploy_with_configdrive_as_bytestring(self): + config_drive = base64.b64encode(b'foo') + result = self.node.set_provision_state( + self.session, 'active', config_drive=config_drive + ) + self.assertIs(result, self.node) + self.session.put.assert_called_once_with( + 'nodes/%s/states/provision' % self.node.id, + json={'target': 'active', 'configdrive': config_drive.decode()}, + headers=mock.ANY, + microversion=None, + retriable_status_codes=_common.RETRIABLE_STATUS_CODES, + ) + def test_rebuild_with_configdrive(self): result = self.node.set_provision_state( self.session, 'rebuild', config_drive='abcd'