From 4e6f879febf771fa81af8782367ca9eae277a452 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Tue, 31 Mar 2015 19:28:02 -0400 Subject: [PATCH] Add Ironic module --- cloud/openstack/os_ironic.py | 212 +++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 cloud/openstack/os_ironic.py diff --git a/cloud/openstack/os_ironic.py b/cloud/openstack/os_ironic.py new file mode 100644 index 00000000000..3f28a5b78dc --- /dev/null +++ b/cloud/openstack/os_ironic.py @@ -0,0 +1,212 @@ +#!/usr/bin/python +# coding: utf-8 -*- + +# (c) 2014, Hewlett-Packard Development Company, L.P. +# +# 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 . + +try: + import shade + HAS_SHADE = True +except ImportError: + HAS_SHADE = False + +# TODO FIX UUID/Add node support +DOCUMENTATION = ''' +--- +module: os_ironic +short_description: Create/Delete Bare Metal Resources from OpenStack +version_added: "1.10" +extends_documentation_fragment: openstack +description: + - Create or Remove Ironic nodes from OpenStack. +options: + state: + description: + - Indicates desired state of the resource + choices: ['present', 'absent'] + default: present + uuid: + description: + - globally unique identifier (UUID) to be given to the resource. Will + be auto-generated if not specified. + required: false + default: None + driver: + description: + - The name of the Ironic Driver to use with this node. + required: true + 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_plugin" + settings set to None. + required: false + default: None + driver_info: + description: + - Information for this server's driver. Will vary based on which + driver is in use. Any sub-field which is populated will be validated + during creation. + power: + - Information necessary to turn this server on / off. This often + includes such things as IPMI username, password, and IP address. + required: true + deploy: + - Information necessary to deploy this server directly, without + using Nova. THIS IS NOT RECOMMENDED. + console: + - Information necessary to connect to this server's serial console. + Not all drivers support this. + management: + - Information necessary to interact with this server's management + interface. May be shared by power_info in some cases. + required: true + nics: + description: + - A list of network interface cards, eg, " - mac: aa:bb:cc:aa:bb:cc" + required: true + properties: + description: + - Definition of the physical characteristics of this server, used for + scheduling purposes + cpu_arch: + description: + - CPU architecture (x86_64, i686, ...) + default: x86_64 + cpus: + description: + - Number of CPU cores this machine has + default: 1 + ram: + description: + - amount of RAM this machine has, in MB + default: 1 + disk_size: + description: + - size of first storage device in this machine (typically + /dev/sda), in GB + default: 1 + +requirements: ["shade"] +''' + +EXAMPLES = ''' +# Enroll a node with some basic properties and driver info +- os_ironic: + cloud: "devstack" + driver: "pxe_ipmitool" + uuid: "a8cb6624-0d9f-4882-affc-046ebb96ec92" + properties: + cpus: 2 + cpu_arch: "x86_64" + ram: 8192 + disk_size: 64 + nics: + - mac: "aa:bb:cc:aa:bb:cc" + - mac: "dd:ee:ff:dd:ee:ff" + driver_info: + power: + ipmi_address: "1.2.3.4" + ipmi_username: "admin" + ipmi_password: "adminpass" + +''' + + +def _parse_properties(module): + p = module.params['properties'] + props = dict( + cpu_arch=p.get('cpu_arch') if p.get('cpu_arch') else 'x86_64', + cpus=p.get('cpus') if p.get('cpus') else 1, + memory_mb=p.get('ram') if p.get('ram') else 1, + local_gb=p.get('disk_size') if p.get('disk_size') else 1, + ) + return props + + +def _parse_driver_info(module): + p = module.params['driver_info'] + info = p.get('power') + if not info: + raise shade.OpenStackCloudException( + "driver_info['power'] is required") + if p.get('console'): + info.update(p.get('console')) + if p.get('management'): + info.update(p.get('management')) + if p.get('deploy'): + info.update(p.get('deploy')) + return info + + +def main(): + argument_spec = openstack_full_argument_spec( + uuid=dict(required=False), + driver=dict(required=True), + driver_info=dict(type='dict', required=True), + nics=dict(type='list', required=True), + properties=dict(type='dict', default={}), + ironic_url=dict(required=False), + ) + module_kwargs = openstack_module_kwargs() + module = AnsibleModule(argument_spec, **module_kwargs) + + if not HAS_SHADE: + module.fail_json(msg='shade is required for this module') + if (module.params['auth_plugin'] == 'None' and + module.params['ironic_url'] is None): + module.fail_json(msg="Authentication appears disabled, Please " + "define an ironic_url parameter") + + if module.params['ironic_url'] and module.params['auth_plugin'] == 'None': + module.params['auth'] = dict(endpoint=module.params['ironic_url']) + try: + cloud = shade.operator_cloud(**module.params) + server = cloud.get_machine_by_uuid(module.params['uuid']) + + if module.params['state'] == 'present': + properties = _parse_properties(module) + driver_info = _parse_driver_info(module) + kwargs = dict( + uuid=module.params['uuid'], + driver=module.params['driver'], + properties=properties, + driver_info=driver_info, + ) + if server is None: + server = cloud.register_machine(module.params['nics'], + **kwargs) + module.exit_json(changed=True, uuid=server.uuid) + else: + # TODO: compare properties here and update if necessary + # ... but the interface for that is terrible! + module.exit_json(changed=False, + result="Server already present") + if module.params['state'] == 'absent': + if server is not None: + cloud.unregister_machine(module.params['nics'], + module.params['uuid']) + module.exit_json(changed=True, result="deleted") + else: + module.exit_json(changed=False, result="Server not found") + except shade.OpenStackCloudException as e: + module.fail_json(msg=e.message) + + +# this is magic, see lib/ansible/module_common.py +from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * +main()