f73a0e385e
Story: 2010586 Task: 47380 Change-Id: I1b88aa925d823d74b2d012153dfe26d35c93dfd5
269 lines
9.8 KiB
Python
269 lines
9.8 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# (c) 2015, 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_action
|
|
short_description: Activate/Deactivate Bare Metal nodes from OpenStack
|
|
author: OpenStack Ansible SIG
|
|
description:
|
|
- Deploy to Bare Metal nodes controlled by Ironic.
|
|
options:
|
|
deploy:
|
|
description:
|
|
- Indicates if the resource should be deployed. Allows for deployment
|
|
logic to be disengaged and control of the node power or maintenance
|
|
state to be changed.
|
|
type: bool
|
|
default: true
|
|
config_drive:
|
|
description:
|
|
- A configdrive file or HTTP(S) URL that will be passed along to the
|
|
node.
|
|
type: raw
|
|
instance_info:
|
|
description:
|
|
- Definition of the instance information which is used to deploy
|
|
the node. This information is only required when I(state) is
|
|
set to C(present) or C(on).
|
|
type: dict
|
|
suboptions:
|
|
image_source:
|
|
description:
|
|
- An HTTP(S) URL where the image can be retrieved from.
|
|
image_checksum:
|
|
description:
|
|
- The checksum of image_source.
|
|
image_disk_format:
|
|
description:
|
|
- The type of image that has been requested to be deployed.
|
|
maintenance:
|
|
description:
|
|
- Set node into maintenance mode.
|
|
- The power state as controlled with I(power) will not be changed
|
|
when maintenance mode of a node is changed.
|
|
type: bool
|
|
maintenance_reason:
|
|
description:
|
|
- A string expression regarding the reason a node is in a
|
|
maintenance mode.
|
|
type: str
|
|
name:
|
|
description:
|
|
- Name or ID of the Bare Metal node.
|
|
type: str
|
|
required: true
|
|
aliases: ['id', 'uuid']
|
|
power:
|
|
description:
|
|
- A setting to allow power state to be asserted allowing nodes
|
|
that are not yet deployed to be powered on, and nodes that
|
|
are deployed to be powered off.
|
|
- I(power) can be C(present), C(absent), C(maintenance), C(on) or
|
|
C(off).
|
|
choices: ['present', 'absent', 'maintenance', 'on', 'off']
|
|
default: present
|
|
type: str
|
|
state:
|
|
description:
|
|
- Indicates desired state of the resource.
|
|
- I(state) can be C(present), C(absent), C(maintenance), C(on) or
|
|
C(off).
|
|
choices: ['present', 'absent', 'maintenance', 'on', 'off']
|
|
default: present
|
|
type: str
|
|
timeout:
|
|
description:
|
|
- Number of seconds to wait for the node activation or deactivation
|
|
to complete.
|
|
type: int
|
|
default: 1800
|
|
extends_documentation_fragment:
|
|
- openstack.cloud.openstack
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
# Activate a node by booting an image with a configdrive attached
|
|
- openstack.cloud.baremetal_node_action:
|
|
instance_info:
|
|
image_source: "http://192.168.1.1/deploy_image.img"
|
|
image_checksum: "356a6b55ecc511a20c33c946c4e678af"
|
|
image_disk_format: "qcow"
|
|
delegate_to: localhost
|
|
deploy: true
|
|
cloud: "openstack"
|
|
config_drive: "http://192.168.1.1/host-configdrive.iso"
|
|
maintenance: false
|
|
power: present
|
|
uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
|
state: present
|
|
|
|
# Activate a node by booting an image with a configdrive json object
|
|
- openstack.cloud.baremetal_node_action:
|
|
auth_type: None
|
|
auth:
|
|
endpoint: "http://192.168.1.1:6385/"
|
|
id: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
|
config_drive:
|
|
meta_data:
|
|
hostname: node1
|
|
public_keys:
|
|
default: ssh-rsa AAA...BBB==
|
|
delegate_to: localhost
|
|
instance_info:
|
|
image_source: "http://192.168.1.1/deploy_image.img"
|
|
image_checksum: "356a6b55ecc511a20c33c946c4e678af"
|
|
image_disk_format: "qcow"
|
|
'''
|
|
|
|
RETURN = r'''
|
|
'''
|
|
|
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (
|
|
OpenStackModule
|
|
)
|
|
|
|
|
|
class BaremetalNodeActionModule(OpenStackModule):
|
|
|
|
argument_spec = dict(
|
|
config_drive=dict(type='raw'),
|
|
deploy=dict(type='bool', default=True),
|
|
instance_info=dict(type='dict'),
|
|
maintenance=dict(type='bool'),
|
|
maintenance_reason=dict(),
|
|
name=dict(required=True, aliases=['id', 'uuid']),
|
|
power=dict(default='present',
|
|
choices=['present', 'absent', 'maintenance', 'on', 'off']),
|
|
state=dict(default='present',
|
|
choices=['present', 'absent', 'maintenance', 'on', 'off']),
|
|
timeout=dict(type='int', default=1800), # increased default value
|
|
)
|
|
|
|
module_kwargs = dict(
|
|
required_if=[
|
|
('state', 'present', ('instance_info',)),
|
|
],
|
|
)
|
|
|
|
def run(self):
|
|
# Fail early on invalid arguments
|
|
config_drive = self.params['config_drive']
|
|
if config_drive and not isinstance(config_drive, (str, dict)):
|
|
self.fail_json(msg='config_drive must be of type str or dict,'
|
|
' not {0}'.format(type(config_drive)))
|
|
|
|
# User has requested desired state to be in maintenance state.
|
|
if self.params['state'] == 'maintenance':
|
|
if self.params['maintenance'] is False:
|
|
self.fail_json(
|
|
msg='state=maintenance contradicts with maintenance=false')
|
|
self.params['maintenance'] = True
|
|
|
|
name_or_id = self.params['name']
|
|
node = self.conn.baremetal.find_node(name_or_id, ignore_missing=False)
|
|
|
|
if node['provision_state'] in ['cleaning',
|
|
'deleting',
|
|
'wait call-back']:
|
|
self.fail_json(msg='Node is in {0} state, cannot act upon the'
|
|
' request as the node is in a transition'
|
|
' state'.format(node['provision_state']))
|
|
|
|
changed = False
|
|
|
|
# Update maintenance state
|
|
if self.params['maintenance']:
|
|
maintenance_reason = self.params['maintenance_reason']
|
|
if not node['maintenance'] \
|
|
or node['maintenance_reason'] != maintenance_reason:
|
|
self.conn.baremetal.set_node_maintenance(
|
|
node['id'], reason=maintenance_reason)
|
|
self.exit_json(changed=True)
|
|
else: # self.params['maintenance'] is False
|
|
if node['maintenance']:
|
|
self.conn.baremetal.unset_node_maintenance(node['id'])
|
|
if node['provision_state'] in 'active':
|
|
# Maintenance state changed
|
|
self.exit_json(changed=True)
|
|
changed = True
|
|
node = self.conn.baremetal.get_node(node['id'])
|
|
|
|
# Update power state
|
|
if node['power_state'] == 'power on':
|
|
if self.params['power'] in ['absent', 'off']:
|
|
# User has requested the node be powered off.
|
|
self.conn.baremetal.set_node_power_state(node['id'],
|
|
'power off')
|
|
self.exit_json(changed=True)
|
|
elif node['power_state'] == 'power off':
|
|
if self.params['power'] not in ['absent', 'off'] \
|
|
or self.params['state'] not in ['absent', 'off']:
|
|
# In the event the power has been toggled on and
|
|
# deployment has been requested, we need to skip this
|
|
# step.
|
|
if self.params['power'] == 'present' \
|
|
and not self.params['deploy']:
|
|
# Node is powered down when it is not awaiting to be
|
|
# provisioned
|
|
self.conn.baremetal.set_node_power_state(node['id'],
|
|
'power on')
|
|
changed = True
|
|
node = self.conn.baremetal.get_node(node['id'])
|
|
else:
|
|
self.fail_json(msg='Node has unknown power state {0}'
|
|
.format(node['power_state']))
|
|
|
|
if self.params['state'] in ['present', 'on']:
|
|
if not self.params['deploy']:
|
|
# User request has explicitly disabled deployment logic
|
|
self.exit_json(changed=changed)
|
|
|
|
if 'active' in node['provision_state']:
|
|
# Node already in an active state
|
|
self.exit_json(changed=changed)
|
|
|
|
# TODO(TheJulia): Update instance info, however info is
|
|
# deployment specific. Perhaps consider adding rebuild
|
|
# support, although there is a known desire to remove
|
|
# rebuild support from Ironic at some point in the future.
|
|
self.conn.baremetal.update_node(
|
|
node['id'],
|
|
instance_info=self.params['instance_info'])
|
|
self.conn.baremetal.validate_node(node['id'])
|
|
self.conn.baremetal.set_node_provision_state(
|
|
node['id'],
|
|
target='active',
|
|
config_drive=self.params['config_drive'],
|
|
wait=self.params['wait'],
|
|
timeout=self.params['timeout'])
|
|
|
|
# TODO(TheJulia): Add more error checking..
|
|
self.exit_json(changed=True)
|
|
|
|
elif node['provision_state'] not in 'deleted':
|
|
self.conn.baremetal.update_node(node['id'], instance_info={})
|
|
self.conn.baremetal.set_node_provision_state(
|
|
node['id'],
|
|
target='deleted',
|
|
wait=self.params['wait'],
|
|
timeout=self.params['timeout'])
|
|
self.exit_json(changed=True)
|
|
|
|
else:
|
|
# self.params['state'] in ['absent', 'off']
|
|
# and node['provision_state'] in 'deleted'
|
|
self.exit_json(changed=changed)
|
|
|
|
|
|
def main():
|
|
module = BaremetalNodeActionModule()
|
|
module()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|