summaryrefslogtreecommitdiffstats
path: root/ansible_collections/openstack/cloud/plugins/modules/quota.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
commit66cec45960ce1d9c794e9399de15c138acb18aed (patch)
tree59cd19d69e9d56b7989b080da7c20ef1a3fe2a5a /ansible_collections/openstack/cloud/plugins/modules/quota.py
parentInitial commit. (diff)
downloadansible-upstream.tar.xz
ansible-upstream.zip
Adding upstream version 7.3.0+dfsg.upstream/7.3.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/openstack/cloud/plugins/modules/quota.py')
-rw-r--r--ansible_collections/openstack/cloud/plugins/modules/quota.py466
1 files changed, 466 insertions, 0 deletions
diff --git a/ansible_collections/openstack/cloud/plugins/modules/quota.py b/ansible_collections/openstack/cloud/plugins/modules/quota.py
new file mode 100644
index 00000000..0d6a4f04
--- /dev/null
+++ b/ansible_collections/openstack/cloud/plugins/modules/quota.py
@@ -0,0 +1,466 @@
+#!/usr/bin/python
+# Copyright (c) 2016 Pason System Corporation
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+DOCUMENTATION = '''
+---
+module: quota
+short_description: Manage OpenStack Quotas
+author: OpenStack Ansible SIG
+description:
+ - Manage OpenStack Quotas. Quotas can be created,
+ updated or deleted using this module. A quota will be updated
+ if matches an existing project and is present.
+options:
+ name:
+ description:
+ - Name of the OpenStack Project to manage.
+ required: true
+ type: str
+ state:
+ description:
+ - A value of present sets the quota and a value of absent resets the quota to system defaults.
+ default: present
+ type: str
+ choices: ['absent', 'present']
+ backup_gigabytes:
+ description: Maximum size of backups in GB's.
+ type: int
+ backups:
+ description: Maximum number of backups allowed.
+ type: int
+ cores:
+ description: Maximum number of CPU's per project.
+ type: int
+ fixed_ips:
+ description: Number of fixed IP's to allow.
+ type: int
+ floating_ips:
+ description: Number of floating IP's to allow in Compute.
+ aliases: ['compute_floating_ips']
+ type: int
+ floatingip:
+ description: Number of floating IP's to allow in Network.
+ aliases: ['network_floating_ips']
+ type: int
+ gigabytes:
+ description: Maximum volume storage allowed for project.
+ type: int
+ gigabytes_types:
+ description:
+ - Per driver volume storage quotas. Keys should be
+ prefixed with C(gigabytes_) values should be ints.
+ type: dict
+ injected_file_size:
+ description: Maximum file size in bytes.
+ type: int
+ injected_files:
+ description: Number of injected files to allow.
+ type: int
+ injected_path_size:
+ description: Maximum path size.
+ type: int
+ instances:
+ description: Maximum number of instances allowed.
+ type: int
+ key_pairs:
+ description: Number of key pairs to allow.
+ type: int
+ loadbalancer:
+ description: Number of load balancers to allow.
+ type: int
+ metadata_items:
+ description: Number of metadata items allowed per instance.
+ type: int
+ network:
+ description: Number of networks to allow.
+ type: int
+ per_volume_gigabytes:
+ description: Maximum size in GB's of individual volumes.
+ type: int
+ pool:
+ description: Number of load balancer pools to allow.
+ type: int
+ port:
+ description: Number of Network ports to allow, this needs to be greater than the instances limit.
+ type: int
+ properties:
+ description: Number of properties to allow.
+ type: int
+ ram:
+ description: Maximum amount of ram in MB to allow.
+ type: int
+ rbac_policy:
+ description: Number of policies to allow.
+ type: int
+ router:
+ description: Number of routers to allow.
+ type: int
+ security_group_rule:
+ description: Number of rules per security group to allow.
+ type: int
+ security_group:
+ description: Number of security groups to allow.
+ type: int
+ server_group_members:
+ description: Number of server group members to allow.
+ type: int
+ server_groups:
+ description: Number of server groups to allow.
+ type: int
+ snapshots:
+ description: Number of snapshots to allow.
+ type: int
+ snapshots_types:
+ description:
+ - Per-driver volume snapshot quotas. Keys should be
+ prefixed with C(snapshots_) values should be ints.
+ type: dict
+ subnet:
+ description: Number of subnets to allow.
+ type: int
+ subnetpool:
+ description: Number of subnet pools to allow.
+ type: int
+ volumes:
+ description: Number of volumes to allow.
+ type: int
+ volumes_types:
+ description:
+ - Per-driver volume count quotas. Keys should be
+ prefixed with C(volumes_) values should be ints.
+ type: dict
+ project:
+ description: Unused, kept for compatability
+ type: int
+
+requirements:
+ - "python >= 3.6"
+ - "openstacksdk >= 0.13.0"
+ - "keystoneauth1 >= 3.4.0"
+
+extends_documentation_fragment:
+- openstack.cloud.openstack
+'''
+
+EXAMPLES = '''
+# List a Project Quota
+- openstack.cloud.quota:
+ cloud: mycloud
+ name: demoproject
+
+# Set a Project back to the defaults
+- openstack.cloud.quota:
+ cloud: mycloud
+ name: demoproject
+ state: absent
+
+# Update a Project Quota for cores
+- openstack.cloud.quota:
+ cloud: mycloud
+ name: demoproject
+ cores: 100
+
+# Update a Project Quota
+- openstack.cloud.quota:
+ name: demoproject
+ cores: 1000
+ volumes: 20
+ volumes_type:
+ - volume_lvm: 10
+
+# Complete example based on list of projects
+- name: Update quotas
+ openstack.cloud.quota:
+ name: "{{ item.name }}"
+ backup_gigabytes: "{{ item.backup_gigabytes }}"
+ backups: "{{ item.backups }}"
+ cores: "{{ item.cores }}"
+ fixed_ips: "{{ item.fixed_ips }}"
+ floating_ips: "{{ item.floating_ips }}"
+ floatingip: "{{ item.floatingip }}"
+ gigabytes: "{{ item.gigabytes }}"
+ injected_file_size: "{{ item.injected_file_size }}"
+ injected_files: "{{ item.injected_files }}"
+ injected_path_size: "{{ item.injected_path_size }}"
+ instances: "{{ item.instances }}"
+ key_pairs: "{{ item.key_pairs }}"
+ loadbalancer: "{{ item.loadbalancer }}"
+ metadata_items: "{{ item.metadata_items }}"
+ per_volume_gigabytes: "{{ item.per_volume_gigabytes }}"
+ pool: "{{ item.pool }}"
+ port: "{{ item.port }}"
+ properties: "{{ item.properties }}"
+ ram: "{{ item.ram }}"
+ security_group_rule: "{{ item.security_group_rule }}"
+ security_group: "{{ item.security_group }}"
+ server_group_members: "{{ item.server_group_members }}"
+ server_groups: "{{ item.server_groups }}"
+ snapshots: "{{ item.snapshots }}"
+ volumes: "{{ item.volumes }}"
+ volumes_types:
+ volumes_lvm: "{{ item.volumes_lvm }}"
+ snapshots_types:
+ snapshots_lvm: "{{ item.snapshots_lvm }}"
+ gigabytes_types:
+ gigabytes_lvm: "{{ item.gigabytes_lvm }}"
+ with_items:
+ - "{{ projects }}"
+ when: item.state == "present"
+'''
+
+RETURN = '''
+openstack_quotas:
+ description: Dictionary describing the project quota.
+ returned: Regardless if changes where made or not
+ type: dict
+ sample:
+ openstack_quotas: {
+ compute: {
+ cores: 150,
+ fixed_ips: -1,
+ floating_ips: 10,
+ injected_file_content_bytes: 10240,
+ injected_file_path_bytes: 255,
+ injected_files: 5,
+ instances: 100,
+ key_pairs: 100,
+ metadata_items: 128,
+ ram: 153600,
+ security_group_rules: 20,
+ security_groups: 10,
+ server_group_members: 10,
+ server_groups: 10
+ },
+ network: {
+ floatingip: 50,
+ loadbalancer: 10,
+ network: 10,
+ pool: 10,
+ port: 160,
+ rbac_policy: 10,
+ router: 10,
+ security_group: 10,
+ security_group_rule: 100,
+ subnet: 10,
+ subnetpool: -1
+ },
+ volume: {
+ backup_gigabytes: 1000,
+ backups: 10,
+ gigabytes: 1000,
+ gigabytes_lvm: -1,
+ per_volume_gigabytes: -1,
+ snapshots: 10,
+ snapshots_lvm: -1,
+ volumes: 10,
+ volumes_lvm: -1
+ }
+ }
+
+'''
+
+from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
+
+
+class QuotaModule(OpenStackModule):
+ argument_spec = dict(
+ name=dict(required=True),
+ state=dict(default='present', choices=['absent', 'present']),
+ backup_gigabytes=dict(required=False, type='int', default=None),
+ backups=dict(required=False, type='int', default=None),
+ cores=dict(required=False, type='int', default=None),
+ fixed_ips=dict(required=False, type='int', default=None),
+ floating_ips=dict(required=False, type='int', default=None, aliases=['compute_floating_ips']),
+ floatingip=dict(required=False, type='int', default=None, aliases=['network_floating_ips']),
+ gigabytes=dict(required=False, type='int', default=None),
+ gigabytes_types=dict(required=False, type='dict', default={}),
+ injected_file_size=dict(required=False, type='int', default=None),
+ injected_files=dict(required=False, type='int', default=None),
+ injected_path_size=dict(required=False, type='int', default=None),
+ instances=dict(required=False, type='int', default=None),
+ key_pairs=dict(required=False, type='int', default=None, no_log=False),
+ loadbalancer=dict(required=False, type='int', default=None),
+ metadata_items=dict(required=False, type='int', default=None),
+ network=dict(required=False, type='int', default=None),
+ per_volume_gigabytes=dict(required=False, type='int', default=None),
+ pool=dict(required=False, type='int', default=None),
+ port=dict(required=False, type='int', default=None),
+ project=dict(required=False, type='int', default=None),
+ properties=dict(required=False, type='int', default=None),
+ ram=dict(required=False, type='int', default=None),
+ rbac_policy=dict(required=False, type='int', default=None),
+ router=dict(required=False, type='int', default=None),
+ security_group_rule=dict(required=False, type='int', default=None),
+ security_group=dict(required=False, type='int', default=None),
+ server_group_members=dict(required=False, type='int', default=None),
+ server_groups=dict(required=False, type='int', default=None),
+ snapshots=dict(required=False, type='int', default=None),
+ snapshots_types=dict(required=False, type='dict', default={}),
+ subnet=dict(required=False, type='int', default=None),
+ subnetpool=dict(required=False, type='int', default=None),
+ volumes=dict(required=False, type='int', default=None),
+ volumes_types=dict(required=False, type='dict', default={})
+ )
+
+ module_kwargs = dict(
+ supports_check_mode=True
+ )
+
+ def _get_volume_quotas(self, project):
+ return self.conn.get_volume_quotas(project)
+
+ def _get_network_quotas(self, project):
+ return self.conn.get_network_quotas(project)
+
+ def _get_compute_quotas(self, project):
+ return self.conn.get_compute_quotas(project)
+
+ def _get_quotas(self, project):
+ quota = {}
+ try:
+ quota['volume'] = self._get_volume_quotas(project)
+ except Exception:
+ self.warn("No public endpoint for volumev2 service was found. Ignoring volume quotas.")
+
+ try:
+ quota['network'] = self._get_network_quotas(project)
+ except Exception:
+ self.warn("No public endpoint for network service was found. Ignoring network quotas.")
+
+ quota['compute'] = self._get_compute_quotas(project)
+
+ for quota_type in quota.keys():
+ quota[quota_type] = self._scrub_results(quota[quota_type])
+
+ return quota
+
+ def _scrub_results(self, quota):
+ filter_attr = [
+ 'HUMAN_ID',
+ 'NAME_ATTR',
+ 'human_id',
+ 'request_ids',
+ 'x_openstack_request_ids',
+ ]
+
+ for attr in filter_attr:
+ if attr in quota:
+ del quota[attr]
+
+ return quota
+
+ def _system_state_change_details(self, project_quota_output):
+ quota_change_request = {}
+ changes_required = False
+
+ for quota_type in project_quota_output.keys():
+ for quota_option in project_quota_output[quota_type].keys():
+ if quota_option in self.params and self.params[quota_option] is not None:
+ if project_quota_output[quota_type][quota_option] != self.params[quota_option]:
+ changes_required = True
+
+ if quota_type not in quota_change_request:
+ quota_change_request[quota_type] = {}
+
+ quota_change_request[quota_type][quota_option] = self.params[quota_option]
+
+ return (changes_required, quota_change_request)
+
+ def _system_state_change(self, project_quota_output):
+ """
+ Determine if changes are required to the current project quota.
+
+ This is done by comparing the current project_quota_output against
+ the desired quota settings set on the module params.
+ """
+
+ changes_required, quota_change_request = self._system_state_change_details(
+ project_quota_output
+ )
+
+ if changes_required:
+ return True
+ else:
+ return False
+
+ def run(self):
+ cloud_params = dict(self.params)
+
+ # In order to handle the different volume types we update module params after.
+ dynamic_types = [
+ 'gigabytes_types',
+ 'snapshots_types',
+ 'volumes_types',
+ ]
+
+ for dynamic_type in dynamic_types:
+ for k, v in self.params[dynamic_type].items():
+ self.params[k] = int(v)
+
+ # Get current quota values
+ project_quota_output = self._get_quotas(cloud_params['name'])
+ changes_required = False
+
+ if self.params['state'] == "absent":
+ # If a quota state is set to absent we should assume there will be changes.
+ # The default quota values are not accessible so we can not determine if
+ # no changes will occur or not.
+ if self.ansible.check_mode:
+ self.exit_json(changed=True)
+
+ # Calling delete_network_quotas when a quota has not been set results
+ # in an error, according to the sdk docs it should return the
+ # current quota.
+ # The following error string is returned:
+ # network client call failed: Quota for tenant 69dd91d217e949f1a0b35a4b901741dc could not be found.
+ neutron_msg1 = "network client call failed: Quota for tenant"
+ neutron_msg2 = "could not be found"
+
+ for quota_type in project_quota_output.keys():
+ quota_call = getattr(self.conn, 'delete_%s_quotas' % (quota_type))
+ try:
+ quota_call(cloud_params['name'])
+ except Exception as e:
+ error_msg = str(e)
+ if error_msg.find(neutron_msg1) > -1 and error_msg.find(neutron_msg2) > -1:
+ pass
+ else:
+ self.fail_json(msg=str(e), extra_data=e.extra_data)
+
+ project_quota_output = self._get_quotas(cloud_params['name'])
+ changes_required = True
+
+ elif self.params['state'] == "present":
+ if self.ansible.check_mode:
+ self.exit_json(changed=self._system_state_change(
+ project_quota_output))
+
+ changes_required, quota_change_request = self._system_state_change_details(
+ project_quota_output
+ )
+
+ if changes_required:
+ for quota_type in quota_change_request.keys():
+ quota_call = getattr(self.conn, 'set_%s_quotas' % (quota_type))
+ quota_call(cloud_params['name'], **quota_change_request[quota_type])
+
+ # Get quota state post changes for validation
+ project_quota_update = self._get_quotas(cloud_params['name'])
+
+ if project_quota_output == project_quota_update:
+ self.fail_json(msg='Could not apply quota update')
+
+ project_quota_output = project_quota_update
+
+ self.exit_json(
+ changed=changes_required, openstack_quotas=project_quota_output)
+
+
+def main():
+ module = QuotaModule()
+ module()
+
+
+if __name__ == '__main__':
+ main()