Coverage for watcher/common/metal_helper/ironic.py: 100%
48 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
1# Copyright 2023 Cloudbase Solutions
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
16from oslo_log import log
18from watcher.common.metal_helper import base
19from watcher.common.metal_helper import constants as metal_constants
21LOG = log.getLogger(__name__)
23POWER_STATES_MAP = {
24 'power on': metal_constants.PowerState.ON,
25 'power off': metal_constants.PowerState.OFF,
26 # For now, we only use ON/OFF states
27 'rebooting': metal_constants.PowerState.ON,
28 'soft power off': metal_constants.PowerState.OFF,
29 'soft reboot': metal_constants.PowerState.ON,
30}
33class IronicNode(base.BaseMetalNode):
34 hv_up_when_powered_off = True
36 def __init__(self, ironic_node, nova_node, ironic_client):
37 super().__init__(nova_node)
39 self._ironic_client = ironic_client
40 self._ironic_node = ironic_node
42 def get_power_state(self):
43 return POWER_STATES_MAP.get(self._ironic_node.power_state,
44 metal_constants.PowerState.UNKNOWN)
46 def get_id(self):
47 return self._ironic_node.uuid
49 def power_on(self):
50 self._ironic_client.node.set_power_state(self.get_id(), "on")
52 def power_off(self):
53 self._ironic_client.node.set_power_state(self.get_id(), "off")
56class IronicHelper(base.BaseMetalHelper):
57 @property
58 def _client(self):
59 if not getattr(self, "_cached_client", None):
60 self._cached_client = self._osc.ironic()
61 return self._cached_client
63 def list_compute_nodes(self):
64 out_list = []
65 # TODO(lpetrut): consider using "detailed=True" instead of making
66 # an additional GET request per node
67 node_list = self._client.node.list()
69 for node in node_list:
70 node_info = self._client.node.get(node.uuid)
71 hypervisor_id = node_info.extra.get('compute_node_id', None)
72 if hypervisor_id is None:
73 LOG.warning('Cannot find compute_node_id in extra '
74 'of ironic node %s', node.uuid)
75 continue
77 hypervisor_node = self.nova_client.hypervisors.get(hypervisor_id)
78 if hypervisor_node is None:
79 LOG.warning('Cannot find hypervisor %s', hypervisor_id)
80 continue
82 out_node = IronicNode(node, hypervisor_node, self._client)
83 out_list.append(out_node)
85 return out_list
87 def get_node(self, node_id):
88 ironic_node = self._client.node.get(node_id)
89 compute_node_id = ironic_node.extra.get('compute_node_id')
90 if compute_node_id:
91 compute_node = self.nova_client.hypervisors.get(compute_node_id)
92 else:
93 compute_node = None
94 return IronicNode(ironic_node, compute_node, self._client)