Blackify openstack.baremetal, openstack.baremetal_introspection
Black used with the '-l 79 -S' flags. A future change will ignore this commit in git-blame history by adding a 'git-blame-ignore-revs' file. Change-Id: I1effcaff4f4c931b46541f8db44ed50c10104cad Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
4589e293e8
commit
f8e42017e7
@ -23,8 +23,13 @@ import tempfile
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def populate_directory(metadata, user_data=None, versions=None,
|
||||
network_data=None, vendor_data=None):
|
||||
def populate_directory(
|
||||
metadata,
|
||||
user_data=None,
|
||||
versions=None,
|
||||
network_data=None,
|
||||
vendor_data=None,
|
||||
):
|
||||
"""Populate a directory with configdrive files.
|
||||
|
||||
:param dict metadata: Metadata.
|
||||
@ -46,21 +51,24 @@ def populate_directory(metadata, user_data=None, versions=None,
|
||||
json.dump(metadata, fp)
|
||||
|
||||
if network_data:
|
||||
with open(os.path.join(subdir, 'network_data.json'),
|
||||
'w') as fp:
|
||||
with open(
|
||||
os.path.join(subdir, 'network_data.json'), 'w'
|
||||
) as fp:
|
||||
json.dump(network_data, fp)
|
||||
|
||||
if vendor_data:
|
||||
with open(os.path.join(subdir, 'vendor_data2.json'),
|
||||
'w') as fp:
|
||||
with open(
|
||||
os.path.join(subdir, 'vendor_data2.json'), 'w'
|
||||
) as fp:
|
||||
json.dump(vendor_data, fp)
|
||||
|
||||
if user_data:
|
||||
# Strictly speaking, user data is binary, but in many cases
|
||||
# it's actually a text (cloud-init, ignition, etc).
|
||||
flag = 't' if isinstance(user_data, str) else 'b'
|
||||
with open(os.path.join(subdir, 'user_data'),
|
||||
'w%s' % flag) as fp:
|
||||
with open(
|
||||
os.path.join(subdir, 'user_data'), 'w%s' % flag
|
||||
) as fp:
|
||||
fp.write(user_data)
|
||||
|
||||
yield d
|
||||
@ -68,8 +76,13 @@ def populate_directory(metadata, user_data=None, versions=None,
|
||||
shutil.rmtree(d)
|
||||
|
||||
|
||||
def build(metadata, user_data=None, versions=None, network_data=None,
|
||||
vendor_data=None):
|
||||
def build(
|
||||
metadata,
|
||||
user_data=None,
|
||||
versions=None,
|
||||
network_data=None,
|
||||
vendor_data=None,
|
||||
):
|
||||
"""Make a configdrive compatible with the Bare Metal service.
|
||||
|
||||
Requires the genisoimage utility to be available.
|
||||
@ -81,8 +94,9 @@ def build(metadata, user_data=None, versions=None, network_data=None,
|
||||
:param dict vendor_data: Extra supplied vendor data.
|
||||
:return: configdrive contents as a base64-encoded string.
|
||||
"""
|
||||
with populate_directory(metadata, user_data, versions,
|
||||
network_data, vendor_data) as path:
|
||||
with populate_directory(
|
||||
metadata, user_data, versions, network_data, vendor_data
|
||||
) as path:
|
||||
return pack(path)
|
||||
|
||||
|
||||
@ -100,16 +114,27 @@ def pack(path):
|
||||
cmds = ['genisoimage', 'mkisofs', 'xorrisofs']
|
||||
for c in cmds:
|
||||
try:
|
||||
p = subprocess.Popen([c,
|
||||
'-o', tmpfile.name,
|
||||
'-ldots', '-allow-lowercase',
|
||||
'-allow-multidot', '-l',
|
||||
'-publisher', 'metalsmith',
|
||||
'-quiet', '-J',
|
||||
'-r', '-V', 'config-2',
|
||||
path],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
p = subprocess.Popen(
|
||||
[
|
||||
c,
|
||||
'-o',
|
||||
tmpfile.name,
|
||||
'-ldots',
|
||||
'-allow-lowercase',
|
||||
'-allow-multidot',
|
||||
'-l',
|
||||
'-publisher',
|
||||
'metalsmith',
|
||||
'-quiet',
|
||||
'-J',
|
||||
'-r',
|
||||
'-V',
|
||||
'config-2',
|
||||
path,
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
except OSError as e:
|
||||
error = e
|
||||
else:
|
||||
@ -120,14 +145,16 @@ def pack(path):
|
||||
raise RuntimeError(
|
||||
'Error generating the configdrive. Make sure the '
|
||||
'"genisoimage", "mkisofs" or "xorrisofs" tool is installed. '
|
||||
'Error: %s' % error)
|
||||
'Error: %s' % error
|
||||
)
|
||||
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError(
|
||||
'Error generating the configdrive.'
|
||||
'Stdout: "%(stdout)s". Stderr: "%(stderr)s"' %
|
||||
{'stdout': stdout, 'stderr': stderr})
|
||||
'Stdout: "%(stdout)s". Stderr: "%(stderr)s"'
|
||||
% {'stdout': stdout, 'stderr': stderr}
|
||||
)
|
||||
|
||||
tmpfile.seek(0)
|
||||
|
||||
|
@ -17,7 +17,7 @@ RETRIABLE_STATUS_CODES = [
|
||||
# HTTP Conflict - happens if a node is locked
|
||||
409,
|
||||
# HTTP Service Unavailable happens if there's no free conductor
|
||||
503
|
||||
503,
|
||||
]
|
||||
"""HTTP status codes that should be retried."""
|
||||
|
||||
@ -88,7 +88,6 @@ CHANGE_BOOT_MODE_VERSION = '1.76'
|
||||
|
||||
|
||||
class ListMixin:
|
||||
|
||||
@classmethod
|
||||
def list(cls, session, details=False, **params):
|
||||
"""This method is a generator which yields resource objects.
|
||||
@ -112,8 +111,9 @@ class ListMixin:
|
||||
base_path = cls.base_path
|
||||
if details:
|
||||
base_path += '/detail'
|
||||
return super(ListMixin, cls).list(session, paginated=True,
|
||||
base_path=base_path, **params)
|
||||
return super(ListMixin, cls).list(
|
||||
session, paginated=True, base_path=base_path, **params
|
||||
)
|
||||
|
||||
|
||||
def comma_separated_list(value):
|
||||
|
@ -63,8 +63,10 @@ class Proxy(proxy.Proxy):
|
||||
return res.fetch(
|
||||
self,
|
||||
error_message="No {resource_type} found for {value}".format(
|
||||
resource_type=resource_type.__name__, value=value),
|
||||
**kwargs)
|
||||
resource_type=resource_type.__name__, value=value
|
||||
),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def chassis(self, details=False, **query):
|
||||
"""Retrieve a generator of chassis.
|
||||
@ -123,8 +125,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: One :class:`~openstack.baremetal.v1.chassis.Chassis` object
|
||||
or None.
|
||||
"""
|
||||
return self._find(_chassis.Chassis, name_or_id,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._find(
|
||||
_chassis.Chassis, name_or_id, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def get_chassis(self, chassis, fields=None):
|
||||
"""Get a specific chassis.
|
||||
@ -178,8 +181,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: The instance of the chassis which was deleted.
|
||||
:rtype: :class:`~openstack.baremetal.v1.chassis.Chassis`.
|
||||
"""
|
||||
return self._delete(_chassis.Chassis, chassis,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._delete(
|
||||
_chassis.Chassis, chassis, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def drivers(self, details=False, **query):
|
||||
"""Retrieve a generator of drivers.
|
||||
@ -221,8 +225,9 @@ class Proxy(proxy.Proxy):
|
||||
driver = self.get_driver(driver)
|
||||
return driver.list_vendor_passthru(self)
|
||||
|
||||
def call_driver_vendor_passthru(self, driver,
|
||||
verb: str, method: str, body=None):
|
||||
def call_driver_vendor_passthru(
|
||||
self, driver, verb: str, method: str, body=None
|
||||
):
|
||||
"""Call driver's vendor_passthru method.
|
||||
|
||||
:param driver: The value can be the name of a driver or a
|
||||
@ -311,8 +316,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: One :class:`~openstack.baremetal.v1.node.Node` object
|
||||
or None.
|
||||
"""
|
||||
return self._find(_node.Node, name_or_id,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._find(
|
||||
_node.Node, name_or_id, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def get_node(self, node, fields=None):
|
||||
"""Get a specific node.
|
||||
@ -345,8 +351,9 @@ class Proxy(proxy.Proxy):
|
||||
res = self._get_resource(_node.Node, node, **attrs)
|
||||
return res.commit(self, retry_on_conflict=retry_on_conflict)
|
||||
|
||||
def patch_node(self, node, patch, reset_interfaces=None,
|
||||
retry_on_conflict=True):
|
||||
def patch_node(
|
||||
self, node, patch, reset_interfaces=None, retry_on_conflict=True
|
||||
):
|
||||
"""Apply a JSON patch to the node.
|
||||
|
||||
:param node: The value can be the name or ID of a node or a
|
||||
@ -368,12 +375,24 @@ class Proxy(proxy.Proxy):
|
||||
:rtype: :class:`~openstack.baremetal.v1.node.Node`
|
||||
"""
|
||||
res = self._get_resource(_node.Node, node)
|
||||
return res.patch(self, patch, retry_on_conflict=retry_on_conflict,
|
||||
reset_interfaces=reset_interfaces)
|
||||
return res.patch(
|
||||
self,
|
||||
patch,
|
||||
retry_on_conflict=retry_on_conflict,
|
||||
reset_interfaces=reset_interfaces,
|
||||
)
|
||||
|
||||
def set_node_provision_state(self, node, target, config_drive=None,
|
||||
clean_steps=None, rescue_password=None,
|
||||
wait=False, timeout=None, deploy_steps=None):
|
||||
def set_node_provision_state(
|
||||
self,
|
||||
node,
|
||||
target,
|
||||
config_drive=None,
|
||||
clean_steps=None,
|
||||
rescue_password=None,
|
||||
wait=False,
|
||||
timeout=None,
|
||||
deploy_steps=None,
|
||||
):
|
||||
"""Run an action modifying node's provision state.
|
||||
|
||||
This call is asynchronous, it will return success as soon as the Bare
|
||||
@ -405,11 +424,16 @@ class Proxy(proxy.Proxy):
|
||||
invalid ``target``.
|
||||
"""
|
||||
res = self._get_resource(_node.Node, node)
|
||||
return res.set_provision_state(self, target, config_drive=config_drive,
|
||||
clean_steps=clean_steps,
|
||||
rescue_password=rescue_password,
|
||||
wait=wait, timeout=timeout,
|
||||
deploy_steps=deploy_steps)
|
||||
return res.set_provision_state(
|
||||
self,
|
||||
target,
|
||||
config_drive=config_drive,
|
||||
clean_steps=clean_steps,
|
||||
rescue_password=rescue_password,
|
||||
wait=wait,
|
||||
timeout=timeout,
|
||||
deploy_steps=deploy_steps,
|
||||
)
|
||||
|
||||
def get_node_boot_device(self, node):
|
||||
"""Get node boot device
|
||||
@ -480,10 +504,14 @@ class Proxy(proxy.Proxy):
|
||||
res = self._get_resource(_node.Node, node)
|
||||
res.inject_nmi(self)
|
||||
|
||||
def wait_for_nodes_provision_state(self, nodes, expected_state,
|
||||
timeout=None,
|
||||
abort_on_failed_state=True,
|
||||
fail=True):
|
||||
def wait_for_nodes_provision_state(
|
||||
self,
|
||||
nodes,
|
||||
expected_state,
|
||||
timeout=None,
|
||||
abort_on_failed_state=True,
|
||||
fail=True,
|
||||
):
|
||||
"""Wait for the nodes to reach the expected state.
|
||||
|
||||
:param nodes: List of nodes - name, ID or
|
||||
@ -507,24 +535,27 @@ class Proxy(proxy.Proxy):
|
||||
reaches an error state and ``abort_on_failed_state`` is ``True``.
|
||||
:raises: :class:`~openstack.exceptions.ResourceTimeout` on timeout.
|
||||
"""
|
||||
log_nodes = ', '.join(n.id if isinstance(n, _node.Node) else n
|
||||
for n in nodes)
|
||||
log_nodes = ', '.join(
|
||||
n.id if isinstance(n, _node.Node) else n for n in nodes
|
||||
)
|
||||
|
||||
finished = []
|
||||
failed = []
|
||||
remaining = nodes
|
||||
try:
|
||||
for count in utils.iterate_timeout(
|
||||
timeout,
|
||||
"Timeout waiting for nodes %(nodes)s to reach "
|
||||
"target state '%(state)s'" % {'nodes': log_nodes,
|
||||
'state': expected_state}):
|
||||
timeout,
|
||||
"Timeout waiting for nodes %(nodes)s to reach "
|
||||
"target state '%(state)s'"
|
||||
% {'nodes': log_nodes, 'state': expected_state},
|
||||
):
|
||||
nodes = [self.get_node(n) for n in remaining]
|
||||
remaining = []
|
||||
for n in nodes:
|
||||
try:
|
||||
if n._check_state_reached(self, expected_state,
|
||||
abort_on_failed_state):
|
||||
if n._check_state_reached(
|
||||
self, expected_state, abort_on_failed_state
|
||||
):
|
||||
finished.append(n)
|
||||
else:
|
||||
remaining.append(n)
|
||||
@ -543,8 +574,11 @@ class Proxy(proxy.Proxy):
|
||||
self.log.debug(
|
||||
'Still waiting for nodes %(nodes)s to reach state '
|
||||
'"%(target)s"',
|
||||
{'nodes': ', '.join(n.id for n in remaining),
|
||||
'target': expected_state})
|
||||
{
|
||||
'nodes': ', '.join(n.id for n in remaining),
|
||||
'target': expected_state,
|
||||
},
|
||||
)
|
||||
except exceptions.ResourceTimeout:
|
||||
if fail:
|
||||
raise
|
||||
@ -568,7 +602,8 @@ class Proxy(proxy.Proxy):
|
||||
``None`` (the default) means no client-side timeout.
|
||||
"""
|
||||
self._get_resource(_node.Node, node).set_power_state(
|
||||
self, target, wait=wait, timeout=timeout)
|
||||
self, target, wait=wait, timeout=timeout
|
||||
)
|
||||
|
||||
def wait_for_node_power_state(self, node, expected_state, timeout=None):
|
||||
"""Wait for the node to reach the power state.
|
||||
@ -731,8 +766,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: One :class:`~openstack.baremetal.v1.port.Port` object
|
||||
or None.
|
||||
"""
|
||||
return self._find(_port.Port, name_or_id,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._find(
|
||||
_port.Port, name_or_id, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def get_port(self, port, fields=None):
|
||||
"""Get a specific port.
|
||||
@ -849,8 +885,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: One :class:`~openstack.baremetal.v1.port_group.PortGroup`
|
||||
object or None.
|
||||
"""
|
||||
return self._find(_portgroup.PortGroup, name_or_id,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._find(
|
||||
_portgroup.PortGroup, name_or_id, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def get_port_group(self, port_group, fields=None):
|
||||
"""Get a specific port group.
|
||||
@ -863,8 +900,9 @@ class Proxy(proxy.Proxy):
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
port group matching the name or ID could be found.
|
||||
"""
|
||||
return self._get_with_fields(_portgroup.PortGroup, port_group,
|
||||
fields=fields)
|
||||
return self._get_with_fields(
|
||||
_portgroup.PortGroup, port_group, fields=fields
|
||||
)
|
||||
|
||||
def update_port_group(self, port_group, **attrs):
|
||||
"""Update a port group.
|
||||
@ -909,8 +947,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: The instance of the port group which was deleted.
|
||||
:rtype: :class:`~openstack.baremetal.v1.port_group.PortGroup`.
|
||||
"""
|
||||
return self._delete(_portgroup.PortGroup, port_group,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._delete(
|
||||
_portgroup.PortGroup, port_group, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def attach_vif_to_node(self, node, vif_id, retry_on_conflict=True):
|
||||
"""Attach a VIF to the node.
|
||||
@ -1026,8 +1065,9 @@ class Proxy(proxy.Proxy):
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
allocation matching the name or ID could be found.
|
||||
"""
|
||||
return self._get_with_fields(_allocation.Allocation, allocation,
|
||||
fields=fields)
|
||||
return self._get_with_fields(
|
||||
_allocation.Allocation, allocation, fields=fields
|
||||
)
|
||||
|
||||
def update_allocation(self, allocation, **attrs):
|
||||
"""Update an allocation.
|
||||
@ -1052,8 +1092,9 @@ class Proxy(proxy.Proxy):
|
||||
:returns: The updated allocation.
|
||||
:rtype: :class:`~openstack.baremetal.v1.allocation.Allocation`
|
||||
"""
|
||||
return self._get_resource(_allocation.Allocation,
|
||||
allocation).patch(self, patch)
|
||||
return self._get_resource(_allocation.Allocation, allocation).patch(
|
||||
self, patch
|
||||
)
|
||||
|
||||
def delete_allocation(self, allocation, ignore_missing=True):
|
||||
"""Delete an allocation.
|
||||
@ -1069,11 +1110,13 @@ class Proxy(proxy.Proxy):
|
||||
:returns: The instance of the allocation which was deleted.
|
||||
:rtype: :class:`~openstack.baremetal.v1.allocation.Allocation`.
|
||||
"""
|
||||
return self._delete(_allocation.Allocation, allocation,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._delete(
|
||||
_allocation.Allocation, allocation, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def wait_for_allocation(self, allocation, timeout=None,
|
||||
ignore_error=False):
|
||||
def wait_for_allocation(
|
||||
self, allocation, timeout=None, ignore_error=False
|
||||
):
|
||||
"""Wait for the allocation to become active.
|
||||
|
||||
:param allocation: The value can be the name or ID of an allocation or
|
||||
@ -1252,8 +1295,11 @@ class Proxy(proxy.Proxy):
|
||||
:class:`~openstack.baremetal.v1.volumeconnector.VolumeConnector`
|
||||
object or None.
|
||||
"""
|
||||
return self._find(_volumeconnector.VolumeConnector, vc_id,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._find(
|
||||
_volumeconnector.VolumeConnector,
|
||||
vc_id,
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
def get_volume_connector(self, volume_connector, fields=None):
|
||||
"""Get a specific volume_connector.
|
||||
@ -1269,9 +1315,9 @@ class Proxy(proxy.Proxy):
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
volume_connector matching the name or ID could be found.`
|
||||
"""
|
||||
return self._get_with_fields(_volumeconnector.VolumeConnector,
|
||||
volume_connector,
|
||||
fields=fields)
|
||||
return self._get_with_fields(
|
||||
_volumeconnector.VolumeConnector, volume_connector, fields=fields
|
||||
)
|
||||
|
||||
def update_volume_connector(self, volume_connector, **attrs):
|
||||
"""Update a volume_connector.
|
||||
@ -1287,8 +1333,9 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`
|
||||
"""
|
||||
return self._update(_volumeconnector.VolumeConnector,
|
||||
volume_connector, **attrs)
|
||||
return self._update(
|
||||
_volumeconnector.VolumeConnector, volume_connector, **attrs
|
||||
)
|
||||
|
||||
def patch_volume_connector(self, volume_connector, patch):
|
||||
"""Apply a JSON patch to the volume_connector.
|
||||
@ -1303,11 +1350,11 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
|
||||
"""
|
||||
return self._get_resource(_volumeconnector.VolumeConnector,
|
||||
volume_connector).patch(self, patch)
|
||||
return self._get_resource(
|
||||
_volumeconnector.VolumeConnector, volume_connector
|
||||
).patch(self, patch)
|
||||
|
||||
def delete_volume_connector(self, volume_connector,
|
||||
ignore_missing=True):
|
||||
def delete_volume_connector(self, volume_connector, ignore_missing=True):
|
||||
"""Delete an volume_connector.
|
||||
|
||||
:param volume_connector: The value can be either the ID of a
|
||||
@ -1324,8 +1371,11 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
|
||||
"""
|
||||
return self._delete(_volumeconnector.VolumeConnector,
|
||||
volume_connector, ignore_missing=ignore_missing)
|
||||
return self._delete(
|
||||
_volumeconnector.VolumeConnector,
|
||||
volume_connector,
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
def volume_targets(self, details=False, **query):
|
||||
"""Retrieve a generator of volume_target.
|
||||
@ -1392,8 +1442,9 @@ class Proxy(proxy.Proxy):
|
||||
:class:`~openstack.baremetal.v1.volumetarget.VolumeTarget`
|
||||
object or None.
|
||||
"""
|
||||
return self._find(_volumetarget.VolumeTarget, vt_id,
|
||||
ignore_missing=ignore_missing)
|
||||
return self._find(
|
||||
_volumetarget.VolumeTarget, vt_id, ignore_missing=ignore_missing
|
||||
)
|
||||
|
||||
def get_volume_target(self, volume_target, fields=None):
|
||||
"""Get a specific volume_target.
|
||||
@ -1409,9 +1460,9 @@ class Proxy(proxy.Proxy):
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
volume_target matching the name or ID could be found.`
|
||||
"""
|
||||
return self._get_with_fields(_volumetarget.VolumeTarget,
|
||||
volume_target,
|
||||
fields=fields)
|
||||
return self._get_with_fields(
|
||||
_volumetarget.VolumeTarget, volume_target, fields=fields
|
||||
)
|
||||
|
||||
def update_volume_target(self, volume_target, **attrs):
|
||||
"""Update a volume_target.
|
||||
@ -1426,8 +1477,7 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`
|
||||
"""
|
||||
return self._update(_volumetarget.VolumeTarget,
|
||||
volume_target, **attrs)
|
||||
return self._update(_volumetarget.VolumeTarget, volume_target, **attrs)
|
||||
|
||||
def patch_volume_target(self, volume_target, patch):
|
||||
"""Apply a JSON patch to the volume_target.
|
||||
@ -1442,11 +1492,11 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget.`
|
||||
"""
|
||||
return self._get_resource(_volumetarget.VolumeTarget,
|
||||
volume_target).patch(self, patch)
|
||||
return self._get_resource(
|
||||
_volumetarget.VolumeTarget, volume_target
|
||||
).patch(self, patch)
|
||||
|
||||
def delete_volume_target(self, volume_target,
|
||||
ignore_missing=True):
|
||||
def delete_volume_target(self, volume_target, ignore_missing=True):
|
||||
"""Delete an volume_target.
|
||||
|
||||
:param volume_target: The value can be either the ID of a
|
||||
@ -1463,8 +1513,11 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`.
|
||||
"""
|
||||
return self._delete(_volumetarget.VolumeTarget,
|
||||
volume_target, ignore_missing=ignore_missing)
|
||||
return self._delete(
|
||||
_volumetarget.VolumeTarget,
|
||||
volume_target,
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
def deploy_templates(self, details=False, **query):
|
||||
"""Retrieve a generator of deploy_templates.
|
||||
@ -1506,11 +1559,11 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
|
||||
"""
|
||||
return self._update(_deploytemplates.DeployTemplate,
|
||||
deploy_template, **attrs)
|
||||
return self._update(
|
||||
_deploytemplates.DeployTemplate, deploy_template, **attrs
|
||||
)
|
||||
|
||||
def delete_deploy_template(self, deploy_template,
|
||||
ignore_missing=True):
|
||||
def delete_deploy_template(self, deploy_template, ignore_missing=True):
|
||||
"""Delete a deploy_template.
|
||||
|
||||
:param deploy_template:The value can be
|
||||
@ -1532,8 +1585,11 @@ class Proxy(proxy.Proxy):
|
||||
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
|
||||
"""
|
||||
|
||||
return self._delete(_deploytemplates.DeployTemplate,
|
||||
deploy_template, ignore_missing=ignore_missing)
|
||||
return self._delete(
|
||||
_deploytemplates.DeployTemplate,
|
||||
deploy_template,
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
def get_deploy_template(self, deploy_template, fields=None):
|
||||
"""Get a specific deployment template.
|
||||
@ -1551,8 +1607,9 @@ class Proxy(proxy.Proxy):
|
||||
when no deployment template matching the name or
|
||||
ID could be found.
|
||||
"""
|
||||
return self._get_with_fields(_deploytemplates.DeployTemplate,
|
||||
deploy_template, fields=fields)
|
||||
return self._get_with_fields(
|
||||
_deploytemplates.DeployTemplate, deploy_template, fields=fields
|
||||
)
|
||||
|
||||
def patch_deploy_template(self, deploy_template, patch):
|
||||
"""Apply a JSON patch to the deploy_templates.
|
||||
@ -1568,8 +1625,9 @@ class Proxy(proxy.Proxy):
|
||||
:rtype:
|
||||
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
|
||||
"""
|
||||
return self._get_resource(_deploytemplates.DeployTemplate,
|
||||
deploy_template).patch(self, patch)
|
||||
return self._get_resource(
|
||||
_deploytemplates.DeployTemplate, deploy_template
|
||||
).patch(self, patch)
|
||||
|
||||
def conductors(self, details=False, **query):
|
||||
"""Retrieve a generator of conductors.
|
||||
@ -1595,5 +1653,6 @@ class Proxy(proxy.Proxy):
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
conductor matching the name could be found.
|
||||
"""
|
||||
return self._get_with_fields(_conductor.Conductor,
|
||||
conductor, fields=fields)
|
||||
return self._get_with_fields(
|
||||
_conductor.Conductor, conductor, fields=fields
|
||||
)
|
||||
|
@ -32,7 +32,9 @@ class Allocation(_common.ListMixin, resource.Resource):
|
||||
commit_jsonpatch = True
|
||||
|
||||
_query_mapping = resource.QueryParameters(
|
||||
'node', 'resource_class', 'state',
|
||||
'node',
|
||||
'resource_class',
|
||||
'state',
|
||||
fields={'type': _common.fields_type},
|
||||
)
|
||||
|
||||
@ -88,18 +90,20 @@ class Allocation(_common.ListMixin, resource.Resource):
|
||||
return self
|
||||
|
||||
for count in utils.iterate_timeout(
|
||||
timeout,
|
||||
"Timeout waiting for the allocation %s" % self.id):
|
||||
timeout, "Timeout waiting for the allocation %s" % self.id
|
||||
):
|
||||
self.fetch(session)
|
||||
|
||||
if self.state == 'error' and not ignore_error:
|
||||
raise exceptions.ResourceFailure(
|
||||
"Allocation %(allocation)s failed: %(error)s" %
|
||||
{'allocation': self.id, 'error': self.last_error})
|
||||
"Allocation %(allocation)s failed: %(error)s"
|
||||
% {'allocation': self.id, 'error': self.last_error}
|
||||
)
|
||||
elif self.state != 'allocating':
|
||||
return self
|
||||
|
||||
session.log.debug(
|
||||
'Still waiting for the allocation %(allocation)s '
|
||||
'to become active, the current state is %(state)s',
|
||||
{'allocation': self.id, 'state': self.state})
|
||||
{'allocation': self.id, 'state': self.state},
|
||||
)
|
||||
|
@ -63,7 +63,8 @@ class Driver(resource.Resource):
|
||||
#: Default management interface implementation.
|
||||
#: Introduced in API microversion 1.30.
|
||||
default_management_interface = resource.Body(
|
||||
"default_management_interface")
|
||||
"default_management_interface"
|
||||
)
|
||||
#: Default network interface implementation.
|
||||
#: Introduced in API microversion 1.30.
|
||||
default_network_interface = resource.Body("default_network_interface")
|
||||
@ -101,7 +102,8 @@ class Driver(resource.Resource):
|
||||
#: Enabled management interface implementations.
|
||||
#: Introduced in API microversion 1.30.
|
||||
enabled_management_interfaces = resource.Body(
|
||||
"enabled_management_interfaces")
|
||||
"enabled_management_interfaces"
|
||||
)
|
||||
#: Enabled network interface implementations.
|
||||
#: Introduced in API microversion 1.30.
|
||||
enabled_network_interfaces = resource.Body("enabled_network_interfaces")
|
||||
@ -135,17 +137,18 @@ class Driver(resource.Resource):
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
request = self._prepare_request()
|
||||
request.url = utils.urljoin(
|
||||
request.url, 'vendor_passthru', 'methods')
|
||||
request.url = utils.urljoin(request.url, 'vendor_passthru', 'methods')
|
||||
response = session.get(request.url, headers=request.headers)
|
||||
|
||||
msg = ("Failed to list list vendor_passthru methods for {driver_name}"
|
||||
.format(driver_name=self.name))
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
msg = "Failed to list list vendor_passthru methods for {driver_name}"
|
||||
exceptions.raise_from_response(
|
||||
response, error_message=msg.format(driver_name=self.name)
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def call_vendor_passthru(self, session,
|
||||
verb: str, method: str, body: dict = None):
|
||||
def call_vendor_passthru(
|
||||
self, session, verb: str, method: str, body: dict = None
|
||||
):
|
||||
"""Call a vendor specific passthru method
|
||||
|
||||
Contents of body are params passed to the hardware driver
|
||||
@ -167,13 +170,18 @@ class Driver(resource.Resource):
|
||||
session = self._get_session(session)
|
||||
request = self._prepare_request()
|
||||
request.url = utils.urljoin(
|
||||
request.url, f'vendor_passthru?method={method}')
|
||||
request.url, f'vendor_passthru?method={method}'
|
||||
)
|
||||
call = getattr(session, verb.lower())
|
||||
response = call(
|
||||
request.url, json=body, headers=request.headers,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
request.url,
|
||||
json=body,
|
||||
headers=request.headers,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES,
|
||||
)
|
||||
|
||||
msg = ("Failed call to method {method} on driver {driver_name}"
|
||||
.format(method=method, driver_name=self.name))
|
||||
msg = "Failed call to method {method} on driver {driver_name}".format(
|
||||
method=method, driver_name=self.name
|
||||
)
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
return response
|
||||
|
@ -51,8 +51,9 @@ class PowerAction(enum.Enum):
|
||||
"""Reboot the node using soft power off."""
|
||||
|
||||
|
||||
class WaitResult(collections.namedtuple('WaitResult',
|
||||
['success', 'failure', 'timeout'])):
|
||||
class WaitResult(
|
||||
collections.namedtuple('WaitResult', ['success', 'failure', 'timeout'])
|
||||
):
|
||||
"""A named tuple representing a result of waiting for several nodes.
|
||||
|
||||
Each component is a list of :class:`~openstack.baremetal.v1.node.Node`
|
||||
@ -65,6 +66,7 @@ class WaitResult(collections.namedtuple('WaitResult',
|
||||
:ivar ~.failure: a list of :class:`~openstack.baremetal.v1.node.Node`
|
||||
objects that hit a failure.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
@ -84,8 +86,12 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
commit_jsonpatch = True
|
||||
|
||||
_query_mapping = resource.QueryParameters(
|
||||
'associated', 'conductor_group', 'driver', 'fault',
|
||||
'provision_state', 'resource_class',
|
||||
'associated',
|
||||
'conductor_group',
|
||||
'driver',
|
||||
'fault',
|
||||
'provision_state',
|
||||
'resource_class',
|
||||
fields={'type': _common.fields_type},
|
||||
instance_id='instance_uuid',
|
||||
is_maintenance='maintenance',
|
||||
@ -292,21 +298,30 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
# Verify that the requested provision state is reachable with
|
||||
# the API version we are going to use.
|
||||
try:
|
||||
microversion = _common.STATE_VERSIONS[
|
||||
expected_provision_state]
|
||||
microversion = _common.STATE_VERSIONS[expected_provision_state]
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
"Node's provision_state must be one of %s for creation, "
|
||||
"got %s" % (', '.join(_common.STATE_VERSIONS),
|
||||
expected_provision_state))
|
||||
"got %s"
|
||||
% (
|
||||
', '.join(_common.STATE_VERSIONS),
|
||||
expected_provision_state,
|
||||
)
|
||||
)
|
||||
else:
|
||||
error_message = ("Cannot create a node with initial provision "
|
||||
"state %s" % expected_provision_state)
|
||||
error_message = (
|
||||
"Cannot create a node with initial provision "
|
||||
"state %s" % expected_provision_state
|
||||
)
|
||||
# Nodes cannot be created as available using new API versions
|
||||
maximum = ('1.10' if expected_provision_state == 'available'
|
||||
else None)
|
||||
maximum = (
|
||||
'1.10' if expected_provision_state == 'available' else None
|
||||
)
|
||||
microversion = self._assert_microversion_for(
|
||||
session, 'create', microversion, maximum=maximum,
|
||||
session,
|
||||
'create',
|
||||
microversion,
|
||||
maximum=maximum,
|
||||
error_message=error_message,
|
||||
)
|
||||
else:
|
||||
@ -315,11 +330,14 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
# Ironic cannot set provision_state itself, so marking it as unchanged
|
||||
self._clean_body_attrs({'provision_state'})
|
||||
|
||||
super(Node, self).create(session, *args, microversion=microversion,
|
||||
**kwargs)
|
||||
super(Node, self).create(
|
||||
session, *args, microversion=microversion, **kwargs
|
||||
)
|
||||
|
||||
if (expected_provision_state == 'manageable'
|
||||
and self.provision_state != 'manageable'):
|
||||
if (
|
||||
expected_provision_state == 'manageable'
|
||||
and self.provision_state != 'manageable'
|
||||
):
|
||||
# Manageable is not reachable directly
|
||||
self.set_provision_state(session, 'manage', wait=True)
|
||||
|
||||
@ -334,17 +352,22 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
:return: This :class:`Node` instance.
|
||||
"""
|
||||
# These fields have to be set through separate API.
|
||||
if ('maintenance_reason' in self._body.dirty
|
||||
or 'maintenance' in self._body.dirty):
|
||||
if (
|
||||
'maintenance_reason' in self._body.dirty
|
||||
or 'maintenance' in self._body.dirty
|
||||
):
|
||||
if not self.is_maintenance and self.maintenance_reason:
|
||||
if 'maintenance' in self._body.dirty:
|
||||
self.maintenance_reason = None
|
||||
else:
|
||||
raise ValueError('Maintenance reason cannot be set when '
|
||||
'maintenance is False')
|
||||
raise ValueError(
|
||||
'Maintenance reason cannot be set when '
|
||||
'maintenance is False'
|
||||
)
|
||||
if self.is_maintenance:
|
||||
self._do_maintenance_action(
|
||||
session, 'put', {'reason': self.maintenance_reason})
|
||||
session, 'put', {'reason': self.maintenance_reason}
|
||||
)
|
||||
else:
|
||||
# This corresponds to setting maintenance=False and
|
||||
# maintenance_reason=None in the same request.
|
||||
@ -358,9 +381,17 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
|
||||
return super(Node, self).commit(session, *args, **kwargs)
|
||||
|
||||
def set_provision_state(self, session, target, config_drive=None,
|
||||
clean_steps=None, rescue_password=None,
|
||||
wait=False, timeout=None, deploy_steps=None):
|
||||
def set_provision_state(
|
||||
self,
|
||||
session,
|
||||
target,
|
||||
config_drive=None,
|
||||
clean_steps=None,
|
||||
rescue_password=None,
|
||||
wait=False,
|
||||
timeout=None,
|
||||
deploy_steps=None,
|
||||
):
|
||||
"""Run an action modifying this node's provision state.
|
||||
|
||||
This call is asynchronous, it will return success as soon as the Bare
|
||||
@ -413,51 +444,65 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
body = {'target': target}
|
||||
if config_drive:
|
||||
if target not in ('active', 'rebuild'):
|
||||
raise ValueError('Config drive can only be provided with '
|
||||
'"active" and "rebuild" targets')
|
||||
raise ValueError(
|
||||
'Config drive can only be provided with '
|
||||
'"active" and "rebuild" targets'
|
||||
)
|
||||
# Not a typo - ironic accepts "configdrive" (without underscore)
|
||||
body['configdrive'] = config_drive
|
||||
|
||||
if clean_steps is not None:
|
||||
if target != 'clean':
|
||||
raise ValueError('Clean steps can only be provided with '
|
||||
'"clean" target')
|
||||
raise ValueError(
|
||||
'Clean steps can only be provided with ' '"clean" target'
|
||||
)
|
||||
body['clean_steps'] = clean_steps
|
||||
|
||||
if deploy_steps is not None:
|
||||
if target not in ('active', 'rebuild'):
|
||||
raise ValueError('Deploy steps can only be provided with '
|
||||
'"deploy" and "rebuild" target')
|
||||
raise ValueError(
|
||||
'Deploy steps can only be provided with '
|
||||
'"deploy" and "rebuild" target'
|
||||
)
|
||||
body['deploy_steps'] = deploy_steps
|
||||
|
||||
if rescue_password is not None:
|
||||
if target != 'rescue':
|
||||
raise ValueError('Rescue password can only be provided with '
|
||||
'"rescue" target')
|
||||
raise ValueError(
|
||||
'Rescue password can only be provided with '
|
||||
'"rescue" target'
|
||||
)
|
||||
body['rescue_password'] = rescue_password
|
||||
|
||||
if wait:
|
||||
try:
|
||||
expected_state = _common.EXPECTED_STATES[target]
|
||||
except KeyError:
|
||||
raise ValueError('For target %s the expected state is not '
|
||||
'known, cannot wait for it' % target)
|
||||
raise ValueError(
|
||||
'For target %s the expected state is not '
|
||||
'known, cannot wait for it' % target
|
||||
)
|
||||
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'states', 'provision')
|
||||
response = session.put(
|
||||
request.url, json=body,
|
||||
headers=request.headers, microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
request.url,
|
||||
json=body,
|
||||
headers=request.headers,
|
||||
microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES,
|
||||
)
|
||||
|
||||
msg = ("Failed to set provision state for bare metal node {node} "
|
||||
"to {target}".format(node=self.id, target=target))
|
||||
msg = (
|
||||
"Failed to set provision state for bare metal node {node} "
|
||||
"to {target}".format(node=self.id, target=target)
|
||||
)
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
if wait:
|
||||
return self.wait_for_provision_state(session,
|
||||
expected_state,
|
||||
timeout=timeout)
|
||||
return self.wait_for_provision_state(
|
||||
session, expected_state, timeout=timeout
|
||||
)
|
||||
else:
|
||||
return self.fetch(session)
|
||||
|
||||
@ -475,10 +520,11 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
:raises: :class:`~openstack.exceptions.ResourceTimeout` on timeout.
|
||||
"""
|
||||
for count in utils.iterate_timeout(
|
||||
timeout,
|
||||
"Timeout waiting for node %(node)s to reach "
|
||||
"power state '%(state)s'" % {'node': self.id,
|
||||
'state': expected_state}):
|
||||
timeout,
|
||||
"Timeout waiting for node %(node)s to reach "
|
||||
"power state '%(state)s'"
|
||||
% {'node': self.id, 'state': expected_state},
|
||||
):
|
||||
self.fetch(session)
|
||||
if self.power_state == expected_state:
|
||||
return self
|
||||
@ -486,11 +532,16 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
session.log.debug(
|
||||
'Still waiting for node %(node)s to reach power state '
|
||||
'"%(target)s", the current state is "%(state)s"',
|
||||
{'node': self.id, 'target': expected_state,
|
||||
'state': self.power_state})
|
||||
{
|
||||
'node': self.id,
|
||||
'target': expected_state,
|
||||
'state': self.power_state,
|
||||
},
|
||||
)
|
||||
|
||||
def wait_for_provision_state(self, session, expected_state, timeout=None,
|
||||
abort_on_failed_state=True):
|
||||
def wait_for_provision_state(
|
||||
self, session, expected_state, timeout=None, abort_on_failed_state=True
|
||||
):
|
||||
"""Wait for the node to reach the expected state.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
@ -510,20 +561,26 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
:raises: :class:`~openstack.exceptions.ResourceTimeout` on timeout.
|
||||
"""
|
||||
for count in utils.iterate_timeout(
|
||||
timeout,
|
||||
"Timeout waiting for node %(node)s to reach "
|
||||
"target state '%(state)s'" % {'node': self.id,
|
||||
'state': expected_state}):
|
||||
timeout,
|
||||
"Timeout waiting for node %(node)s to reach "
|
||||
"target state '%(state)s'"
|
||||
% {'node': self.id, 'state': expected_state},
|
||||
):
|
||||
self.fetch(session)
|
||||
if self._check_state_reached(session, expected_state,
|
||||
abort_on_failed_state):
|
||||
if self._check_state_reached(
|
||||
session, expected_state, abort_on_failed_state
|
||||
):
|
||||
return self
|
||||
|
||||
session.log.debug(
|
||||
'Still waiting for node %(node)s to reach state '
|
||||
'"%(target)s", the current state is "%(state)s"',
|
||||
{'node': self.id, 'target': expected_state,
|
||||
'state': self.provision_state})
|
||||
{
|
||||
'node': self.id,
|
||||
'target': expected_state,
|
||||
'state': self.provision_state,
|
||||
},
|
||||
)
|
||||
|
||||
def wait_for_reservation(self, session, timeout=None):
|
||||
"""Wait for a lock on the node to be released.
|
||||
@ -552,9 +609,9 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
return self
|
||||
|
||||
for count in utils.iterate_timeout(
|
||||
timeout,
|
||||
"Timeout waiting for the lock to be released on node %s" %
|
||||
self.id):
|
||||
timeout,
|
||||
"Timeout waiting for the lock to be released on node %s" % self.id,
|
||||
):
|
||||
self.fetch(session)
|
||||
if self.reservation is None:
|
||||
return self
|
||||
@ -562,10 +619,12 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
session.log.debug(
|
||||
'Still waiting for the lock to be released on node '
|
||||
'%(node)s, currently locked by conductor %(host)s',
|
||||
{'node': self.id, 'host': self.reservation})
|
||||
{'node': self.id, 'host': self.reservation},
|
||||
)
|
||||
|
||||
def _check_state_reached(self, session, expected_state,
|
||||
abort_on_failed_state=True):
|
||||
def _check_state_reached(
|
||||
self, session, expected_state, abort_on_failed_state=True
|
||||
):
|
||||
"""Wait for the node to reach the expected state.
|
||||
|
||||
:param session: The session to use for making this request.
|
||||
@ -581,29 +640,39 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
reaches an error state and ``abort_on_failed_state`` is ``True``.
|
||||
"""
|
||||
# NOTE(dtantsur): microversion 1.2 changed None to available
|
||||
if (self.provision_state == expected_state
|
||||
or (expected_state == 'available'
|
||||
and self.provision_state is None)):
|
||||
if self.provision_state == expected_state or (
|
||||
expected_state == 'available' and self.provision_state is None
|
||||
):
|
||||
return True
|
||||
elif not abort_on_failed_state:
|
||||
return False
|
||||
|
||||
if (self.provision_state.endswith(' failed')
|
||||
or self.provision_state == 'error'):
|
||||
if (
|
||||
self.provision_state.endswith(' failed')
|
||||
or self.provision_state == 'error'
|
||||
):
|
||||
raise exceptions.ResourceFailure(
|
||||
"Node %(node)s reached failure state \"%(state)s\"; "
|
||||
"the last error is %(error)s" %
|
||||
{'node': self.id, 'state': self.provision_state,
|
||||
'error': self.last_error})
|
||||
"the last error is %(error)s"
|
||||
% {
|
||||
'node': self.id,
|
||||
'state': self.provision_state,
|
||||
'error': self.last_error,
|
||||
}
|
||||
)
|
||||
# Special case: a failure state for "manage" transition can be
|
||||
# "enroll"
|
||||
elif (expected_state == 'manageable'
|
||||
and self.provision_state == 'enroll' and self.last_error):
|
||||
elif (
|
||||
expected_state == 'manageable'
|
||||
and self.provision_state == 'enroll'
|
||||
and self.last_error
|
||||
):
|
||||
raise exceptions.ResourceFailure(
|
||||
"Node %(node)s could not reach state manageable: "
|
||||
"failed to verify management credentials; "
|
||||
"the last error is %(error)s" %
|
||||
{'node': self.id, 'error': self.last_error})
|
||||
"the last error is %(error)s"
|
||||
% {'node': self.id, 'error': self.last_error}
|
||||
)
|
||||
|
||||
def inject_nmi(self, session):
|
||||
"""Inject NMI.
|
||||
@ -630,7 +699,7 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES,
|
||||
)
|
||||
|
||||
msg = ("Failed to inject NMI to node {node}".format(node=self.id))
|
||||
msg = "Failed to inject NMI to node {node}".format(node=self.id)
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
def set_power_state(self, session, target, wait=False, timeout=None):
|
||||
@ -654,8 +723,10 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
try:
|
||||
expected = _common.EXPECTED_POWER_STATES[target]
|
||||
except KeyError:
|
||||
raise ValueError("Cannot use target power state %s with wait, "
|
||||
"the expected state is not known" % target)
|
||||
raise ValueError(
|
||||
"Cannot use target power state %s with wait, "
|
||||
"the expected state is not known" % target
|
||||
)
|
||||
|
||||
session = self._get_session(session)
|
||||
|
||||
@ -672,12 +743,17 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'states', 'power')
|
||||
response = session.put(
|
||||
request.url, json=body,
|
||||
headers=request.headers, microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
request.url,
|
||||
json=body,
|
||||
headers=request.headers,
|
||||
microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES,
|
||||
)
|
||||
|
||||
msg = ("Failed to set power state for bare metal node {node} "
|
||||
"to {target}".format(node=self.id, target=target))
|
||||
msg = (
|
||||
"Failed to set power state for bare metal node {node} "
|
||||
"to {target}".format(node=self.id, target=target)
|
||||
)
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
if wait:
|
||||
@ -704,8 +780,11 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
version = self._assert_microversion_for(
|
||||
session, 'commit', _common.VIF_VERSION,
|
||||
error_message=("Cannot use VIF attachment API"))
|
||||
session,
|
||||
'commit',
|
||||
_common.VIF_VERSION,
|
||||
error_message=("Cannot use VIF attachment API"),
|
||||
)
|
||||
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'vifs')
|
||||
@ -714,12 +793,16 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
if not retry_on_conflict:
|
||||
retriable_status_codes = set(retriable_status_codes) - {409}
|
||||
response = session.post(
|
||||
request.url, json=body,
|
||||
headers=request.headers, microversion=version,
|
||||
retriable_status_codes=retriable_status_codes)
|
||||
request.url,
|
||||
json=body,
|
||||
headers=request.headers,
|
||||
microversion=version,
|
||||
retriable_status_codes=retriable_status_codes,
|
||||
)
|
||||
|
||||
msg = ("Failed to attach VIF {vif} to bare metal node {node}"
|
||||
.format(node=self.id, vif=vif_id))
|
||||
msg = "Failed to attach VIF {vif} to bare metal node {node}".format(
|
||||
node=self.id, vif=vif_id
|
||||
)
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
|
||||
def detach_vif(self, session, vif_id, ignore_missing=True):
|
||||
@ -742,23 +825,31 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
version = self._assert_microversion_for(
|
||||
session, 'commit', _common.VIF_VERSION,
|
||||
error_message=("Cannot use VIF attachment API"))
|
||||
session,
|
||||
'commit',
|
||||
_common.VIF_VERSION,
|
||||
error_message=("Cannot use VIF attachment API"),
|
||||
)
|
||||
|
||||
request = self._prepare_request(requires_id=True)
|
||||
request.url = utils.urljoin(request.url, 'vifs', vif_id)
|
||||
response = session.delete(
|
||||
request.url, headers=request.headers, microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
|
||||
request.url,
|
||||
headers=request.headers,
|
||||
microversion=version,
|
||||
retriable_status_codes=_common.RETRIABLE_STATUS_CODES,
|
||||
)
|
||||
|
||||
if ignore_missing and response.status_code == 400:
|
||||
session.log.debug(
|
||||
'VIF %(vif)s was already removed from node %(node)s',
|
||||
{'vif': vif_id, 'node': self.id})
|
||||
{'vif': vif_id, 'node': self.id},
|
||||
)
|
||||
return False
|
||||
|
||||
msg = ("Failed to detach VIF {vif} from bare metal node {node}"
|
||||
.format(node=self.id, vif=vif_id))
|
||||
msg = "Failed to detach VIF {vif} from bare metal node {node}".format(
|
||||
node=self.id, vif=vif_id
|
||||
)
|
||||
exceptions.raise_from_response(response, error_message=msg)
|
||||
return True
|
||||
|
||||
@ -777,16 +868,21 @@ class Node(_common.ListMixin, resource.Resource):
|
||||
"""
|
||||
session = self._get_session(session)
|
||||
version = self._assert_microversion_for(
|
||||
session, 'fetch', _common.VIF_VERSION,
|
||||
error_message=("Cannot use VIF attachment API"))
|
||||
session,
|
||||
'fetch',
|
||||
_common.VIF_VERSION,
|
||||
error_message=("Cannot use VIF attachment API"),
|
||||
)
|
||||
|
||||
request = self._prepare_request( |