Add support for retired{_reason} fields.
This change adds support to set and unset the 'retired' and 'retired_reason' fields. It also extends the 'list' command with an additional '--retired' parameter to list only nodes which have the retired property. Story: #2005425 Task: #38143 Depends-On: https://review.opendev.org/703981 Change-Id: I5fe379c4ff439b3a083ae819ce5b4bdbddd22b3a
This commit is contained in:
parent
a64370701e
commit
81eebfc404
@ -40,7 +40,7 @@ from ironicclient import exc
|
||||
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
|
||||
# for full details.
|
||||
DEFAULT_VER = '1.9'
|
||||
LAST_KNOWN_API_VERSION = 60
|
||||
LAST_KNOWN_API_VERSION = 61
|
||||
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -591,6 +591,12 @@ class ListBaremetalNode(command.Lister):
|
||||
default=None,
|
||||
help=_("Limit list to nodes not in maintenance mode"),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--retired',
|
||||
dest='retired',
|
||||
action='store_true',
|
||||
default=None,
|
||||
help=_("Limit list to retired nodes."))
|
||||
parser.add_argument(
|
||||
'--fault',
|
||||
dest='fault',
|
||||
@ -683,7 +689,7 @@ class ListBaremetalNode(command.Lister):
|
||||
params['associated'] = True
|
||||
if parsed_args.unassociated:
|
||||
params['associated'] = False
|
||||
for field in ['maintenance', 'fault', 'conductor_group']:
|
||||
for field in ['maintenance', 'fault', 'conductor_group', 'retired']:
|
||||
if getattr(parsed_args, field) is not None:
|
||||
params[field] = getattr(parsed_args, field)
|
||||
for field in ['provision_state', 'driver', 'resource_class',
|
||||
@ -1160,6 +1166,16 @@ class SetBaremetalNode(command.Command):
|
||||
metavar='<protected_reason>',
|
||||
help=_('Set the reason of marking the node as protected'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--retired',
|
||||
action='store_true',
|
||||
help=_('Mark the node as retired'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--retired-reason',
|
||||
metavar='<retired_reason>',
|
||||
help=_('Set the reason of marking the node as retired'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--target-raid-config',
|
||||
metavar='<target_raid_config>',
|
||||
@ -1227,7 +1243,7 @@ class SetBaremetalNode(command.Command):
|
||||
for field in ['automated_clean', 'instance_uuid', 'name',
|
||||
'chassis_uuid', 'driver', 'resource_class',
|
||||
'conductor_group', 'protected', 'protected_reason',
|
||||
'owner', 'description']:
|
||||
'retired', 'retired_reason', 'owner', 'description']:
|
||||
value = getattr(parsed_args, field)
|
||||
if value:
|
||||
properties.extend(utils.args_array_to_patch(
|
||||
@ -1500,6 +1516,17 @@ class UnsetBaremetalNode(command.Command):
|
||||
help=_('Unset the protected reason (gets unset automatically when '
|
||||
'protected is unset)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--retired",
|
||||
action="store_true",
|
||||
help=_('Unset the retired flag on the node'),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--retired-reason",
|
||||
action="store_true",
|
||||
help=_('Unset the retired reason (gets unset automatically when '
|
||||
'retired is unset)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--owner",
|
||||
action="store_true",
|
||||
@ -1532,8 +1559,8 @@ class UnsetBaremetalNode(command.Command):
|
||||
'management_interface', 'network_interface',
|
||||
'power_interface', 'raid_interface', 'rescue_interface',
|
||||
'storage_interface', 'vendor_interface',
|
||||
'protected', 'protected_reason', 'owner',
|
||||
'description']:
|
||||
'protected', 'protected_reason', 'retired',
|
||||
'retired_reason', 'owner', 'description']:
|
||||
if getattr(parsed_args, field):
|
||||
properties.extend(utils.args_array_to_patch('remove', [field]))
|
||||
|
||||
|
@ -658,6 +658,8 @@ class TestBaremetalList(TestBaremetal):
|
||||
'Rescue Interface',
|
||||
'Reservation',
|
||||
'Resource Class',
|
||||
'Retired',
|
||||
'Retired Reason',
|
||||
'Storage Interface',
|
||||
'Target Power State',
|
||||
'Target Provision State',
|
||||
@ -2454,6 +2456,50 @@ class TestBaremetalSet(TestBaremetal):
|
||||
reset_interfaces=None,
|
||||
)
|
||||
|
||||
def test_baremetal_set_retired(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
'--retired'
|
||||
]
|
||||
verifylist = [
|
||||
('node', 'node_uuid'),
|
||||
('retired', True)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/retired', 'value': 'True', 'op': 'add'}],
|
||||
reset_interfaces=None,
|
||||
)
|
||||
|
||||
def test_baremetal_set_retired_with_reason(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
'--retired',
|
||||
'--retired-reason', 'out of warranty!'
|
||||
]
|
||||
verifylist = [
|
||||
('node', 'node_uuid'),
|
||||
('retired', True),
|
||||
('retired_reason', 'out of warranty!')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/retired', 'value': 'True', 'op': 'add'},
|
||||
{'path': '/retired_reason', 'value': 'out of warranty!',
|
||||
'op': 'add'}],
|
||||
reset_interfaces=None,
|
||||
)
|
||||
|
||||
def test_baremetal_set_extra(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
@ -3007,6 +3053,44 @@ class TestBaremetalUnset(TestBaremetal):
|
||||
[{'path': '/protected_reason', 'op': 'remove'}]
|
||||
)
|
||||
|
||||
def test_baremetal_unset_retired(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
'--retired',
|
||||
]
|
||||
verifylist = [
|
||||
('node', 'node_uuid'),
|
||||
('retired', True)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/retired', 'op': 'remove'}]
|
||||
)
|
||||
|
||||
def test_baremetal_unset_retired_reason(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
'--retired-reason',
|
||||
]
|
||||
verifylist = [
|
||||
('node', 'node_uuid'),
|
||||
('retired_reason', True)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/retired_reason', 'op': 'remove'}]
|
||||
)
|
||||
|
||||
def test_baremetal_unset_extra(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
|
@ -48,7 +48,8 @@ NODE2 = {'uuid': '66666666-7777-8888-9999-111111111111',
|
||||
'properties': {'num_cpu': 4},
|
||||
'resource_class': 'bar',
|
||||
'extra': {},
|
||||
'owner': '33333333-2222-1111-0000-111111111111'}
|
||||
'owner': '33333333-2222-1111-0000-111111111111',
|
||||
'retired': True}
|
||||
PORT = {'uuid': '11111111-2222-3333-4444-555555555555',
|
||||
'node_uuid': '66666666-7777-8888-9999-000000000000',
|
||||
'address': 'AA:AA:AA:AA:AA:AA',
|
||||
@ -170,6 +171,13 @@ fake_responses = {
|
||||
{"nodes": [NODE2]},
|
||||
)
|
||||
},
|
||||
'/v1/nodes/?retired=True':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"nodes": [NODE2]},
|
||||
)
|
||||
},
|
||||
'/v1/nodes/?associated=True&maintenance=True':
|
||||
{
|
||||
'GET': (
|
||||
@ -177,6 +185,13 @@ fake_responses = {
|
||||
{"nodes": [NODE2]},
|
||||
)
|
||||
},
|
||||
'/v1/nodes/?associated=True&retired=True':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"nodes": [NODE2]},
|
||||
)
|
||||
},
|
||||
'/v1/nodes/?provision_state=available':
|
||||
{
|
||||
'GET': (
|
||||
@ -798,6 +813,15 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertThat(nodes, HasLength(1))
|
||||
self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid'))
|
||||
|
||||
def test_node_list_retired(self):
|
||||
nodes = self.mgr.list(retired=True)
|
||||
expect = [
|
||||
('GET', '/v1/nodes/?retired=True', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(nodes, HasLength(1))
|
||||
self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid'))
|
||||
|
||||
def test_node_list_provision_state(self):
|
||||
nodes = self.mgr.list(provision_state="available")
|
||||
expect = [
|
||||
@ -875,6 +899,15 @@ class NodeManagerTest(testtools.TestCase):
|
||||
self.assertThat(nodes, HasLength(1))
|
||||
self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid'))
|
||||
|
||||
def test_node_list_associated_and_retired(self):
|
||||
nodes = self.mgr.list(associated=True, retired=True)
|
||||
expect = [
|
||||
('GET', '/v1/nodes/?associated=True&retired=True', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(nodes, HasLength(1))
|
||||
self.assertEqual(NODE2['uuid'], getattr(nodes[0], 'uuid'))
|
||||
|
||||
def test_node_list_with_conductor(self):
|
||||
nodes = self.mgr.list(conductor='fake-conductor')
|
||||
expect = [
|
||||
|
@ -56,11 +56,12 @@ class NodeManager(base.CreateManager):
|
||||
'automated_clean']
|
||||
_resource_name = 'nodes'
|
||||
|
||||
def list(self, associated=None, maintenance=None, marker=None, limit=None,
|
||||
detail=False, sort_key=None, sort_dir=None, fields=None,
|
||||
provision_state=None, driver=None, resource_class=None,
|
||||
chassis=None, fault=None, os_ironic_api_version=None,
|
||||
conductor_group=None, conductor=None, owner=None):
|
||||
def list(self, associated=None, maintenance=None, marker=None,
|
||||
limit=None, detail=False, sort_key=None, sort_dir=None,
|
||||
fields=None, provision_state=None, driver=None,
|
||||
resource_class=None, chassis=None, fault=None,
|
||||
os_ironic_api_version=None, conductor_group=None,
|
||||
conductor=None, owner=None, retired=None):
|
||||
"""Retrieve a list of nodes.
|
||||
|
||||
:param associated: Optional. Either a Boolean or a string
|
||||
@ -72,6 +73,9 @@ class NodeManager(base.CreateManager):
|
||||
to return nodes in maintenance mode (True or
|
||||
"True"), or not in maintenance mode (False or
|
||||
"False").
|
||||
:param retired: Optional. Either a Boolean or a string representation
|
||||
of a Boolean that indicates whether to return retired
|
||||
nodes (True or "True").
|
||||
:param provision_state: Optional. String value to get only nodes in
|
||||
that provision state.
|
||||
:param marker: Optional, the UUID of a node, eg the last
|
||||
@ -135,6 +139,8 @@ class NodeManager(base.CreateManager):
|
||||
filters.append('associated=%s' % associated)
|
||||
if maintenance is not None:
|
||||
filters.append('maintenance=%s' % maintenance)
|
||||
if retired is not None:
|
||||
filters.append('retired=%s' % retired)
|
||||
if fault is not None:
|
||||
filters.append('fault=%s' % fault)
|
||||
if provision_state is not None:
|
||||
|
@ -103,6 +103,8 @@ class Resource(object):
|
||||
'raid_config': 'Current RAID configuration',
|
||||
'reservation': 'Reservation',
|
||||
'resource_class': 'Resource Class',
|
||||
'retired': 'Retired',
|
||||
'retired_reason': 'Retired Reason',
|
||||
'state': 'State',
|
||||
'steps': 'Steps',
|
||||
'target_power_state': 'Target Power State',
|
||||
@ -258,6 +260,8 @@ NODE_DETAILED_RESOURCE = Resource(
|
||||
'rescue_interface',
|
||||
'reservation',
|
||||
'resource_class',
|
||||
'retired',
|
||||
'retired_reason',
|
||||
'storage_interface',
|
||||
'target_power_state',
|
||||
'target_provision_state',
|
||||
|
10
releasenotes/notes/add_retired_field-6ec9f97c7c2f86ec.yaml
Normal file
10
releasenotes/notes/add_retired_field-6ec9f97c7c2f86ec.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds the ability to set and unset the ``retired`` and
|
||||
``retired_reason`` with API 1.61. Setting the ``retired``
|
||||
field on a node excludes it from scheduling, but still
|
||||
allows the node to be cleaned (unlike maintenance, for
|
||||
instance). The fields can be set irrespective of the
|
||||
node's state and are meant to be used to prepare nodes
|
||||
for removal from ironic.
|
Loading…
Reference in New Issue
Block a user