
With "extends_documentation_fragment: ['openstack.cloud.openstack']" it is not necessary to list required Python libraries in section 'requirements' of DOCUMENTATION docstring in modules. Ansible will merge requirements from doc fragments and DOCUMENTATION docstring which previously resulted in duplicates such as in server module [0]: * openstacksdk * openstacksdk >= 0.36, < 0.99.0 * python >= 3.6 When removing the 'requirements' section from server module, then Ansible will list openstacksdk once only: * openstacksdk >= 0.36, < 0.99.0 * python >= 3.6 To see what documentation Ansible will produce for server module run: ansible-doc --type module openstack.cloud.server [0] https://docs.ansible.com/ansible/latest/collections/openstack/\ cloud/server_module.html Change-Id: I727ed95ee480bb644b5a533f6a9526973677064c
207 lines
5.8 KiB
Python
207 lines
5.8 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
DOCUMENTATION = r'''
|
|
---
|
|
module: compute_flavor_access
|
|
short_description: Manage access to OpenStack compute flavors
|
|
author: OpenStack Ansible SIG
|
|
description:
|
|
- Add or remove access to OpenStack compute flavor
|
|
options:
|
|
name:
|
|
description:
|
|
- Name or ID of the compute flavor.
|
|
required: true
|
|
type: str
|
|
project:
|
|
description:
|
|
- ID or Name of project to grant.
|
|
- Allow I(project) to access private flavor (name or ID).
|
|
type: str
|
|
required: true
|
|
project_domain:
|
|
description:
|
|
- Domain the project belongs to (name or ID).
|
|
- This can be used in case collisions between project names exist.
|
|
type: str
|
|
state:
|
|
description:
|
|
- Indicate whether project should have access to compute flavor or not.
|
|
default: present
|
|
type: str
|
|
choices: ['present', 'absent']
|
|
notes:
|
|
- A compute flavor must not be private to manage project access.
|
|
extends_documentation_fragment:
|
|
- openstack.cloud.openstack
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
- name: Grant access to tiny flavor
|
|
openstack.cloud.compute_flavor_access:
|
|
cloud: devstack
|
|
name: tiny
|
|
project: demo
|
|
state: present
|
|
|
|
- name: Revoke access to compute flavor
|
|
openstack.cloud.compute_flavor_access:
|
|
cloud: devstack
|
|
name: tiny
|
|
project: demo
|
|
state: absent
|
|
'''
|
|
|
|
RETURN = '''
|
|
flavor:
|
|
description: Dictionary describing the flavor.
|
|
returned: On success when I(state) is 'present'
|
|
type: dict
|
|
contains:
|
|
description:
|
|
description: Description attached to flavor
|
|
returned: success
|
|
type: str
|
|
sample: Example description
|
|
disk:
|
|
description: Size of local disk, in GB.
|
|
returned: success
|
|
type: int
|
|
sample: 10
|
|
ephemeral:
|
|
description: Ephemeral space size, in GB.
|
|
returned: success
|
|
type: int
|
|
sample: 10
|
|
extra_specs:
|
|
description: Flavor metadata
|
|
returned: success
|
|
type: dict
|
|
sample:
|
|
"quota:disk_read_iops_sec": 5000
|
|
"aggregate_instance_extra_specs:pinned": false
|
|
id:
|
|
description: Flavor ID.
|
|
returned: success
|
|
type: str
|
|
sample: "515256b8-7027-4d73-aa54-4e30a4a4a339"
|
|
is_disabled:
|
|
description: Whether the flavor is disabled
|
|
returned: success
|
|
type: bool
|
|
sample: true
|
|
is_public:
|
|
description: Make flavor accessible to the public.
|
|
returned: success
|
|
type: bool
|
|
sample: true
|
|
name:
|
|
description: Flavor name.
|
|
returned: success
|
|
type: str
|
|
sample: "tiny"
|
|
original_name:
|
|
description: The name of this flavor when returned by server list/show
|
|
type: str
|
|
returned: success
|
|
ram:
|
|
description: Amount of memory, in MB.
|
|
returned: success
|
|
type: int
|
|
sample: 1024
|
|
rxtx_factor:
|
|
description: |
|
|
The bandwidth scaling factor this flavor receives on the network
|
|
returned: success
|
|
type: int
|
|
sample: 100
|
|
swap:
|
|
description: Swap space size, in MB.
|
|
returned: success
|
|
type: int
|
|
sample: 100
|
|
vcpus:
|
|
description: Number of virtual CPUs.
|
|
returned: success
|
|
type: int
|
|
sample: 2
|
|
'''
|
|
|
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
|
|
|
|
|
|
class ComputeFlavorAccess(OpenStackModule):
|
|
argument_spec = dict(
|
|
name=dict(required=True),
|
|
project=dict(required=True),
|
|
project_domain=dict(),
|
|
state=dict(default='present', choices=['absent', 'present']),
|
|
)
|
|
|
|
module_kwargs = dict(
|
|
supports_check_mode=True,
|
|
)
|
|
|
|
# TODO: Merge with equal function from volume_type_access module.
|
|
def _project_and_project_domain(self):
|
|
project_name_or_id = self.params['project']
|
|
project_domain_name_or_id = self.params['project_domain']
|
|
|
|
if project_domain_name_or_id:
|
|
domain_id = self.conn.identity.find_domain(
|
|
project_domain_name_or_id, ignore_missing=False).id
|
|
else:
|
|
domain_id = None
|
|
|
|
kwargs = dict() if domain_id is None else dict(domain_id=domain_id)
|
|
|
|
if project_name_or_id:
|
|
project_id = self.conn.identity.find_project(
|
|
project_name_or_id, ignore_missing=False, *kwargs).id
|
|
else:
|
|
project_id = None
|
|
|
|
return project_id, domain_id
|
|
|
|
def run(self):
|
|
name_or_id = self.params['name']
|
|
flavor = self.conn.compute.find_flavor(name_or_id,
|
|
ignore_missing=False)
|
|
|
|
state = self.params['state']
|
|
if state == 'present' and flavor.is_public:
|
|
raise ValueError('access can only be granted to private flavors')
|
|
|
|
project_id, domain_id = self._project_and_project_domain()
|
|
|
|
flavor_access = self.conn.compute.get_flavor_access(flavor.id)
|
|
project_ids = [access.get('tenant_id') for access in flavor_access]
|
|
|
|
if (project_id in project_ids and state == 'present') \
|
|
or (project_id not in project_ids and state == 'absent'):
|
|
self.exit_json(changed=False,
|
|
flavor=flavor.to_dict(computed=False))
|
|
|
|
if self.ansible.check_mode:
|
|
self.exit_json(changed=True, flavor=flavor.to_dict(computed=False))
|
|
|
|
if project_id in project_ids: # and state == 'absent'
|
|
self.conn.compute.flavor_remove_tenant_access(flavor.id,
|
|
project_id)
|
|
else: # project_id not in project_ids and state == 'present'
|
|
self.conn.compute.flavor_add_tenant_access(flavor.id, project_id)
|
|
|
|
self.exit_json(changed=True, flavor=flavor.to_dict(computed=False))
|
|
|
|
|
|
def main():
|
|
module = ComputeFlavorAccess()
|
|
module()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|