File nova_host_aggregate of Package python-ardana-packager

#!/usr/bin/python
#coding: utf-8 -*-

#
# 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 <http://www.gnu.org/licenses/>.

try:
    from novaclient import client as nova_client
    from novaclient import exceptions as exc
except ImportError:
    print("failed=True msg='novaclient is required for this module to work'")

DOCUMENTATION = '''
---
module: nova_host_aggregate
version_added: "1.8"
short_description: Add/Delete nova host aggregates and availability zones
description:
   - Add or Remove nova host aggregates and availability zones
options:
   login_username:
     description:
        - login username to authenticate to keystone
     required: true
     default: admin
   login_password:
     description:
        - Password of login user
     required: true
     default: 'yes'
   login_tenant_name:
     description:
        - The tenant name of the login user
     required: true
     default: 'yes'
   auth_url:
     description:
        - The keystone url for authentication
     required: false
     default: 'http://127.0.0.1:35357/v2.0/'
   region_name:
     description:
        - Name of the region
     required: false
     default: None
   state:
     description:
        - Indicate desired state of the resource
     choices: ['present', 'absent']
     default: present
   name:
     description:
        - Name that has to be given to the host aggregate
     required: true
     default: None
   availability_zone:
     description:
        - Name that has to be given to the availability zone
     required: false
     default: None
   host:
     description:
        - Name of host to add
     required: false
     default: None
   force:
     description:
        - forcibly delete the aggregate
     required: false
     default: None

requirements: ["novaclient"]
author: Scott Wulf
'''
EXAMPLES = '''
# Creates a host aggregate
- nova_host_aggregate: state=present login_username=admin
                login_password=admin login_tenant_name=admin name=aggregate1

# Creates a host aggregate and availability zone
- nova_host_aggregate: state=present login_username=admin
                login_password=admin login_tenant_name=admin name=aggregate1
                availability_zone=zone1

# Adds a host to an availability zone
- nova_host_aggregate: state=present login_username=admin
                login_password=admin login_tenant_name=admin name=aggregate1
                host=host1

# Forcibly deletes a host aggregate
- nova_host_aggregate: state=absent login_username=admin
                login_password=admin login_tenant_name=admin name=aggregate1
                force=true

# Removes a host from an availability zone
- nova_host_aggregate: state=absent login_username=admin
                login_password=admin login_tenant_name=admin name=aggregate1
                host=host1
'''

def get_aggregate(client, name):
    """ Retrieve an aggregate by id or name """
    list = [x for x in client.aggregates.list() if x.name == name]
    count = len(list)
    if count == 0:
        raise KeyError('No host aggregate with id or name %s' % name)
    elif count > 1:
        raise ValueError('%d host aggregates with id or name %s' % (count, name))
    else:
        return list[0]


def get_aggregate_id(client, name):
    return get_aggregate(client, name).id


def ensure_aggregate_exists(client, name, zone, check_mode):
    """ Ensure that an aggregate exists.

        Return (True, id) if a new aggregate was created/updated, (False, id) if it
        already existed.
    """

    # Check if aggregate already exists
    try:
        aggregate = get_aggregate(client, name)
    except KeyError:
        # aggregate does not exist yet
        pass
    else:
        if not zone or aggregate.availability_zone == zone:
            return (False, aggregate.id)
        else:
            # We need to update the aggregate details
            if check_mode:
                return (True, aggregate.id)
            else:
                #aggregate.update('availability_zone=%s' % zone)
                aggregate.update({'availability_zone': zone})
                return (True, aggregate.id)

    # We now know we will have to create a new aggregate
    if check_mode:
        return (True, None)

    aggregate = client.aggregates.create(name, zone)
    return (True, aggregate.id)


def ensure_aggregate_absent(client, name, force_delete, check_mode):
    """ Ensure that an aggregate does not exist

         Return True if it was removed, False if it did not exist
         in the first place
    """
    try:
        aggregate = get_aggregate(client, name)
    except KeyError:
        return False

    # We now know we will have to delete the object
    if check_mode:
        return True

    # clean up aggregate for deletion
    if force_delete:
        for host in aggregate.hosts:
            aggregate.remove_host(host)

    aggregate.delete()
    return True


def ensure_aggregate_host_exists(client, name, host, check_mode):
    """ Ensure that the host exists.

        Return True if the host was added, False otherwise.
    """

    aggregate = get_aggregate(client, name)
    if host in aggregate.hosts:
        return False

    if check_mode:
        return True

    aggregate.add_host(host)
    return True


def ensure_aggregate_host_absent(client, name, host, check_mode):
    """ Ensure that the host does not exist

         Return True if it was removed, False otherwise
    """
    aggregate = get_aggregate(client, name)
    if not host in aggregate.hosts:
        return False

    if check_mode:
        return True

    aggregate.remove_host(host)
    return True


def dispatch(client, aggregate_name=None, availability_zone=None, host=None, force_delete=False,
             state='present', check_mode=False):
    """ Dispatch to the appropriate method.

        Returns a dict that will be passed to exit_json
    """
    id = None
    if aggregate_name and state == 'present':
        changed0, id = ensure_aggregate_exists(client, aggregate_name,
                                               availability_zone, check_mode)
        changed1 = False
        if host:
            changed1 = ensure_aggregate_host_exists(client, aggregate_name, host, check_mode)
        changed = changed0 or changed1
    elif aggregate_name and state == 'absent':
        if host:
            changed = ensure_aggregate_host_absent(client, aggregate_name, host, check_mode)
        else:
            changed = ensure_aggregate_absent(client, aggregate_name, force_delete, check_mode)
    else:
        # Should never reach here
        raise ValueError('Code should never reach here')

    return dict(changed=changed, id=id)

def main():
    module = AnsibleModule(
        argument_spec=dict(
            auth_url=dict(required=False,
                          default='http://127.0.0.1:35357/v2.0'),
            login_tenant_name=dict(required=False),
            login_username=dict(required=False, default='admin'),
            login_password=dict(required=False, default='password'),
            region_name=dict(required=False, default='RegionOne'),

            name                 = dict(required=True),
            availability_zone    = dict(default=None),
            host                 = dict(default=None),
            force                = dict(default=False),
            state                = dict(default='present', choices=['absent', 'present'])
        ),
        supports_check_mode=True
    )

    aggregate_name = module.params['name']
    availability_zone = module.params['availability_zone']
    hostname = module.params['host']
    force_delete = module.params['force']
    if force_delete:
        force_delete = force_delete.lower() in ['true', '1']

    state = module.params['state']
    check_mode = module.check_mode

    client = nova_client.Client('2',
                                module.params['login_username'],
                                module.params['login_password'],
                                module.params['login_tenant_name'],
                                module.params['auth_url'],
                                region_name=module.params['region_name'],
                                service_type='compute',
                                endpoint_type='internalURL')
    try:
        client.authenticate()
    except exc.Unauthorized, e:
        module.fail_json(msg = "Invalid OpenStack Nova credentials.: %s" % e.message)
    except exc.AuthorizationFailure, e:
        module.fail_json(msg = "Unable to authorize user: %s" % e.message)

    try:
        d = dispatch(client, aggregate_name, availability_zone, hostname, force_delete, state, check_mode)
    except Exception, e:
        if check_mode:
            module.exit_json(changed=True,
                             msg='Exception: %s' % e)
        else:
            module.fail_json(msg='Exception: %s' % e)
    else:
        module.exit_json(**d)


# import module snippets
from ansible.module_utils.basic import *
main()
openSUSE Build Service is sponsored by