diff --git a/plugins/modules/baremetal_node_state.py b/plugins/modules/baremetal_node_state.py new file mode 100644 index 0000000..a8936de --- /dev/null +++ b/plugins/modules/baremetal_node_state.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# (c) 2015, Hewlett-Packard Development Company, L.P. +# Copyright 2017 StackHPC Ltd. +# +# This module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software. If not, see . + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = r''' +module: baremetal_node_state +short_description: Set provision state of Bare Metal Resources from OpenStack +author: "Mark Goddard " +extends_documentation_fragment: openstack +description: + - Set the provision state of OpenStack ironic bare metal nodes. +options: + provision_state: + description: + - Indicates desired provision state of the resource + choices: ['manage', 'provide'] + default: present + uuid: + description: + - globally unique identifier (UUID) to be given to the resource. + required: false + default: None + ironic_url: + description: + - If noauth mode is utilized, this is required to be set to the + endpoint URL for the Ironic API. Use with "auth" and "auth_type" + settings set to None. + required: false + default: None + wait: + description: + - A boolean value instructing the module to wait for node + activation or deactivation to complete before returning. + required: false + default: False + version_added: "2.1" + timeout: + description: + - An integer value representing the number of seconds to + wait for the node activation or deactivation to complete. + version_added: "2.1" + availability_zone: + description: + - Ignored. Present for backwards compatibility + required: false +''' + +EXAMPLES = r''' +baremeta_node_state: + cloud: "openstack" + uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69" + provision_state: provide + delegate_to: localhost +''' + +from ansible_collections.openstack.cloud.plugins.module_utils.openstack import ( + OpenStackModule +) + + +def _choose_id_value(module): + if module.params['uuid']: + return module.params['uuid'] + if module.params['name']: + return module.params['name'] + return None + + +def _change_required(current_provision_state, action): + """Return whether a change to the provision state is required. + + :param current_provision_state: The current provision state of the node. + :param action: The requested action. + """ + if action == 'manage': + if current_provision_state == 'manageable': + return False + if action == 'provide': + if current_provision_state == 'available': + return False + return True + + +class BaremetalDeployTemplateModule(OpenStackModule): + argument_spec = dict( + uuid=dict(required=False), + name=dict(required=False), + ironic_url=dict(required=False), + provision_state=dict(required=True, + choices=['manage', 'provide']), + wait=dict(type='bool', required=False, default=False), + timeout=dict(required=False, type='int', default=1800), + ) + module_kwargs = dict( + required_one_of=[ + ('uuid', 'name'), + ], + ) + + def run(self): + if (self.params['auth_type'] in [None, 'None'] and + self.params['ironic_url'] is None): + self.fail_json(msg="Authentication appears disabled, Please " + "define an ironic_url parameter") + + if (self.params['ironic_url'] and + self.params['auth_type'] in [None, 'None']): + self.params['auth'] = dict( + endpoint=self.params['ironic_url'] + ) + + node_id = _choose_id_value(self) + + if not node_id: + self.fail_json(msg="A uuid or name value must be defined " + "to use this module.") + + try: + sdk, cloud = openstack_cloud_from_module(self) + node = cloud.get_machine(node_id) + + if node is None: + self.fail_json(msg="node not found") + + uuid = node['uuid'] + changed = False + wait = self.params['wait'] + timeout = self.params['timeout'] + provision_state = self.params['provision_state'] + + if node['provision_state'] in [ + 'cleaning', + 'deleting', + 'wait call-back']: + self.fail_json(msg="Node is in %s state, cannot act upon the " + "request as the node is in a transition " + "state" % node['provision_state']) + + if _change_required(node['provision_state'], provision_state): + cloud.node_set_provision_state(uuid, provision_state, wait=wait, + timeout=timeout) + changed = True + + self.exit_json(changed=changed) + + except Exception as e: + self.fail_json(msg=str(e)) + + +def main(): + module = BaremetalNodeStateModule() + module() + + +if __name__ == "__main__": + main() diff --git a/roles/os_ironic_state/README.md b/roles/os_ironic_state/README.md new file mode 100644 index 0000000..9990599 --- /dev/null +++ b/roles/os_ironic_state/README.md @@ -0,0 +1,50 @@ +OpenStack Ironic Node State +=========================== + +This role can be used to set the provision state of ironic nodes. + +Requirements +------------ + +The OpenStack keystone and ironic APIs should be accessible from the target +host. + +Role Variables +-------------- + +`os_ironic_state_auth_type`: Authentication type as used by `os_*` modules' +`auth_type` argument. + +`os_ironic_state_auth`: Authentication options as used by `os_*` modules' +`auth` argument. + +`os_ironic_state_cacert`: CA certificate as used by `os_*` modules' `cacert` +argument. + +`os_ironic_state_interface` is the endpoint URL type to fetch from the service +catalog. Maybe be one of `public`, `admin`, or `internal`. + +`os_ironic_state_name`: Name of the ironic node. + +`os_ironic_state_provision_state`: Desired provision state. + +`os_ironic_state_delegate_to`: Host to delegate to. + +`os_ironic_state_wait`: Whether to wait for the state transition to complete. +Default is `True`. + +`os_ironic_state_timeout`: Time to wait for state transition to complete, if +`os_ironic_state_wait` is `True`. Default is 1200 seconds. + +Dependencies +------------ + +The delegate host should have the `openstacksdk` Python package installed. + +Example Playbook +---------------- + +Author Information +------------------ + +- Mark Goddard () diff --git a/roles/os_ironic_state/defaults/main.yml b/roles/os_ironic_state/defaults/main.yml new file mode 100644 index 0000000..69965b9 --- /dev/null +++ b/roles/os_ironic_state/defaults/main.yml @@ -0,0 +1,29 @@ +--- +# Authentication type as used by os_* modules' 'auth_type' argument. +os_ironic_state_auth_type: + +# Authentication options as used by os_* modules' 'auth' argument. +os_ironic_state_auth: {} + +# CA certificate as used by os_* modules' 'cacert' argument. +os_ironic_state_cacert: + +# Endpoint URL type to fetch from the service catalog. Maybe be one of: +# public, admin, or internal. +os_ironic_state_interface: + +# Name of the ironic node. +os_ironic_state_name: + +# Desired provision state. +os_ironic_state_provision_state: + +# Host to delegate to. +os_ironic_state_delegate_to: + +# Whether to wait for the state transition to complete. +os_ironic_state_wait: true + +# Time to wait for state transition to complete, if os_ironic_state_wait is +# True. +os_ironic_state_timeout: 1200 diff --git a/roles/os_ironic_state/tasks/main.yml b/roles/os_ironic_state/tasks/main.yml new file mode 100644 index 0000000..4c6da00 --- /dev/null +++ b/roles/os_ironic_state/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: Ensure baremetal compute nodes provision states are set + stackhpc.openstack.baremetal_node_state: + auth_type: "{{ os_ironic_state_auth_type }}" + auth: "{{ os_ironic_state_auth }}" + cacert: "{{ os_ironic_state_cacert | default(omit, true) }}" + interface: "{{ os_ironic_state_interface | default(omit, true) }}" + name: "{{ os_ironic_state_name }}" + provision_state: "{{ os_ironic_state_provision_state }}" + timeout: "{{ os_ironic_state_timeout }}" + wait: "{{ os_ironic_state_wait }}" + delegate_to: "{{ os_ironic_state_delegate_to }}" + vars: + # NOTE: Without this, the delegate hosts's ansible_host variable will not + # be respected. + ansible_host: "{{ hostvars[os_ironic_state_delegate_to].ansible_host | default(os_ironic_state_delegate_to) }}" diff --git a/roles/os_ironic_state/tests/inventory b/roles/os_ironic_state/tests/inventory new file mode 100644 index 0000000..5f8076c --- /dev/null +++ b/roles/os_ironic_state/tests/inventory @@ -0,0 +1 @@ +localhost ansible_connection='local' ansible_python_interpreter='/usr/bin/env python' diff --git a/roles/os_ironic_state/tests/test.yml b/roles/os_ironic_state/tests/test.yml new file mode 100644 index 0000000..a652d48 --- /dev/null +++ b/roles/os_ironic_state/tests/test.yml @@ -0,0 +1,6 @@ +--- +- name: Test os_ironic_state + hosts: all + connection: local + roles: + - stackhpc.openstack.os_ironic_state