Integrate Ironic client
Change-Id: If956902cf63517d62c600d54b12af6eb232f7dd1
This commit is contained in:
parent
99a7b0a219
commit
f42ddc9b17
@ -14,6 +14,7 @@ pbr==5.5.1
|
||||
podman==1.6.0
|
||||
python-glanceclient==3.2.2
|
||||
python-heatclient==2.3.0
|
||||
python-ironicclient==4.6.1
|
||||
python-neutronclient==7.2.1
|
||||
python-novaclient==17.2.1
|
||||
python-octaviaclient==2.2.0
|
||||
|
@ -13,6 +13,7 @@ paramiko>=2.7.2 # LGPLv2.1
|
||||
pbr>=5.5.1 # Apache-2.0
|
||||
python-glanceclient>=3.2.2 # Apache-2.0
|
||||
python-heatclient>=2.3.0 # Apache-2.0
|
||||
python-ironicclient>=4.6.1 # Apache-2.0
|
||||
python-neutronclient>=7.2.1 # Apache-2.0
|
||||
python-novaclient>=17.2.1 # Apache-2.0
|
||||
python-octaviaclient>=2.2.0 # Apache-2.0
|
||||
|
23
tobiko/openstack/ironic/__init__.py
Normal file
23
tobiko/openstack/ironic/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright 2021 Red Hat
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from tobiko.openstack.ironic import _client
|
||||
from tobiko.openstack.ironic import _node
|
||||
|
||||
get_ironic_client = _client.get_ironic_client
|
||||
|
||||
power_off_node = _node.power_off_node
|
||||
power_on_node = _node.power_on_node
|
||||
IronicNodeType = _node.IronicNodeType
|
74
tobiko/openstack/ironic/_client.py
Normal file
74
tobiko/openstack/ironic/_client.py
Normal file
@ -0,0 +1,74 @@
|
||||
# Copyright 2021 Red Hat
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import typing
|
||||
|
||||
import ironicclient
|
||||
import ironicclient.v1.client
|
||||
from oslo_log import log
|
||||
|
||||
import tobiko
|
||||
from tobiko.openstack import _client
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
CLIENT_CLASSES = (ironicclient.v1.client.Client,)
|
||||
IronicClient = typing.Union[ironicclient.v1.client.Client]
|
||||
|
||||
|
||||
class IronicClientFixture(_client.OpenstackClientFixture):
|
||||
|
||||
def init_client(self, session) -> IronicClient:
|
||||
return ironicclient.client.get_client(1, session=session)
|
||||
|
||||
|
||||
class IronicClientManager(_client.OpenstackClientManager):
|
||||
|
||||
def create_client(self, session) -> IronicClientFixture:
|
||||
return IronicClientFixture(session=session)
|
||||
|
||||
|
||||
CLIENTS = IronicClientManager()
|
||||
|
||||
IronicClientType = typing.Union[IronicClient,
|
||||
IronicClientFixture,
|
||||
typing.Type[IronicClientFixture],
|
||||
None]
|
||||
|
||||
|
||||
def ironic_client(obj: IronicClientType) -> IronicClient:
|
||||
if obj is None:
|
||||
return get_ironic_client()
|
||||
|
||||
if isinstance(obj, CLIENT_CLASSES):
|
||||
return obj
|
||||
|
||||
fixture = tobiko.setup_fixture(obj)
|
||||
if isinstance(fixture, IronicClientFixture):
|
||||
assert fixture.client is not None
|
||||
return fixture.client
|
||||
|
||||
message = f"Object '{obj}' is not an IronicClientFixture instance"
|
||||
raise TypeError(message)
|
||||
|
||||
|
||||
def get_ironic_client(session=None, shared=True, init_client=None,
|
||||
manager=None) -> IronicClient:
|
||||
manager = manager or CLIENTS
|
||||
client = manager.get_client(session=session, shared=shared,
|
||||
init_client=init_client)
|
||||
tobiko.setup_fixture(client)
|
||||
return client.client
|
151
tobiko/openstack/ironic/_node.py
Normal file
151
tobiko/openstack/ironic/_node.py
Normal file
@ -0,0 +1,151 @@
|
||||
# Copyright 2021 Red Hat
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import typing
|
||||
|
||||
import ironicclient.v1.client
|
||||
from oslo_log import log
|
||||
|
||||
import tobiko
|
||||
from tobiko.openstack.ironic import _client
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
IronicNode = typing.Union[ironicclient.v1.node.Node]
|
||||
IronicNodeType = typing.Union[str, IronicNode]
|
||||
|
||||
|
||||
def get_node_id(node: typing.Optional[IronicNodeType] = None,
|
||||
node_id: typing.Optional[str] = None) -> str:
|
||||
if node_id is None:
|
||||
if isinstance(node, str):
|
||||
node_id = node
|
||||
else:
|
||||
assert node is not None
|
||||
node_id = node.uuid
|
||||
return node_id
|
||||
|
||||
|
||||
def get_node(node: typing.Optional[IronicNodeType] = None,
|
||||
node_id: typing.Optional[str] = None,
|
||||
client: _client.IronicClientType = None,
|
||||
**params) -> IronicNode:
|
||||
node_id = get_node_id(node=node, node_id=node_id)
|
||||
return _client.ironic_client(client).node.get(node_id, **params)
|
||||
|
||||
|
||||
class WaitForNodePowerStateError(tobiko.TobikoException):
|
||||
message = ("Node {node_id} not changing power state from "
|
||||
"{node_power_state} to {power_state}")
|
||||
|
||||
|
||||
class WaitForNodePowerStateTimeout(WaitForNodePowerStateError):
|
||||
message = ("Node {node_id} didn't change its state from "
|
||||
"{node_power_state} to {power_state} state after "
|
||||
"{timeout} seconds")
|
||||
|
||||
|
||||
IRONIC_NODE_TRANSIENT_POWER_STATES: typing.Dict[str, typing.List[str]] = {
|
||||
'power on': ['power off'],
|
||||
'power off': ['power on'],
|
||||
}
|
||||
|
||||
|
||||
def wait_for_node_power_state(
|
||||
node: IronicNodeType,
|
||||
power_state: str,
|
||||
client: _client.IronicClientType = None,
|
||||
timeout: tobiko.Seconds = None,
|
||||
sleep_time: tobiko.Seconds = None,
|
||||
transient_status: typing.Optional[typing.List[str]] = None) -> \
|
||||
IronicNode:
|
||||
if transient_status is None:
|
||||
transient_status = IRONIC_NODE_TRANSIENT_POWER_STATES.get(
|
||||
power_state) or []
|
||||
node_id = get_node_id(node)
|
||||
for attempt in tobiko.retry(timeout=timeout,
|
||||
interval=sleep_time,
|
||||
default_timeout=300.,
|
||||
default_interval=5.):
|
||||
_node = get_node(node_id=node_id, client=client)
|
||||
if _node.power_state == power_state:
|
||||
break
|
||||
|
||||
if _node.power_state not in transient_status:
|
||||
raise WaitForNodePowerStateError(
|
||||
node_id=node_id,
|
||||
node_power_state=_node.power_state,
|
||||
power_state=power_state)
|
||||
try:
|
||||
attempt.check_time_left()
|
||||
except tobiko.RetryTimeLimitError as ex:
|
||||
raise WaitForNodePowerStateTimeout(
|
||||
node_id=node_id,
|
||||
node_power_state=_node.power_state,
|
||||
power_state=power_state,
|
||||
timeout=timeout) from ex
|
||||
|
||||
LOG.debug(f"Waiting for baremetal node {node_id} power state to get "
|
||||
f"from {_node.power_state} to {power_state}...")
|
||||
else:
|
||||
raise RuntimeError("Retry look break before timing out")
|
||||
|
||||
return _node
|
||||
|
||||
|
||||
def power_off_node(node: IronicNodeType,
|
||||
soft=False,
|
||||
client: _client.IronicClientType = None,
|
||||
timeout: tobiko.Seconds = None,
|
||||
sleep_time: tobiko.Seconds = None) \
|
||||
-> IronicNode:
|
||||
client = _client.ironic_client(client)
|
||||
node = get_node(node=node, client=client)
|
||||
if node.power_state == 'power off':
|
||||
return node
|
||||
|
||||
LOG.info(f"Power off baremetal node '{node.uuid}' "
|
||||
f"(power state = '{node.power_state}').")
|
||||
client.node.set_power_state(node.uuid,
|
||||
state='off',
|
||||
soft=soft,
|
||||
timeout=timeout)
|
||||
return wait_for_node_power_state(node=node.uuid,
|
||||
power_state='power off',
|
||||
client=client,
|
||||
timeout=timeout,
|
||||
sleep_time=sleep_time)
|
||||
|
||||
|
||||
def power_on_node(node: IronicNodeType,
|
||||
client: _client.IronicClientType = None,
|
||||
timeout: tobiko.Seconds = None,
|
||||
sleep_time: tobiko.Seconds = None) -> \
|
||||
IronicNode:
|
||||
client = _client.ironic_client(client)
|
||||
node = get_node(node=node, client=client)
|
||||
if node.power_state == 'power on':
|
||||
return node
|
||||
|
||||
LOG.info(f"Power on baremetal node '{node.uuid}' "
|
||||
f"(power_state='{node.power_state}').")
|
||||
client.node.set_power_state(node_id=node.uuid, state='on')
|
||||
|
||||
return wait_for_node_power_state(node=node.uuid,
|
||||
power_state='power on',
|
||||
client=client,
|
||||
timeout=timeout,
|
||||
sleep_time=sleep_time)
|
@ -45,6 +45,7 @@ migrate_server = _client.migrate_server
|
||||
confirm_resize = _client.confirm_resize
|
||||
reboot_server = _client.reboot_server
|
||||
NovaServer = _client.NovaServer
|
||||
ServerType = _client.ServerType
|
||||
|
||||
WaitForCloudInitTimeoutError = _cloud_init.WaitForCloudInitTimeoutError
|
||||
cloud_config = _cloud_init.cloud_config
|
||||
|
Loading…
Reference in New Issue
Block a user