ansible-collections-openstack/plugins/modules/baremetal_node.py

693 lines
24 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2014, Hewlett-Packard Development Company, L.P.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
DOCUMENTATION = r'''
---
module: baremetal_node
short_description: Create/Delete Bare Metal Resources from OpenStack
author: OpenStack Ansible SIG
description:
- Create or Remove Ironic nodes from OpenStack.
options:
bios_interface:
description:
- The bios interface for this node, e.g. C(no-bios).
type: str
boot_interface:
description:
- The boot interface for this node, e.g. C(pxe).
type: str
chassis_id:
description:
- Associate the node with a pre-defined chassis.
type: str
aliases: ['chassis_uuid']
console_interface:
description:
- The console interface for this node, e.g. C(no-console).
type: str
deploy_interface:
description:
- The deploy interface for this node, e.g. C(iscsi).
type: str
driver:
description:
- The name of the Ironic Driver to use with this node.
- Required when I(state) is C(present)
type: str
driver_info:
description:
- Information for this node's driver. Will vary based on which
driver is in use. Any sub-field which is populated will be validated
during creation. For compatibility reasons sub-fields `power`,
`deploy`, `management` and `console` are flattened.
required: true
type: dict
id:
description:
- ID to be given to the baremetal node. Will be auto-generated on
creation if not specified, and I(name) is specified.
- Definition of I(id) will always take precedence over I(name).
type: str
aliases: ['uuid']
inspect_interface:
description:
- The interface used for node inspection, e.g. C(no-inspect).
type: str
management_interface:
description:
- The interface for out-of-band management of this node, e.g.
"ipmitool".
type: str
name:
description:
- unique name identifier to be given to the resource.
type: str
network_interface:
description:
- The network interface provider to use when describing
connections for this node.
type: str
nics:
description:
- 'A list of network interface cards, eg, C( - mac: aa:bb:cc:aa:bb:cc)'
- This node attribute cannot be updated.
required: true
type: list
elements: dict
suboptions:
mac:
description: The MAC address of the network interface card.
type: str
required: true
power_interface:
description:
- The interface used to manage power actions on this node, e.g.
C(ipmitool).
type: str
properties:
description:
- Definition of the physical characteristics of this node
- Used for scheduling purposes
type: dict
suboptions:
cpu_arch:
description:
- CPU architecture (x86_64, i686, ...)
type: str
cpus:
description:
- Number of CPU cores this machine has
type: str
memory_mb:
description:
- Amount of RAM in MB this machine has
aliases: ['ram']
type: str
local_gb:
description:
- Size in GB of first storage device in this machine (typically
/dev/sda)
aliases: ['disk_size']
type: str
capabilities:
description:
- Special capabilities for this node such as boot_option etc.
- For more information refer to
U(https://docs.openstack.org/ironic/latest/install/advanced.html).
type: str
root_device:
description:
- Root disk device hints for deployment.
- For allowed hints refer to
U(https://docs.openstack.org/ironic/latest/install/advanced.html).
type: dict
raid_interface:
description:
- Interface used for configuring raid on this node.
type: str
rescue_interface:
description:
- Interface used for node rescue, e.g. C(no-rescue).
type: str
resource_class:
description:
- The specific resource type to which this node belongs.
type: str
skip_update_of_masked_password:
description:
- Deprecated, no longer used.
- Updating or specifing a password has not been supported for a while.
type: bool
state:
description:
- Indicates desired state of the resource
choices: ['present', 'absent']
default: present
type: str
storage_interface:
description:
- Interface used for attaching and detaching volumes on this node, e.g.
C(cinder).
type: str
timeout:
description:
- Number of seconds to wait for the newly created node to reach the
available state.
type: int
default: 1800
vendor_interface:
description:
- Interface for all vendor-specific actions on this node, e.g.
C(no-vendor).
type: str
requirements:
- "python >= 3.6"
- "openstacksdk"
extends_documentation_fragment:
- openstack.cloud.openstack
'''
EXAMPLES = r'''
- name: Enroll a node with some basic properties and driver info
openstack.cloud.baremetal_node:
chassis_id: "00000000-0000-0000-0000-000000000001"
cloud: "devstack"
driver: "pxe_ipmitool"
driver_info:
ipmi_address: "1.2.3.4"
ipmi_username: "admin"
ipmi_password: "adminpass"
id: "00000000-0000-0000-0000-000000000002"
nics:
- mac: "aa:bb:cc:aa:bb:cc"
- mac: "dd:ee:ff:dd:ee:ff"
properties:
capabilities: "boot_option:local"
cpu_arch: "x86_64"
cpus: 2
local_gb: 64
memory_mb: 8192
root_device:
wwn: "0x4000cca77fc4dba1"
'''
RETURN = r'''
node:
description: Dictionary describing the Bare Metal node.
type: dict
returned: On success when I(state) is 'present'.
contains:
allocation_id:
description: The UUID of the allocation associated with the node.
If not null, will be the same as instance_id (the
opposite is not always true). Unlike instance_id,
this field is read-only. Please use the Allocation API
to remove allocations.
returned: success
type: str
bios_interface:
description: The bios interface to be used for this node.
returned: success
type: str
boot_interface:
description: The boot interface for a node, e.g. "pxe".
returned: success
type: str
boot_mode:
description: The boot mode for a node, either "uefi" or "bios"
returned: success
type: str
chassis_id:
description: UUID of the chassis associated with this node. May be
empty or None.
returned: success
type: str
clean_step:
description: The current clean step.
returned: success
type: str
conductor:
description: |
The conductor currently servicing a node.
returned: success
type: str
conductor_group:
description: The conductor group for a node.
returned: success
type: str
console_interface:
description: The console interface for a node, e.g. "no-console".
returned: success
type: str
created_at:
description: Bare Metal node created at timestamp.
returned: success
type: str
deploy_interface:
description: The deploy interface for a node, e.g. "direct".
returned: success
type: str
deploy_step:
description: The current deploy step.
returned: success
type: str
driver:
description: The name of the driver.
returned: success
type: str
driver_info:
description: All the metadata required by the driver to manage this
node. List of fields varies between drivers, and can
be retrieved from the
/v1/drivers/<DRIVER_NAME>/properties resource.
returned: success
type: dict
driver_internal_info:
description: Internal metadata set and stored by the node's driver.
returned: success
type: dict
extra:
description: A set of one or more arbitrary metadata key and value
pairs.
returned: success
type: dict
fault:
description: The fault indicates the active fault detected by
ironic, typically the node is in "maintenance mode".
None means no fault has been detected by ironic.
"power failure" indicates ironic failed to retrieve
power state from this node. There are other possible
types, e.g., "clean failure" and "rescue abort
failure".
returned: success
type: str
id:
description: The UUID for the resource.
returned: success
type: str
inspect_interface:
description: The interface used for node inspection.
returned: success
type: str
instance_id:
description: UUID of the Nova instance associated with this node.
returned: success
type: str
instance_info:
description: Information used to customize the deployed image. May
include root partition size, a base 64 encoded config
drive, and other metadata. Note that this field is
erased automatically when the instance is deleted
(this is done by requesting the node provision state
be changed to DELETED).
returned: success
type: dict
is_automated_clean_enabled:
description: Indicates whether the node will perform automated
clean or not.
returned: success
type: bool
is_console_enabled:
description: Indicates whether console access is enabled or
disabled on this node.
returned: success
type: bool
is_maintenance:
description: Whether or not this node is currently in "maintenance
mode". Setting a node into maintenance mode removes it
from the available resource pool and halts some
internal automation. This can happen manually (eg, via
an API request) or automatically when Ironic detects a
hardware fault that prevents communication with the
machine.
returned: success
type: bool
is_protected:
description: Whether the node is protected from undeploying,
rebuilding and deletion.
returned: success
type: bool
is_retired:
description: Whether the node is retired and can hence no longer be
provided, i.e. move from manageable to available, and
will end up in manageable after cleaning (rather than
available).
returned: success
type: bool
is_secure_boot:
description: Indicates whether node is currently booted with
secure_boot turned on.
returned: success
type: bool
last_error:
description: Any error from the most recent (last) transaction that
started but failed to finish.
returned: success
type: str
links:
description: A list of relative links, including self and bookmark
links.
returned: success
type: list
maintenance_reason:
description: User-settable description of the reason why this node
was placed into maintenance mode
returned: success
type: str
management_interface:
description: Interface for out-of-band node management.
returned: success
type: str
name:
description: Human-readable identifier for the node resource. May
be undefined. Certain words are reserved.
returned: success
type: str
network_interface:
description: Which Network Interface provider to use when plumbing
the network connections for this node.
returned: success
type: str
owner:
description: A string or UUID of the tenant who owns the object.
returned: success
type: str
ports:
description: List of ironic ports on this node.
returned: success
type: list
port_groups:
description: List of ironic port groups on this node.
returned: success
type: list
power_interface:
description: Interface used for performing power actions on the
node, e.g. "ipmitool".
returned: success
type: str
power_state:
description: The current power state of this node. Usually, "power
on" or "power off", but may be "None" if Ironic is
unable to determine the power state (eg, due to
hardware failure).
returned: success
type: str
properties:
description: Physical characteristics of this node. Populated by
ironic-inspector during inspection. May be edited via
the REST API at any time.
returned: success
type: dict
protected_reason:
description: The reason the node is marked as protected.
returned: success
type: str
provision_state:
description: The current provisioning state of this node.
returned: success
type: str
raid_config:
description: Represents the current RAID configuration of the node.
Introduced with the cleaning feature.
returned: success
type: dict
raid_interface:
description: Interface used for configuring RAID on this node.
returned: success
type: str
rescue_interface:
description: The interface used for node rescue, e.g. "no-rescue".
returned: success
type: str
reservation:
description: The name of an Ironic Conductor host which is holding
a lock on this node, if a lock is held. Usually
"null", but this field can be useful for debugging.
returned: success
type: str
resource_class:
description: A string which can be used by external schedulers to
identify this node as a unit of a specific type of
resource. For more details, see
https://docs.openstack.org/ironic/latest/install/configure-nova-flavors.html
returned: success
type: str
retired_reason:
description: The reason the node is marked as retired.
returned: success
type: str
states:
description: Links to the collection of states.
returned: success
type: list
storage_interface:
description: Interface used for attaching and detaching volumes on
this node, e.g. "cinder".
returned: success
type: str
target_power_state:
description: If a power state transition has been requested, this
field represents the requested (ie, "target") state,
either "power on" or "power off".
returned: success
type: str
target_provision_state:
description: If a provisioning action has been requested, this
field represents the requested (ie, "target") state.
Note that a node may go through several states during
its transition to this target state. For instance,
when requesting an instance be deployed to an
AVAILABLE node, the node may go through the following
state change progression, AVAILABLE -> DEPLOYING ->
DEPLOYWAIT -> DEPLOYING -> ACTIVE
returned: success
type: str
target_raid_config:
description: Represents the requested RAID configuration of the
node, which will be applied when the node next
transitions through the CLEANING state. Introduced
with the cleaning feature.
returned: success
type: dict
traits:
description: List of traits for this node.
returned: success
type: list
updated_at:
description: Bare Metal node updated at timestamp.
returned: success
type: str
vendor_interface:
description: Interface for vendor-specific functionality on this
node, e.g. "no-vendor".
returned: success
type: str
'''
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (
OpenStackModule
)
class BaremetalNodeModule(OpenStackModule):
argument_spec = dict(
bios_interface=dict(),
boot_interface=dict(),
chassis_id=dict(aliases=['chassis_uuid']),
console_interface=dict(),
deploy_interface=dict(),
driver=dict(),
driver_info=dict(type='dict', required=True),
id=dict(aliases=['uuid']),
inspect_interface=dict(),
management_interface=dict(),
name=dict(),
network_interface=dict(),
nics=dict(type='list', required=True, elements='dict'),
power_interface=dict(),
properties=dict(
type='dict',
options=dict(
cpu_arch=dict(),
cpus=dict(),
memory_mb=dict(aliases=['ram']),
local_gb=dict(aliases=['disk_size']),
capabilities=dict(),
root_device=dict(type='dict'),
),
),
raid_interface=dict(),
rescue_interface=dict(),
resource_class=dict(),
skip_update_of_masked_password=dict(
type='bool',
removed_in_version='3.0.0',
removed_from_collection='openstack.cloud',
),
state=dict(default='present', choices=['present', 'absent']),
storage_interface=dict(),
timeout=dict(default=1800, type='int'), # increased default value
vendor_interface=dict(),
)
module_kwargs = dict(
required_if=[
('state', 'present', ('driver',)),
],
required_one_of=[
('id', 'name'),
],
supports_check_mode=True,
)
def run(self):
name_or_id = \
self.params['id'] if self.params['id'] else self.params['name']
node = self.conn.baremetal.find_node(name_or_id)
state = self.params['state']
if self.ansible.check_mode:
self.exit_json(changed=self._will_change(state, node))
if state == 'present' and not node:
node = self._create()
self.exit_json(changed=True,
node=node.to_dict(computed=False))
elif state == 'present' and node:
update = self._build_update(node)
if update:
node = self._update(node, update)
self.exit_json(changed=bool(update),
node=node.to_dict(computed=False))
elif state == 'absent' and node:
self._delete(node)
self.exit_json(changed=True)
elif state == 'absent' and not node:
self.exit_json(changed=False)
def _build_update(self, node):
update = {}
# TODO(TheJulia): Presently this does not support updating nics.
# Support needs to be added.
# Update all known updateable attributes
node_attributes = dict(
(k, self.params[k])
for k in [
'bios_interface',
'boot_interface',
'chassis_id',
'console_interface',
'deploy_interface',
'driver',
'driver_info',
'inspect_interface',
'management_interface',
'name',
'network_interface',
'power_interface',
'raid_interface',
'rescue_interface',
'resource_class',
'storage_interface',
'vendor_interface',
]
if k in self.params and self.params[k] is not None
and self.params[k] != node[k])
properties = self.params['properties']
if properties is not None:
properties = dict(
(k, v) for k, v in properties.items() if v is not None)
if properties and properties != node['properties']:
node_attributes['properties'] = properties
# name can only be updated if id is given
if self.params['id'] is None and 'name' in node_attributes:
self.fail_json(msg='The name of a node cannot be updated without'
' specifying an id')
if node_attributes:
update['node_attributes'] = node_attributes
return update
def _create(self):
kwargs = {}
for k in ('bios_interface',
'boot_interface',
'chassis_id',
'console_interface',
'deploy_interface',
'driver',
'driver_info',
'id',
'inspect_interface',
'management_interface',
'name',
'network_interface',
'power_interface',
'raid_interface',
'rescue_interface',
'resource_class',
'storage_interface',
'vendor_interface'):
if self.params[k] is not None:
kwargs[k] = self.params[k]
properties = self.params['properties']
if properties is not None:
properties = dict(
(k, v) for k, v in properties.items() if v is not None)
if properties:
kwargs['properties'] = properties
node = self.conn.register_machine(
nics=self.params['nics'],
wait=self.params['wait'],
timeout=self.params['timeout'],
**kwargs)
self.exit_json(changed=True, node=node.to_dict(computed=False))
def _delete(self, node):
self.conn.unregister_machine(
nics=self.params['nics'], uuid=node['id'])
def _update(self, node, update):
node_attributes = update.get('node_attributes')
if node_attributes:
node = self.conn.baremetal.update_node(
node['id'], **node_attributes)
return node
def _will_change(self, state, node):
if state == 'present' and not node:
return True
elif state == 'present' and node:
return bool(self._build_update(node))
elif state == 'absent' and node:
return False
else:
# state == 'absent' and not node:
return True
def main():
module = BaremetalNodeModule()
module()
if __name__ == "__main__":
main()