diff --git a/ironicclient/osc/v1/baremetal_allocation.py b/ironicclient/osc/v1/baremetal_allocation.py index e65f641b0..e23517fc0 100644 --- a/ironicclient/osc/v1/baremetal_allocation.py +++ b/ironicclient/osc/v1/baremetal_allocation.py @@ -275,3 +275,99 @@ class DeleteBaremetalAllocation(command.Command): if failures: raise exc.ClientException("\n".join(failures)) + + +class SetBaremetalAllocation(command.Command): + """Set baremetal allocation properties.""" + + log = logging.getLogger(__name__ + ".SetBaremetalAllocation") + + def get_parser(self, prog_name): + parser = super(SetBaremetalAllocation, self).get_parser(prog_name) + + parser.add_argument( + "allocation", + metavar="", + help=_("Name or UUID of the allocation") + ) + parser.add_argument( + "--name", + metavar="", + help=_("Set the name of the allocation") + ) + parser.add_argument( + "--extra", + metavar="", + action="append", + help=_("Extra property to set on this allocation " + "(repeat option to set multiple extra properties)") + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + + baremetal_client = self.app.client_manager.baremetal + + properties = [] + if parsed_args.name: + properties.extend(utils.args_array_to_patch( + 'add', ["name=%s" % parsed_args.name])) + if parsed_args.extra: + properties.extend(utils.args_array_to_patch( + 'add', ["extra/" + x for x in parsed_args.extra])) + + if properties: + baremetal_client.allocation.update( + parsed_args.allocation, properties) + else: + self.log.warning("Please specify what to set.") + + +class UnsetBaremetalAllocation(command.Command): + """Unset baremetal allocation properties.""" + log = logging.getLogger(__name__ + ".UnsetBaremetalAllocation") + + def get_parser(self, prog_name): + parser = super(UnsetBaremetalAllocation, self).get_parser( + prog_name) + + parser.add_argument( + "allocation", + metavar="", + help=_("Name or UUID of the allocation") + ) + parser.add_argument( + "--name", + action="store_true", + default=False, + help=_("Unset the name of the allocation") + ) + parser.add_argument( + "--extra", + metavar="", + action='append', + help=_('Extra property to unset on this baremetal allocation ' + '(repeat option to unset multiple extra property).'), + ) + + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + + baremetal_client = self.app.client_manager.baremetal + + properties = [] + if parsed_args.name: + properties.extend(utils.args_array_to_patch('remove', + ['name'])) + if parsed_args.extra: + properties.extend(utils.args_array_to_patch('remove', + ['extra/' + x for x in parsed_args.extra])) + + if properties: + baremetal_client.allocation.update(parsed_args.allocation, + properties) + else: + self.log.warning("Please specify what to unset.") diff --git a/ironicclient/tests/functional/osc/v1/test_baremetal_allocation.py b/ironicclient/tests/functional/osc/v1/test_baremetal_allocation.py index b7a66ad38..9dcac0639 100644 --- a/ironicclient/tests/functional/osc/v1/test_baremetal_allocation.py +++ b/ironicclient/tests/functional/osc/v1/test_baremetal_allocation.py @@ -158,3 +158,32 @@ class BaremetalAllocationTests(base.TestCase): self.assertRaisesRegex(exceptions.CommandFailed, '--resource-class', self.openstack, base_cmd) + + def test_set_unset(self): + """Check baremetal allocation set and unset commands. + + Test steps: + 1) Create baremetal allocation in setUp. + 2) Set extra data for allocation. + 3) Check that baremetal allocation extra data was set. + 4) Unset extra data for allocation. + 5) Check that baremetal allocation extra data was unset. + """ + name = data_utils.rand_name('baremetal-allocation') + allocation = self.allocation_create(params='--name {}'.format(name)) + extra_key = 'ext' + extra_value = 'testdata' + self.openstack( + 'baremetal allocation set --extra {0}={1} {2}' + .format(extra_key, extra_value, allocation['uuid'])) + + show_prop = self.allocation_show(allocation['uuid'], + fields=['extra']) + self.assertEqual(extra_value, show_prop['extra'][extra_key]) + + self.openstack('baremetal allocation unset --extra {0} {1}' + .format(extra_key, allocation['uuid'])) + + show_prop = self.allocation_show(allocation['uuid'], + fields=['extra']) + self.assertNotIn(extra_key, show_prop['extra']) diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_allocation.py b/ironicclient/tests/unit/osc/v1/test_baremetal_allocation.py index 3dfbb8272..ef9990d54 100644 --- a/ironicclient/tests/unit/osc/v1/test_baremetal_allocation.py +++ b/ironicclient/tests/unit/osc/v1/test_baremetal_allocation.py @@ -490,3 +490,130 @@ class TestBaremetalAllocationDelete(TestBaremetalAllocation): self.assertRaises(osctestutils.ParserException, self.check_parser, self.cmd, arglist, verifylist) + + +class TestBaremetalAllocationSet(TestBaremetalAllocation): + def setUp(self): + super(TestBaremetalAllocationSet, self).setUp() + + self.baremetal_mock.allocation.update.return_value = ( + baremetal_fakes.FakeBaremetalResource( + None, + copy.deepcopy(baremetal_fakes.ALLOCATION), + loaded=True)) + + self.cmd = baremetal_allocation.SetBaremetalAllocation( + self.app, None) + + def test_baremetal_allocation_set_name(self): + new_name = 'foo' + arglist = [ + baremetal_fakes.baremetal_uuid, + '--name', new_name] + verifylist = [ + ('allocation', baremetal_fakes.baremetal_uuid), + ('name', new_name)] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.allocation.update.assert_called_once_with( + baremetal_fakes.baremetal_uuid, + [{'path': '/name', 'value': new_name, 'op': 'add'}]) + + def test_baremetal_allocation_set_extra(self): + extra_value = 'foo=bar' + arglist = [ + baremetal_fakes.baremetal_uuid, + '--extra', extra_value] + verifylist = [ + ('allocation', baremetal_fakes.baremetal_uuid), + ('extra', [extra_value])] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.allocation.update.assert_called_once_with( + baremetal_fakes.baremetal_uuid, + [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}]) + + def test_baremetal_allocation_set_no_options(self): + arglist = [] + verifylist = [] + self.assertRaises(osctestutils.ParserException, + self.check_parser, + self.cmd, arglist, verifylist) + + +class TestBaremetalAllocationUnset(TestBaremetalAllocation): + def setUp(self): + super(TestBaremetalAllocationUnset, self).setUp() + + self.baremetal_mock.allocation.update.return_value = ( + baremetal_fakes.FakeBaremetalResource( + None, + copy.deepcopy(baremetal_fakes.ALLOCATION), + loaded=True)) + + self.cmd = baremetal_allocation.UnsetBaremetalAllocation( + self.app, None) + + def test_baremetal_allocation_unset_name(self): + arglist = [ + baremetal_fakes.baremetal_uuid, '--name'] + verifylist = [('allocation', + baremetal_fakes.baremetal_uuid), + ('name', True)] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.allocation.update.assert_called_once_with( + baremetal_fakes.baremetal_uuid, + [{'path': '/name', 'op': 'remove'}]) + + def test_baremetal_allocation_unset_extra(self): + arglist = [ + baremetal_fakes.baremetal_uuid, '--extra', 'key1'] + verifylist = [('allocation', + baremetal_fakes.baremetal_uuid), + ('extra', ['key1'])] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.allocation.update.assert_called_once_with( + baremetal_fakes.baremetal_uuid, + [{'path': '/extra/key1', 'op': 'remove'}]) + + def test_baremetal_allocation_unset_multiple_extras(self): + arglist = [ + baremetal_fakes.baremetal_uuid, + '--extra', 'key1', '--extra', 'key2'] + verifylist = [('allocation', + baremetal_fakes.baremetal_uuid), + ('extra', ['key1', 'key2'])] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.baremetal_mock.allocation.update.assert_called_once_with( + baremetal_fakes.baremetal_uuid, + [{'path': '/extra/key1', 'op': 'remove'}, + {'path': '/extra/key2', 'op': 'remove'}]) + + def test_baremetal_allocation_unset_no_options(self): + arglist = [] + verifylist = [] + self.assertRaises(osctestutils.ParserException, + self.check_parser, + self.cmd, arglist, verifylist) + + def test_baremetal_allocation_unset_no_property(self): + uuid = baremetal_fakes.baremetal_uuid + arglist = [uuid] + verifylist = [('allocation', uuid)] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + self.assertFalse(self.baremetal_mock.allocation.update.called) diff --git a/ironicclient/v1/allocation.py b/ironicclient/v1/allocation.py index 64b2913e8..f835828d3 100644 --- a/ironicclient/v1/allocation.py +++ b/ironicclient/v1/allocation.py @@ -139,3 +139,11 @@ class AllocationManager(base.CreateManager): 'active, the current state is %(actual)s', {'allocation': allocation_id, 'actual': allocation.state}) + + def update(self, allocation_id, patch): + """Updates the Allocation. Only 'name' and 'extra' field are allowed. + + :param allocation_id: The UUID or name of an allocation. + :param patch: a json PATCH document to apply to this allocation. + """ + return self._update(resource_id=allocation_id, patch=patch) diff --git a/releasenotes/notes/allow-allocation-update-b4fb715045ab40a2.yaml b/releasenotes/notes/allow-allocation-update-b4fb715045ab40a2.yaml new file mode 100644 index 000000000..21f84b679 --- /dev/null +++ b/releasenotes/notes/allow-allocation-update-b4fb715045ab40a2.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Adds support for the allocation update API introduced in API + version 1.57. Adds new commands: + + * ``openstack baremetal allocation set`` + * ``openstack baremetal allocation unset`` diff --git a/setup.cfg b/setup.cfg index 52a8b0488..cd3cb1262 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,8 @@ openstack.baremetal.v1 = baremetal_allocation_delete = ironicclient.osc.v1.baremetal_allocation:DeleteBaremetalAllocation baremetal_allocation_list = ironicclient.osc.v1.baremetal_allocation:ListBaremetalAllocation baremetal_allocation_show = ironicclient.osc.v1.baremetal_allocation:ShowBaremetalAllocation + baremetal_allocation_set = ironicclient.osc.v1.baremetal_allocation:SetBaremetalAllocation + baremetal_allocation_unset = ironicclient.osc.v1.baremetal_allocation:UnsetBaremetalAllocation baremetal_chassis_create = ironicclient.osc.v1.baremetal_chassis:CreateBaremetalChassis baremetal_chassis_delete = ironicclient.osc.v1.baremetal_chassis:DeleteBaremetalChassis baremetal_chassis_list = ironicclient.osc.v1.baremetal_chassis:ListBaremetalChassis