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

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. 

15 

16from oslo_log import log 

17 

18from watcher.common.metal_helper import base 

19from watcher.common.metal_helper import constants as metal_constants 

20 

21LOG = log.getLogger(__name__) 

22 

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} 

31 

32 

33class IronicNode(base.BaseMetalNode): 

34 hv_up_when_powered_off = True 

35 

36 def __init__(self, ironic_node, nova_node, ironic_client): 

37 super().__init__(nova_node) 

38 

39 self._ironic_client = ironic_client 

40 self._ironic_node = ironic_node 

41 

42 def get_power_state(self): 

43 return POWER_STATES_MAP.get(self._ironic_node.power_state, 

44 metal_constants.PowerState.UNKNOWN) 

45 

46 def get_id(self): 

47 return self._ironic_node.uuid 

48 

49 def power_on(self): 

50 self._ironic_client.node.set_power_state(self.get_id(), "on") 

51 

52 def power_off(self): 

53 self._ironic_client.node.set_power_state(self.get_id(), "off") 

54 

55 

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 

62 

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() 

68 

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 

76 

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 

81 

82 out_node = IronicNode(node, hypervisor_node, self._client) 

83 out_list.append(out_node) 

84 

85 return out_list 

86 

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)