
Be consistent with Ansible docs [1], [2], [3].
[1] https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html
[2] https://docs.ansible.com/ansible-core/devel/dev_guide/testing/sanity/shebang.html
[3] b86a18bd27/test/lib/ansible_test/_util/controller/sanity/code-smell/shebang.py
Change-Id: Ia3976bb3fcca662cefa219edeef057bcb7143c01
251 lines
7.6 KiB
Python
251 lines
7.6 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2016 Jakub Jursa <jakub.jursa1@gmail.com>
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: host_aggregate
|
|
short_description: Manage OpenStack host aggregates
|
|
author: OpenStack Ansible SIG
|
|
description:
|
|
- Create, update, or delete OpenStack host aggregates. If a aggregate
|
|
with the supplied name already exists, it will be updated with the
|
|
new name, new availability zone, new metadata and new list of hosts.
|
|
options:
|
|
name:
|
|
description: Name of the aggregate.
|
|
required: true
|
|
type: str
|
|
metadata:
|
|
description: Metadata dict.
|
|
type: dict
|
|
availability_zone:
|
|
description: Availability zone to create aggregate into.
|
|
type: str
|
|
hosts:
|
|
description: List of hosts to set for an aggregate.
|
|
type: list
|
|
elements: str
|
|
purge_hosts:
|
|
description: Whether hosts not in I(hosts) should be removed from the aggregate
|
|
type: bool
|
|
default: true
|
|
state:
|
|
description: Should the resource be present or absent.
|
|
choices: [present, absent]
|
|
default: present
|
|
type: str
|
|
requirements:
|
|
- "python >= 3.6"
|
|
- "openstacksdk"
|
|
|
|
extends_documentation_fragment:
|
|
- openstack.cloud.openstack
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
# Create a host aggregate
|
|
- openstack.cloud.host_aggregate:
|
|
cloud: mycloud
|
|
state: present
|
|
name: db_aggregate
|
|
hosts:
|
|
- host1
|
|
- host2
|
|
metadata:
|
|
type: dbcluster
|
|
|
|
# Add an additional host to the aggregate
|
|
- openstack.cloud.host_aggregate:
|
|
cloud: mycloud
|
|
state: present
|
|
name: db_aggregate
|
|
hosts:
|
|
- host3
|
|
purge_hosts: false
|
|
metadata:
|
|
type: dbcluster
|
|
|
|
# Delete an aggregate
|
|
- openstack.cloud.host_aggregate:
|
|
cloud: mycloud
|
|
state: absent
|
|
name: db_aggregate
|
|
'''
|
|
|
|
RETURN = r'''
|
|
aggregate:
|
|
description: A host aggregate resource.
|
|
type: dict
|
|
returned: On success, when I(state) is present
|
|
contains:
|
|
availability_zone:
|
|
description: Availability zone of the aggregate
|
|
type: str
|
|
returned: always
|
|
created_at:
|
|
description: The date and time when the resource was created
|
|
type: str
|
|
returned: always
|
|
deleted_at:
|
|
description:
|
|
- The date and time when the resource was deleted
|
|
- Null unless I(is_deleted) is true
|
|
type: str
|
|
returned: always
|
|
hosts:
|
|
description: Hosts belonging to the aggregate
|
|
type: str
|
|
returned: always
|
|
id:
|
|
description: The UUID of the aggregate.
|
|
type: str
|
|
returned: always
|
|
is_deleted:
|
|
description: Whether or not the resource is deleted
|
|
type: bool
|
|
returned: always
|
|
metadata:
|
|
description: Metadata attached to the aggregate
|
|
type: str
|
|
returned: always
|
|
name:
|
|
description: Name of the aggregate
|
|
type: str
|
|
returned: always
|
|
updated_at:
|
|
description: The date and time when the resource was updated
|
|
type: str
|
|
returned: always
|
|
uuid:
|
|
description: UUID of the aggregate
|
|
type: str
|
|
returned: always
|
|
'''
|
|
|
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
|
|
|
|
|
|
class ComputeHostAggregateModule(OpenStackModule):
|
|
argument_spec = dict(
|
|
name=dict(required=True),
|
|
metadata=dict(type='dict'),
|
|
availability_zone=dict(),
|
|
hosts=dict(type='list', elements='str'),
|
|
purge_hosts=dict(default=True, type='bool'),
|
|
state=dict(default='present', choices=['absent', 'present']),
|
|
)
|
|
|
|
module_kwargs = dict(
|
|
supports_check_mode=True
|
|
)
|
|
|
|
def _needs_update(self, aggregate):
|
|
new_metadata = self.params['metadata'] or {}
|
|
|
|
if self.params['availability_zone'] is not None:
|
|
new_metadata['availability_zone'] = self.params['availability_zone']
|
|
|
|
if self.params['hosts'] is not None:
|
|
if self.params['purge_hosts']:
|
|
if set(self.params['hosts']) != set(aggregate.hosts):
|
|
return True
|
|
else:
|
|
intersection = set(self.params['hosts']).intersection(set(aggregate.hosts))
|
|
if set(self.params['hosts']) != intersection:
|
|
return True
|
|
|
|
for param in ('availability_zone', 'metadata'):
|
|
if self.params[param] is not None and \
|
|
self.params[param] != aggregate[param]:
|
|
return True
|
|
|
|
return False
|
|
|
|
def _system_state_change(self, aggregate):
|
|
state = self.params['state']
|
|
if state == 'absent' and aggregate:
|
|
return True
|
|
|
|
if state == 'present':
|
|
if aggregate is None:
|
|
return True
|
|
return self._needs_update(aggregate)
|
|
|
|
return False
|
|
|
|
def _update_hosts(self, aggregate, hosts, purge_hosts):
|
|
if hosts is None:
|
|
return
|
|
|
|
hosts_to_add = set(hosts) - set(aggregate['hosts'] or [])
|
|
for host in hosts_to_add:
|
|
self.conn.compute.add_host_to_aggregate(aggregate.id, host)
|
|
|
|
if not purge_hosts:
|
|
return
|
|
|
|
hosts_to_remove = set(aggregate["hosts"] or []) - set(hosts)
|
|
for host in hosts_to_remove:
|
|
self.conn.compute.remove_host_from_aggregate(aggregate.id, host)
|
|
|
|
def run(self):
|
|
name = self.params['name']
|
|
metadata = self.params['metadata']
|
|
availability_zone = self.params['availability_zone']
|
|
hosts = self.params['hosts']
|
|
purge_hosts = self.params['purge_hosts']
|
|
state = self.params['state']
|
|
|
|
if metadata is not None:
|
|
metadata.pop('availability_zone', None)
|
|
|
|
aggregate = self.conn.compute.find_aggregate(name)
|
|
|
|
if self.ansible.check_mode:
|
|
self.exit_json(changed=self._system_state_change(aggregate))
|
|
|
|
changed = False
|
|
if state == 'present':
|
|
if aggregate is None:
|
|
aggregate = self.conn.compute.create_aggregate(
|
|
name=name, availability_zone=availability_zone)
|
|
self._update_hosts(aggregate, hosts, False)
|
|
if metadata:
|
|
self.conn.compute.set_aggregate_metadata(aggregate, metadata)
|
|
changed = True
|
|
elif self._needs_update(aggregate):
|
|
if availability_zone is not None:
|
|
aggregate = self.conn.compute.update_aggregate(
|
|
aggregate, name=name,
|
|
availability_zone=availability_zone)
|
|
if metadata is not None:
|
|
metas = metadata
|
|
for i in set(aggregate.metadata.keys() - set(metadata.keys())):
|
|
if i != 'availability_zone':
|
|
metas[i] = None
|
|
self.conn.compute.set_aggregate_metadata(aggregate, metas)
|
|
self._update_hosts(aggregate, hosts, purge_hosts)
|
|
changed = True
|
|
aggregate = self.conn.compute.find_aggregate(name)
|
|
if aggregate:
|
|
aggregate = aggregate.to_dict(computed=False)
|
|
self.exit_json(changed=changed, aggregate=aggregate)
|
|
|
|
elif state == 'absent' and aggregate is not None:
|
|
self._update_hosts(aggregate, [], True)
|
|
self.conn.compute.delete_aggregate(aggregate.id)
|
|
changed = True
|
|
self.exit_json(changed=changed)
|
|
|
|
|
|
def main():
|
|
module = ComputeHostAggregateModule()
|
|
module()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|