diff options
author | Ansible Core Team <info@ansible.com> | 2020-03-09 09:40:35 +0000 |
---|---|---|
committer | Ansible Core Team <info@ansible.com> | 2020-03-09 09:40:35 +0000 |
commit | 618745158a000818c4793da5e4cd524022adf342 (patch) | |
tree | f83de0dd309ae4bd65cf867af0c8924b5cee7c32 | |
parent | 37e8b907bcfdd5bfd3e4c8c5af8de23641874e32 (diff) | |
download | ansible-618745158a000818c4793da5e4cd524022adf342.tar.gz |
Migrated to openstack.cloud
60 files changed, 0 insertions, 14290 deletions
diff --git a/lib/ansible/module_utils/openstack.py b/lib/ansible/module_utils/openstack.py deleted file mode 100644 index 87570c6b71..0000000000 --- a/lib/ansible/module_utils/openstack.py +++ /dev/null @@ -1,163 +0,0 @@ -# This code is part of Ansible, but is an independent component. -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os - -from ansible.module_utils.six import iteritems - - -def openstack_argument_spec(): - # DEPRECATED: This argument spec is only used for the deprecated old - # OpenStack modules. It turns out that modern OpenStack auth is WAY - # more complex than this. - # Consume standard OpenStack environment variables. - # This is mainly only useful for ad-hoc command line operation as - # in playbooks one would assume variables would be used appropriately - OS_AUTH_URL = os.environ.get('OS_AUTH_URL', 'http://127.0.0.1:35357/v2.0/') - OS_PASSWORD = os.environ.get('OS_PASSWORD', None) - OS_REGION_NAME = os.environ.get('OS_REGION_NAME', None) - OS_USERNAME = os.environ.get('OS_USERNAME', 'admin') - OS_TENANT_NAME = os.environ.get('OS_TENANT_NAME', OS_USERNAME) - - spec = dict( - login_username=dict(default=OS_USERNAME), - auth_url=dict(default=OS_AUTH_URL), - region_name=dict(default=OS_REGION_NAME), - availability_zone=dict(), - ) - if OS_PASSWORD: - spec['login_password'] = dict(default=OS_PASSWORD) - else: - spec['login_password'] = dict(required=True) - if OS_TENANT_NAME: - spec['login_tenant_name'] = dict(default=OS_TENANT_NAME) - else: - spec['login_tenant_name'] = dict(required=True) - return spec - - -def openstack_find_nova_addresses(addresses, ext_tag, key_name=None): - - ret = [] - for (k, v) in iteritems(addresses): - if key_name and k == key_name: - ret.extend([addrs['addr'] for addrs in v]) - else: - for interface_spec in v: - if 'OS-EXT-IPS:type' in interface_spec and interface_spec['OS-EXT-IPS:type'] == ext_tag: - ret.append(interface_spec['addr']) - return ret - - -def openstack_full_argument_spec(**kwargs): - spec = dict( - cloud=dict(default=None, type='raw'), - auth_type=dict(default=None), - auth=dict(default=None, type='dict', no_log=True), - region_name=dict(default=None), - availability_zone=dict(default=None), - validate_certs=dict(default=None, type='bool', aliases=['verify']), - ca_cert=dict(default=None, aliases=['cacert']), - client_cert=dict(default=None, aliases=['cert']), - client_key=dict(default=None, no_log=True, aliases=['key']), - wait=dict(default=True, type='bool'), - timeout=dict(default=180, type='int'), - api_timeout=dict(default=None, type='int'), - interface=dict( - default='public', choices=['public', 'internal', 'admin'], - aliases=['endpoint_type']), - ) - spec.update(kwargs) - return spec - - -def openstack_module_kwargs(**kwargs): - ret = {} - for key in ('mutually_exclusive', 'required_together', 'required_one_of'): - if key in kwargs: - if key in ret: - ret[key].extend(kwargs[key]) - else: - ret[key] = kwargs[key] - - return ret - - -def openstack_cloud_from_module(module, min_version='0.12.0'): - from distutils.version import StrictVersion - try: - # Due to the name shadowing we should import other way - import importlib - sdk = importlib.import_module('openstack') - sdk_version = importlib.import_module('openstack.version') - except ImportError: - module.fail_json(msg='openstacksdk is required for this module') - - if min_version: - min_version = max(StrictVersion('0.12.0'), StrictVersion(min_version)) - else: - min_version = StrictVersion('0.12.0') - - if StrictVersion(sdk_version.__version__) < min_version: - module.fail_json( - msg="To utilize this module, the installed version of " - "the openstacksdk library MUST be >={min_version}.".format( - min_version=min_version)) - - cloud_config = module.params.pop('cloud', None) - try: - if isinstance(cloud_config, dict): - fail_message = ( - "A cloud config dict was provided to the cloud parameter" - " but also a value was provided for {param}. If a cloud" - " config dict is provided, {param} should be" - " excluded.") - for param in ( - 'auth', 'region_name', 'validate_certs', - 'ca_cert', 'client_key', 'api_timeout', 'auth_type'): - if module.params[param] is not None: - module.fail_json(msg=fail_message.format(param=param)) - # For 'interface' parameter, fail if we receive a non-default value - if module.params['interface'] != 'public': - module.fail_json(msg=fail_message.format(param='interface')) - return sdk, sdk.connect(**cloud_config) - else: - return sdk, sdk.connect( - cloud=cloud_config, - auth_type=module.params['auth_type'], - auth=module.params['auth'], - region_name=module.params['region_name'], - verify=module.params['validate_certs'], - cacert=module.params['ca_cert'], - key=module.params['client_key'], - api_timeout=module.params['api_timeout'], - interface=module.params['interface'], - ) - except sdk.exceptions.SDKException as e: - # Probably a cloud configuration/login error - module.fail_json(msg=str(e)) diff --git a/lib/ansible/modules/cloud/openstack/os_auth.py b/lib/ansible/modules/cloud/openstack/os_auth.py deleted file mode 100644 index 0f86ab103e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_auth.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_auth -short_description: Retrieve an auth token -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Retrieve an auth token from an OpenStack Cloud -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -- name: Authenticate to the cloud and retrieve the service catalog - os_auth: - cloud: rax-dfw - -- name: Show service catalog - debug: - var: service_catalog -''' - -RETURN = ''' -auth_token: - description: Openstack API Auth Token - returned: success - type: str -service_catalog: - description: A dictionary of available API endpoints - returned: success - type: dict -''' - -import traceback - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec() - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - sdk, cloud = openstack_cloud_from_module(module) - try: - module.exit_json( - changed=False, - ansible_facts=dict( - auth_token=cloud.auth_token, - service_catalog=cloud.service_catalog)) - except Exception as e: - module.fail_json(msg=str(e), exception=traceback.format_exc()) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_client_config.py b/lib/ansible/modules/cloud/openstack/os_client_config.py deleted file mode 100644 index a8f8f69e5f..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_client_config.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_client_config -short_description: Get OpenStack Client config -description: - - Get I(openstack) client config data from clouds.yaml or environment -version_added: "2.0" -notes: - - Facts are placed in the C(openstack.clouds) variable. -options: - clouds: - description: - - List of clouds to limit the return list to. No value means return - information on all configured clouds - required: false - default: [] -requirements: [ os-client-config ] -author: "Monty Taylor (@emonty)" -''' - -EXAMPLES = ''' -- name: Get list of clouds that do not support security groups - os_client_config: - -- debug: - var: "{{ item }}" - with_items: "{{ openstack.clouds | rejectattr('secgroup_source', 'none') | list }}" - -- name: Get the information back just about the mordred cloud - os_client_config: - clouds: - - mordred -''' - -try: - import os_client_config - from os_client_config import exceptions - HAS_OS_CLIENT_CONFIG = True -except ImportError: - HAS_OS_CLIENT_CONFIG = False - -from ansible.module_utils.basic import AnsibleModule - - -def main(): - module = AnsibleModule(argument_spec=dict( - clouds=dict(required=False, type='list', default=[]), - )) - - if not HAS_OS_CLIENT_CONFIG: - module.fail_json(msg='os-client-config is required for this module') - - p = module.params - - try: - config = os_client_config.OpenStackConfig() - clouds = [] - for cloud in config.get_all_clouds(): - if not p['clouds'] or cloud.name in p['clouds']: - cloud.config['name'] = cloud.name - clouds.append(cloud.config) - module.exit_json(ansible_facts=dict(openstack=dict(clouds=clouds))) - except exceptions.OpenStackConfigException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_coe_cluster.py b/lib/ansible/modules/cloud/openstack/os_coe_cluster.py deleted file mode 100644 index 26e3a18aeb..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_coe_cluster.py +++ /dev/null @@ -1,282 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2018 Catalyst IT Ltd. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_coe_cluster -short_description: Add/Remove COE cluster from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.8" -author: "Feilong Wang (@flwang)" -description: - - Add or Remove COE cluster from the OpenStack Container Infra service. -options: - availability_zone: - description: - - Ignored. Present for backwards compatibility - cluster_template_id: - description: - - The template ID of cluster template. - required: true - discovery_url: - description: - - Url used for cluster node discovery - docker_volume_size: - description: - - The size in GB of the docker volume - flavor_id: - description: - - The flavor of the minion node for this ClusterTemplate - keypair: - description: - - Name of the keypair to use. - labels: - description: - - One or more key/value pairs - master_flavor_id: - description: - - The flavor of the master node for this ClusterTemplate - master_count: - description: - - The number of master nodes for this cluster - default: 1 - name: - description: - - Name that has to be given to the cluster template - required: true - node_count: - description: - - The number of nodes for this cluster - default: 1 - state: - description: - - Indicate desired state of the resource. - choices: [present, absent] - default: present - timeout: - description: - - Timeout for creating the cluster in minutes. Default to 60 mins - if not set - default: 60 -requirements: ["openstacksdk"] -''' - -RETURN = ''' -id: - description: The cluster UUID. - returned: On success when I(state) is 'present' - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" -cluster: - description: Dictionary describing the cluster. - returned: On success when I(state) is 'present' - type: complex - contains: - api_address: - description: - - Api address of cluster master node - type: str - sample: https://172.24.4.30:6443 - cluster_template_id: - description: The cluster_template UUID - type: str - sample: '7b1418c8-cea8-48fc-995d-52b66af9a9aa' - coe_version: - description: - - Version of the COE software currently running in this cluster - type: str - sample: v1.11.1 - container_version: - description: - - "Version of the container software. Example: docker version." - type: str - sample: 1.12.6 - created_at: - description: - - The time in UTC at which the cluster is created - type: str - sample: "2018-08-16T10:29:45+00:00" - create_timeout: - description: - - Timeout for creating the cluster in minutes. Default to 60 if - not set. - type: int - sample: 60 - discovery_url: - description: - - Url used for cluster node discovery - type: str - sample: https://discovery.etcd.io/a42ee38e7113f31f4d6324f24367aae5 - faults: - description: - - Fault info collected from the Heat resources of this cluster - type: dict - sample: {'0': 'ResourceInError: resources[0].resources...'} - flavor_id: - description: - - The flavor of the minion node for this cluster - type: str - sample: c1.c1r1 - keypair: - description: - - Name of the keypair to use. - type: str - sample: mykey - labels: - description: One or more key/value pairs - type: dict - sample: {'key1': 'value1', 'key2': 'value2'} - master_addresses: - description: - - IP addresses of cluster master nodes - type: list - sample: ['172.24.4.5'] - master_count: - description: - - The number of master nodes for this cluster. - type: int - sample: 1 - master_flavor_id: - description: - - The flavor of the master node for this cluster - type: str - sample: c1.c1r1 - name: - description: - - Name that has to be given to the cluster - type: str - sample: k8scluster - node_addresses: - description: - - IP addresses of cluster slave nodes - type: list - sample: ['172.24.4.8'] - node_count: - description: - - The number of master nodes for this cluster. - type: int - sample: 1 - stack_id: - description: - - Stack id of the Heat stack - type: str - sample: '07767ec6-85f5-44cb-bd63-242a8e7f0d9d' - status: - description: Status of the cluster from the heat stack - type: str - sample: 'CREATE_COMLETE' - status_reason: - description: - - Status reason of the cluster from the heat stack - type: str - sample: 'Stack CREATE completed successfully' - updated_at: - description: - - The time in UTC at which the cluster is updated - type: str - sample: '2018-08-16T10:39:25+00:00' - uuid: - description: - - Unique UUID for this cluster - type: str - sample: '86246a4d-a16c-4a58-9e96ad7719fe0f9d' -''' - -EXAMPLES = ''' -# Create a new Kubernetes cluster -- os_coe_cluster: - name: k8s - cluster_template_id: k8s-ha - keypair: mykey - master_count: 3 - node_count: 5 -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _parse_labels(labels): - if isinstance(labels, str): - labels_dict = {} - for kv_str in labels.split(","): - k, v = kv_str.split("=") - labels_dict[k] = v - return labels_dict - if not labels: - return {} - return labels - - -def main(): - argument_spec = openstack_full_argument_spec( - cluster_template_id=dict(required=True), - discovery_url=dict(default=None), - docker_volume_size=dict(type='int'), - flavor_id=dict(default=None), - keypair=dict(default=None), - labels=dict(default=None, type='raw'), - master_count=dict(type='int', default=1), - master_flavor_id=dict(default=None), - name=dict(required=True), - node_count=dict(type='int', default=1), - state=dict(default='present', choices=['absent', 'present']), - timeout=dict(type='int', default=60), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - params = module.params.copy() - - state = module.params['state'] - name = module.params['name'] - cluster_template_id = module.params['cluster_template_id'] - - kwargs = dict( - discovery_url=module.params['discovery_url'], - docker_volume_size=module.params['docker_volume_size'], - flavor_id=module.params['flavor_id'], - keypair=module.params['keypair'], - labels=_parse_labels(params['labels']), - master_count=module.params['master_count'], - master_flavor_id=module.params['master_flavor_id'], - node_count=module.params['node_count'], - create_timeout=module.params['timeout'], - ) - - sdk, cloud = openstack_cloud_from_module(module) - try: - changed = False - cluster = cloud.get_coe_cluster(name_or_id=name, filters={'cluster_template_id': cluster_template_id}) - - if state == 'present': - if not cluster: - cluster = cloud.create_coe_cluster(name, cluster_template_id=cluster_template_id, **kwargs) - changed = True - else: - changed = False - - module.exit_json(changed=changed, cluster=cluster, id=cluster['uuid']) - elif state == 'absent': - if not cluster: - module.exit_json(changed=False) - else: - cloud.delete_coe_cluster(name) - module.exit_json(changed=True) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_coe_cluster_template.py b/lib/ansible/modules/cloud/openstack/os_coe_cluster_template.py deleted file mode 100644 index 75121f0afa..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_coe_cluster_template.py +++ /dev/null @@ -1,373 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2018 Catalyst IT Ltd. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_coe_cluster_template -short_description: Add/Remove COE cluster template from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.7" -author: "Feilong Wang (@flwang)" -description: - - Add or Remove COE cluster template from the OpenStack Container Infra - service. -options: - availability_zone: - description: - - Ignored. Present for backwards compatibility - coe: - description: - - The Container Orchestration Engine for this clustertemplate - choices: [kubernetes, swarm, mesos] - dns_nameserver: - description: - - The DNS nameserver address - default: '8.8.8.8' - docker_storage_driver: - description: - - Docker storage driver - choices: [devicemapper, overlay, overlay2] - docker_volume_size: - description: - - The size in GB of the docker volume - external_network_id: - description: - - The external network to attach to the Cluster - fixed_network: - description: - - The fixed network name to attach to the Cluster - fixed_subnet: - description: - - The fixed subnet name to attach to the Cluster - flavor_id: - description: - - The flavor of the minion node for this ClusterTemplate - floating_ip_enabled: - description: - - Indicates whether created clusters should have a floating ip or not - type: bool - default: 'yes' - keypair_id: - description: - - Name or ID of the keypair to use. - image_id: - description: - - Image id the cluster will be based on - labels: - description: - - One or more key/value pairs wrapped in string - http_proxy: - description: - - Address of a proxy that will receive all HTTP requests and relay them - The format is a URL including a port number - https_proxy: - description: - - Address of a proxy that will receive all HTTPS requests and relay - them. The format is a URL including a port number - master_flavor_id: - description: - - The flavor of the master node for this ClusterTemplate - master_lb_enabled: - description: - - Indicates whether created clusters should have a load balancer - for master nodes or not - type: bool - default: 'no' - name: - description: - - Name that has to be given to the cluster template - required: true - network_driver: - description: - - The name of the driver used for instantiating container networks - choices: [flannel, calico, docker] - no_proxy: - description: - - A comma separated list of IPs for which proxies should not be - used in the cluster - public: - description: - - Indicates whether the ClusterTemplate is public or not - type: bool - default: 'no' - registry_enabled: - description: - - Indicates whether the docker registry is enabled - type: bool - default: 'no' - server_type: - description: - - Server type for this ClusterTemplate - choices: [vm, bm] - default: vm - state: - description: - - Indicate desired state of the resource. - choices: [present, absent] - default: present - tls_disabled: - description: - - Indicates whether the TLS should be disabled - type: bool - default: 'no' - volume_driver: - description: - - The name of the driver used for instantiating container volumes - choices: [cinder, rexray] -requirements: ["openstacksdk"] -''' - -RETURN = ''' -id: - description: The cluster UUID. - returned: On success when I(state) is 'present' - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" -cluster_template: - description: Dictionary describing the template. - returned: On success when I(state) is 'present' - type: complex - contains: - coe: - description: The Container Orchestration Engine for this clustertemplate - type: str - sample: kubernetes - dns_nameserver: - description: The DNS nameserver address - type: str - sample: '8.8.8.8' - docker_storage_driver: - description: Docker storage driver - type: str - sample: devicemapper - docker_volume_size: - description: The size in GB of the docker volume - type: int - sample: 5 - external_network_id: - description: The external network to attach to the Cluster - type: str - sample: public - fixed_network: - description: The fixed network name to attach to the Cluster - type: str - sample: 07767ec6-85f5-44cb-bd63-242a8e7f0d9d - fixed_subnet: - description: - - The fixed subnet name to attach to the Cluster - type: str - sample: 05567ec6-85f5-44cb-bd63-242a8e7f0d9d - flavor_id: - description: - - The flavor of the minion node for this ClusterTemplate - type: str - sample: c1.c1r1 - floating_ip_enabled: - description: - - Indicates whether created clusters should have a floating ip or not - type: bool - sample: true - keypair_id: - description: - - Name or ID of the keypair to use. - type: str - sample: mykey - image_id: - description: - - Image id the cluster will be based on - type: str - sample: 05567ec6-85f5-44cb-bd63-242a8e7f0e9d - labels: - description: One or more key/value pairs wrapped in string - type: str - sample: 'key1=value1, key2=value2' - http_proxy: - description: - - Address of a proxy that will receive all HTTP requests and relay them - The format is a URL including a port number - type: str - sample: http://10.0.0.11:9090 - https_proxy: - description: - - Address of a proxy that will receive all HTTPS requests and relay - them. The format is a URL including a port number - type: str - sample: https://10.0.0.10:8443 - master_flavor_id: - description: - - The flavor of the master node for this ClusterTemplate - type: str - sample: c1.c1r1 - master_lb_enabled: - description: - - Indicates whether created clusters should have a load balancer - for master nodes or not - type: bool - sample: true - name: - description: - - Name that has to be given to the cluster template - type: str - sample: k8scluster - network_driver: - description: - - The name of the driver used for instantiating container networks - type: str - sample: calico - no_proxy: - description: - - A comma separated list of IPs for which proxies should not be - used in the cluster - type: str - sample: 10.0.0.4,10.0.0.5 - public: - description: - - Indicates whether the ClusterTemplate is public or not - type: bool - sample: false - registry_enabled: - description: - - Indicates whether the docker registry is enabled - type: bool - sample: false - server_type: - description: - - Server type for this ClusterTemplate - type: str - sample: vm - tls_disabled: - description: - - Indicates whether the TLS should be disabled - type: bool - sample: false - volume_driver: - description: - - The name of the driver used for instantiating container volumes - type: str - sample: cinder -''' - -EXAMPLES = ''' -# Create a new Kubernetes cluster template -- os_coe_cluster_template: - name: k8s - coe: kubernetes - keypair_id: mykey - image_id: 2a8c9888-9054-4b06-a1ca-2bb61f9adb72 - public: no -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _parse_labels(labels): - if isinstance(labels, str): - labels_dict = {} - for kv_str in labels.split(","): - k, v = kv_str.split("=") - labels_dict[k.strip()] = v.strip() - return labels_dict - if not labels: - return {} - return labels - - -def main(): - argument_spec = openstack_full_argument_spec( - coe=dict(required=True, choices=['kubernetes', 'swarm', 'mesos']), - dns_nameserver=dict(default='8.8.8.8'), - docker_storage_driver=dict(choices=['devicemapper', 'overlay', 'overlay2']), - docker_volume_size=dict(type='int'), - external_network_id=dict(default=None), - fixed_network=dict(default=None), - fixed_subnet=dict(default=None), - flavor_id=dict(default=None), - floating_ip_enabled=dict(type='bool', default=True), - keypair_id=dict(default=None), - image_id=dict(required=True), - labels=dict(default=None, type='raw'), - http_proxy=dict(default=None), - https_proxy=dict(default=None), - master_lb_enabled=dict(type='bool', default=False), - master_flavor_id=dict(default=None), - name=dict(required=True), - network_driver=dict(choices=['flannel', 'calico', 'docker']), - no_proxy=dict(default=None), - public=dict(type='bool', default=False), - registry_enabled=dict(type='bool', default=False), - server_type=dict(default="vm", choices=['vm', 'bm']), - state=dict(default='present', choices=['absent', 'present']), - tls_disabled=dict(type='bool', default=False), - volume_driver=dict(choices=['cinder', 'rexray']), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - params = module.params.copy() - - state = module.params['state'] - name = module.params['name'] - coe = module.params['coe'] - image_id = module.params['image_id'] - - kwargs = dict( - dns_nameserver=module.params['dns_nameserver'], - docker_storage_driver=module.params['docker_storage_driver'], - docker_volume_size=module.params['docker_volume_size'], - external_network_id=module.params['external_network_id'], - fixed_network=module.params['fixed_network'], - fixed_subnet=module.params['fixed_subnet'], - flavor_id=module.params['flavor_id'], - floating_ip_enabled=module.params['floating_ip_enabled'], - keypair_id=module.params['keypair_id'], - labels=_parse_labels(params['labels']), - http_proxy=module.params['http_proxy'], - https_proxy=module.params['https_proxy'], - master_lb_enabled=module.params['master_lb_enabled'], - master_flavor_id=module.params['master_flavor_id'], - network_driver=module.params['network_driver'], - no_proxy=module.params['no_proxy'], - public=module.params['public'], - registry_enabled=module.params['registry_enabled'], - server_type=module.params['server_type'], - tls_disabled=module.params['tls_disabled'], - volume_driver=module.params['volume_driver'], - ) - - sdk, cloud = openstack_cloud_from_module(module) - try: - changed = False - template = cloud.get_coe_cluster_template(name_or_id=name, filters={'coe': coe, 'image_id': image_id}) - - if state == 'present': - if not template: - template = cloud.create_coe_cluster_template(name, coe=coe, image_id=image_id, **kwargs) - changed = True - else: - changed = False - - module.exit_json(changed=changed, cluster_template=template, id=template['uuid']) - elif state == 'absent': - if not template: - module.exit_json(changed=False) - else: - cloud.delete_coe_cluster_template(name) - module.exit_json(changed=True) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_flavor_info.py b/lib/ansible/modules/cloud/openstack/os_flavor_info.py deleted file mode 100644 index 3919cde8b0..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_flavor_info.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 IBM -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_flavor_info -short_description: Retrieve information about one or more flavors -author: "David Shrewsbury (@Shrews)" -version_added: "2.1" -description: - - Retrieve information about available OpenStack instance flavors. By default, - information about ALL flavors are retrieved. Filters can be applied to get - information for only matching flavors. For example, you can filter on the - amount of RAM available to the flavor, or the number of virtual CPUs - available to the flavor, or both. When specifying multiple filters, - *ALL* filters must match on a flavor before that flavor is returned as - a fact. - - This module was called C(os_flavor_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_flavor_info) module no longer returns C(ansible_facts)! -notes: - - The result contains a list of unsorted flavors. -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - name: - description: - - A flavor name. Cannot be used with I(ram) or I(vcpus) or I(ephemeral). - ram: - description: - - "A string used for filtering flavors based on the amount of RAM - (in MB) desired. This string accepts the following special values: - 'MIN' (return flavors with the minimum amount of RAM), and 'MAX' - (return flavors with the maximum amount of RAM)." - - - "A specific amount of RAM may also be specified. Any flavors with this - exact amount of RAM will be returned." - - - "A range of acceptable RAM may be given using a special syntax. Simply - prefix the amount of RAM with one of these acceptable range values: - '<', '>', '<=', '>='. These values represent less than, greater than, - less than or equal to, and greater than or equal to, respectively." - type: bool - default: 'no' - vcpus: - description: - - A string used for filtering flavors based on the number of virtual - CPUs desired. Format is the same as the I(ram) parameter. - type: bool - default: 'no' - limit: - description: - - Limits the number of flavors returned. All matching flavors are - returned by default. - ephemeral: - description: - - A string used for filtering flavors based on the amount of ephemeral - storage. Format is the same as the I(ram) parameter - type: bool - default: 'no' - version_added: "2.3" - availability_zone: - description: - - Ignored. Present for backwards compatibility -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -# Gather information about all available flavors -- os_flavor_info: - cloud: mycloud - register: result - -- debug: - msg: "{{ result.openstack_flavors }}" - -# Gather information for the flavor named "xlarge-flavor" -- os_flavor_info: - cloud: mycloud - name: "xlarge-flavor" - -# Get all flavors that have exactly 512 MB of RAM. -- os_flavor_info: - cloud: mycloud - ram: "512" - -# Get all flavors that have 1024 MB or more of RAM. -- os_flavor_info: - cloud: mycloud - ram: ">=1024" - -# Get a single flavor that has the minimum amount of RAM. Using the 'limit' -# option will guarantee only a single flavor is returned. -- os_flavor_info: - cloud: mycloud - ram: "MIN" - limit: 1 - -# Get all flavors with 1024 MB of RAM or more, AND exactly 2 virtual CPUs. -- os_flavor_info: - cloud: mycloud - ram: ">=1024" - vcpus: "2" - -# Get all flavors with 1024 MB of RAM or more, exactly 2 virtual CPUs, and -# less than 30gb of ephemeral storage. -- os_flavor_info: - cloud: mycloud - ram: ">=1024" - vcpus: "2" - ephemeral: "<30" -''' - - -RETURN = ''' -openstack_flavors: - description: Dictionary describing the flavors. - returned: On success. - type: complex - contains: - id: - description: Flavor ID. - returned: success - type: str - sample: "515256b8-7027-4d73-aa54-4e30a4a4a339" - name: - description: Flavor name. - returned: success - type: str - sample: "tiny" - 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 - ram: - description: Amount of memory, in MB. - returned: success - type: int - sample: 1024 - 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 - is_public: - description: Make flavor accessible to the public. - returned: success - type: bool - sample: true -''' - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - ram=dict(required=False, default=None), - vcpus=dict(required=False, default=None), - limit=dict(required=False, default=None, type='int'), - ephemeral=dict(required=False, default=None), - ) - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[ - ['name', 'ram'], - ['name', 'vcpus'], - ['name', 'ephemeral'] - ] - ) - module = AnsibleModule(argument_spec, **module_kwargs) - is_old_facts = module._name == 'os_flavor_facts' - if is_old_facts: - module.deprecate("The 'os_flavor_facts' module has been renamed to 'os_flavor_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - name = module.params['name'] - vcpus = module.params['vcpus'] - ram = module.params['ram'] - ephemeral = module.params['ephemeral'] - limit = module.params['limit'] - - filters = {} - if vcpus: - filters['vcpus'] = vcpus - if ram: - filters['ram'] = ram - if ephemeral: - filters['ephemeral'] = ephemeral - - sdk, cloud = openstack_cloud_from_module(module) - try: - if name: - flavors = cloud.search_flavors(filters={'name': name}) - - else: - flavors = cloud.list_flavors() - if filters: - flavors = cloud.range_search(flavors, filters) - - if limit is not None: - flavors = flavors[:limit] - - if is_old_facts: - module.exit_json(changed=False, - ansible_facts=dict(openstack_flavors=flavors)) - else: - module.exit_json(changed=False, - openstack_flavors=flavors) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_floating_ip.py b/lib/ansible/modules/cloud/openstack/os_floating_ip.py deleted file mode 100644 index b11048599e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_floating_ip.py +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/python - -# Copyright: (c) 2015, Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_floating_ip -version_added: "2.0" -author: Davide Guerri (@dguerri) <davide.guerri@hp.com> -short_description: Add/Remove floating IP from an instance -extends_documentation_fragment: openstack -description: - - Add or Remove a floating IP to an instance. - - Returns the floating IP when attaching only if I(wait=true). -options: - server: - description: - - The name or ID of the instance to which the IP address - should be assigned. - required: true - network: - description: - - The name or ID of a neutron external network or a nova pool name. - floating_ip_address: - description: - - A floating IP address to attach or to detach. Required only if I(state) - is absent. When I(state) is present can be used to specify a IP address - to attach. - reuse: - description: - - When I(state) is present, and I(floating_ip_address) is not present, - this parameter can be used to specify whether we should try to reuse - a floating IP address already allocated to the project. - type: bool - default: 'no' - fixed_address: - description: - - To which fixed IP of server the floating IP address should be - attached to. - nat_destination: - description: - - The name or id of a neutron private network that the fixed IP to - attach floating IP is on - aliases: ["fixed_network", "internal_network"] - version_added: "2.3" - wait: - description: - - When attaching a floating IP address, specify whether to wait for it to appear as attached. - - Must be set to C(yes) for the module to return the value of the floating IP. - type: bool - default: 'no' - timeout: - description: - - Time to wait for an IP address to appear as attached. See wait. - required: false - default: 60 - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - purge: - description: - - When I(state) is absent, indicates whether or not to delete the floating - IP completely, or only detach it from the server. Default is to detach only. - type: bool - default: 'no' - version_added: "2.1" - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -EXAMPLES = ''' -# Assign a floating IP to the fist interface of `cattle001` from an exiting -# external network or nova pool. A new floating IP from the first available -# external network is allocated to the project. -- os_floating_ip: - cloud: dguerri - server: cattle001 - -# Assign a new floating IP to the instance fixed ip `192.0.2.3` of -# `cattle001`. If a free floating IP is already allocated to the project, it is -# reused; if not, a new one is created. -- os_floating_ip: - cloud: dguerri - state: present - reuse: yes - server: cattle001 - network: ext_net - fixed_address: 192.0.2.3 - wait: true - timeout: 180 - -# Assign a new floating IP from the network `ext_net` to the instance fixed -# ip in network `private_net` of `cattle001`. -- os_floating_ip: - cloud: dguerri - state: present - server: cattle001 - network: ext_net - nat_destination: private_net - wait: true - timeout: 180 - -# Detach a floating IP address from a server -- os_floating_ip: - cloud: dguerri - state: absent - floating_ip_address: 203.0.113.2 - server: cattle001 -''' - -from ansible.module_utils.basic import AnsibleModule, remove_values -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _get_floating_ip(cloud, floating_ip_address): - f_ips = cloud.search_floating_ips( - filters={'floating_ip_address': floating_ip_address}) - if not f_ips: - return None - - return f_ips[0] - - -def main(): - argument_spec = openstack_full_argument_spec( - server=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - network=dict(required=False, default=None), - floating_ip_address=dict(required=False, default=None), - reuse=dict(required=False, type='bool', default=False), - fixed_address=dict(required=False, default=None), - nat_destination=dict(required=False, default=None, - aliases=['fixed_network', 'internal_network']), - wait=dict(required=False, type='bool', default=False), - timeout=dict(required=False, type='int', default=60), - purge=dict(required=False, type='bool', default=False), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - server_name_or_id = module.params['server'] - state = module.params['state'] - network = module.params['network'] - floating_ip_address = module.params['floating_ip_address'] - reuse = module.params['reuse'] - fixed_address = module.params['fixed_address'] - nat_destination = module.params['nat_destination'] - wait = module.params['wait'] - timeout = module.params['timeout'] - purge = module.params['purge'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - - server = cloud.get_server(server_name_or_id) - if server is None: - module.fail_json( - msg="server {0} not found".format(server_name_or_id)) - - if state == 'present': - # If f_ip already assigned to server, check that it matches - # requirements. - public_ip = cloud.get_server_public_ip(server) - f_ip = _get_floating_ip(cloud, public_ip) if public_ip else public_ip - if f_ip: - if network: - network_id = cloud.get_network(name_or_id=network)["id"] - else: - network_id = None - # check if we have floating ip on given nat_destination network - if nat_destination: - nat_floating_addrs = [addr for addr in server.addresses.get( - cloud.get_network(nat_destination)['name'], []) - if addr['addr'] == public_ip and - addr['OS-EXT-IPS:type'] == 'floating'] - - if len(nat_floating_addrs) == 0: - module.fail_json(msg="server {server} already has a " - "floating-ip on a different " - "nat-destination than '{nat_destination}'" - .format(server=server_name_or_id, - nat_destination=nat_destination)) - - if all([fixed_address, f_ip.fixed_ip_address == fixed_address, - network, f_ip.network != network_id]): - # Current state definitely conflicts with requirements - module.fail_json(msg="server {server} already has a " - "floating-ip on requested " - "interface but it doesn't match " - "requested network {network}: {fip}" - .format(server=server_name_or_id, - network=network, - fip=remove_values(f_ip, - module.no_log_values))) - if not network or f_ip.network == network_id: - # Requirements are met - module.exit_json(changed=False, floating_ip=f_ip) - - # Requirements are vague enough to ignore existing f_ip and try - # to create a new f_ip to the server. - - server = cloud.add_ips_to_server( - server=server, ips=floating_ip_address, ip_pool=network, - reuse=reuse, fixed_address=fixed_address, wait=wait, - timeout=timeout, nat_destination=nat_destination) - fip_address = cloud.get_server_public_ip(server) - # Update the floating IP status - f_ip = _get_floating_ip(cloud, fip_address) - module.exit_json(changed=True, floating_ip=f_ip) - - elif state == 'absent': - if floating_ip_address is None: - if not server_name_or_id: - module.fail_json(msg="either server or floating_ip_address are required") - server = cloud.get_server(server_name_or_id) - floating_ip_address = cloud.get_server_public_ip(server) - - f_ip = _get_floating_ip(cloud, floating_ip_address) - - if not f_ip: - # Nothing to detach - module.exit_json(changed=False) - changed = False - if f_ip["fixed_ip_address"]: - cloud.detach_ip_from_server( - server_id=server['id'], floating_ip_id=f_ip['id']) - # Update the floating IP status - f_ip = cloud.get_floating_ip(id=f_ip['id']) - changed = True - if purge: - cloud.delete_floating_ip(f_ip['id']) - module.exit_json(changed=True) - module.exit_json(changed=changed, floating_ip=f_ip) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_group.py b/lib/ansible/modules/cloud/openstack/os_group.py deleted file mode 100644 index 3f7e291c1c..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_group.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 IBM -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_group -short_description: Manage OpenStack Identity Groups -extends_documentation_fragment: openstack -version_added: "2.1" -author: "Monty Taylor (@emonty), David Shrewsbury (@Shrews)" -description: - - Manage OpenStack Identity Groups. Groups can be created, deleted or - updated. Only the I(description) value can be updated. -options: - name: - description: - - Group name - required: true - description: - description: - - Group description - domain_id: - description: - - Domain id to create the group in if the cloud supports domains. - version_added: "2.3" - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a group named "demo" -- os_group: - cloud: mycloud - state: present - name: demo - description: "Demo Group" - domain_id: demoid - -# Update the description on existing "demo" group -- os_group: - cloud: mycloud - state: present - name: demo - description: "Something else" - domain_id: demoid - -# Delete group named "demo" -- os_group: - cloud: mycloud - state: absent - name: demo -''' - -RETURN = ''' -group: - description: Dictionary describing the group. - returned: On success when I(state) is 'present'. - type: complex - contains: - id: - description: Unique group ID - type: str - sample: "ee6156ff04c645f481a6738311aea0b0" - name: - description: Group name - type: str - sample: "demo" - description: - description: Group description - type: str - sample: "Demo Group" - domain_id: - description: Domain for the group - type: str - sample: "default" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, description, group): - if state == 'present' and not group: - return True - if state == 'present' and description is not None and group.description != description: - return True - if state == 'absent' and group: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - description=dict(required=False, default=None), - domain_id=dict(required=False, default=None), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - name = module.params.get('name') - description = module.params.get('description') - state = module.params.get('state') - - domain_id = module.params.pop('domain_id') - - sdk, cloud = openstack_cloud_from_module(module) - try: - if domain_id: - group = cloud.get_group(name, filters={'domain_id': domain_id}) - else: - group = cloud.get_group(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, description, group)) - - if state == 'present': - if group is None: - group = cloud.create_group( - name=name, description=description, domain=domain_id) - changed = True - else: - if description is not None and group.description != description: - group = cloud.update_group( - group.id, description=description) - changed = True - else: - changed = False - module.exit_json(changed=changed, group=group) - - elif state == 'absent': - if group is None: - changed = False - else: - cloud.delete_group(group.id) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_group_info.py b/lib/ansible/modules/cloud/openstack/os_group_info.py deleted file mode 100644 index 0630516d71..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_group_info.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2019, Phillipe Smith <phillipelnx@gmail.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_group_info -short_description: Retrieve info about one or more OpenStack groups -extends_documentation_fragment: openstack -version_added: "2.9" -author: "Phillipe Smith (@phsmith)" -description: - - Retrieve info about a one or more OpenStack groups. -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - name: - description: - - Name or ID of the group. - required: true - type: str - domain: - description: - - Name or ID of the domain containing the group if the cloud supports domains - type: str - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - type: dict - availability_zone: - description: - - Ignored. Present for backwards compatibility - type: str -''' - -EXAMPLES = ''' -# Gather info about previously created groups -- name: gather info - hosts: localhost - tasks: - - name: Gather info about previously created groups - os_group_info: - cloud: awesomecloud - register: openstack_groups - - debug: - var: openstack_groups - -# Gather info about a previously created group by name -- name: gather info - hosts: localhost - tasks: - - name: Gather info about a previously created group by name - os_group_info: - cloud: awesomecloud - name: demogroup - register: openstack_groups - - debug: - var: openstack_groups - -# Gather info about a previously created group in a specific domain -- name: gather info - hosts: localhost - tasks: - - name: Gather info about a previously created group in a specific domain - os_group_info: - cloud: awesomecloud - name: demogroup - domain: admindomain - register: openstack_groups - - debug: - var: openstack_groups - -# Gather info about a previously created group in a specific domain with filter -- name: gather info - hosts: localhost - tasks: - - name: Gather info about a previously created group in a specific domain with filter - os_group_info: - cloud: awesomecloud - name: demogroup - domain: admindomain - filters: - enabled: False - register: openstack_groups - - debug: - var: openstack_groups -''' - - -RETURN = ''' -openstack_groups: - description: Dictionary describing all the matching groups. - returned: always, but can be null - type: complex - contains: - name: - description: Name given to the group. - returned: success - type: str - description: - description: Description of the group. - returned: success - type: str - id: - description: Unique UUID. - returned: success - type: str - domain_id: - description: Domain ID containing the group (keystone v3 clouds only) - returned: success - type: bool -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - domain=dict(required=False, default=None), - filters=dict(required=False, type='dict', default=None), - ) - - module = AnsibleModule(argument_spec) - - sdk, opcloud = openstack_cloud_from_module(module) - try: - name = module.params['name'] - domain = module.params['domain'] - filters = module.params['filters'] - - if domain: - try: - # We assume admin is passing domain id - dom = opcloud.get_domain(domain)['id'] - domain = dom - except Exception: - # If we fail, maybe admin is passing a domain name. - # Note that domains have unique names, just like id. - dom = opcloud.search_domains(filters={'name': domain}) - if dom: - domain = dom[0]['id'] - else: - module.fail_json(msg='Domain name or ID does not exist') - - if not filters: - filters = {} - - groups = opcloud.search_groups(name, filters, domain_id=domain) - module.exit_json(changed=False, groups=groups) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_image.py b/lib/ansible/modules/cloud/openstack/os_image.py deleted file mode 100644 index fc272a9fdf..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_image.py +++ /dev/null @@ -1,235 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -# TODO(mordred): we need to support "location"(v1) and "locations"(v2) - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_image -short_description: Add/Delete images from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Add or Remove images from the OpenStack Image Repository -options: - name: - description: - - The name of the image when uploading - or the name/ID of the image if deleting - required: true - id: - version_added: "2.4" - description: - - The ID of the image when uploading an image - checksum: - version_added: "2.5" - description: - - The checksum of the image - disk_format: - description: - - The format of the disk that is getting uploaded - default: qcow2 - container_format: - description: - - The format of the container - default: bare - owner: - description: - - The owner of the image - min_disk: - description: - - The minimum disk space (in GB) required to boot this image - min_ram: - description: - - The minimum ram (in MB) required to boot this image - is_public: - description: - - Whether the image can be accessed publicly. Note that publicizing an image requires admin role by default. - type: bool - default: 'yes' - protected: - version_added: "2.9" - description: - - Prevent image from being deleted - type: bool - default: 'no' - filename: - description: - - The path to the file which has to be uploaded - ramdisk: - description: - - The name of an existing ramdisk image that will be associated with this image - kernel: - description: - - The name of an existing kernel image that will be associated with this image - properties: - description: - - Additional properties to be associated with this image - default: {} - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility - volume: - version_added: "2.10" - description: - - ID of a volume to create an image from. - - The volume must be in AVAILABLE state. -requirements: ["openstacksdk"] -''' - -EXAMPLES = ''' -# Upload an image from a local file named cirros-0.3.0-x86_64-disk.img -- os_image: - auth: - auth_url: https://identity.example.com - username: admin - password: passme - project_name: admin - os_user_domain_name: Default - os_project_domain_name: Default - name: cirros - container_format: bare - disk_format: qcow2 - state: present - filename: cirros-0.3.0-x86_64-disk.img - kernel: cirros-vmlinuz - ramdisk: cirros-initrd - properties: - cpu_arch: x86_64 - distro: ubuntu - -# Create image from volume attached to an instance -- name: create volume snapshot - os_volume_snapshot: - auth: - "{{ auth }}" - display_name: myvol_snapshot - volume: myvol - force: yes - register: myvol_snapshot - -- name: create volume from snapshot - os_volume: - auth: - "{{ auth }}" - size: "{{ myvol_snapshot.snapshot.size }}" - snapshot_id: "{{ myvol_snapshot.snapshot.id }}" - display_name: myvol_snapshot_volume - wait: yes - register: myvol_snapshot_volume - -- name: create image from volume snapshot - os_image: - auth: - "{{ auth }}" - volume: "{{ myvol_snapshot_volume.volume.id }}" - name: myvol_image -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - id=dict(default=None), - checksum=dict(default=None), - disk_format=dict(default='qcow2', choices=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']), - container_format=dict(default='bare', choices=['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']), - owner=dict(default=None), - min_disk=dict(type='int', default=0), - min_ram=dict(type='int', default=0), - is_public=dict(type='bool', default=False), - protected=dict(type='bool', default=False), - filename=dict(default=None), - ramdisk=dict(default=None), - kernel=dict(default=None), - properties=dict(type='dict', default={}), - volume=dict(default=None), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[['filename', 'volume']], - ) - module = AnsibleModule(argument_spec, **module_kwargs) - - sdk, cloud = openstack_cloud_from_module(module) - try: - - changed = False - if module.params['id']: - image = cloud.get_image(name_or_id=module.params['id']) - elif module.params['checksum']: - image = cloud.get_image(name_or_id=module.params['name'], filters={'checksum': module.params['checksum']}) - else: - image = cloud.get_image(name_or_id=module.params['name']) - - if module.params['state'] == 'present': - if not image: - kwargs = {} - if module.params['id'] is not None: - kwargs['id'] = module.params['id'] - image = cloud.create_image( - name=module.params['name'], - filename=module.params['filename'], - disk_format=module.params['disk_format'], - container_format=module.params['container_format'], - wait=module.params['wait'], - timeout=module.params['timeout'], - is_public=module.params['is_public'], - protected=module.params['protected'], - min_disk=module.params['min_disk'], - min_ram=module.params['min_ram'], - volume=module.params['volume'], - **kwargs - ) - changed = True - if not module.params['wait']: - module.exit_json(changed=changed, image=image, id=image.id) - - cloud.update_image_properties( - image=image, - kernel=module.params['kernel'], - ramdisk=module.params['ramdisk'], - protected=module.params['protected'], - **module.params['properties']) - image = cloud.get_image(name_or_id=image.id) - module.exit_json(changed=changed, image=image, id=image.id) - - elif module.params['state'] == 'absent': - if not image: - changed = False - else: - cloud.delete_image( - name_or_id=module.params['name'], - wait=module.params['wait'], - timeout=module.params['timeout']) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_image_info.py b/lib/ansible/modules/cloud/openstack/os_image_info.py deleted file mode 100644 index 7ae55dd15e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_image_info.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' -module: os_image_info -short_description: Retrieve information about an image within OpenStack. -version_added: "2.0" -author: "Davide Agnello (@dagnello)" -description: - - Retrieve information about a image image from OpenStack. - - This module was called C(os_image_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_image_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - image: - description: - - Name or ID of the image - required: false - properties: - description: - - Dict of properties of the images used for query - type: dict - required: false - version_added: '2.9' - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -- name: Gather information about a previously created image named image1 - os_image_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - image: image1 - register: result - -- name: Show openstack information - debug: - msg: "{{ result.openstack_image }}" - -# Show all available Openstack images -- name: Retrieve all available Openstack images - os_image_info: - register: result - -- name: Show images - debug: - msg: "{{ result.openstack_image }}" - -# Show images matching requested properties -- name: Retrieve images having properties with desired values - os_image_facts: - properties: - some_property: some_value - OtherProp: OtherVal - -- name: Show images - debug: - msg: "{{ result.openstack_image }}" -''' - -RETURN = ''' -openstack_image: - description: has all the openstack information about the image - returned: always, but can be null - type: complex - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Name given to the image. - returned: success - type: str - status: - description: Image status. - returned: success - type: str - created_at: - description: Image created at timestamp. - returned: success - type: str - deleted: - description: Image deleted flag. - returned: success - type: bool - container_format: - description: Container format of the image. - returned: success - type: str - min_ram: - description: Min amount of RAM required for this image. - returned: success - type: int - disk_format: - description: Disk format of the image. - returned: success - type: str - updated_at: - description: Image updated at timestamp. - returned: success - type: str - properties: - description: Additional properties associated with the image. - returned: success - type: dict - min_disk: - description: Min amount of disk space required for this image. - returned: success - type: int - protected: - description: Image protected flag. - returned: success - type: bool - checksum: - description: Checksum for the image. - returned: success - type: str - owner: - description: Owner for the image. - returned: success - type: str - is_public: - description: Is public flag of the image. - returned: success - type: bool - deleted_at: - description: Image deleted at timestamp. - returned: success - type: str - size: - description: Size of the image. - returned: success - type: int -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - image=dict(required=False), - properties=dict(default=None, type='dict'), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - is_old_facts = module._name == 'os_image_facts' - if is_old_facts: - module.deprecate("The 'os_image_facts' module has been renamed to 'os_image_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, cloud = openstack_cloud_from_module(module) - try: - if module.params['image']: - image = cloud.get_image(module.params['image']) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_image=image)) - else: - module.exit_json(changed=False, openstack_image=image) - else: - images = cloud.search_images(filters=module.params['properties']) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_image=images)) - else: - module.exit_json(changed=False, openstack_image=images) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_ironic.py b/lib/ansible/modules/cloud/openstack/os_ironic.py deleted file mode 100644 index 6a09afe2fa..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_ironic.py +++ /dev/null @@ -1,355 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# (c) 2014, Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_ironic -short_description: Create/Delete Bare Metal Resources from OpenStack -extends_documentation_fragment: openstack -author: "Monty Taylor (@emonty)" -version_added: "2.0" -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, and name is specified. - - Definition of a UUID will always take precedence to a name value. - name: - description: - - unique name identifier to be given to the resource. - driver: - description: - - The name of the Ironic Driver to use with this node. - required: true - chassis_uuid: - description: - - Associate the node with a pre-defined chassis. - 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_type" - settings set to 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. - suboptions: - power: - description: - - Information necessary to turn this server on / off. - This often includes such things as IPMI username, password, and IP address. - required: true - deploy: - description: - - Information necessary to deploy this server directly, without using Nova. THIS IS NOT RECOMMENDED. - console: - description: - - Information necessary to connect to this server's serial console. Not all drivers support this. - management: - description: - - 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 - suboptions: - 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 - capabilities: - description: - - special capabilities for the node, such as boot_option, node_role etc - (see U(https://docs.openstack.org/ironic/latest/install/advanced.html) - for more information) - default: "" - version_added: "2.8" - root_device: - description: - - Root disk device hints for deployment. - (see U(https://docs.openstack.org/ironic/latest/install/include/root-device-hints.html) - for allowed hints) - default: "" - version_added: "2.8" - skip_update_of_driver_password: - description: - - Allows the code that would assert changes to nodes to skip the - update if the change is a single line consisting of the password - field. As of Kilo, by default, passwords are always masked to API - requests, which means the logic as a result always attempts to - re-assert the password field. - type: bool - default: 'no' - availability_zone: - description: - - Ignored. Present for backwards compatibility - -requirements: ["openstacksdk", "jsonpatch"] -''' - -EXAMPLES = ''' -# Enroll a node with some basic properties and driver info -- os_ironic: - cloud: "devstack" - driver: "pxe_ipmitool" - uuid: "00000000-0000-0000-0000-000000000002" - properties: - cpus: 2 - cpu_arch: "x86_64" - ram: 8192 - disk_size: 64 - capabilities: "boot_option:local" - root_device: - wwn: "0x4000cca77fc4dba1" - 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" - chassis_uuid: "00000000-0000-0000-0000-000000000001" - -''' - -try: - import jsonpatch - HAS_JSONPATCH = True -except ImportError: - HAS_JSONPATCH = False - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -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, - capabilities=p.get('capabilities') if p.get('capabilities') else '', - root_device=p.get('root_device') if p.get('root_device') else '', - ) - return props - - -def _parse_driver_info(sdk, module): - p = module.params['driver_info'] - info = p.get('power') - if not info: - raise sdk.exceptions.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 _choose_id_value(module): - if module.params['uuid']: - return module.params['uuid'] - if module.params['name']: - return module.params['name'] - return None - - -def _choose_if_password_only(module, patch): - if len(patch) == 1: - if 'password' in patch[0]['path'] and module.params['skip_update_of_masked_password']: - # Return false to abort update as the password appears - # to be the only element in the patch. - return False - return True - - -def _exit_node_not_updated(module, server): - module.exit_json( - changed=False, - result="Node not updated", - uuid=server['uuid'], - provision_state=server['provision_state'] - ) - - -def main(): - argument_spec = openstack_full_argument_spec( - uuid=dict(required=False), - name=dict(required=False), - driver=dict(required=False), - driver_info=dict(type='dict', required=True), - nics=dict(type='list', required=True), - properties=dict(type='dict', default={}), - ironic_url=dict(required=False), - chassis_uuid=dict(required=False), - skip_update_of_masked_password=dict(required=False, type='bool'), - state=dict(required=False, default='present') - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - if not HAS_JSONPATCH: - module.fail_json(msg='jsonpatch is required for this module') - if (module.params['auth_type'] in [None, 'None'] and - module.params['ironic_url'] is None): - module.fail_json(msg="Authentication appears to be disabled, " - "Please define an ironic_url parameter") - - if (module.params['ironic_url'] and - module.params['auth_type'] in [None, 'None']): - module.params['auth'] = dict( - endpoint=module.params['ironic_url'] - ) - - node_id = _choose_id_value(module) - - sdk, cloud = openstack_cloud_from_module(module) - try: - server = cloud.get_machine(node_id) - if module.params['state'] == 'present': - if module.params['driver'] is None: - module.fail_json(msg="A driver must be defined in order " - "to set a node to present.") - - properties = _parse_properties(module) - driver_info = _parse_driver_info(sdk, module) - kwargs = dict( - driver=module.params['driver'], - properties=properties, - driver_info=driver_info, - name=module.params['name'], - ) - - if module.params['chassis_uuid']: - kwargs['chassis_uuid'] = module.params['chassis_uuid'] - - if server is None: - # Note(TheJulia): Add a specific UUID to the request if - # present in order to be able to re-use kwargs for if - # the node already exists logic, since uuid cannot be - # updated. - if module.params['uuid']: - kwargs['uuid'] = module.params['uuid'] - - server = cloud.register_machine(module.params['nics'], - **kwargs) - module.exit_json(changed=True, uuid=server['uuid'], - provision_state=server['provision_state']) - else: - # TODO(TheJulia): Presently this does not support updating - # nics. Support needs to be added. - # - # Note(TheJulia): This message should never get logged - # however we cannot realistically proceed if neither a - # name or uuid was supplied to begin with. - if not node_id: - module.fail_json(msg="A uuid or name value " - "must be defined") - - # Note(TheJulia): Constructing the configuration to compare - # against. The items listed in the server_config block can - # be updated via the API. - - server_config = dict( - driver=server['driver'], - properties=server['properties'], - driver_info=server['driver_info'], - name=server['name'], - ) - - # Add the pre-existing chassis_uuid only if - # it is present in the server configuration. - if hasattr(server, 'chassis_uuid'): - server_config['chassis_uuid'] = server['chassis_uuid'] - - # Note(TheJulia): If a password is defined and concealed, a - # patch will always be generated and re-asserted. - patch = jsonpatch.JsonPatch.from_diff(server_config, kwargs) - - if not patch: - _exit_node_not_updated(module, server) - elif _choose_if_password_only(module, list(patch)): - # Note(TheJulia): Normally we would allow the general - # exception catch below, however this allows a specific - # message. - try: - server = cloud.patch_machine( - server['uuid'], - list(patch)) - except Exception as e: - module.fail_json(msg="Failed to update node, " - "Error: %s" % e.message) - - # Enumerate out a list of changed paths. - change_list = [] - for change in list(patch): - change_list.append(change['path']) - module.exit_json(changed=True, - result="Node Updated", - changes=change_list, - uuid=server['uuid'], - provision_state=server['provision_state']) - - # Return not updated by default as the conditions were not met - # to update. - _exit_node_not_updated(module, server) - - if module.params['state'] == 'absent': - if not node_id: - module.fail_json(msg="A uuid or name value must be defined " - "in order to remove a node.") - - if server is not None: - cloud.unregister_machine(module.params['nics'], - server['uuid']) - module.exit_json(changed=True, result="deleted") - else: - module.exit_json(changed=False, result="Server not found") - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_ironic_inspect.py b/lib/ansible/modules/cloud/openstack/os_ironic_inspect.py deleted file mode 100644 index 2ebb8eebbd..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_ironic_inspect.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# (c) 2015-2016, Hewlett Packard Enterprise Development Company LP -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_ironic_inspect -short_description: Explicitly triggers baremetal node introspection in ironic. -extends_documentation_fragment: openstack -author: "Julia Kreger (@juliakreger)" -version_added: "2.1" -description: - - Requests Ironic to set a node into inspect state in order to collect metadata regarding the node. - This command may be out of band or in-band depending on the ironic driver configuration. - This is only possible on nodes in 'manageable' and 'available' state. -options: - mac: - description: - - unique mac address that is used to attempt to identify the host. - uuid: - description: - - globally unique identifier (UUID) to identify the host. - name: - description: - - unique name identifier to identify the host in Ironic. - 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_type" settings set to None. - timeout: - description: - - A timeout in seconds to tell the role to wait for the node to complete introspection if wait is set to True. - default: 1200 - availability_zone: - description: - - Ignored. Present for backwards compatibility - -requirements: ["openstacksdk"] -''' - -RETURN = ''' -ansible_facts: - description: Dictionary of new facts representing discovered properties of the node.. - returned: changed - type: complex - contains: - memory_mb: - description: Amount of node memory as updated in the node properties - type: str - sample: "1024" - cpu_arch: - description: Detected CPU architecture type - type: str - sample: "x86_64" - local_gb: - description: Total size of local disk storage as updated in node properties. - type: str - sample: "10" - cpus: - description: Count of cpu cores defined in the updated node properties. - type: str - sample: "1" -''' - -EXAMPLES = ''' -# Invoke node inspection -- os_ironic_inspect: - name: "testnode1" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _choose_id_value(module): - if module.params['uuid']: - return module.params['uuid'] - if module.params['name']: - return module.params['name'] - return None - - -def main(): - argument_spec = openstack_full_argument_spec( - auth_type=dict(required=False), - uuid=dict(required=False), - name=dict(required=False), - mac=dict(required=False), - ironic_url=dict(required=False), - timeout=dict(default=1200, type='int', required=False), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - if (module.params['auth_type'] in [None, 'None'] and - module.params['ironic_url'] is None): - module.fail_json(msg="Authentication appears to be disabled, " - "Please define an ironic_url parameter") - - if (module.params['ironic_url'] and - module.params['auth_type'] in [None, 'None']): - module.params['auth'] = dict( - endpoint=module.params['ironic_url'] - ) - - sdk, cloud = openstack_cloud_from_module(module) - try: - if module.params['name'] or module.params['uuid']: - server = cloud.get_machine(_choose_id_value(module)) - elif module.params['mac']: - server = cloud.get_machine_by_mac(module.params['mac']) - else: - module.fail_json(msg="The worlds did not align, " - "the host was not found as " - "no name, uuid, or mac was " - "defined.") - if server: - cloud.inspect_machine(server['uuid'], module.params['wait']) - # TODO(TheJulia): diff properties, ?and ports? and determine - # if a change occurred. In theory, the node is always changed - # if introspection is able to update the record. - module.exit_json(changed=True, - ansible_facts=server['properties']) - - else: - module.fail_json(msg="node not found.") - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_ironic_node.py b/lib/ansible/modules/cloud/openstack/os_ironic_node.py deleted file mode 100644 index 78abb0592d..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_ironic_node.py +++ /dev/null @@ -1,333 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# (c) 2015, Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_ironic_node -short_description: Activate/Deactivate Bare Metal Resources from OpenStack -author: "Monty Taylor (@emonty)" -extends_documentation_fragment: openstack -version_added: "2.0" -description: - - Deploy to nodes controlled by Ironic. -options: - state: - description: - - Indicates desired state of the resource - choices: ['present', 'absent'] - default: present - deploy: - description: - - Indicates if the resource should be deployed. Allows for deployment - logic to be disengaged and control of the node power or maintenance - state to be changed. - type: bool - default: 'yes' - uuid: - description: - - globally unique identifier (UUID) to be given to the resource. - 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_type" - settings set to None. - config_drive: - description: - - A configdrive file or HTTP(S) URL that will be passed along to the - node. - instance_info: - description: - - Definition of the instance information which is used to deploy - the node. This information is only required when an instance is - set to present. - suboptions: - image_source: - description: - - An HTTP(S) URL where the image can be retrieved from. - image_checksum: - description: - - The checksum of image_source. - image_disk_format: - description: - - The type of image that has been requested to be deployed. - power: - description: - - A setting to allow power state to be asserted allowing nodes - that are not yet deployed to be powered on, and nodes that - are deployed to be powered off. - choices: ['present', 'absent'] - default: present - maintenance: - description: - - A setting to allow the direct control if a node is in - maintenance mode. - type: bool - default: 'no' - maintenance_reason: - description: - - A string expression regarding the reason a node is in a - maintenance mode. - wait: - description: - - A boolean value instructing the module to wait for node - activation or deactivation to complete before returning. - type: bool - default: 'no' - version_added: "2.1" - timeout: - description: - - An integer value representing the number of seconds to - wait for the node activation or deactivation to complete. - version_added: "2.1" - availability_zone: - description: - - Ignored. Present for backwards compatibility -''' - -EXAMPLES = ''' -# Activate a node by booting an image with a configdrive attached -os_ironic_node: - cloud: "openstack" - uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69" - state: present - power: present - deploy: True - maintenance: False - config_drive: "http://192.168.1.1/host-configdrive.iso" - instance_info: - image_source: "http://192.168.1.1/deploy_image.img" - image_checksum: "356a6b55ecc511a20c33c946c4e678af" - image_disk_format: "qcow" - delegate_to: localhost -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _choose_id_value(module): - if module.params['uuid']: - return module.params['uuid'] - if module.params['name']: - return module.params['name'] - return None - - -def _is_true(value): - true_values = [True, 'yes', 'Yes', 'True', 'true', 'present', 'on'] - if value in true_values: - return True - return False - - -def _is_false(value): - false_values = [False, None, 'no', 'No', 'False', 'false', 'absent', 'off'] - if value in false_values: - return True - return False - - -def _check_set_maintenance(module, cloud, node): - if _is_true(module.params['maintenance']): - if _is_false(node['maintenance']): - cloud.set_machine_maintenance_state( - node['uuid'], - True, - reason=module.params['maintenance_reason']) - module.exit_json(changed=True, msg="Node has been set into " - "maintenance mode") - else: - # User has requested maintenance state, node is already in the - # desired state, checking to see if the reason has changed. - if (str(node['maintenance_reason']) not in - str(module.params['maintenance_reason'])): - cloud.set_machine_maintenance_state( - node['uuid'], - True, - reason=module.params['maintenance_reason']) - module.exit_json(changed=True, msg="Node maintenance reason " - "updated, cannot take any " - "additional action.") - elif _is_false(module.params['maintenance']): - if node['maintenance'] is True: - cloud.remove_machine_from_maintenance(node['uuid']) - return True - else: - module.fail_json(msg="maintenance parameter was set but a valid " - "the value was not recognized.") - return False - - -def _check_set_power_state(module, cloud, node): - if 'power on' in str(node['power_state']): - if _is_false(module.params['power']): - # User has requested the node be powered off. - cloud.set_machine_power_off(node['uuid']) - module.exit_json(changed=True, msg="Power requested off") - if 'power off' in str(node['power_state']): - if (_is_false(module.params['power']) and - _is_false(module.params['state'])): - return False - if (_is_false(module.params['power']) and - _is_false(module.params['state'])): - module.exit_json( - changed=False, - msg="Power for node is %s, node must be reactivated " - "OR set to state absent" - ) - # In the event the power has been toggled on and - # deployment has been requested, we need to skip this - # step. - if (_is_true(module.params['power']) and - _is_false(module.params['deploy'])): - # Node is powered down when it is not awaiting to be provisioned - cloud.set_machine_power_on(node['uuid']) - return True - # Default False if no action has been taken. - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - uuid=dict(required=False), - name=dict(required=False), - instance_info=dict(type='dict', required=False), - config_drive=dict(required=False), - ironic_url=dict(required=False), - state=dict(required=False, default='present'), - maintenance=dict(required=False), - maintenance_reason=dict(required=False), - power=dict(required=False, default='present'), - deploy=dict(required=False, default=True), - wait=dict(type='bool', required=False, default=False), - timeout=dict(required=False, type='int', default=1800), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - if (module.params['auth_type'] in [None, '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_type'] in [None, 'None']): - module.params['auth'] = dict( - endpoint=module.params['ironic_url'] - ) - - node_id = _choose_id_value(module) - - if not node_id: - module.fail_json(msg="A uuid or name value must be defined " - "to use this module.") - sdk, cloud = openstack_cloud_from_module(module) - try: - node = cloud.get_machine(node_id) - - if node is None: - module.fail_json(msg="node not found") - - uuid = node['uuid'] - instance_info = module.params['instance_info'] - changed = False - wait = module.params['wait'] - timeout = module.params['timeout'] - - # User has requested desired state to be in maintenance state. - if module.params['state'] == 'maintenance': - module.params['maintenance'] = True - - if node['provision_state'] in [ - 'cleaning', - 'deleting', - 'wait call-back']: - module.fail_json(msg="Node is in %s state, cannot act upon the " - "request as the node is in a transition " - "state" % node['provision_state']) - # TODO(TheJulia) This is in-development code, that requires - # code in the shade library that is still in development. - if _check_set_maintenance(module, cloud, node): - if node['provision_state'] in 'active': - module.exit_json(changed=True, - result="Maintenance state changed") - changed = True - node = cloud.get_machine(node_id) - - if _check_set_power_state(module, cloud, node): - changed = True - node = cloud.get_machine(node_id) - - if _is_true(module.params['state']): - if _is_false(module.params['deploy']): - module.exit_json( - changed=changed, - result="User request has explicitly disabled " - "deployment logic" - ) - - if 'active' in node['provision_state']: - module.exit_json( - changed=changed, - result="Node already in an active state." - ) - - if instance_info is None: - module.fail_json( - changed=changed, - msg="When setting an instance to present, " - "instance_info is a required variable.") - - # TODO(TheJulia): Update instance info, however info is - # deployment specific. Perhaps consider adding rebuild - # support, although there is a known desire to remove - # rebuild support from Ironic at some point in the future. - cloud.update_machine(uuid, instance_info=instance_info) - cloud.validate_node(uuid) - if not wait: - cloud.activate_node(uuid, module.params['config_drive']) - else: - cloud.activate_node( - uuid, - configdrive=module.params['config_drive'], - wait=wait, - timeout=timeout) - # TODO(TheJulia): Add more error checking.. - module.exit_json(changed=changed, result="node activated") - - elif _is_false(module.params['state']): - if node['provision_state'] not in "deleted": - cloud.update_machine(uuid, instance_info={}) - if not wait: - cloud.deactivate_node(uuid) - else: - cloud.deactivate_node( - uuid, - wait=wait, - timeout=timeout) - - module.exit_json(changed=True, result="deleted") - else: - module.exit_json(changed=False, result="node not found") - else: - module.fail_json(msg="State must be present, absent, " - "maintenance, off") - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_keypair.py b/lib/ansible/modules/cloud/openstack/os_keypair.py deleted file mode 100644 index 85a0fdf0a0..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_keypair.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# Copyright (c) 2013, John Dewey <john@dewey.ws> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_keypair -short_description: Add/Delete a keypair from OpenStack -author: "Benno Joy (@bennojoy)" -extends_documentation_fragment: openstack -version_added: "2.0" -description: - - Add or Remove key pair from OpenStack -options: - name: - description: - - Name that has to be given to the key pair - required: true - public_key: - description: - - The public key that would be uploaded to nova and injected into VMs - upon creation. - public_key_file: - description: - - Path to local file containing ssh public key. Mutually exclusive - with public_key. - state: - description: - - Should the resource be present or absent. If state is replace and - the key exists but has different content, delete it and recreate it - with the new content. - choices: [present, absent, replace] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -''' - -EXAMPLES = ''' -# Creates a key pair with the running users public key -- os_keypair: - cloud: mordred - state: present - name: ansible_key - public_key_file: /home/me/.ssh/id_rsa.pub - -# Creates a new key pair and the private key returned after the run. -- os_keypair: - cloud: rax-dfw - state: present - name: ansible_key -''' - -RETURN = ''' -id: - description: Unique UUID. - returned: success - type: str -name: - description: Name given to the keypair. - returned: success - type: str -public_key: - description: The public key value for the keypair. - returned: success - type: str -private_key: - description: The private key value for the keypair. - returned: Only when a keypair is generated for the user (e.g., when creating one - and a public key is not specified). - type: str -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(module, keypair): - state = module.params['state'] - if state == 'present' and not keypair: - return True - if state == 'absent' and keypair: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - public_key=dict(default=None), - public_key_file=dict(default=None), - state=dict(default='present', - choices=['absent', 'present', 'replace']), - ) - - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[['public_key', 'public_key_file']]) - - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - name = module.params['name'] - public_key = module.params['public_key'] - - if module.params['public_key_file']: - with open(module.params['public_key_file']) as public_key_fh: - public_key = public_key_fh.read().rstrip() - - sdk, cloud = openstack_cloud_from_module(module) - try: - keypair = cloud.get_keypair(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, keypair)) - - if state in ('present', 'replace'): - if keypair and keypair['name'] == name: - if public_key and (public_key != keypair['public_key']): - if state == 'present': - module.fail_json( - msg="Key name %s present but key hash not the same" - " as offered. Delete key first." % name - ) - else: - cloud.delete_keypair(name) - keypair = cloud.create_keypair(name, public_key) - changed = True - else: - changed = False - else: - keypair = cloud.create_keypair(name, public_key) - changed = True - - module.exit_json(changed=changed, - key=keypair, - id=keypair['id']) - - elif state == 'absent': - if keypair: - cloud.delete_keypair(name) - module.exit_json(changed=True) - module.exit_json(changed=False) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_keystone_domain.py b/lib/ansible/modules/cloud/openstack/os_keystone_domain.py deleted file mode 100644 index 2cf4920100..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_keystone_domain.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_keystone_domain -short_description: Manage OpenStack Identity Domains -author: - - Monty Taylor (@emonty) - - Haneef Ali (@haneefs) -extends_documentation_fragment: openstack -version_added: "2.1" -description: - - Create, update, or delete OpenStack Identity domains. If a domain - with the supplied name already exists, it will be updated with the - new description and enabled attributes. -options: - name: - description: - - Name that has to be given to the instance - required: true - description: - description: - - Description of the domain - enabled: - description: - - Is the domain enabled - type: bool - default: 'yes' - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a domain -- os_keystone_domain: - cloud: mycloud - state: present - name: demo - description: Demo Domain - -# Delete a domain -- os_keystone_domain: - cloud: mycloud - state: absent - name: demo -''' - -RETURN = ''' -domain: - description: Dictionary describing the domain. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Domain ID. - type: str - sample: "474acfe5-be34-494c-b339-50f06aa143e4" - name: - description: Domain name. - type: str - sample: "demo" - description: - description: Domain description. - type: str - sample: "Demo Domain" - enabled: - description: Domain description. - type: bool - sample: True - -id: - description: The domain ID. - returned: On success when I(state) is 'present' - type: str - sample: "474acfe5-be34-494c-b339-50f06aa143e4" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, domain): - if module.params['description'] is not None and \ - domain.description != module.params['description']: - return True - if domain.enabled != module.params['enabled']: - return True - return False - - -def _system_state_change(module, domain): - state = module.params['state'] - if state == 'absent' and domain: - return True - - if state == 'present': - if domain is None: - return True - return _needs_update(module, domain) - - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - description=dict(default=None), - enabled=dict(default=True, type='bool'), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - name = module.params['name'] - description = module.params['description'] - enabled = module.params['enabled'] - state = module.params['state'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - - domains = cloud.search_domains(filters=dict(name=name)) - - if len(domains) > 1: - module.fail_json(msg='Domain name %s is not unique' % name) - elif len(domains) == 1: - domain = domains[0] - else: - domain = None - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, domain)) - - if state == 'present': - if domain is None: - domain = cloud.create_domain( - name=name, description=description, enabled=enabled) - changed = True - else: - if _needs_update(module, domain): - domain = cloud.update_domain( - domain.id, name=name, description=description, - enabled=enabled) - changed = True - else: - changed = False - module.exit_json(changed=changed, domain=domain, id=domain.id) - - elif state == 'absent': - if domain is None: - changed = False - else: - cloud.delete_domain(domain.id) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_keystone_domain_info.py b/lib/ansible/modules/cloud/openstack/os_keystone_domain_info.py deleted file mode 100644 index 919b301ab5..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_keystone_domain_info.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 Hewlett-Packard Enterprise Corporation -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_keystone_domain_info -short_description: Retrieve information about one or more OpenStack domains -extends_documentation_fragment: openstack -version_added: "2.1" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -description: - - Retrieve information about a one or more OpenStack domains - - This module was called C(os_keystone_domain_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_keystone_domain_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "sdk" -options: - name: - description: - - Name or ID of the domain - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - availability_zone: - description: - - Ignored. Present for backwards compatibility -''' - -EXAMPLES = ''' -# Gather information about previously created domain -- os_keystone_domain_info: - cloud: awesomecloud - register: result -- debug: - msg: "{{ result.openstack_domains }}" - -# Gather information about a previously created domain by name -- os_keystone_domain_info: - cloud: awesomecloud - name: demodomain - register: result -- debug: - msg: "{{ result.openstack_domains }}" - -# Gather information about a previously created domain with filter -- os_keystone_domain_info: - cloud: awesomecloud - name: demodomain - filters: - enabled: false - register: result -- debug: - msg: "{{ result.openstack_domains }}" -''' - - -RETURN = ''' -openstack_domains: - description: has all the OpenStack information about domains - returned: always, but can be null - type: complex - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Name given to the domain. - returned: success - type: str - description: - description: Description of the domain. - returned: success - type: str - enabled: - description: Flag to indicate if the domain is enabled. - returned: success - type: bool -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - filters=dict(required=False, type='dict', default=None), - ) - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[ - ['name', 'filters'], - ] - ) - module = AnsibleModule(argument_spec, **module_kwargs) - is_old_facts = module._name == 'os_keystone_domain_facts' - if is_old_facts: - module.deprecate("The 'os_keystone_domain_facts' module has been renamed to 'os_keystone_domain_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, opcloud = openstack_cloud_from_module(module) - try: - name = module.params['name'] - filters = module.params['filters'] - - if name: - # Let's suppose user is passing domain ID - try: - domains = opcloud.get_domain(name) - except Exception: - domains = opcloud.search_domains(filters={'name': name}) - - else: - domains = opcloud.search_domains(filters) - - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_domains=domains)) - else: - module.exit_json(changed=False, openstack_domains=domains) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_keystone_endpoint.py b/lib/ansible/modules/cloud/openstack/os_keystone_endpoint.py deleted file mode 100644 index 9705990838..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_keystone_endpoint.py +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/python - -# Copyright: (c) 2017, VEXXHOST, Inc. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_keystone_endpoint -short_description: Manage OpenStack Identity service endpoints -extends_documentation_fragment: openstack -author: - - Mohammed Naser (@mnaser) - - Alberto Murillo (@albertomurillo) -version_added: "2.5" -description: - - Create, update, or delete OpenStack Identity service endpoints. If a - service with the same combination of I(service), I(interface) and I(region) - exist, the I(url) and I(state) (C(present) or C(absent)) will be updated. -options: - service: - description: - - Name or id of the service. - required: true - endpoint_interface: - description: - - Interface of the service. - choices: [admin, public, internal] - required: true - url: - description: - - URL of the service. - required: true - region: - description: - - Region that the service belongs to. Note that I(region_name) is used for authentication. - enabled: - description: - - Is the service enabled. - default: True - type: bool - state: - description: - - Should the resource be C(present) or C(absent). - choices: [present, absent] - default: present -requirements: - - openstacksdk >= 0.13.0 -''' - -EXAMPLES = ''' -- name: Create a service for glance - os_keystone_endpoint: - cloud: mycloud - service: glance - endpoint_interface: public - url: http://controller:9292 - region: RegionOne - state: present - -- name: Delete a service for nova - os_keystone_endpoint: - cloud: mycloud - service: nova - endpoint_interface: public - region: RegionOne - state: absent -''' - -RETURN = ''' -endpoint: - description: Dictionary describing the endpoint. - returned: On success when I(state) is C(present) - type: complex - contains: - id: - description: Endpoint ID. - type: str - sample: 3292f020780b4d5baf27ff7e1d224c44 - region: - description: Region Name. - type: str - sample: RegionOne - service_id: - description: Service ID. - type: str - sample: b91f1318f735494a825a55388ee118f3 - interface: - description: Endpoint Interface. - type: str - sample: public - url: - description: Service URL. - type: str - sample: http://controller:9292 - enabled: - description: Service status. - type: bool - sample: True -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, endpoint): - if endpoint.enabled != module.params['enabled']: - return True - if endpoint.url != module.params['url']: - return True - return False - - -def _system_state_change(module, endpoint): - state = module.params['state'] - if state == 'absent' and endpoint: - return True - - if state == 'present': - if endpoint is None: - return True - return _needs_update(module, endpoint) - - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - service=dict(type='str', required=True), - endpoint_interface=dict(type='str', required=True, choices=['admin', 'public', 'internal']), - url=dict(type='str', required=True), - region=dict(type='str'), - enabled=dict(type='bool', default=True), - state=dict(type='str', default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - service_name_or_id = module.params['service'] - interface = module.params['endpoint_interface'] - url = module.params['url'] - region = module.params['region'] - enabled = module.params['enabled'] - state = module.params['state'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - - service = cloud.get_service(service_name_or_id) - if service is None: - module.fail_json(msg='Service %s does not exist' % service_name_or_id) - - filters = dict(service_id=service.id, interface=interface) - if region is not None: - filters['region'] = region - endpoints = cloud.search_endpoints(filters=filters) - - if len(endpoints) > 1: - module.fail_json(msg='Service %s, interface %s and region %s are ' - 'not unique' % - (service_name_or_id, interface, region)) - elif len(endpoints) == 1: - endpoint = endpoints[0] - else: - endpoint = None - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, endpoint)) - - if state == 'present': - if endpoint is None: - result = cloud.create_endpoint(service_name_or_id=service, - url=url, interface=interface, - region=region, enabled=enabled) - endpoint = result[0] - changed = True - else: - if _needs_update(module, endpoint): - endpoint = cloud.update_endpoint( - endpoint.id, url=url, enabled=enabled) - changed = True - else: - changed = False - module.exit_json(changed=changed, endpoint=endpoint) - - elif state == 'absent': - if endpoint is None: - changed = False - else: - cloud.delete_endpoint(endpoint.id) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_keystone_role.py b/lib/ansible/modules/cloud/openstack/os_keystone_role.py deleted file mode 100644 index e3a752706e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_keystone_role.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 IBM -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_keystone_role -short_description: Manage OpenStack Identity Roles -extends_documentation_fragment: openstack -version_added: "2.1" -author: - - Monty Taylor (@emonty) - - David Shrewsbury (@Shrews) -description: - - Manage OpenStack Identity Roles. -options: - name: - description: - - Role Name - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a role named "demo" -- os_keystone_role: - cloud: mycloud - state: present - name: demo - -# Delete the role named "demo" -- os_keystone_role: - cloud: mycloud - state: absent - name: demo -''' - -RETURN = ''' -role: - description: Dictionary describing the role. - returned: On success when I(state) is 'present'. - type: complex - contains: - id: - description: Unique role ID. - type: str - sample: "677bfab34c844a01b88a217aa12ec4c2" - name: - description: Role name. - type: str - sample: "demo" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, role): - if state == 'present' and not role: - return True - if state == 'absent' and role: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - name = module.params.get('name') - state = module.params.get('state') - - sdk, cloud = openstack_cloud_from_module(module) - try: - role = cloud.get_role(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, role)) - - if state == 'present': - if role is None: - role = cloud.create_role(name) - changed = True - else: - changed = False - module.exit_json(changed=changed, role=role) - elif state == 'absent': - if role is None: - changed = False - else: - cloud.delete_role(name) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_keystone_service.py b/lib/ansible/modules/cloud/openstack/os_keystone_service.py deleted file mode 100644 index cd11e4ceca..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_keystone_service.py +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/python -# Copyright 2016 Sam Yaple -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_keystone_service -short_description: Manage OpenStack Identity services -extends_documentation_fragment: openstack -author: "Sam Yaple (@SamYaple)" -version_added: "2.2" -description: - - Create, update, or delete OpenStack Identity service. If a service - with the supplied name already exists, it will be updated with the - new description and enabled attributes. -options: - name: - description: - - Name of the service - required: true - description: - description: - - Description of the service - enabled: - description: - - Is the service enabled - type: bool - default: 'yes' - service_type: - description: - - The type of service - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a service for glance -- os_keystone_service: - cloud: mycloud - state: present - name: glance - service_type: image - description: OpenStack Image Service -# Delete a service -- os_keystone_service: - cloud: mycloud - state: absent - name: glance - service_type: image -''' - -RETURN = ''' -service: - description: Dictionary describing the service. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Service ID. - type: str - sample: "3292f020780b4d5baf27ff7e1d224c44" - name: - description: Service name. - type: str - sample: "glance" - service_type: - description: Service type. - type: str - sample: "image" - description: - description: Service description. - type: str - sample: "OpenStack Image Service" - enabled: - description: Service status. - type: bool - sample: True -id: - description: The service ID. - returned: On success when I(state) is 'present' - type: str - sample: "3292f020780b4d5baf27ff7e1d224c44" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, service): - if service.enabled != module.params['enabled']: - return True - if service.description is not None and \ - service.description != module.params['description']: - return True - return False - - -def _system_state_change(module, service): - state = module.params['state'] - if state == 'absent' and service: - return True - - if state == 'present': - if service is None: - return True - return _needs_update(module, service) - - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - description=dict(default=None), - enabled=dict(default=True, type='bool'), - name=dict(required=True), - service_type=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - description = module.params['description'] - enabled = module.params['enabled'] - name = module.params['name'] - state = module.params['state'] - service_type = module.params['service_type'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - services = cloud.search_services(name_or_id=name, - filters=dict(type=service_type)) - - if len(services) > 1: - module.fail_json(msg='Service name %s and type %s are not unique' % - (name, service_type)) - elif len(services) == 1: - service = services[0] - else: - service = None - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, service)) - - if state == 'present': - if service is None: - service = cloud.create_service(name=name, description=description, - type=service_type, enabled=True) - changed = True - else: - if _needs_update(module, service): - service = cloud.update_service( - service.id, name=name, type=service_type, enabled=enabled, - description=description) - changed = True - else: - changed = False - module.exit_json(changed=changed, service=service, id=service.id) - - elif state == 'absent': - if service is None: - changed = False - else: - cloud.delete_service(service.id) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_listener.py b/lib/ansible/modules/cloud/openstack/os_listener.py deleted file mode 100644 index 6d29f55e9f..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_listener.py +++ /dev/null @@ -1,256 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2018 Catalyst Cloud Ltd. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_listener -short_description: Add/Delete a listener for a load balancer from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.7" -author: "Lingxian Kong (@lingxiankong)" -description: - - Add or Remove a listener for a load balancer from the OpenStack load-balancer service. -options: - name: - description: - - Name that has to be given to the listener - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - loadbalancer: - description: - - The name or id of the load balancer that this listener belongs to. - required: true - protocol: - description: - - The protocol for the listener. - choices: [HTTP, HTTPS, TCP, TERMINATED_HTTPS] - default: HTTP - protocol_port: - description: - - The protocol port number for the listener. - default: 80 - wait: - description: - - If the module should wait for the load balancer to be ACTIVE. - type: bool - default: 'yes' - timeout: - description: - - The amount of time the module should wait for the load balancer to get - into ACTIVE state. - default: 180 - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -RETURN = ''' -id: - description: The listener UUID. - returned: On success when I(state) is 'present' - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" -listener: - description: Dictionary describing the listener. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Unique UUID. - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" - name: - description: Name given to the listener. - type: str - sample: "test" - description: - description: The listener description. - type: str - sample: "description" - load_balancer_id: - description: The load balancer UUID this listener belongs to. - type: str - sample: "b32eef7e-d2a6-4ea4-a301-60a873f89b3b" - loadbalancers: - description: A list of load balancer IDs.. - type: list - sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] - provisioning_status: - description: The provisioning status of the listener. - type: str - sample: "ACTIVE" - operating_status: - description: The operating status of the listener. - type: str - sample: "ONLINE" - is_admin_state_up: - description: The administrative state of the listener. - type: bool - sample: true - protocol: - description: The protocol for the listener. - type: str - sample: "HTTP" - protocol_port: - description: The protocol port number for the listener. - type: int - sample: 80 -''' - -EXAMPLES = ''' -# Create a listener, wait for the loadbalancer to be active. -- os_listener: - cloud: mycloud - endpoint_type: admin - state: present - name: test-listener - loadbalancer: test-loadbalancer - protocol: HTTP - protocol_port: 8080 - -# Create a listener, do not wait for the loadbalancer to be active. -- os_listener: - cloud: mycloud - endpoint_type: admin - state: present - name: test-listener - loadbalancer: test-loadbalancer - protocol: HTTP - protocol_port: 8080 - wait: no - -# Delete a listener -- os_listener: - cloud: mycloud - endpoint_type: admin - state: absent - name: test-listener - loadbalancer: test-loadbalancer -''' - -import time - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, \ - openstack_module_kwargs, openstack_cloud_from_module - - -def _lb_wait_for_status(module, cloud, lb, status, failures, interval=5): - """Wait for load balancer to be in a particular provisioning status.""" - timeout = module.params['timeout'] - - total_sleep = 0 - if failures is None: - failures = [] - - while total_sleep < timeout: - lb = cloud.load_balancer.get_load_balancer(lb.id) - if lb.provisioning_status == status: - return None - if lb.provisioning_status in failures: - module.fail_json( - msg="Load Balancer %s transitioned to failure state %s" % - (lb.id, lb.provisioning_status) - ) - - time.sleep(interval) - total_sleep += interval - - module.fail_json( - msg="Timeout waiting for Load Balancer %s to transition to %s" % - (lb.id, status) - ) - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - loadbalancer=dict(required=True), - protocol=dict(default='HTTP', - choices=['HTTP', 'HTTPS', 'TCP', 'TERMINATED_HTTPS']), - protocol_port=dict(default=80, type='int', required=False), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - sdk, cloud = openstack_cloud_from_module(module) - loadbalancer = module.params['loadbalancer'] - loadbalancer_id = None - - try: - changed = False - listener = cloud.load_balancer.find_listener( - name_or_id=module.params['name']) - - if module.params['state'] == 'present': - if not listener: - lb = cloud.load_balancer.find_load_balancer(loadbalancer) - if not lb: - module.fail_json( - msg='load balancer %s is not found' % loadbalancer - ) - loadbalancer_id = lb.id - - listener = cloud.load_balancer.create_listener( - name=module.params['name'], - loadbalancer_id=loadbalancer_id, - protocol=module.params['protocol'], - protocol_port=module.params['protocol_port'], - ) - changed = True - - if not module.params['wait']: - module.exit_json(changed=changed, - listener=listener.to_dict(), - id=listener.id) - - if module.params['wait']: - # Check in case the listener already exists. - lb = cloud.load_balancer.find_load_balancer(loadbalancer) - if not lb: - module.fail_json( - msg='load balancer %s is not found' % loadbalancer - ) - _lb_wait_for_status(module, cloud, lb, "ACTIVE", ["ERROR"]) - - module.exit_json(changed=changed, listener=listener.to_dict(), - id=listener.id) - elif module.params['state'] == 'absent': - if not listener: - changed = False - else: - cloud.load_balancer.delete_listener(listener) - changed = True - - if module.params['wait']: - # Wait for the load balancer to be active after deleting - # the listener. - lb = cloud.load_balancer.find_load_balancer(loadbalancer) - if not lb: - module.fail_json( - msg='load balancer %s is not found' % loadbalancer - ) - _lb_wait_for_status(module, cloud, lb, "ACTIVE", ["ERROR"]) - - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_loadbalancer.py b/lib/ansible/modules/cloud/openstack/os_loadbalancer.py deleted file mode 100644 index f1ff83eea7..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_loadbalancer.py +++ /dev/null @@ -1,605 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2018 Catalyst Cloud Ltd. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_loadbalancer -short_description: Add/Delete load balancer from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.7" -author: "Lingxian Kong (@lingxiankong)" -description: - - Add or Remove load balancer from the OpenStack load-balancer - service(Octavia). Load balancer update is not supported for now. -options: - name: - description: - - Name that has to be given to the load balancer - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - vip_network: - description: - - The name or id of the network for the virtual IP of the load balancer. - One of I(vip_network), I(vip_subnet), or I(vip_port) must be specified - for creation. - vip_subnet: - description: - - The name or id of the subnet for the virtual IP of the load balancer. - One of I(vip_network), I(vip_subnet), or I(vip_port) must be specified - for creation. - vip_port: - description: - - The name or id of the load balancer virtual IP port. One of - I(vip_network), I(vip_subnet), or I(vip_port) must be specified for - creation. - vip_address: - description: - - IP address of the load balancer virtual IP. - public_ip_address: - description: - - Public IP address associated with the VIP. - auto_public_ip: - description: - - Allocate a public IP address and associate with the VIP automatically. - type: bool - default: 'no' - public_network: - description: - - The name or ID of a Neutron external network. - delete_public_ip: - description: - - When C(state=absent) and this option is true, any public IP address - associated with the VIP will be deleted along with the load balancer. - type: bool - default: 'no' - listeners: - description: - - A list of listeners that attached to the load balancer. - suboptions: - name: - description: - - The listener name or ID. - protocol: - description: - - The protocol for the listener. - default: HTTP - protocol_port: - description: - - The protocol port number for the listener. - default: 80 - pool: - description: - - The pool attached to the listener. - suboptions: - name: - description: - - The pool name or ID. - protocol: - description: - - The protocol for the pool. - default: HTTP - lb_algorithm: - description: - - The load balancing algorithm for the pool. - default: ROUND_ROBIN - members: - description: - - A list of members that added to the pool. - suboptions: - name: - description: - - The member name or ID. - address: - description: - - The IP address of the member. - protocol_port: - description: - - The protocol port number for the member. - default: 80 - subnet: - description: - - The name or ID of the subnet the member service is - accessible from. - wait: - description: - - If the module should wait for the load balancer to be created or - deleted. - type: bool - default: 'yes' - timeout: - description: - - The amount of time the module should wait. - default: 180 - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -RETURN = ''' -id: - description: The load balancer UUID. - returned: On success when C(state=present) - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" -loadbalancer: - description: Dictionary describing the load balancer. - returned: On success when C(state=present) - type: complex - contains: - id: - description: Unique UUID. - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" - name: - description: Name given to the load balancer. - type: str - sample: "lingxian_test" - vip_network_id: - description: Network ID the load balancer virtual IP port belongs in. - type: str - sample: "f171db43-56fd-41cf-82d7-4e91d741762e" - vip_subnet_id: - description: Subnet ID the load balancer virtual IP port belongs in. - type: str - sample: "c53e3c70-9d62-409a-9f71-db148e7aa853" - vip_port_id: - description: The load balancer virtual IP port ID. - type: str - sample: "2061395c-1c01-47ab-b925-c91b93df9c1d" - vip_address: - description: The load balancer virtual IP address. - type: str - sample: "192.168.2.88" - public_vip_address: - description: The load balancer public VIP address. - type: str - sample: "10.17.8.254" - provisioning_status: - description: The provisioning status of the load balancer. - type: str - sample: "ACTIVE" - operating_status: - description: The operating status of the load balancer. - type: str - sample: "ONLINE" - is_admin_state_up: - description: The administrative state of the load balancer. - type: bool - sample: true - listeners: - description: The associated listener IDs, if any. - type: list - sample: [{"id": "7aa1b380-beec-459c-a8a7-3a4fb6d30645"}, {"id": "692d06b8-c4f8-4bdb-b2a3-5a263cc23ba6"}] - pools: - description: The associated pool IDs, if any. - type: list - sample: [{"id": "27b78d92-cee1-4646-b831-e3b90a7fa714"}, {"id": "befc1fb5-1992-4697-bdb9-eee330989344"}] -''' - -EXAMPLES = ''' -# Create a load balancer by specifying the VIP subnet. -- os_loadbalancer: - auth: - auth_url: https://identity.example.com - username: admin - password: passme - project_name: admin - state: present - name: my_lb - vip_subnet: my_subnet - timeout: 150 - -# Create a load balancer by specifying the VIP network and the IP address. -- os_loadbalancer: - auth: - auth_url: https://identity.example.com - username: admin - password: passme - project_name: admin - state: present - name: my_lb - vip_network: my_network - vip_address: 192.168.0.11 - -# Create a load balancer together with its sub-resources in the 'all in one' -# way. A public IP address is also allocated to the load balancer VIP. -- os_loadbalancer: - auth: - auth_url: https://identity.example.com - username: admin - password: passme - project_name: admin - name: lingxian_test - state: present - vip_subnet: kong_subnet - auto_public_ip: yes - public_network: public - listeners: - - name: lingxian_80 - protocol: TCP - protocol_port: 80 - pool: - name: lingxian_80_pool - protocol: TCP - members: - - name: mywebserver1 - address: 192.168.2.81 - protocol_port: 80 - subnet: webserver_subnet - - name: lingxian_8080 - protocol: TCP - protocol_port: 8080 - pool: - name: lingxian_8080-pool - protocol: TCP - members: - - name: mywebserver2 - address: 192.168.2.82 - protocol_port: 8080 - wait: yes - timeout: 600 - -# Delete a load balancer(and all its related resources) -- os_loadbalancer: - auth: - auth_url: https://identity.example.com - username: admin - password: passme - project_name: admin - state: absent - name: my_lb - -# Delete a load balancer(and all its related resources) together with the -# public IP address(if any) attached to it. -- os_loadbalancer: - auth: - auth_url: https://identity.example.com - username: admin - password: passme - project_name: admin - state: absent - name: my_lb - delete_public_ip: yes -''' - -import time - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, \ - openstack_module_kwargs, openstack_cloud_from_module - - -def _wait_for_lb(module, cloud, lb, status, failures, interval=5): - """Wait for load balancer to be in a particular provisioning status.""" - timeout = module.params['timeout'] - - total_sleep = 0 - if failures is None: - failures = [] - - while total_sleep < timeout: - lb = cloud.load_balancer.find_load_balancer(lb.id) - - if lb: - if lb.provisioning_status == status: - return None - if lb.provisioning_status in failures: - module.fail_json( - msg="Load Balancer %s transitioned to failure state %s" % - (lb.id, lb.provisioning_status) - ) - else: - if status == "DELETED": - return None - else: - module.fail_json( - msg="Load Balancer %s transitioned to DELETED" % lb.id - ) - - time.sleep(interval) - total_sleep += interval - - module.fail_json( - msg="Timeout waiting for Load Balancer %s to transition to %s" % - (lb.id, status) - ) - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - vip_network=dict(required=False), - vip_subnet=dict(required=False), - vip_port=dict(required=False), - vip_address=dict(required=False), - listeners=dict(type='list', default=[]), - public_ip_address=dict(required=False, default=None), - auto_public_ip=dict(required=False, default=False, type='bool'), - public_network=dict(required=False), - delete_public_ip=dict(required=False, default=False, type='bool'), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - sdk, cloud = openstack_cloud_from_module(module) - - vip_network = module.params['vip_network'] - vip_subnet = module.params['vip_subnet'] - vip_port = module.params['vip_port'] - listeners = module.params['listeners'] - public_vip_address = module.params['public_ip_address'] - allocate_fip = module.params['auto_public_ip'] - delete_fip = module.params['delete_public_ip'] - public_network = module.params['public_network'] - - vip_network_id = None - vip_subnet_id = None - vip_port_id = None - - try: - changed = False - lb = cloud.load_balancer.find_load_balancer( - name_or_id=module.params['name']) - - if module.params['state'] == 'present': - if not lb: - if not (vip_network or vip_subnet or vip_port): - module.fail_json( - msg="One of vip_network, vip_subnet, or vip_port must " - "be specified for load balancer creation" - ) - - if vip_network: - network = cloud.get_network(vip_network) - if not network: - module.fail_json( - msg='network %s is not found' % vip_network - ) - vip_network_id = network.id - if vip_subnet: - subnet = cloud.get_subnet(vip_subnet) - if not subnet: - module.fail_json( - msg='subnet %s is not found' % vip_subnet - ) - vip_subnet_id = subnet.id - if vip_port: - port = cloud.get_port(vip_port) - if not port: - module.fail_json( - msg='port %s is not found' % vip_port - ) - vip_port_id = port.id - - lb = cloud.load_balancer.create_load_balancer( - name=module.params['name'], - vip_network_id=vip_network_id, - vip_subnet_id=vip_subnet_id, - vip_port_id=vip_port_id, - vip_address=module.params['vip_address'], - ) - changed = True - - if not listeners and not module.params['wait']: - module.exit_json( - changed=changed, - loadbalancer=lb.to_dict(), - id=lb.id - ) - - _wait_for_lb(module, cloud, lb, "ACTIVE", ["ERROR"]) - - for listener_def in listeners: - listener_name = listener_def.get("name") - pool_def = listener_def.get("pool") - - if not listener_name: - module.fail_json(msg='listener name is required') - - listener = cloud.load_balancer.find_listener( - name_or_id=listener_name - ) - - if not listener: - _wait_for_lb(module, cloud, lb, "ACTIVE", ["ERROR"]) - - protocol = listener_def.get("protocol", "HTTP") - protocol_port = listener_def.get("protocol_port", 80) - - listener = cloud.load_balancer.create_listener( - name=listener_name, - loadbalancer_id=lb.id, - protocol=protocol, - protocol_port=protocol_port, - ) - changed = True - - # Ensure pool in the listener. - if pool_def: - pool_name = pool_def.get("name") - members = pool_def.get('members', []) - - if not pool_name: - module.fail_json(msg='pool name is required') - - pool = cloud.load_balancer.find_pool(name_or_id=pool_name) - - if not pool: - _wait_for_lb(module, cloud, lb, "ACTIVE", ["ERROR"]) - - protocol = pool_def.get("protocol", "HTTP") - lb_algorithm = pool_def.get("lb_algorithm", - "ROUND_ROBIN") - - pool = cloud.load_balancer.create_pool( - name=pool_name, - listener_id=listener.id, - protocol=protocol, - lb_algorithm=lb_algorithm - ) - changed = True - - # Ensure members in the pool - for member_def in members: - member_name = member_def.get("name") - if not member_name: - module.fail_json(msg='member name is required') - - member = cloud.load_balancer.find_member(member_name, - pool.id) - - if not member: - _wait_for_lb(module, cloud, lb, "ACTIVE", - ["ERROR"]) - - address = member_def.get("address") - if not address: - module.fail_json( - msg='member address for member %s is ' - 'required' % member_name - ) - - subnet_id = member_def.get("subnet") - if subnet_id: - subnet = cloud.get_subnet(subnet_id) - if not subnet: - module.fail_json( - msg='subnet %s for member %s is not ' - 'found' % (subnet_id, member_name) - ) - subnet_id = subnet.id - - protocol_port = member_def.get("protocol_port", 80) - - member = cloud.load_balancer.create_member( - pool, - name=member_name, - address=address, - protocol_port=protocol_port, - subnet_id=subnet_id - ) - changed = True - - # Associate public ip to the load balancer VIP. If - # public_vip_address is provided, use that IP, otherwise, either - # find an available public ip or create a new one. - fip = None - orig_public_ip = None - new_public_ip = None - if public_vip_address or allocate_fip: - ips = cloud.network.ips( - port_id=lb.vip_port_id, - fixed_ip_address=lb.vip_address - ) - ips = list(ips) - if ips: - orig_public_ip = ips[0] - new_public_ip = orig_public_ip.floating_ip_address - - if public_vip_address and public_vip_address != orig_public_ip: - fip = cloud.network.find_ip(public_vip_address) - if not fip: - module.fail_json( - msg='Public IP %s is unavailable' % public_vip_address - ) - - # Release origin public ip first - cloud.network.update_ip( - orig_public_ip, - fixed_ip_address=None, - port_id=None - ) - - # Associate new public ip - cloud.network.update_ip( - fip, - fixed_ip_address=lb.vip_address, - port_id=lb.vip_port_id - ) - - new_public_ip = public_vip_address - changed = True - elif allocate_fip and not orig_public_ip: - fip = cloud.network.find_available_ip() - if not fip: - if not public_network: - module.fail_json(msg="Public network is not provided") - - pub_net = cloud.network.find_network(public_network) - if not pub_net: - module.fail_json( - msg='Public network %s not found' % - public_network - ) - fip = cloud.network.create_ip( - floating_network_id=pub_net.id - ) - - cloud.network.update_ip( - fip, - fixed_ip_address=lb.vip_address, - port_id=lb.vip_port_id - ) - - new_public_ip = fip.floating_ip_address - changed = True - - # Include public_vip_address in the result. - lb = cloud.load_balancer.find_load_balancer(name_or_id=lb.id) - lb_dict = lb.to_dict() - lb_dict.update({"public_vip_address": new_public_ip}) - - module.exit_json( - changed=changed, - loadbalancer=lb_dict, - id=lb.id - ) - elif module.params['state'] == 'absent': - changed = False - public_vip_address = None - - if lb: - if delete_fip: - ips = cloud.network.ips( - port_id=lb.vip_port_id, - fixed_ip_address=lb.vip_address - ) - ips = list(ips) - if ips: - public_vip_address = ips[0] - - # Deleting load balancer with `cascade=False` does not make - # sense because the deletion will always fail if there are - # sub-resources. - cloud.load_balancer.delete_load_balancer(lb, cascade=True) - changed = True - - if module.params['wait']: - _wait_for_lb(module, cloud, lb, "DELETED", ["ERROR"]) - - if delete_fip and public_vip_address: - cloud.network.delete_ip(public_vip_address) - changed = True - - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_member.py b/lib/ansible/modules/cloud/openstack/os_member.py deleted file mode 100644 index 7b5632ec6d..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_member.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2018 Catalyst Cloud Ltd. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_member -short_description: Add/Delete a member for a pool in load balancer from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.7" -author: "Lingxian Kong (@lingxiankong)" -description: - - Add or Remove a member for a pool from the OpenStack load-balancer service. -options: - name: - description: - - Name that has to be given to the member - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - pool: - description: - - The name or id of the pool that this member belongs to. - required: true - protocol_port: - description: - - The protocol port number for the member. - default: 80 - address: - description: - - The IP address of the member. - subnet_id: - description: - - The subnet ID the member service is accessible from. - wait: - description: - - If the module should wait for the load balancer to be ACTIVE. - type: bool - default: 'yes' - timeout: - description: - - The amount of time the module should wait for the load balancer to get - into ACTIVE state. - default: 180 - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -RETURN = ''' -id: - description: The member UUID. - returned: On success when I(state) is 'present' - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" -member: - description: Dictionary describing the member. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Unique UUID. - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" - name: - description: Name given to the member. - type: str - sample: "test" - description: - description: The member description. - type: str - sample: "description" - provisioning_status: - description: The provisioning status of the member. - type: str - sample: "ACTIVE" - operating_status: - description: The operating status of the member. - type: str - sample: "ONLINE" - is_admin_state_up: - description: The administrative state of the member. - type: bool - sample: true - protocol_port: - description: The protocol port number for the member. - type: int - sample: 80 - subnet_id: - description: The subnet ID the member service is accessible from. - type: str - sample: "489247fa-9c25-11e8-9679-00224d6b7bc1" - address: - description: The IP address of the backend member server. - type: str - sample: "192.168.2.10" -''' - -EXAMPLES = ''' -# Create a member, wait for the member to be created. -- os_member: - cloud: mycloud - endpoint_type: admin - state: present - name: test-member - pool: test-pool - address: 192.168.10.3 - protocol_port: 8080 - -# Delete a listener -- os_member: - cloud: mycloud - endpoint_type: admin - state: absent - name: test-member - pool: test-pool -''' - -import time - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, \ - openstack_module_kwargs, openstack_cloud_from_module - - -def _wait_for_member_status(module, cloud, pool_id, member_id, status, - failures, interval=5): - timeout = module.params['timeout'] - - total_sleep = 0 - if failures is None: - failures = [] - - while total_sleep < timeout: - member = cloud.load_balancer.get_member(member_id, pool_id) - provisioning_status = member.provisioning_status - if provisioning_status == status: - return member - if provisioning_status in failures: - module.fail_json( - msg="Member %s transitioned to failure state %s" % - (member_id, provisioning_status) - ) - - time.sleep(interval) - total_sleep += interval - - module.fail_json( - msg="Timeout waiting for member %s to transition to %s" % - (member_id, status) - ) - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - pool=dict(required=True), - address=dict(default=None), - protocol_port=dict(default=80, type='int'), - subnet_id=dict(default=None), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - sdk, cloud = openstack_cloud_from_module(module) - name = module.params['name'] - pool = module.params['pool'] - - try: - changed = False - - pool_ret = cloud.load_balancer.find_pool(name_or_id=pool) - if not pool_ret: - module.fail_json(msg='pool %s is not found' % pool) - - pool_id = pool_ret.id - member = cloud.load_balancer.find_member(name, pool_id) - - if module.params['state'] == 'present': - if not member: - member = cloud.load_balancer.create_member( - pool_ret, - address=module.params['address'], - name=name, - protocol_port=module.params['protocol_port'], - subnet_id=module.params['subnet_id'] - ) - changed = True - - if not module.params['wait']: - module.exit_json(changed=changed, - member=member.to_dict(), - id=member.id) - - if module.params['wait']: - member = _wait_for_member_status(module, cloud, pool_id, - member.id, "ACTIVE", - ["ERROR"]) - - module.exit_json(changed=changed, member=member.to_dict(), - id=member.id) - - elif module.params['state'] == 'absent': - if member: - cloud.load_balancer.delete_member(member, pool_ret) - changed = True - - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_network.py b/lib/ansible/modules/cloud/openstack/os_network.py deleted file mode 100644 index 79f4b0f9e3..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_network.py +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_network -short_description: Creates/removes networks from OpenStack -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Add or remove network from OpenStack. -options: - name: - description: - - Name to be assigned to the network. - required: true - shared: - description: - - Whether this network is shared or not. - type: bool - default: 'no' - admin_state_up: - description: - - Whether the state should be marked as up or down. - type: bool - default: 'yes' - external: - description: - - Whether this network is externally accessible. - type: bool - default: 'no' - state: - description: - - Indicate desired state of the resource. - choices: ['present', 'absent'] - default: present - provider_physical_network: - description: - - The physical network where this network object is implemented. - version_added: "2.1" - provider_network_type: - description: - - The type of physical network that maps to this network resource. - version_added: "2.1" - provider_segmentation_id: - description: - - An isolated segment on the physical network. The I(network_type) - attribute defines the segmentation model. For example, if the - I(network_type) value is vlan, this ID is a vlan identifier. If - the I(network_type) value is gre, this ID is a gre key. - version_added: "2.1" - project: - description: - - Project name or ID containing the network (name admin-only) - version_added: "2.1" - availability_zone: - description: - - Ignored. Present for backwards compatibility - port_security_enabled: - description: - - Whether port security is enabled on the network or not. - Network will use OpenStack defaults if this option is - not utilised. - type: bool - version_added: "2.8" - mtu: - description: - - The maximum transmission unit (MTU) value to address fragmentation. - Network will use OpenStack defaults if this option is - not provided. - type: int - version_added: "2.9" - dns_domain: - description: - - The DNS domain value to set. - Network will use Openstack defaults if this option is - not provided. - version_added: "2.9" -requirements: - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create an externally accessible network named 'ext_network'. -- os_network: - cloud: mycloud - state: present - name: ext_network - external: true -''' - -RETURN = ''' -network: - description: Dictionary describing the network. - returned: On success when I(state) is 'present'. - type: complex - contains: - id: - description: Network ID. - type: str - sample: "4bb4f9a5-3bd2-4562-bf6a-d17a6341bb56" - name: - description: Network name. - type: str - sample: "ext_network" - shared: - description: Indicates whether this network is shared across all tenants. - type: bool - sample: false - status: - description: Network status. - type: str - sample: "ACTIVE" - mtu: - description: The MTU of a network resource. - type: int - sample: 0 - dns_domain: - description: The DNS domain of a network resource. - type: str - sample: "sample.openstack.org." - admin_state_up: - description: The administrative state of the network. - type: bool - sample: true - port_security_enabled: - description: The port security status - type: bool - sample: true - router:external: - description: Indicates whether this network is externally accessible. - type: bool - sample: true - tenant_id: - description: The tenant ID. - type: str - sample: "06820f94b9f54b119636be2728d216fc" - subnets: - description: The associated subnets. - type: list - sample: [] - "provider:physical_network": - description: The physical network where this network object is implemented. - type: str - sample: my_vlan_net - "provider:network_type": - description: The type of physical network that maps to this network resource. - type: str - sample: vlan - "provider:segmentation_id": - description: An isolated segment on the physical network. - type: str - sample: 101 -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - shared=dict(default=False, type='bool'), - admin_state_up=dict(default=True, type='bool'), - external=dict(default=False, type='bool'), - provider_physical_network=dict(required=False), - provider_network_type=dict(required=False), - provider_segmentation_id=dict(required=False, type='int'), - state=dict(default='present', choices=['absent', 'present']), - project=dict(default=None), - port_security_enabled=dict(type='bool'), - mtu=dict(required=False, type='int'), - dns_domain=dict(required=False) - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - state = module.params['state'] - name = module.params['name'] - shared = module.params['shared'] - admin_state_up = module.params['admin_state_up'] - external = module.params['external'] - provider_physical_network = module.params['provider_physical_network'] - provider_network_type = module.params['provider_network_type'] - provider_segmentation_id = module.params['provider_segmentation_id'] - project = module.params.get('project') - port_security_enabled = module.params.get('port_security_enabled') - mtu = module.params.get('mtu') - dns_domain = module.params.get('dns_domain') - - sdk, cloud = openstack_cloud_from_module(module) - try: - if project is not None: - proj = cloud.get_project(project) - if proj is None: - module.fail_json(msg='Project %s could not be found' % project) - project_id = proj['id'] - filters = {'tenant_id': project_id} - else: - project_id = None - filters = None - net = cloud.get_network(name, filters=filters) - - if state == 'present': - if not net: - provider = {} - if provider_physical_network: - provider['physical_network'] = provider_physical_network - if provider_network_type: - provider['network_type'] = provider_network_type - if provider_segmentation_id: - provider['segmentation_id'] = provider_segmentation_id - - if project_id is not None: - net = cloud.create_network(name, shared, admin_state_up, - external, provider, project_id, - port_security_enabled=port_security_enabled, - mtu_size=mtu, dns_domain=dns_domain) - else: - net = cloud.create_network(name, shared, admin_state_up, - external, provider, - port_security_enabled=port_security_enabled, - mtu_size=mtu, dns_domain=dns_domain) - changed = True - else: - changed = False - module.exit_json(changed=changed, network=net, id=net['id']) - - elif state == 'absent': - if not net: - module.exit_json(changed=False) - else: - cloud.delete_network(name) - module.exit_json(changed=True) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_networks_info.py b/lib/ansible/modules/cloud/openstack/os_networks_info.py deleted file mode 100644 index d580f46728..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_networks_info.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_networks_info -short_description: Retrieve information about one or more OpenStack networks. -version_added: "2.0" -author: "Davide Agnello (@dagnello)" -description: - - Retrieve information about one or more networks from OpenStack. - - This module was called C(os_networks_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_networks_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "sdk" -options: - name: - description: - - Name or ID of the Network - required: false - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - required: false - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -- name: Gather information about previously created networks - os_networks_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - register: result - -- name: Show openstack networks - debug: - msg: "{{ result.openstack_networks }}" - -- name: Gather information about a previously created network by name - os_networks_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - name: network1 - register: result - -- name: Show openstack networks - debug: - msg: "{{ result.openstack_networks }}" - -- name: Gather information about a previously created network with filter - # Note: name and filters parameters are Not mutually exclusive - os_networks_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - filters: - tenant_id: 55e2ce24b2a245b09f181bf025724cbe - subnets: - - 057d4bdf-6d4d-4728-bb0f-5ac45a6f7400 - - 443d4dc0-91d4-4998-b21c-357d10433483 - register: result - -- name: Show openstack networks - debug: - msg: "{{ result.openstack_networks }}" -''' - -RETURN = ''' -openstack_networks: - description: has all the openstack information about the networks - returned: always, but can be null - type: complex - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Name given to the network. - returned: success - type: str - status: - description: Network status. - returned: success - type: str - subnets: - description: Subnet(s) included in this network. - returned: success - type: list - elements: str - tenant_id: - description: Tenant id associated with this network. - returned: success - type: str - shared: - description: Network shared flag. - returned: success - type: bool -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - filters=dict(required=False, type='dict', default=None) - ) - module = AnsibleModule(argument_spec) - is_old_facts = module._name == 'os_networks_facts' - if is_old_facts: - module.deprecate("The 'os_networks_facts' module has been renamed to 'os_networks_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, cloud = openstack_cloud_from_module(module) - try: - networks = cloud.search_networks(module.params['name'], - module.params['filters']) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_networks=networks)) - else: - module.exit_json(changed=False, openstack_networks=networks) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_nova_flavor.py b/lib/ansible/modules/cloud/openstack/os_nova_flavor.py deleted file mode 100644 index aa6ee1e750..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_nova_flavor.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_nova_flavor -short_description: Manage OpenStack compute flavors -extends_documentation_fragment: openstack -version_added: "2.0" -author: "David Shrewsbury (@Shrews)" -description: - - Add or remove flavors from OpenStack. -options: - state: - description: - - Indicate desired state of the resource. When I(state) is 'present', - then I(ram), I(vcpus), and I(disk) are all required. There are no - default values for those parameters. - choices: ['present', 'absent'] - default: present - name: - description: - - Flavor name. - required: true - ram: - description: - - Amount of memory, in MB. - vcpus: - description: - - Number of virtual CPUs. - disk: - description: - - Size of local disk, in GB. - default: 0 - type: int - ephemeral: - description: - - Ephemeral space size, in GB. - default: 0 - swap: - description: - - Swap space size, in MB. - default: 0 - rxtx_factor: - description: - - RX/TX factor. - default: 1.0 - is_public: - description: - - Make flavor accessible to the public. - type: bool - default: 'yes' - flavorid: - description: - - ID for the flavor. This is optional as a unique UUID will be - assigned if a value is not specified. - default: "auto" - availability_zone: - description: - - Ignored. Present for backwards compatibility - extra_specs: - description: - - Metadata dictionary - version_added: "2.3" -requirements: ["openstacksdk"] -''' - -EXAMPLES = ''' -- name: "Create 'tiny' flavor with 1024MB of RAM, 1 virtual CPU, and 10GB of local disk, and 10GB of ephemeral." - os_nova_flavor: - cloud: mycloud - state: present - name: tiny - ram: 1024 - vcpus: 1 - disk: 10 - ephemeral: 10 - -- name: "Delete 'tiny' flavor" - os_nova_flavor: - cloud: mycloud - state: absent - name: tiny - -- name: Create flavor with metadata - os_nova_flavor: - cloud: mycloud - state: present - name: tiny - ram: 1024 - vcpus: 1 - disk: 10 - extra_specs: - "quota:disk_read_iops_sec": 5000 - "aggregate_instance_extra_specs:pinned": false -''' - -RETURN = ''' -flavor: - description: Dictionary describing the flavor. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Flavor ID. - returned: success - type: str - sample: "515256b8-7027-4d73-aa54-4e30a4a4a339" - name: - description: Flavor name. - returned: success - type: str - sample: "tiny" - 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 - ram: - description: Amount of memory, in MB. - returned: success - type: int - sample: 1024 - 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 - is_public: - description: Make flavor accessible to the public. - returned: success - type: bool - sample: true - extra_specs: - description: Flavor metadata - returned: success - type: dict - sample: - "quota:disk_read_iops_sec": 5000 - "aggregate_instance_extra_specs:pinned": false -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(module, flavor): - state = module.params['state'] - if state == 'present' and not flavor: - return True - if state == 'absent' and flavor: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - state=dict(required=False, default='present', - choices=['absent', 'present']), - name=dict(required=False), - - # required when state is 'present' - ram=dict(required=False, type='int'), - vcpus=dict(required=False, type='int'), - - disk=dict(required=False, default=0, type='int'), - ephemeral=dict(required=False, default=0, type='int'), - swap=dict(required=False, default=0, type='int'), - rxtx_factor=dict(required=False, default=1.0, type='float'), - is_public=dict(required=False, default=True, type='bool'), - flavorid=dict(required=False, default="auto"), - extra_specs=dict(required=False, default=None, type='dict'), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule( - argument_spec, - supports_check_mode=True, - required_if=[ - ('state', 'present', ['ram', 'vcpus', 'disk']) - ], - **module_kwargs) - - state = module.params['state'] - name = module.params['name'] - extra_specs = module.params['extra_specs'] or {} - - sdk, cloud = openstack_cloud_from_module(module) - try: - flavor = cloud.get_flavor(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, flavor)) - - if state == 'present': - old_extra_specs = {} - require_update = False - - if flavor: - old_extra_specs = flavor['extra_specs'] - for param_key in ['ram', 'vcpus', 'disk', 'ephemeral', 'swap', 'rxtx_factor', 'is_public']: - if module.params[param_key] != flavor[param_key]: - require_update = True - break - - if flavor and require_update: - cloud.delete_flavor(name) - flavor = None - - if not flavor: - flavor = cloud.create_flavor( - name=name, - ram=module.params['ram'], - vcpus=module.params['vcpus'], - disk=module.params['disk'], - flavorid=module.params['flavorid'], - ephemeral=module.params['ephemeral'], - swap=module.params['swap'], - rxtx_factor=module.params['rxtx_factor'], - is_public=module.params['is_public'] - ) - changed = True - else: - changed = False - - new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()]) - unset_keys = set(old_extra_specs.keys()) - set(extra_specs.keys()) - - if unset_keys and not require_update: - cloud.unset_flavor_specs(flavor['id'], unset_keys) - - if old_extra_specs != new_extra_specs: - cloud.set_flavor_specs(flavor['id'], extra_specs) - - changed = (changed or old_extra_specs != new_extra_specs) - - module.exit_json(changed=changed, - flavor=flavor, - id=flavor['id']) - - elif state == 'absent': - if flavor: - cloud.delete_flavor(name) - module.exit_json(changed=True) - module.exit_json(changed=False) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_nova_host_aggregate.py b/lib/ansible/modules/cloud/openstack/os_nova_host_aggregate.py deleted file mode 100644 index 94bd628988..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_nova_host_aggregate.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/python -# 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) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_nova_host_aggregate -short_description: Manage OpenStack host aggregates -extends_documentation_fragment: openstack -author: "Jakub Jursa (@kuboj)" -version_added: "2.3" -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 - metadata: - description: Metadata dict. - availability_zone: - description: Availability zone to create aggregate into. - hosts: - description: List of hosts to set for an aggregate. - state: - description: Should the resource be present or absent. - choices: [present, absent] - default: present -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a host aggregate -- os_nova_host_aggregate: - cloud: mycloud - state: present - name: db_aggregate - hosts: - - host1 - - host2 - metadata: - type: dbcluster -# Delete an aggregate -- os_nova_host_aggregate: - cloud: mycloud - state: absent - name: db_aggregate -''' - -RETURN = ''' - -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, aggregate): - new_metadata = (module.params['metadata'] or {}) - - if module.params['availability_zone'] is not None: - new_metadata['availability_zone'] = module.params['availability_zone'] - - if ((module.params['name'] != aggregate.name) or - (module.params['hosts'] is not None and set(module.params['hosts']) != set(aggregate.hosts)) or - (module.params['availability_zone'] is not None and module.params['availability_zone'] != aggregate.availability_zone) or - (module.params['metadata'] is not None and new_metadata != aggregate.metadata)): - return True - - return False - - -def _system_state_change(module, aggregate): - state = module.params['state'] - if state == 'absent' and aggregate: - return True - - if state == 'present': - if aggregate is None: - return True - return _needs_update(module, aggregate) - - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - metadata=dict(required=False, default=None, type='dict'), - availability_zone=dict(required=False, default=None), - hosts=dict(required=False, default=None, type='list'), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - name = module.params['name'] - metadata = module.params['metadata'] - availability_zone = module.params['availability_zone'] - hosts = module.params['hosts'] - state = module.params['state'] - - if metadata is not None: - metadata.pop('availability_zone', None) - - sdk, cloud = openstack_cloud_from_module(module) - try: - aggregates = cloud.search_aggregates(name_or_id=name) - - if len(aggregates) == 1: - aggregate = aggregates[0] - elif len(aggregates) == 0: - aggregate = None - else: - raise Exception("Should not happen") - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, aggregate)) - - if state == 'present': - if aggregate is None: - aggregate = cloud.create_aggregate(name=name, - availability_zone=availability_zone) - if hosts: - for h in hosts: - cloud.add_host_to_aggregate(aggregate.id, h) - if metadata: - cloud.set_aggregate_metadata(aggregate.id, metadata) - changed = True - else: - if _needs_update(module, aggregate): - if availability_zone is not None: - aggregate = cloud.update_aggregate(aggregate.id, 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 - cloud.set_aggregate_metadata(aggregate.id, metas) - if hosts is not None: - for i in (set(aggregate.hosts) - set(hosts)): - cloud.remove_host_from_aggregate(aggregate.id, i) - for i in (set(hosts) - set(aggregate.hosts)): - cloud.add_host_to_aggregate(aggregate.id, i) - changed = True - else: - changed = False - module.exit_json(changed=changed) - - elif state == 'absent': - if aggregate is None: - changed = False - else: - if hosts: - for h in hosts: - cloud.remove_host_from_aggregate(aggregate.id, h) - cloud.delete_aggregate(aggregate.id) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_object.py b/lib/ansible/modules/cloud/openstack/os_object.py deleted file mode 100644 index 51d6ae3243..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_object.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_object -short_description: Create or Delete objects and containers from OpenStack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -extends_documentation_fragment: openstack -description: - - Create or Delete objects and containers from OpenStack -options: - container: - description: - - The name of the container in which to create the object - required: true - name: - description: - - Name to be give to the object. If omitted, operations will be on - the entire container - required: false - filename: - description: - - Path to local file to be uploaded. - required: false - container_access: - description: - - desired container access level. - required: false - choices: ['private', 'public'] - default: private - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -''' - -EXAMPLES = ''' -- name: "Create a object named 'fstab' in the 'config' container" - os_object: - cloud: mordred - state: present - name: fstab - container: config - filename: /etc/fstab - -- name: Delete a container called config and all of its contents - os_object: - cloud: rax-iad - state: absent - container: config -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def process_object( - cloud_obj, container, name, filename, container_access, **kwargs): - - changed = False - container_obj = cloud_obj.get_container(container) - if kwargs['state'] == 'present': - if not container_obj: - container_obj = cloud_obj.create_container(container) - changed = True - if cloud_obj.get_container_access(container) != container_access: - cloud_obj.set_container_access(container, container_access) - changed = True - if name: - if cloud_obj.is_object_stale(container, name, filename): - cloud_obj.create_object(container, name, filename) - changed = True - else: - if container_obj: - if name: - if cloud_obj.get_object_metadata(container, name): - cloud_obj.delete_object(container, name) - changed = True - else: - cloud_obj.delete_container(container) - changed = True - return changed - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - container=dict(required=True), - filename=dict(required=False, default=None), - container_access=dict(default='private', choices=['private', 'public']), - state=dict(default='present', choices=['absent', 'present']), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - - sdk, cloud = openstack_cloud_from_module(module) - try: - changed = process_object(cloud, **module.params) - - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_pool.py b/lib/ansible/modules/cloud/openstack/os_pool.py deleted file mode 100644 index 694305094e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_pool.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2018 Catalyst Cloud Ltd. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function - -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_pool -short_description: Add/Delete a pool in the load balancing service from OpenStack Cloud -extends_documentation_fragment: openstack -version_added: "2.7" -author: "Lingxian Kong (@lingxiankong)" -description: - - Add or Remove a pool from the OpenStack load-balancer service. -options: - name: - description: - - Name that has to be given to the pool - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - loadbalancer: - description: - - The name or id of the load balancer that this pool belongs to. - Either loadbalancer or listener must be specified for pool creation. - listener: - description: - - The name or id of the listener that this pool belongs to. - Either loadbalancer or listener must be specified for pool creation. - protocol: - description: - - The protocol for the pool. - choices: [HTTP, HTTPS, PROXY, TCP, UDP] - default: HTTP - lb_algorithm: - description: - - The load balancing algorithm for the pool. - choices: [LEAST_CONNECTIONS, ROUND_ROBIN, SOURCE_IP] - default: ROUND_ROBIN - wait: - description: - - If the module should wait for the pool to be ACTIVE. - type: bool - default: 'yes' - timeout: - description: - - The amount of time the module should wait for the pool to get - into ACTIVE state. - default: 180 - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -RETURN = ''' -id: - description: The pool UUID. - returned: On success when I(state) is 'present' - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" -listener: - description: Dictionary describing the pool. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Unique UUID. - type: str - sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" - name: - description: Name given to the pool. - type: str - sample: "test" - description: - description: The pool description. - type: str - sample: "description" - loadbalancers: - description: A list of load balancer IDs. - type: list - sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] - listeners: - description: A list of listener IDs. - type: list - sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] - members: - description: A list of member IDs. - type: list - sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] - loadbalancer_id: - description: The load balancer ID the pool belongs to. This field is set when the pool doesn't belong to any listener in the load balancer. - type: str - sample: "7c4be3f8-9c2f-11e8-83b3-44a8422643a4" - listener_id: - description: The listener ID the pool belongs to. - type: str - sample: "956aa716-9c2f-11e8-83b3-44a8422643a4" - provisioning_status: - description: The provisioning status of the pool. - type: str - sample: "ACTIVE" - operating_status: - description: The operating status of the pool. - type: str - sample: "ONLINE" - is_admin_state_up: - description: The administrative state of the pool. - type: bool - sample: true - protocol: - description: The protocol for the pool. - type: str - sample: "HTTP" - lb_algorithm: - description: The load balancing algorithm for the pool. - type: str - sample: "ROUND_ROBIN" -''' - -EXAMPLES = ''' -# Create a pool, wait for the pool to be active. -- os_pool: - cloud: mycloud - endpoint_type: admin - state: present - name: test-pool - loadbalancer: test-loadbalancer - protocol: HTTP - lb_algorithm: ROUND_ROBIN - -# Delete a pool -- os_pool: - cloud: mycloud - endpoint_type: admin - state: absent - name: test-pool -''' - -import time - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, \ - openstack_module_kwargs, openstack_cloud_from_module - - -def _wait_for_pool_status(module, cloud, pool_id, status, failures, - interval=5): - timeout = module.params['timeout'] - - total_sleep = 0 - if failures is None: - failures = [] - - while total_sleep < timeout: - pool = cloud.load_balancer.get_pool(pool_id) - provisioning_status = pool.provisioning_status - if provisioning_status == status: - return pool - if provisioning_status in failures: - module.fail_json( - msg="pool %s transitioned to failure state %s" % - (pool_id, provisioning_status) - ) - - time.sleep(interval) - total_sleep += interval - - module.fail_json( - msg="timeout waiting for pool %s to transition to %s" % - (pool_id, status) - ) - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - loadbalancer=dict(default=None), - listener=dict(default=None), - protocol=dict(default='HTTP', - choices=['HTTP', 'HTTPS', 'TCP', 'UDP', 'PROXY']), - lb_algorithm=dict( - default='ROUND_ROBIN', - choices=['ROUND_ROBIN', 'LEAST_CONNECTIONS', 'SOURCE_IP'] - ) - ) - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[['loadbalancer', 'listener']] - ) - module = AnsibleModule(argument_spec, **module_kwargs) - sdk, cloud = openstack_cloud_from_module(module) - - loadbalancer = module.params['loadbalancer'] - listener = module.params['listener'] - - try: - changed = False - pool = cloud.load_balancer.find_pool(name_or_id=module.params['name']) - - if module.params['state'] == 'present': - if not pool: - loadbalancer_id = None - if not (loadbalancer or listener): - module.fail_json( - msg="either loadbalancer or listener must be provided" - ) - - if loadbalancer: - lb = cloud.load_balancer.find_load_balancer(loadbalancer) - if not lb: - module.fail_json(msg='load balancer %s is not ' - 'found' % loadbalancer) - loadbalancer_id = lb.id - - listener_id = None - if listener: - listener_ret = cloud.load_balancer.find_listener(listener) - if not listener_ret: - module.fail_json(msg='listener %s is not found' - % listener) - listener_id = listener_ret.id - - pool = cloud.load_balancer.create_pool( - name=module.params['name'], - loadbalancer_id=loadbalancer_id, - listener_id=listener_id, - protocol=module.params['protocol'], - lb_algorithm=module.params['lb_algorithm'] - ) - changed = True - - if not module.params['wait']: - module.exit_json(changed=changed, - pool=pool.to_dict(), - id=pool.id) - - if module.params['wait']: - pool = _wait_for_pool_status(module, cloud, pool.id, "ACTIVE", - ["ERROR"]) - - module.exit_json(changed=changed, pool=pool.to_dict(), - id=pool.id) - - elif module.params['state'] == 'absent': - if pool: - cloud.load_balancer.delete_pool(pool) - changed = True - - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_port.py b/lib/ansible/modules/cloud/openstack/os_port.py deleted file mode 100644 index 01b77b0c0a..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_port.py +++ /dev/null @@ -1,441 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_port -short_description: Add/Update/Delete ports from an OpenStack cloud. -extends_documentation_fragment: openstack -author: "Davide Agnello (@dagnello)" -version_added: "2.0" -description: - - Add, Update or Remove ports from an OpenStack cloud. A I(state) of - 'present' will ensure the port is created or updated if required. -requirements: - - "ordereddict unless python >= 2.7" - - "openstacksdk" -options: - network: - description: - - Network ID or name this port belongs to. - required: true - name: - description: - - Name that has to be given to the port. - fixed_ips: - description: - - Desired IP and/or subnet for this port. Subnet is referenced by - subnet_id and IP is referenced by ip_address. - admin_state_up: - description: - - Sets admin state. - type: bool - mac_address: - description: - - MAC address of this port. - security_groups: - description: - - Security group(s) ID(s) or name(s) associated with the port (comma - separated string or YAML list) - no_security_groups: - description: - - Do not associate a security group with this port. - type: bool - default: 'no' - allowed_address_pairs: - description: - - "Allowed address pairs list. Allowed address pairs are supported with - dictionary structure. - e.g. allowed_address_pairs: - - ip_address: 10.1.0.12 - mac_address: ab:cd:ef:12:34:56 - - ip_address: ..." - extra_dhcp_opts: - description: - - "Extra dhcp options to be assigned to this port. Extra options are - supported with dictionary structure. Note that options cannot be removed - only updated. - e.g. extra_dhcp_opts: - - opt_name: opt name1 - opt_value: value1 - ip_version: 4 - - opt_name: ..." - device_owner: - description: - - The ID of the entity that uses this port. - device_id: - description: - - Device ID of device using this port. - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility - vnic_type: - description: - - The type of the port that should be created - choices: [normal, direct, direct-physical, macvtap, baremetal, virtio-forwarder] - version_added: "2.8" - port_security_enabled: - description: - - Whether to enable or disable the port security on the network. - type: bool - version_added: "2.8" -''' - -EXAMPLES = ''' -# Create a port -- os_port: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: port1 - network: foo - -# Create a port with a static IP -- os_port: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: port1 - network: foo - fixed_ips: - - ip_address: 10.1.0.21 - -# Create a port with No security groups -- os_port: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: port1 - network: foo - no_security_groups: True - -# Update the existing 'port1' port with multiple security groups (version 1) -- os_port: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: port1 - security_groups: 1496e8c7-4918-482a-9172-f4f00fc4a3a5,057d4bdf-6d4d-472... - -# Update the existing 'port1' port with multiple security groups (version 2) -- os_port: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: port1 - security_groups: - - 1496e8c7-4918-482a-9172-f4f00fc4a3a5 - - 057d4bdf-6d4d-472... - -# Create port of type 'direct' -- os_port: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: port1 - network: foo - vnic_type: direct -''' - -RETURN = ''' -id: - description: Unique UUID. - returned: success - type: str -name: - description: Name given to the port. - returned: success - type: str -network_id: - description: Network ID this port belongs in. - returned: success - type: str -security_groups: - description: Security group(s) associated with this port. - returned: success - type: list -status: - description: Port's status. - returned: success - type: str -fixed_ips: - description: Fixed ip(s) associated with this port. - returned: success - type: list -tenant_id: - description: Tenant id associated with this port. - returned: success - type: str -allowed_address_pairs: - description: Allowed address pairs with this port. - returned: success - type: list -admin_state_up: - description: Admin state up flag for this port. - returned: success - type: bool -vnic_type: - description: Type of the created port - returned: success - type: str -port_security_enabled: - description: Port security state on the network. - returned: success - type: bool -''' - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -try: - from collections import OrderedDict - HAS_ORDEREDDICT = True -except ImportError: - try: - from ordereddict import OrderedDict - HAS_ORDEREDDICT = True - except ImportError: - HAS_ORDEREDDICT = False - - -def _needs_update(module, port, cloud): - """Check for differences in the updatable values. - - NOTE: We don't currently allow name updates. - """ - compare_simple = ['admin_state_up', - 'mac_address', - 'device_owner', - 'device_id', - 'binding:vnic_type', - 'port_security_enabled'] - compare_list_dict = ['allowed_address_pairs', - 'extra_dhcp_opts'] - compare_list = ['security_groups'] - - for key in compare_simple: - if module.params[key] is not None and module.params[key] != port[key]: - return True - for key in compare_list: - if module.params[key] is not None and (set(module.params[key]) != - set(port[key])): - return True - - for key in compare_list_dict: - if not module.params[key]: - if not port[key]: - return True - - # sort dicts in list - port_ordered = [OrderedDict(sorted(d.items())) for d in port[key]] - param_ordered = [OrderedDict(sorted(d.items())) for d in module.params[key]] - - for d in param_ordered: - if d not in port_ordered: - return True - - for d in port_ordered: - if d not in param_ordered: - return True - - # NOTE: if port was created or updated with 'no_security_groups=True', - # subsequent updates without 'no_security_groups' flag or - # 'no_security_groups=False' and no specified 'security_groups', will not - # result in an update to the port where the default security group is - # applied. - if module.params['no_security_groups'] and port['security_groups'] != []: - return True - - if module.params['fixed_ips'] is not None: - for item in module.params['fixed_ips']: - if 'ip_address' in item: - # if ip_address in request does not match any in existing port, - # update is required. - if not any(match['ip_address'] == item['ip_address'] - for match in port['fixed_ips']): - return True - if 'subnet_id' in item: - return True - for item in port['fixed_ips']: - # if ip_address in existing port does not match any in request, - # update is required. - if not any(match.get('ip_address') == item['ip_address'] - for match in module.params['fixed_ips']): - return True - - return False - - -def _system_state_change(module, port, cloud): - state = module.params['state'] - if state == 'present': - if not port: - return True - return _needs_update(module, port, cloud) - if state == 'absent' and port: - return True - return False - - -def _compose_port_args(module, cloud): - port_kwargs = {} - optional_parameters = ['name', - 'fixed_ips', - 'admin_state_up', - 'mac_address', - 'security_groups', - 'allowed_address_pairs', - 'extra_dhcp_opts', - 'device_owner', - 'device_id', - 'binding:vnic_type', - 'port_security_enabled'] - for optional_param in optional_parameters: - if module.params[optional_param] is not None: - port_kwargs[optional_param] = module.params[optional_param] - - if module.params['no_security_groups']: - port_kwargs['security_groups'] = [] - - return port_kwargs - - -def get_security_group_id(module, cloud, security_group_name_or_id): - security_group = cloud.get_security_group(security_group_name_or_id) - if not security_group: - module.fail_json(msg="Security group: %s, was not found" - % security_group_name_or_id) - return security_group['id'] - - -def main(): - argument_spec = openstack_full_argument_spec( - network=dict(required=False), - name=dict(required=False), - fixed_ips=dict(type='list', default=None), - admin_state_up=dict(type='bool', default=None), - mac_address=dict(default=None), - security_groups=dict(default=None, type='list'), - no_security_groups=dict(default=False, type='bool'), - allowed_address_pairs=dict(type='list', default=None), - extra_dhcp_opts=dict(type='list', default=None), - device_owner=dict(default=None), - device_id=dict(default=None), - state=dict(default='present', choices=['absent', 'present']), - vnic_type=dict(default=None, - choices=['normal', 'direct', 'direct-physical', - 'macvtap', 'baremetal', 'virtio-forwarder']), - port_security_enabled=dict(default=None, type='bool') - ) - - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[ - ['no_security_groups', 'security_groups'], - ] - ) - - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - if not HAS_ORDEREDDICT: - module.fail_json(msg=missing_required_lib('ordereddict')) - - name = module.params['name'] - state = module.params['state'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - if module.params['security_groups']: - # translate security_groups to UUID's if names where provided - module.params['security_groups'] = [ - get_security_group_id(module, cloud, v) - for v in module.params['security_groups'] - ] - - # Neutron API accept 'binding:vnic_type' as an argument - # for the port type. - module.params['binding:vnic_type'] = module.params.pop('vnic_type') - - port = None - network_id = None - if name: - port = cloud.get_port(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, port, cloud)) - - changed = False - if state == 'present': - if not port: - network = module.params['network'] - if not network: - module.fail_json( - msg="Parameter 'network' is required in Port Create" - ) - port_kwargs = _compose_port_args(module, cloud) - network_object = cloud.get_network(network) - - if network_object: - network_id = network_object['id'] - else: - module.fail_json( - msg="Specified network was not found." - ) - - port = cloud.create_port(network_id, **port_kwargs) - changed = True - else: - if _needs_update(module, port, cloud): - port_kwargs = _compose_port_args(module, cloud) - port = cloud.update_port(port['id'], **port_kwargs) - changed = True - module.exit_json(changed=changed, id=port['id'], port=port) - - if state == 'absent': - if port: - cloud.delete_port(port['id']) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_port_info.py b/lib/ansible/modules/cloud/openstack/os_port_info.py deleted file mode 100644 index d59282b32f..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_port_info.py +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2016 IBM -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' -module: os_port_info -short_description: Retrieve information about ports within OpenStack. -version_added: "2.1" -author: "David Shrewsbury (@Shrews)" -description: - - Retrieve information about ports from OpenStack. - - This module was called C(os_port_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_port_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - port: - description: - - Unique name or ID of a port. - filters: - description: - - A dictionary of meta data to use for further filtering. Elements - of this dictionary will be matched against the returned port - dictionaries. Matching is currently limited to strings within - the port dictionary, or strings within nested dictionaries. - availability_zone: - description: - - Ignored. Present for backwards compatibility -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -# Gather information about all ports -- os_port_info: - cloud: mycloud - register: result - -- debug: - msg: "{{ result.openstack_ports }}" - -# Gather information about a single port -- os_port_info: - cloud: mycloud - port: 6140317d-e676-31e1-8a4a-b1913814a471 - -# Gather information about all ports that have device_id set to a specific value -# and with a status of ACTIVE. -- os_port_info: - cloud: mycloud - filters: - device_id: 1038a010-3a37-4a9d-82ea-652f1da36597 - status: ACTIVE -''' - -RETURN = ''' -openstack_ports: - description: List of port dictionaries. A subset of the dictionary keys - listed below may be returned, depending on your cloud provider. - returned: always, but can be null - type: complex - contains: - admin_state_up: - description: The administrative state of the router, which is - up (true) or down (false). - returned: success - type: bool - sample: true - allowed_address_pairs: - description: A set of zero or more allowed address pairs. An - address pair consists of an IP address and MAC address. - returned: success - type: list - sample: [] - "binding:host_id": - description: The UUID of the host where the port is allocated. - returned: success - type: str - sample: "b4bd682d-234a-4091-aa5b-4b025a6a7759" - "binding:profile": - description: A dictionary the enables the application running on - the host to pass and receive VIF port-specific - information to the plug-in. - returned: success - type: dict - sample: {} - "binding:vif_details": - description: A dictionary that enables the application to pass - information about functions that the Networking API - provides. - returned: success - type: dict - sample: {"port_filter": true} - "binding:vif_type": - description: The VIF type for the port. - returned: success - type: dict - sample: "ovs" - "binding:vnic_type": - description: The virtual network interface card (vNIC) type that is - bound to the neutron port. - returned: success - type: str - sample: "normal" - device_id: - description: The UUID of the device that uses this port. - returned: success - type: str - sample: "b4bd682d-234a-4091-aa5b-4b025a6a7759" - device_owner: - description: The UUID of the entity that uses this port. - returned: success - type: str - sample: "network:router_interface" - dns_assignment: - description: DNS assignment information. - returned: success - type: list - dns_name: - description: DNS name - returned: success - type: str - sample: "" - extra_dhcp_opts: - description: A set of zero or more extra DHCP option pairs. - An option pair consists of an option value and name. - returned: success - type: list - sample: [] - fixed_ips: - description: The IP addresses for the port. Includes the IP address - and UUID of the subnet. - returned: success - type: list - id: - description: The UUID of the port. - returned: success - type: str - sample: "3ec25c97-7052-4ab8-a8ba-92faf84148de" - ip_address: - description: The IP address. - returned: success - type: str - sample: "127.0.0.1" - mac_address: - description: The MAC address. - returned: success - type: str - sample: "00:00:5E:00:53:42" - name: - description: The port name. - returned: success - type: str - sample: "port_name" - network_id: - description: The UUID of the attached network. - returned: success - type: str - sample: "dd1ede4f-3952-4131-aab6-3b8902268c7d" - port_security_enabled: - description: The port security status. The status is enabled (true) or disabled (false). - returned: success - type: bool - sample: false - security_groups: - description: The UUIDs of any attached security groups. - returned: success - type: list - status: - description: The port status. - returned: success - type: str - sample: "ACTIVE" - tenant_id: - description: The UUID of the tenant who owns the network. - returned: success - type: str - sample: "51fce036d7984ba6af4f6c849f65ef00" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - argument_spec = openstack_full_argument_spec( - port=dict(required=False), - filters=dict(type='dict', required=False), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - is_old_facts = module._name == 'os_port_facts' - if is_old_facts: - module.deprecate("The 'os_port_facts' module has been renamed to 'os_port_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - port = module.params.get('port') - filters = module.params.get('filters') - - sdk, cloud = openstack_cloud_from_module(module) - try: - ports = cloud.search_ports(port, filters) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_ports=ports)) - else: - module.exit_json(changed=False, openstack_ports=ports) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_project.py b/lib/ansible/modules/cloud/openstack/os_project.py deleted file mode 100644 index 17922285e5..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_project.py +++ /dev/null @@ -1,211 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2015 IBM Corporation -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_project -short_description: Manage OpenStack Projects -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Alberto Gireud (@agireud)" -description: - - Manage OpenStack Projects. Projects can be created, - updated or deleted using this module. A project will be updated - if I(name) matches an existing project and I(state) is present. - The value for I(name) cannot be updated without deleting and - re-creating the project. -options: - name: - description: - - Name for the project - required: true - description: - description: - - Description for the project - domain_id: - description: - - Domain id to create the project in if the cloud supports domains. - aliases: ['domain'] - enabled: - description: - - Is the project enabled - type: bool - default: 'yes' - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a project -- os_project: - cloud: mycloud - endpoint_type: admin - state: present - name: demoproject - description: demodescription - domain_id: demoid - enabled: True - -# Delete a project -- os_project: - cloud: mycloud - endpoint_type: admin - state: absent - name: demoproject -''' - - -RETURN = ''' -project: - description: Dictionary describing the project. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Project ID - type: str - sample: "f59382db809c43139982ca4189404650" - name: - description: Project name - type: str - sample: "demoproject" - description: - description: Project description - type: str - sample: "demodescription" - enabled: - description: Boolean to indicate if project is enabled - type: bool - sample: True -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, project): - keys = ('description', 'enabled') - for key in keys: - if module.params[key] is not None and module.params[key] != project.get(key): - return True - - return False - - -def _system_state_change(module, project): - state = module.params['state'] - if state == 'present': - if project is None: - changed = True - else: - if _needs_update(module, project): - changed = True - else: - changed = False - - elif state == 'absent': - if project is None: - changed = False - else: - changed = True - - return changed - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - description=dict(required=False, default=None), - domain_id=dict(required=False, default=None, aliases=['domain']), - enabled=dict(default=True, type='bool'), - state=dict(default='present', choices=['absent', 'present']) - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule( - argument_spec, - supports_check_mode=True, - **module_kwargs - ) - - name = module.params['name'] - description = module.params['description'] - domain = module.params.get('domain_id') - enabled = module.params['enabled'] - state = module.params['state'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - if domain: - try: - # We assume admin is passing domain id - dom = cloud.get_domain(domain)['id'] - domain = dom - except Exception: - # If we fail, maybe admin is passing a domain name. - # Note that domains have unique names, just like id. - try: - dom = cloud.search_domains(filters={'name': domain})[0]['id'] - domain = dom - except Exception: - # Ok, let's hope the user is non-admin and passing a sane id - pass - - if domain: - project = cloud.get_project(name, domain_id=domain) - else: - project = cloud.get_project(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, project)) - - if state == 'present': - if project is None: - project = cloud.create_project( - name=name, description=description, - domain_id=domain, - enabled=enabled) - changed = True - else: - if _needs_update(module, project): - project = cloud.update_project( - project['id'], description=description, - enabled=enabled) - changed = True - else: - changed = False - module.exit_json(changed=changed, project=project) - - elif state == 'absent': - if project is None: - changed = False - else: - cloud.delete_project(project['id']) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=e.message, extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_project_access.py b/lib/ansible/modules/cloud/openstack/os_project_access.py deleted file mode 100644 index 912936f1f6..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_project_access.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/python - -# 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/>. - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - -DOCUMENTATION = ''' ---- -module: os_project_access -short_description: Manage OpenStack compute flavors access -extends_documentation_fragment: openstack -version_added: "2.5" -author: "Roberto Polli (@ioggstream)" -description: - - Add or remove flavor, volume_type or other resources access - from OpenStack. -options: - state: - description: - - Indicate desired state of the resource. - choices: ['present', 'absent'] - required: false - default: present - target_project_id: - description: - - Project id. - required: true - resource_type: - description: - - The resource type (eg. nova_flavor, cinder_volume_type). - resource_name: - description: - - The resource name (eg. tiny). - availability_zone: - description: - - The availability zone of the resource. -requirements: - - "openstacksdk" - -''' - -EXAMPLES = ''' -- name: "Enable access to tiny flavor to your tenant." - os_project_access: - cloud: mycloud - state: present - target_project_id: f0f1f2f3f4f5f67f8f9e0e1 - resource_name: tiny - resource_type: nova_flavor - - -- name: "Disable access to the given flavor to project" - os_project_access: - cloud: mycloud - state: absent - target_project_id: f0f1f2f3f4f5f67f8f9e0e1 - resource_name: tiny - resource_type: nova_flavor -''' - -RETURN = ''' -flavor: - description: Dictionary describing the flavor. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Flavor ID. - returned: success - type: str - sample: "515256b8-7027-4d73-aa54-4e30a4a4a339" - name: - description: Flavor name. - returned: success - type: str - sample: "tiny" - -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - argument_spec = openstack_full_argument_spec( - state=dict(required=False, default='present', - choices=['absent', 'present']), - - target_project_id=dict(required=True, type='str'), - resource_type=dict(required=True, type='str'), - resource_name=dict(required=True, type='str'), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule( - argument_spec, - supports_check_mode=True, - required_if=[ - ('state', 'present', ['target_project_id']) - ], - **module_kwargs) - - sdk, cloud = openstack_cloud_from_module(module) - - changed = False - state = module.params['state'] - resource_name = module.params['resource_name'] - resource_type = module.params['resource_type'] - target_project_id = module.params['target_project_id'] - - try: - if resource_type == 'nova_flavor': - # returns Munch({'NAME_ATTR': 'name', - # 'tenant_id': u'37e55da59ec842649d84230f3a24eed5', - # 'HUMAN_ID': False, - # 'flavor_id': u'6d4d37b9-0480-4a8c-b8c9-f77deaad73f9', - # 'request_ids': [], 'human_id': None}), - _get_resource = cloud.get_flavor - _list_resource_access = cloud.list_flavor_access - _add_resource_access = cloud.add_flavor_access - _remove_resource_access = cloud.remove_flavor_access - elif resource_type == 'cinder_volume_type': - # returns [Munch({ - # 'project_id': u'178cdb9955b047eea7afbe582038dc94', - # 'properties': {'request_ids': [], 'NAME_ATTR': 'name', - # 'human_id': None, - # 'HUMAN_ID': False}, - # 'id': u'd5573023-b290-42c8-b232-7c5ca493667f'}), - _get_resource = cloud.get_volume_type - _list_resource_access = cloud.get_volume_type_access - _add_resource_access = cloud.add_volume_type_access - _remove_resource_access = cloud.remove_volume_type_access - else: - module.exit_json(changed=False, - resource_name=resource_name, - resource_type=resource_type, - error="Not implemented.") - - resource = _get_resource(resource_name) - if not resource: - module.exit_json(changed=False, - resource_name=resource_name, - resource_type=resource_type, - error="Not found.") - resource_id = getattr(resource, 'id', resource['id']) - # _list_resource_access returns a list of dicts containing 'project_id' - acls = _list_resource_access(resource_id) - - if not all(acl.get('project_id') for acl in acls): - module.exit_json(changed=False, - resource_name=resource_name, - resource_type=resource_type, - error="Missing project_id in resource output.") - allowed_tenants = [acl['project_id'] for acl in acls] - - changed_access = any(( - state == 'present' and target_project_id not in allowed_tenants, - state == 'absent' and target_project_id in allowed_tenants - )) - if module.check_mode or not changed_access: - module.exit_json(changed=changed_access, - resource=resource, - id=resource_id) - - if state == 'present': - _add_resource_access( - resource_id, target_project_id - ) - elif state == 'absent': - _remove_resource_access( - resource_id, target_project_id - ) - - module.exit_json(changed=True, - resource=resource, - id=resource_id) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), **module.params) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_project_info.py b/lib/ansible/modules/cloud/openstack/os_project_info.py deleted file mode 100644 index 0ce12c7d3a..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_project_info.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 Hewlett-Packard Enterprise Corporation -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_project_info -short_description: Retrieve information about one or more OpenStack projects -extends_documentation_fragment: openstack -version_added: "2.1" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -description: - - Retrieve information about a one or more OpenStack projects - - This module was called C(os_project_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_project_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - name: - description: - - Name or ID of the project - required: true - domain: - description: - - Name or ID of the domain containing the project if the cloud supports domains - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - availability_zone: - description: - - Ignored. Present for backwards compatibility -''' - -EXAMPLES = ''' -# Gather information about previously created projects -- os_project_info: - cloud: awesomecloud - register: result -- debug: - msg: "{{ result.openstack_projects }}" - -# Gather information about a previously created project by name -- os_project_info: - cloud: awesomecloud - name: demoproject - register: result -- debug: - msg: "{{ result.openstack_projects }}" - -# Gather information about a previously created project in a specific domain -- os_project_info: - cloud: awesomecloud - name: demoproject - domain: admindomain - register: result -- debug: - msg: "{{ result.openstack_projects }}" - -# Gather information about a previously created project in a specific domain with filter -- os_project_info: - cloud: awesomecloud - name: demoproject - domain: admindomain - filters: - enabled: False - register: result -- debug: - msg: "{{ result.openstack_projects }}" -''' - - -RETURN = ''' -openstack_projects: - description: has all the OpenStack information about projects - returned: always, but can be null - type: complex - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Name given to the project. - returned: success - type: str - description: - description: Description of the project - returned: success - type: str - enabled: - description: Flag to indicate if the project is enabled - returned: success - type: bool - domain_id: - description: Domain ID containing the project (keystone v3 clouds only) - returned: success - type: bool -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - domain=dict(required=False, default=None), - filters=dict(required=False, type='dict', default=None), - ) - - module = AnsibleModule(argument_spec) - is_old_facts = module._name == 'os_project_facts' - if is_old_facts: - module.deprecate("The 'os_project_facts' module has been renamed to 'os_project_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, opcloud = openstack_cloud_from_module(module) - try: - name = module.params['name'] - domain = module.params['domain'] - filters = module.params['filters'] - - if domain: - try: - # We assume admin is passing domain id - dom = opcloud.get_domain(domain)['id'] - domain = dom - except Exception: - # If we fail, maybe admin is passing a domain name. - # Note that domains have unique names, just like id. - dom = opcloud.search_domains(filters={'name': domain}) - if dom: - domain = dom[0]['id'] - else: - module.fail_json(msg='Domain name or ID does not exist') - - if not filters: - filters = {} - - filters['domain_id'] = domain - - projects = opcloud.search_projects(name, filters) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_projects=projects)) - else: - module.exit_json(changed=False, openstack_projects=projects) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_quota.py b/lib/ansible/modules/cloud/openstack/os_quota.py deleted file mode 100644 index 5cf40040ec..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_quota.py +++ /dev/null @@ -1,463 +0,0 @@ -#!/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) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_quota -short_description: Manage OpenStack Quotas -extends_documentation_fragment: openstack -version_added: "2.3" -author: "Michael Gale (@mgale) <gale.michael@gmail.com>" -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 - state: - description: - - A value of present sets the quota and a value of absent resets the quota to system defaults. - default: present - backup_gigabytes: - description: Maximum size of backups in GB's. - backups: - description: Maximum number of backups allowed. - cores: - description: Maximum number of CPU's per project. - fixed_ips: - description: Number of fixed IP's to allow. - floating_ips: - description: Number of floating IP's to allow in Compute. - aliases: ['compute_floating_ips'] - floatingip: - description: Number of floating IP's to allow in Network. - aliases: ['network_floating_ips'] - gigabytes: - description: Maximum volume storage allowed for project. - gigabytes_lvm: - description: Maximum size in GB's of individual lvm volumes. - injected_file_size: - description: Maximum file size in bytes. - injected_files: - description: Number of injected files to allow. - injected_path_size: - description: Maximum path size. - instances: - description: Maximum number of instances allowed. - key_pairs: - description: Number of key pairs to allow. - loadbalancer: - description: Number of load balancers to allow. - version_added: "2.4" - network: - description: Number of networks to allow. - per_volume_gigabytes: - description: Maximum size in GB's of individual volumes. - pool: - description: Number of load balancer pools to allow. - version_added: "2.4" - port: - description: Number of Network ports to allow, this needs to be greater than the instances limit. - properties: - description: Number of properties to allow. - ram: - description: Maximum amount of ram in MB to allow. - rbac_policy: - description: Number of policies to allow. - router: - description: Number of routers to allow. - security_group_rule: - description: Number of rules per security group to allow. - security_group: - description: Number of security groups to allow. - server_group_members: - description: Number of server group members to allow. - server_groups: - description: Number of server groups to allow. - snapshots: - description: Number of snapshots to allow. - snapshots_lvm: - description: Number of LVM snapshots to allow. - subnet: - description: Number of subnets to allow. - subnetpool: - description: Number of subnet pools to allow. - volumes: - description: Number of volumes to allow. - volumes_lvm: - description: Number of LVM volumes to allow. - availability_zone: - description: - - Ignored. Present for backwards compatibility - - -requirements: - - "python >= 2.7" - - "openstacksdk >= 0.13.0" - - "keystoneauth1 >= 3.4.0" -''' - -EXAMPLES = ''' -# List a Project Quota -- os_quota: - cloud: mycloud - name: demoproject - -# Set a Project back to the defaults -- os_quota: - cloud: mycloud - name: demoproject - state: absent - -# Update a Project Quota for cores -- os_quota: - cloud: mycloud - name: demoproject - cores: 100 - -# Update a Project Quota -- os_quota: - name: demoproject - cores: 1000 - volumes: 20 - volumes_type: - - volume_lvm: 10 - -# Complete example based on list of projects -- name: Update quotas - os_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 }}" - 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: complex - 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 - } - } - -''' - -import traceback - -KEYSTONEAUTH1_IMP_ERR = None -try: - from keystoneauth1 import exceptions as ksa_exceptions - HAS_KEYSTONEAUTH1 = True -except ImportError: - KEYSTONEAUTH1_IMP_ERR = traceback.format_exc() - HAS_KEYSTONEAUTH1 = False - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _get_volume_quotas(cloud, project): - - return cloud.get_volume_quotas(project) - - -def _get_network_quotas(cloud, project): - - return cloud.get_network_quotas(project) - - -def _get_compute_quotas(cloud, project): - - return cloud.get_compute_quotas(project) - - -def _get_quotas(sdk, module, cloud, project): - - quota = {} - try: - quota['volume'] = _get_volume_quotas(cloud, project) - except ksa_exceptions.EndpointNotFound: - module.warn("No public endpoint for volumev2 service was found. Ignoring volume quotas.") - - try: - quota['network'] = _get_network_quotas(cloud, project) - except ksa_exceptions.EndpointNotFound: - module.warn("No public endpoint for network service was found. Ignoring network quotas.") - - quota['compute'] = _get_compute_quotas(cloud, project) - - for quota_type in quota.keys(): - quota[quota_type] = _scrub_results(quota[quota_type]) - - return quota - - -def _scrub_results(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(module, 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 module.params and module.params[quota_option] is not None: - if project_quota_output[quota_type][quota_option] != module.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] = module.params[quota_option] - - return (changes_required, quota_change_request) - - -def _system_state_change(module, 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 = _system_state_change_details( - module, - project_quota_output - ) - - if changes_required: - return True - else: - return False - - -def main(): - - argument_spec = openstack_full_argument_spec( - 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), - loadbalancer=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 = AnsibleModule(argument_spec, - supports_check_mode=True - ) - - if not HAS_KEYSTONEAUTH1: - module.fail_json(msg=missing_required_lib("keystoneauth1"), exception=KEYSTONEAUTH1_IMP_ERR) - - sdk, cloud = openstack_cloud_from_module(module) - try: - cloud_params = dict(module.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 module.params[dynamic_type].items(): - module.params[k] = int(v) - - # Get current quota values - project_quota_output = _get_quotas( - sdk, module, cloud, cloud_params['name']) - changes_required = False - - if module.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 module.check_mode: - module.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(cloud, 'delete_%s_quotas' % (quota_type)) - try: - quota_call(cloud_params['name']) - except sdk.exceptions.OpenStackCloudException as e: - error_msg = str(e) - if error_msg.find(neutron_msg1) > -1 and error_msg.find(neutron_msg2) > -1: - pass - else: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - project_quota_output = _get_quotas( - sdk, module, cloud, cloud_params['name']) - changes_required = True - - elif module.params['state'] == "present": - if module.check_mode: - module.exit_json(changed=_system_state_change(module, project_quota_output)) - - changes_required, quota_change_request = _system_state_change_details( - module, - project_quota_output - ) - - if changes_required: - for quota_type in quota_change_request.keys(): - quota_call = getattr(cloud, '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 = _get_quotas( - sdk, module, cloud, cloud_params['name']) - - if project_quota_output == project_quota_update: - module.fail_json(msg='Could not apply quota update') - - project_quota_output = project_quota_update - - module.exit_json(changed=changes_required, - openstack_quotas=project_quota_output - ) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_recordset.py b/lib/ansible/modules/cloud/openstack/os_recordset.py deleted file mode 100644 index 3bd4b6f0a8..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_recordset.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 Hewlett-Packard Enterprise -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_recordset -short_description: Manage OpenStack DNS recordsets -extends_documentation_fragment: openstack -version_added: "2.2" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -description: - - Manage OpenStack DNS recordsets. Recordsets can be created, deleted or - updated. Only the I(records), I(description), and I(ttl) values - can be updated. -options: - zone: - description: - - Zone managing the recordset - required: true - name: - description: - - Name of the recordset - required: true - recordset_type: - description: - - Recordset type - required: true - records: - description: - - List of recordset definitions - required: true - description: - description: - - Description of the recordset - ttl: - description: - - TTL (Time To Live) value in seconds - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a recordset named "www.example.net." -- os_recordset: - cloud: mycloud - state: present - zone: example.net. - name: www - recordset_type: primary - records: ['10.1.1.1'] - description: test recordset - ttl: 3600 - -# Update the TTL on existing "www.example.net." recordset -- os_recordset: - cloud: mycloud - state: present - zone: example.net. - name: www - ttl: 7200 - -# Delete recordset named "www.example.net." -- os_recordset: - cloud: mycloud - state: absent - zone: example.net. - name: www -''' - -RETURN = ''' -recordset: - description: Dictionary describing the recordset. - returned: On success when I(state) is 'present'. - type: complex - contains: - id: - description: Unique recordset ID - type: str - sample: "c1c530a3-3619-46f3-b0f6-236927b2618c" - name: - description: Recordset name - type: str - sample: "www.example.net." - zone_id: - description: Zone id - type: str - sample: 9508e177-41d8-434e-962c-6fe6ca880af7 - type: - description: Recordset type - type: str - sample: "A" - description: - description: Recordset description - type: str - sample: "Test description" - ttl: - description: Zone TTL value - type: int - sample: 3600 - records: - description: Recordset records - type: list - sample: ['10.0.0.1'] -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, records, description, ttl, zone, recordset): - if state == 'present': - if recordset is None: - return True - if records is not None and recordset['records'] != records: - return True - if description is not None and recordset['description'] != description: - return True - if ttl is not None and recordset['ttl'] != ttl: - return True - if state == 'absent' and recordset: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - zone=dict(required=True), - name=dict(required=True), - recordset_type=dict(required=False), - records=dict(required=False, type='list'), - description=dict(required=False, default=None), - ttl=dict(required=False, default=None, type='int'), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - required_if=[ - ('state', 'present', - ['recordset_type', 'records'])], - supports_check_mode=True, - **module_kwargs) - - zone = module.params.get('zone') - name = module.params.get('name') - state = module.params.get('state') - - sdk, cloud = openstack_cloud_from_module(module) - try: - recordset_type = module.params.get('recordset_type') - recordset_filter = {'type': recordset_type} - - recordsets = cloud.search_recordsets(zone, name_or_id=name, filters=recordset_filter) - - if len(recordsets) == 1: - recordset = recordsets[0] - try: - recordset_id = recordset['id'] - except KeyError as e: - module.fail_json(msg=str(e)) - else: - # recordsets is filtered by type and should never be more than 1 return - recordset = None - - if state == 'present': - records = module.params.get('records') - description = module.params.get('description') - ttl = module.params.get('ttl') - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, - records, description, - ttl, zone, - recordset)) - - if recordset is None: - recordset = cloud.create_recordset( - zone=zone, name=name, recordset_type=recordset_type, - records=records, description=description, ttl=ttl) - changed = True - else: - if records is None: - records = [] - - pre_update_recordset = recordset - changed = _system_state_change(state, records, - description, ttl, - zone, pre_update_recordset) - if changed: - zone = cloud.update_recordset( - zone, recordset_id, - records=records, - description=description, - ttl=ttl) - - module.exit_json(changed=changed, recordset=recordset) - - elif state == 'absent': - if module.check_mode: - module.exit_json(changed=_system_state_change(state, - None, None, - None, - None, recordset)) - - if recordset is None: - changed = False - else: - cloud.delete_recordset(zone, recordset_id) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_router.py b/lib/ansible/modules/cloud/openstack/os_router.py deleted file mode 100644 index 56abc21493..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_router.py +++ /dev/null @@ -1,487 +0,0 @@ -#!/usr/bin/python -# -# Copyright: Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_router -short_description: Create or delete routers from OpenStack -extends_documentation_fragment: openstack -version_added: "2.0" -author: "David Shrewsbury (@Shrews)" -description: - - Create or Delete routers from OpenStack. Although Neutron allows - routers to share the same name, this module enforces name uniqueness - to be more user friendly. -options: - state: - description: - - Indicate desired state of the resource - choices: ['present', 'absent'] - default: present - name: - description: - - Name to be give to the router - required: true - admin_state_up: - description: - - Desired admin state of the created or existing router. - type: bool - default: 'yes' - enable_snat: - description: - - Enable Source NAT (SNAT) attribute. - type: bool - network: - description: - - Unique name or ID of the external gateway network. - - required I(interfaces) or I(enable_snat) are provided. - project: - description: - - Unique name or ID of the project. - version_added: "2.2" - external_fixed_ips: - description: - - The IP address parameters for the external gateway network. Each - is a dictionary with the subnet name or ID (subnet) and the IP - address to assign on the subnet (ip). If no IP is specified, - one is automatically assigned from that subnet. - interfaces: - description: - - List of subnets to attach to the router internal interface. Default - gateway associated with the subnet will be automatically attached - with the router's internal interface. - In order to provide an ip address different from the default - gateway,parameters are passed as dictionary with keys as network - name or ID(net), subnet name or ID (subnet) and the IP of - port (portip) from the network. - User defined portip is often required when a multiple router need - to be connected to a single subnet for which the default gateway has - been already used. - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -EXAMPLES = ''' -# Create a simple router, not attached to a gateway or subnets. -- os_router: - cloud: mycloud - state: present - name: simple_router - -# Create a simple router, not attached to a gateway or subnets for a given project. -- os_router: - cloud: mycloud - state: present - name: simple_router - project: myproj - -# Creates a router attached to ext_network1 on an IPv4 subnet and one -# internal subnet interface. -- os_router: - cloud: mycloud - state: present - name: router1 - network: ext_network1 - external_fixed_ips: - - subnet: public-subnet - ip: 172.24.4.2 - interfaces: - - private-subnet - -# Create another router with two internal subnet interfaces.One with user defined port -# ip and another with default gateway. -- os_router: - cloud: mycloud - state: present - name: router2 - network: ext_network1 - interfaces: - - net: private-net - subnet: private-subnet - portip: 10.1.1.10 - - project-subnet - -# Create another router with two internal subnet interface.One with user defined port -# ip and and another with default gateway. -- os_router: - cloud: mycloud - state: present - name: router2 - network: ext_network1 - interfaces: - - net: private-net - subnet: private-subnet - portip: 10.1.1.10 - - project-subnet - -# Create another router with two internal subnet interface. one with user defined port -# ip and and another with default gateway. -- os_router: - cloud: mycloud - state: present - name: router2 - network: ext_network1 - interfaces: - - net: private-net - subnet: private-subnet - portip: 10.1.1.10 - - project-subnet - -# Update existing router1 external gateway to include the IPv6 subnet. -# Note that since 'interfaces' is not provided, any existing internal -# interfaces on an existing router will be left intact. -- os_router: - cloud: mycloud - state: present - name: router1 - network: ext_network1 - external_fixed_ips: - - subnet: public-subnet - ip: 172.24.4.2 - - subnet: ipv6-public-subnet - ip: 2001:db8::3 - -# Delete router1 -- os_router: - cloud: mycloud - state: absent - name: router1 -''' - -RETURN = ''' -router: - description: Dictionary describing the router. - returned: On success when I(state) is 'present' - type: complex - contains: - id: - description: Router ID. - type: str - sample: "474acfe5-be34-494c-b339-50f06aa143e4" - name: - description: Router name. - type: str - sample: "router1" - admin_state_up: - description: Administrative state of the router. - type: bool - sample: true - status: - description: The router status. - type: str - sample: "ACTIVE" - tenant_id: - description: The tenant ID. - type: str - sample: "861174b82b43463c9edc5202aadc60ef" - external_gateway_info: - description: The external gateway parameters. - type: dict - sample: { - "enable_snat": true, - "external_fixed_ips": [ - { - "ip_address": "10.6.6.99", - "subnet_id": "4272cb52-a456-4c20-8f3c-c26024ecfa81" - } - ] - } - routes: - description: The extra routes configuration for L3 router. - type: list -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -ROUTER_INTERFACE_OWNERS = set([ - 'network:router_interface', - 'network:router_interface_distributed', - 'network:ha_router_replicated_interface' -]) - - -def _router_internal_interfaces(cloud, router): - for port in cloud.list_router_interfaces(router, 'internal'): - if port['device_owner'] in ROUTER_INTERFACE_OWNERS: - yield port - - -def _needs_update(cloud, module, router, network, internal_subnet_ids, internal_port_ids, filters=None): - """Decide if the given router needs an update. - """ - if router['admin_state_up'] != module.params['admin_state_up']: - return True - if router['external_gateway_info']: - # check if enable_snat is set in module params - if module.params['enable_snat'] is not None: - if router['external_gateway_info'].get('enable_snat', True) != module.params['enable_snat']: - return True - if network: - if not router['external_gateway_info']: - return True - elif router['external_gateway_info']['network_id'] != network['id']: - return True - - # check external interfaces - if module.params['external_fixed_ips']: - for new_iface in module.params['external_fixed_ips']: - subnet = cloud.get_subnet(new_iface['subnet'], filters) - exists = False - - # compare the requested interface with existing, looking for an existing match - for existing_iface in router['external_gateway_info']['external_fixed_ips']: - if existing_iface['subnet_id'] == subnet['id']: - if 'ip' in new_iface: - if existing_iface['ip_address'] == new_iface['ip']: - # both subnet id and ip address match - exists = True - break - else: - # only the subnet was given, so ip doesn't matter - exists = True - break - - # this interface isn't present on the existing router - if not exists: - return True - - # check internal interfaces - if module.params['interfaces']: - existing_subnet_ids = [] - for port in _router_internal_interfaces(cloud, router): - if 'fixed_ips' in port: - for fixed_ip in port['fixed_ips']: - existing_subnet_ids.append(fixed_ip['subnet_id']) - - for iface in module.params['interfaces']: - if isinstance(iface, dict): - for p_id in internal_port_ids: - p = cloud.get_port(name_or_id=p_id) - if 'fixed_ips' in p: - for fip in p['fixed_ips']: - internal_subnet_ids.append(fip['subnet_id']) - - if set(internal_subnet_ids) != set(existing_subnet_ids): - internal_subnet_ids = [] - return True - - return False - - -def _system_state_change(cloud, module, router, network, internal_ids, internal_portids, filters=None): - """Check if the system state would be changed.""" - state = module.params['state'] - if state == 'absent' and router: - return True - if state == 'present': - if not router: - return True - return _needs_update(cloud, module, router, network, internal_ids, internal_portids, filters) - return False - - -def _build_kwargs(cloud, module, router, network): - kwargs = { - 'admin_state_up': module.params['admin_state_up'], - } - - if router: - kwargs['name_or_id'] = router['id'] - else: - kwargs['name'] = module.params['name'] - - if network: - kwargs['ext_gateway_net_id'] = network['id'] - # can't send enable_snat unless we have a network - if module.params.get('enable_snat') is not None: - kwargs['enable_snat'] = module.params['enable_snat'] - - if module.params['external_fixed_ips']: - kwargs['ext_fixed_ips'] = [] - for iface in module.params['external_fixed_ips']: - subnet = cloud.get_subnet(iface['subnet']) - d = {'subnet_id': subnet['id']} - if 'ip' in iface: - d['ip_address'] = iface['ip'] - kwargs['ext_fixed_ips'].append(d) - - return kwargs - - -def _validate_subnets(module, cloud, filters=None): - external_subnet_ids = [] - internal_subnet_ids = [] - internal_port_ids = [] - existing_port_ips = [] - existing_port_ids = [] - if module.params['external_fixed_ips']: - for iface in module.params['external_fixed_ips']: - subnet = cloud.get_subnet(iface['subnet']) - if not subnet: - module.fail_json(msg='subnet %s not found' % iface['subnet']) - external_subnet_ids.append(subnet['id']) - - if module.params['interfaces']: - for iface in module.params['interfaces']: - if isinstance(iface, str): - subnet = cloud.get_subnet(iface, filters) - if not subnet: - module.fail_json(msg='subnet %s not found' % iface) - internal_subnet_ids.append(subnet['id']) - elif isinstance(iface, dict): - subnet = cloud.get_subnet(iface['subnet'], filters) - if not subnet: - module.fail_json(msg='subnet %s not found' % iface['subnet']) - net = cloud.get_network(iface['net']) - if not net: - module.fail_json(msg='net %s not found' % iface['net']) - if "portip" not in iface: - internal_subnet_ids.append(subnet['id']) - elif not iface['portip']: - module.fail_json(msg='put an ip in portip or remove it from list to assign default port to router') - else: - for existing_port in cloud.list_ports(filters={'network_id': net.id}): - for fixed_ip in existing_port['fixed_ips']: - if iface['portip'] == fixed_ip['ip_address']: - internal_port_ids.append(existing_port.id) - existing_port_ips.append(fixed_ip['ip_address']) - if iface['portip'] not in existing_port_ips: - p = cloud.create_port(network_id=net.id, fixed_ips=[{'ip_address': iface['portip'], 'subnet_id': subnet.id}]) - if p: - internal_port_ids.append(p.id) - - return external_subnet_ids, internal_subnet_ids, internal_port_ids - - -def main(): - argument_spec = openstack_full_argument_spec( - state=dict(default='present', choices=['absent', 'present']), - name=dict(required=True), - admin_state_up=dict(type='bool', default=True), - enable_snat=dict(type='bool'), - network=dict(default=None), - interfaces=dict(type='list', default=None), - external_fixed_ips=dict(type='list', default=None), - project=dict(default=None) - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - name = module.params['name'] - network = module.params['network'] - project = module.params['project'] - - if module.params['external_fixed_ips'] and not network: - module.fail_json(msg='network is required when supplying external_fixed_ips') - - sdk, cloud = openstack_cloud_from_module(module) - try: - if project is not None: - proj = cloud.get_project(project) - if proj is None: - module.fail_json(msg='Project %s could not be found' % project) - project_id = proj['id'] - filters = {'tenant_id': project_id} - else: - project_id = None - filters = None - - router = cloud.get_router(name, filters=filters) - net = None - if network: - net = cloud.get_network(network) - if not net: - module.fail_json(msg='network %s not found' % network) - - # Validate and cache the subnet IDs so we can avoid duplicate checks - # and expensive API calls. - external_ids, subnet_internal_ids, internal_portids = _validate_subnets(module, cloud, filters) - if module.check_mode: - module.exit_json( - changed=_system_state_change(cloud, module, router, net, subnet_internal_ids, internal_portids, filters) - ) - - if state == 'present': - changed = False - - if not router: - kwargs = _build_kwargs(cloud, module, router, net) - if project_id: - kwargs['project_id'] = project_id - router = cloud.create_router(**kwargs) - for int_s_id in subnet_internal_ids: - cloud.add_router_interface(router, subnet_id=int_s_id) - changed = True - # add interface by port id as well - for int_p_id in internal_portids: - cloud.add_router_interface(router, port_id=int_p_id) - changed = True - else: - if _needs_update(cloud, module, router, net, subnet_internal_ids, internal_portids, filters): - kwargs = _build_kwargs(cloud, module, router, net) - updated_router = cloud.update_router(**kwargs) - - # Protect against update_router() not actually - # updating the router. - if not updated_router: - changed = False - - # On a router update, if any internal interfaces were supplied, - # just detach all existing internal interfaces and attach the new. - if internal_portids or subnet_internal_ids: - router = updated_router - ports = _router_internal_interfaces(cloud, router) - for port in ports: - cloud.remove_router_interface(router, port_id=port['id']) - if internal_portids: - external_ids, subnet_internal_ids, internal_portids = _validate_subnets(module, cloud, filters) - for int_p_id in internal_portids: - cloud.add_router_interface(router, port_id=int_p_id) - changed = True - if subnet_internal_ids: - for s_id in subnet_internal_ids: - cloud.add_router_interface(router, subnet_id=s_id) - changed = True - - module.exit_json(changed=changed, - router=router, - id=router['id']) - - elif state == 'absent': - if not router: - module.exit_json(changed=False) - else: - # We need to detach all internal interfaces on a router before - # we will be allowed to delete it. - ports = _router_internal_interfaces(cloud, router) - router_id = router['id'] - for port in ports: - cloud.remove_router_interface(router, port_id=port['id']) - cloud.delete_router(router_id) - module.exit_json(changed=True) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_security_group.py b/lib/ansible/modules/cloud/openstack/os_security_group.py deleted file mode 100644 index d05765bf1f..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_security_group.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_security_group -short_description: Add/Delete security groups from an OpenStack cloud. -extends_documentation_fragment: openstack -author: "Monty Taylor (@emonty)" -version_added: "2.0" -description: - - Add or Remove security groups from an OpenStack cloud. -options: - name: - description: - - Name that has to be given to the security group. This module - requires that security group names be unique. - required: true - description: - description: - - Long description of the purpose of the security group - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - project: - description: - - Unique name or ID of the project. - required: false - version_added: "2.7" - availability_zone: - description: - - Ignored. Present for backwards compatibility -''' - -EXAMPLES = ''' -# Create a security group -- os_security_group: - cloud: mordred - state: present - name: foo - description: security group for foo servers - -# Update the existing 'foo' security group description -- os_security_group: - cloud: mordred - state: present - name: foo - description: updated description for the foo security group - -# Create a security group for a given project -- os_security_group: - cloud: mordred - state: present - name: foo - project: myproj -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, secgroup): - """Check for differences in the updatable values. - - NOTE: We don't currently allow name updates. - """ - if secgroup['description'] != module.params['description']: - return True - return False - - -def _system_state_change(module, secgroup): - state = module.params['state'] - if state == 'present': - if not secgroup: - return True - return _needs_update(module, secgroup) - if state == 'absent' and secgroup: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - description=dict(default=''), - state=dict(default='present', choices=['absent', 'present']), - project=dict(default=None), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - name = module.params['name'] - state = module.params['state'] - description = module.params['description'] - project = module.params['project'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - if project is not None: - proj = cloud.get_project(project) - if proj is None: - module.fail_json(msg='Project %s could not be found' % project) - project_id = proj['id'] - else: - project_id = cloud.current_project_id - - if project_id: - filters = {'tenant_id': project_id} - else: - filters = None - - secgroup = cloud.get_security_group(name, filters=filters) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, secgroup)) - - changed = False - if state == 'present': - if not secgroup: - kwargs = {} - if project_id: - kwargs['project_id'] = project_id - secgroup = cloud.create_security_group(name, description, - **kwargs) - changed = True - else: - if _needs_update(module, secgroup): - secgroup = cloud.update_security_group( - secgroup['id'], description=description) - changed = True - module.exit_json( - changed=changed, id=secgroup['id'], secgroup=secgroup) - - if state == 'absent': - if secgroup: - cloud.delete_security_group(secgroup['id']) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == "__main__": - main() diff --git a/lib/ansible/modules/cloud/openstack/os_security_group_rule.py b/lib/ansible/modules/cloud/openstack/os_security_group_rule.py deleted file mode 100644 index 0c84dfd6d3..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_security_group_rule.py +++ /dev/null @@ -1,385 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_security_group_rule -short_description: Add/Delete rule from an existing security group -author: - - "Benno Joy (@bennojoy)" - - "Jeffrey van Pelt (@Thulium-Drake)" -extends_documentation_fragment: openstack -version_added: "2.0" -description: - - Add or Remove rule from an existing security group -options: - security_group: - description: - - Name or ID of the security group - required: true - protocol: - description: - - IP protocols ANY TCP UDP ICMP 112 (VRRP) 132 (SCTP) - choices: ['any', 'tcp', 'udp', 'icmp', '112', '132', None] - port_range_min: - description: - - Starting port - port_range_max: - description: - - Ending port - remote_ip_prefix: - description: - - Source IP address(es) in CIDR notation (exclusive with remote_group) - remote_group: - description: - - Name or ID of the Security group to link (exclusive with - remote_ip_prefix) - ethertype: - description: - - Must be IPv4 or IPv6, and addresses represented in CIDR must - match the ingress or egress rules. Not all providers support IPv6. - choices: ['IPv4', 'IPv6'] - default: IPv4 - direction: - description: - - The direction in which the security group rule is applied. Not - all providers support egress. - choices: ['egress', 'ingress'] - default: ingress - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - project: - description: - - Unique name or ID of the project. - required: false - version_added: "2.7" - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: ["openstacksdk"] -''' - -EXAMPLES = ''' -# Create a security group rule -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: tcp - port_range_min: 80 - port_range_max: 80 - remote_ip_prefix: 0.0.0.0/0 - -# Create a security group rule for ping -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: icmp - remote_ip_prefix: 0.0.0.0/0 - -# Another way to create the ping rule -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: icmp - port_range_min: -1 - port_range_max: -1 - remote_ip_prefix: 0.0.0.0/0 - -# Create a TCP rule covering all ports -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: tcp - port_range_min: 1 - port_range_max: 65535 - remote_ip_prefix: 0.0.0.0/0 - -# Another way to create the TCP rule above (defaults to all ports) -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: tcp - remote_ip_prefix: 0.0.0.0/0 - -# Create a rule for VRRP with numbered protocol 112 -- os_security_group_rule: - security_group: loadbalancer_sg - protocol: 112 - remote_group: loadbalancer-node_sg - -# Create a security group rule for a given project -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: icmp - remote_ip_prefix: 0.0.0.0/0 - project: myproj - -# Remove the default created egress rule for IPv4 -- os_security_group_rule: - cloud: mordred - security_group: foo - protocol: any - remote_ip_prefix: 0.0.0.0/0 -''' - -RETURN = ''' -id: - description: Unique rule UUID. - type: str - returned: state == present -direction: - description: The direction in which the security group rule is applied. - type: str - sample: 'egress' - returned: state == present -ethertype: - description: One of IPv4 or IPv6. - type: str - sample: 'IPv4' - returned: state == present -port_range_min: - description: The minimum port number in the range that is matched by - the security group rule. - type: int - sample: 8000 - returned: state == present -port_range_max: - description: The maximum port number in the range that is matched by - the security group rule. - type: int - sample: 8000 - returned: state == present -protocol: - description: The protocol that is matched by the security group rule. - type: str - sample: 'tcp' - returned: state == present -remote_ip_prefix: - description: The remote IP prefix to be associated with this security group rule. - type: str - sample: '0.0.0.0/0' - returned: state == present -security_group_id: - description: The security group ID to associate with this security group rule. - type: str - returned: state == present -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _ports_match(protocol, module_min, module_max, rule_min, rule_max): - """ - Capture the complex port matching logic. - - The port values coming in for the module might be -1 (for ICMP), - which will work only for Nova, but this is handled by sdk. Likewise, - they might be None, which works for Neutron, but not Nova. This too is - handled by sdk. Since sdk will consistently return these port - values as None, we need to convert any -1 values input to the module - to None here for comparison. - - For TCP and UDP protocols, None values for both min and max are - represented as the range 1-65535 for Nova, but remain None for - Neutron. sdk returns the full range when Nova is the backend (since - that is how Nova stores them), and None values for Neutron. If None - values are input to the module for both values, then we need to adjust - for comparison. - """ - - # Check if the user is supplying -1 for ICMP. - if protocol == 'icmp': - if module_min and int(module_min) == -1: - module_min = None - if module_max and int(module_max) == -1: - module_max = None - - # Rules with 'any' protocol do not match ports - if protocol == 'any': - return True - - # Check if the user is supplying -1 or None values for full TPC/UDP port range. - if protocol in ['tcp', 'udp'] or protocol is None: - if module_min and module_max and int(module_min) == int(module_max) == -1: - module_min = None - module_max = None - - if ((module_min is None and module_max is None) and - (rule_min and int(rule_min) == 1 and - rule_max and int(rule_max) == 65535)): - # (None, None) == (1, 65535) - return True - - # Sanity check to make sure we don't have type comparison issues. - if module_min: - module_min = int(module_min) - if module_max: - module_max = int(module_max) - if rule_min: - rule_min = int(rule_min) - if rule_max: - rule_max = int(rule_max) - - return module_min == rule_min and module_max == rule_max - - -def _find_matching_rule(module, secgroup, remotegroup): - """ - Find a rule in the group that matches the module parameters. - :returns: The matching rule dict, or None if no matches. - """ - protocol = module.params['protocol'] - remote_ip_prefix = module.params['remote_ip_prefix'] - ethertype = module.params['ethertype'] - direction = module.params['direction'] - remote_group_id = remotegroup['id'] - - for rule in secgroup['security_group_rules']: - if (protocol == rule['protocol'] and - remote_ip_prefix == rule['remote_ip_prefix'] and - ethertype == rule['ethertype'] and - direction == rule['direction'] and - remote_group_id == rule['remote_group_id'] and - _ports_match(protocol, - module.params['port_range_min'], - module.params['port_range_max'], - rule['port_range_min'], - rule['port_range_max'])): - return rule - return None - - -def _system_state_change(module, secgroup, remotegroup): - state = module.params['state'] - if secgroup: - rule_exists = _find_matching_rule(module, secgroup, remotegroup) - else: - return False - - if state == 'present' and not rule_exists: - return True - if state == 'absent' and rule_exists: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - security_group=dict(required=True), - # NOTE(Shrews): None is an acceptable protocol value for - # Neutron, but Nova will balk at this. - protocol=dict(default=None, - choices=[None, 'any', 'tcp', 'udp', 'icmp', '112', '132']), - port_range_min=dict(required=False, type='int'), - port_range_max=dict(required=False, type='int'), - remote_ip_prefix=dict(required=False, default=None), - remote_group=dict(required=False, default=None), - ethertype=dict(default='IPv4', - choices=['IPv4', 'IPv6']), - direction=dict(default='ingress', - choices=['egress', 'ingress']), - state=dict(default='present', - choices=['absent', 'present']), - project=dict(default=None), - ) - - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[ - ['remote_ip_prefix', 'remote_group'], - ] - ) - - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - security_group = module.params['security_group'] - remote_group = module.params['remote_group'] - project = module.params['project'] - changed = False - - sdk, cloud = openstack_cloud_from_module(module) - try: - if project is not None: - proj = cloud.get_project(project) - if proj is None: - module.fail_json(msg='Project %s could not be found' % project) - project_id = proj['id'] - else: - project_id = cloud.current_project_id - - if project_id: - filters = {'tenant_id': project_id} - else: - filters = None - - secgroup = cloud.get_security_group(security_group, filters=filters) - - if remote_group: - remotegroup = cloud.get_security_group(remote_group, - filters=filters) - else: - remotegroup = {'id': None} - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, secgroup, remotegroup)) - - if state == 'present': - if module.params['protocol'] == 'any': - module.params['protocol'] = None - - if not secgroup: - module.fail_json(msg='Could not find security group %s' % - security_group) - - rule = _find_matching_rule(module, secgroup, remotegroup) - if not rule: - kwargs = {} - if project_id: - kwargs['project_id'] = project_id - rule = cloud.create_security_group_rule( - secgroup['id'], - port_range_min=module.params['port_range_min'], - port_range_max=module.params['port_range_max'], - protocol=module.params['protocol'], - remote_ip_prefix=module.params['remote_ip_prefix'], - remote_group_id=remotegroup['id'], - direction=module.params['direction'], - ethertype=module.params['ethertype'], - **kwargs - ) - changed = True - module.exit_json(changed=changed, rule=rule, id=rule['id']) - - if state == 'absent' and secgroup: - rule = _find_matching_rule(module, secgroup, remotegroup) - if rule: - cloud.delete_security_group_rule(rule['id']) - changed = True - - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_server.py b/lib/ansible/modules/cloud/openstack/os_server.py deleted file mode 100644 index 02c57b1faf..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_server.py +++ /dev/null @@ -1,852 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# Copyright (c) 2013, Benno Joy <benno@ansible.com> -# Copyright (c) 2013, John Dewey <john@dewey.ws> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_server -short_description: Create/Delete Compute Instances from OpenStack -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Create or Remove compute instances from OpenStack. -options: - name: - description: - - Name that has to be given to the instance. It is also possible to - specify the ID of the instance instead of its name if I(state) is I(absent). - required: true - image: - description: - - The name or id of the base image to boot. - required: true - image_exclude: - description: - - Text to use to filter image names, for the case, such as HP, where - there are multiple image names matching the common identifying - portions. image_exclude is a negative match filter - it is text that - may not exist in the image name. Defaults to "(deprecated)" - flavor: - description: - - The name or id of the flavor in which the new instance has to be - created. Mutually exclusive with flavor_ram - default: 1 - flavor_ram: - description: - - The minimum amount of ram in MB that the flavor in which the new - instance has to be created must have. Mutually exclusive with flavor. - default: 1 - flavor_include: - description: - - Text to use to filter flavor names, for the case, such as Rackspace, - where there are multiple flavors that have the same ram count. - flavor_include is a positive match filter - it must exist in the - flavor name. - key_name: - description: - - The key pair name to be used when creating a instance - security_groups: - description: - - Names of the security groups to which the instance should be - added. This may be a YAML list or a comma separated string. - network: - description: - - Name or ID of a network to attach this instance to. A simpler - version of the nics parameter, only one of network or nics should - be supplied. - nics: - description: - - A list of networks to which the instance's interface should - be attached. Networks may be referenced by net-id/net-name/port-id - or port-name. - - 'Also this accepts a string containing a list of (net/port)-(id/name) - Eg: nics: "net-id=uuid-1,port-name=myport" - Only one of network or nics should be supplied.' - suboptions: - tag: - description: - - 'A "tag" for the specific port to be passed via metadata. - Eg: tag: test_tag' - version_added: '2.10' - auto_ip: - description: - - Ensure instance has public ip however the cloud wants to do that - type: bool - default: 'yes' - aliases: ['auto_floating_ip', 'public_ip'] - floating_ips: - description: - - list of valid floating IPs that pre-exist to assign to this node - floating_ip_pools: - description: - - Name of floating IP pool from which to choose a floating IP - meta: - description: - - 'A list of key value pairs that should be provided as a metadata to - the new instance or a string containing a list of key-value pairs. - Eg: meta: "key1=value1,key2=value2"' - wait: - description: - - If the module should wait for the instance to be created. - type: bool - default: 'yes' - timeout: - description: - - The amount of time the module should wait for the instance to get - into active state. - default: 180 - config_drive: - description: - - Whether to boot the server with config drive enabled - type: bool - default: 'no' - userdata: - description: - - Opaque blob of data which is made available to the instance - boot_from_volume: - description: - - Should the instance boot from a persistent volume created based on - the image given. Mutually exclusive with boot_volume. - type: bool - default: 'no' - volume_size: - description: - - The size of the volume to create in GB if booting from volume based - on an image. - boot_volume: - description: - - Volume name or id to use as the volume to boot from. Implies - boot_from_volume. Mutually exclusive with image and boot_from_volume. - aliases: ['root_volume'] - terminate_volume: - description: - - If C(yes), delete volume when deleting instance (if booted from volume) - type: bool - default: 'no' - volumes: - description: - - A list of preexisting volumes names or ids to attach to the instance - default: [] - scheduler_hints: - description: - - Arbitrary key/value pairs to the scheduler for custom use - version_added: "2.1" - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - delete_fip: - description: - - When I(state) is absent and this option is true, any floating IP - associated with the instance will be deleted along with the instance. - type: bool - default: 'no' - version_added: "2.2" - reuse_ips: - description: - - When I(auto_ip) is true and this option is true, the I(auto_ip) code - will attempt to re-use unassigned floating ips in the project before - creating a new one. It is important to note that it is impossible - to safely do this concurrently, so if your use case involves - concurrent server creation, it is highly recommended to set this to - false and to delete the floating ip associated with a server when - the server is deleted using I(delete_fip). - type: bool - default: 'yes' - version_added: "2.2" - availability_zone: - description: - - Availability zone in which to create the server. -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -- name: Create a new instance and attaches to a network and passes metadata to the instance - os_server: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: vm1 - image: 4f905f38-e52a-43d2-b6ec-754a13ffb529 - key_name: ansible_key - timeout: 200 - flavor: 4 - nics: - - net-id: 34605f38-e52a-25d2-b6ec-754a13ffb723 - - net-name: another_network - meta: - hostname: test1 - group: uge_master - -# Create a new instance in HP Cloud AE1 region availability zone az2 and -# automatically assigns a floating IP -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - state: present - auth: - auth_url: https://identity.example.com - username: username - password: Equality7-2521 - project_name: username-project1 - name: vm1 - region_name: region-b.geo-1 - availability_zone: az2 - image: 9302692b-b787-4b52-a3a6-daebb79cb498 - key_name: test - timeout: 200 - flavor: 101 - security_groups: default - auto_ip: yes - -# Create a new instance in named cloud mordred availability zone az2 -# and assigns a pre-known floating IP -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - state: present - cloud: mordred - name: vm1 - availability_zone: az2 - image: 9302692b-b787-4b52-a3a6-daebb79cb498 - key_name: test - timeout: 200 - flavor: 101 - floating_ips: - - 12.34.56.79 - -# Create a new instance with 4G of RAM on Ubuntu Trusty, ignoring -# deprecated images -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - name: vm1 - state: present - cloud: mordred - region_name: region-b.geo-1 - image: Ubuntu Server 14.04 - image_exclude: deprecated - flavor_ram: 4096 - -# Create a new instance with 4G of RAM on Ubuntu Trusty on a Performance node -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - name: vm1 - cloud: rax-dfw - state: present - image: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM) - flavor_ram: 4096 - flavor_include: Performance - -# Creates a new instance and attaches to multiple network -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance with a string - os_server: - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: vm1 - image: 4f905f38-e52a-43d2-b6ec-754a13ffb529 - key_name: ansible_key - timeout: 200 - flavor: 4 - nics: "net-id=4cb08b20-62fe-11e5-9d70-feff819cdc9f,net-id=542f0430-62fe-11e5-9d70-feff819cdc9f..." - -- name: Creates a new instance and attaches to a network and passes metadata to the instance - os_server: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: vm1 - image: 4f905f38-e52a-43d2-b6ec-754a13ffb529 - key_name: ansible_key - timeout: 200 - flavor: 4 - nics: - - net-id: 34605f38-e52a-25d2-b6ec-754a13ffb723 - - net-name: another_network - meta: "hostname=test1,group=uge_master" - -- name: Creates a new instance and attaches to a specific network - os_server: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: vm1 - image: 4f905f38-e52a-43d2-b6ec-754a13ffb529 - key_name: ansible_key - timeout: 200 - flavor: 4 - network: another_network - -# Create a new instance with 4G of RAM on a 75G Ubuntu Trusty volume -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - name: vm1 - state: present - cloud: mordred - region_name: ams01 - image: Ubuntu Server 14.04 - flavor_ram: 4096 - boot_from_volume: True - volume_size: 75 - -# Creates a new instance with 2 volumes attached -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - name: vm1 - state: present - cloud: mordred - region_name: ams01 - image: Ubuntu Server 14.04 - flavor_ram: 4096 - volumes: - - photos - - music - -# Creates a new instance with provisioning userdata using Cloud-Init -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - name: vm1 - state: present - image: "Ubuntu Server 14.04" - flavor: "P-1" - network: "Production" - userdata: | - #cloud-config - chpasswd: - list: | - ubuntu:{{ default_password }} - expire: False - packages: - - ansible - package_upgrade: true - -# Creates a new instance with provisioning userdata using Bash Scripts -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - name: vm1 - state: present - image: "Ubuntu Server 14.04" - flavor: "P-1" - network: "Production" - userdata: | - {%- raw -%}#!/bin/bash - echo " up ip route add 10.0.0.0/8 via {% endraw -%}{{ intra_router }}{%- raw -%}" >> /etc/network/interfaces.d/eth0.conf - echo " down ip route del 10.0.0.0/8" >> /etc/network/interfaces.d/eth0.conf - ifdown eth0 && ifup eth0 - {% endraw %} - -# Create a new instance with server group for (anti-)affinity -# server group ID is returned from os_server_group module. -- name: launch a compute instance - hosts: localhost - tasks: - - name: launch an instance - os_server: - state: present - name: vm1 - image: 4f905f38-e52a-43d2-b6ec-754a13ffb529 - flavor: 4 - scheduler_hints: - group: f5c8c61a-9230-400a-8ed2-3b023c190a7f - -# Create an instance with "tags" for the nic -- name: Create instance with nics "tags" - os_server: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: vm1 - image: 4f905f38-e52a-43d2-b6ec-754a13ffb529 - key_name: ansible_key - flavor: 4 - nics: - - port-name: net1_port1 - tag: test_tag - - net-name: another_network - -# Deletes an instance via its ID -- name: remove an instance - hosts: localhost - tasks: - - name: remove an instance - os_server: - name: abcdef01-2345-6789-0abc-def0123456789 - state: absent - -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import ( - openstack_find_nova_addresses, openstack_cloud_from_module, - openstack_full_argument_spec, openstack_module_kwargs) - - -def _exit_hostvars(module, cloud, server, diff, changed=True): - redact_keys = ['adminPass'] - for k in redact_keys: - if k in diff['before']: - diff['before'][k] = '***' - if k in diff['after']: - diff['after'][k] = '***' - if k in server: - server[k] = '***' - - if module.check_mode: - hostvars = server - else: - hostvars = cloud.get_openstack_vars(server) - - module.exit_json( - changed=changed, diff=diff, server=server, id=server.get('id', None), openstack=hostvars) - - -def _parse_nics(nics): - for net in nics: - if isinstance(net, str): - for nic in net.split(','): - yield dict((nic.split('='),)) - else: - yield net - - -def _network_args(module, cloud): - args = [] - nics = module.params['nics'] - - if not isinstance(nics, list): - module.fail_json(msg='The \'nics\' parameter must be a list.') - - for num, net in enumerate(_parse_nics(nics)): - if not isinstance(net, dict): - module.fail_json( - msg='Each entry in the \'nics\' parameter must be a dict.') - - if net.get('net-id'): - args.append(net) - elif net.get('net-name'): - by_name = cloud.get_network(net['net-name']) - if not by_name: - module.fail_json( - msg='Could not find network by net-name: %s' % - net['net-name']) - resolved_net = net.copy() - del resolved_net['net-name'] - resolved_net['net-id'] = by_name['id'] - args.append(resolved_net) - elif net.get('port-id'): - args.append(net) - elif net.get('port-name'): - by_name = cloud.get_port(net['port-name']) - if not by_name: - module.fail_json( - msg='Could not find port by port-name: %s' % - net['port-name']) - resolved_net = net.copy() - del resolved_net['port-name'] - resolved_net['port-id'] = by_name['id'] - args.append(resolved_net) - - if 'tag' in net: - args[num]['tag'] = net['tag'] - return args - - -def _parse_meta(meta): - if isinstance(meta, str): - metas = {} - for kv_str in meta.split(','): - k, v = kv_str.split('=') - metas[k] = v - return metas - if not meta: - return {} - return meta - - -def _delete_server(module, cloud): - if module.check_mode: - return True - - try: - cloud.delete_server( - module.params['name'], wait=module.params['wait'], - timeout=module.params['timeout'], - delete_ips=module.params['delete_fip']) - except Exception as e: - module.fail_json(msg='Error in deleting vm: %s' % e.message) - return True - - -def _create_server(module, cloud): - flavor = module.params['flavor'] - flavor_ram = module.params['flavor_ram'] - flavor_include = module.params['flavor_include'] - - image_id = None - if not module.params['boot_volume']: - image_id = cloud.get_image_id( - module.params['image'], module.params['image_exclude']) - if not image_id: - module.fail_json(msg='Could not find image %s' % - module.params['image']) - - if flavor: - flavor_dict = cloud.get_flavor(flavor) - if not flavor_dict: - module.fail_json(msg='Could not find flavor %s' % flavor) - else: - flavor_dict = cloud.get_flavor_by_ram(flavor_ram, flavor_include) - if not flavor_dict: - module.fail_json(msg='Could not find any matching flavor') - - if module.check_mode: - server = dict( - name=module.params['name'], - security_groups=module.params['security_groups'] - ) - return server - - nics = _network_args(module, cloud) - module.params['meta'] = _parse_meta(module.params['meta']) - - bootkwargs = dict( - name=module.params['name'], - image=image_id, - flavor=flavor_dict['id'], - nics=nics, - meta=module.params['meta'], - security_groups=module.params['security_groups'], - userdata=module.params['userdata'], - config_drive=module.params['config_drive'], - ) - for optional_param in ( - 'key_name', 'availability_zone', 'network', - 'scheduler_hints', 'volume_size', 'volumes'): - if module.params[optional_param]: - bootkwargs[optional_param] = module.params[optional_param] - - server = cloud.create_server( - ip_pool=module.params['floating_ip_pools'], - ips=module.params['floating_ips'], - auto_ip=module.params['auto_ip'], - boot_volume=module.params['boot_volume'], - boot_from_volume=module.params['boot_from_volume'], - terminate_volume=module.params['terminate_volume'], - reuse_ips=module.params['reuse_ips'], - wait=module.params['wait'], timeout=module.params['timeout'], - **bootkwargs - ) - - return server - - -def _update_server(module, cloud, server): - changed = False - sg_changed = False - ip_changed = False - - module.params['meta'] = _parse_meta(module.params['meta']) - - # cloud.set_server_metadata only updates the key=value pairs, it doesn't - # touch existing ones - update_meta = {} - for (k, v) in module.params['meta'].items(): - if k not in server.metadata or server.metadata[k] != v: - update_meta[k] = v - - if update_meta: - if module.check_mode: - server['metadata'].update(update_meta) - else: - cloud.set_server_metadata(server, update_meta) - changed = True - - # these functions perform update checks themselves - (sg_changed, server) = _update_security_groups(module, cloud, server) - (ip_changed, server) = _update_ips(module, cloud, server) - - if sg_changed or ip_changed: - changed = True - - if changed and not module.check_mode: - # Refresh server vars - server = cloud.get_server(module.params['name']) - - return (changed, server) - - -def _detach_ip_list(cloud, server, extra_ips): - for ip in extra_ips: - ip_id = cloud.get_floating_ip( - id=None, filters={'floating_ip_address': ip}) - cloud.detach_ip_from_server( - server_id=server.id, floating_ip_id=ip_id) - - -def _update_ips(module, cloud, server): - changed = False - - auto_ip = module.params['auto_ip'] - floating_ips = module.params['floating_ips'] - floating_ip_pools = module.params['floating_ip_pools'] - - if floating_ip_pools or floating_ips: - ips = openstack_find_nova_addresses(server.addresses, 'floating') - if not ips: - # If we're configured to have a floating but we don't have one, - # let's add one - server = cloud.add_ips_to_server( - server, - auto_ip=auto_ip, - ips=floating_ips, - ip_pool=floating_ip_pools, - wait=module.params['wait'], - timeout=module.params['timeout'], - ) - changed = True - elif floating_ips: - # we were configured to have specific ips, let's make sure we have - # those - missing_ips = [] - for ip in floating_ips: - if ip not in ips: - missing_ips.append(ip) - if missing_ips: - server = cloud.add_ip_list(server, missing_ips, - wait=module.params['wait'], - timeout=module.params['timeout']) - changed = True - extra_ips = [] - for ip in ips: - if ip not in floating_ips: - extra_ips.append(ip) - if extra_ips: - _detach_ip_list(cloud, server, extra_ips) - changed = True - elif auto_ip: - if server['interface_ip']: - changed = False - else: - # We're configured for auto_ip but we're not showing an - # interface_ip. Maybe someone deleted an IP out from under us. - server = cloud.add_ips_to_server( - server, - auto_ip=auto_ip, - ips=floating_ips, - ip_pool=floating_ip_pools, - wait=module.params['wait'], - timeout=module.params['timeout'], - ) - changed = True - return (changed, server) - - -def _update_security_groups(module, cloud, server): - changed = False - - # server security groups were added to shade in 1.19. Until then this - # module simply ignored trying to update security groups and only set them - # on newly created hosts. - if not (hasattr(cloud, 'add_server_security_groups') and - hasattr(cloud, 'remove_server_security_groups')): - return changed, server - - module_security_groups = set(module.params['security_groups']) - server_security_groups = set(sg['name'] for sg in server.security_groups) - - add_sgs = module_security_groups - server_security_groups - remove_sgs = server_security_groups - module_security_groups - - if module.check_mode: - if add_sgs: - sg_list = [dict(name=sg) for sg in add_sgs] - server['security_groups'].extend(sg_list) - changed = True - - if remove_sgs: - sg_list = [dict(name=sg) for sg in server_security_groups if sg not in remove_sgs] - server['security_groups'] = sg_list - changed = True - - return (changed, server) - - if add_sgs: - cloud.add_server_security_groups(server, list(add_sgs)) - changed = True - - if remove_sgs: - cloud.remove_server_security_groups(server, list(remove_sgs)) - changed = True - - return (changed, server) - - -def _present_server(module, cloud): - changed = False - diff = {'before': '', 'after': ''} - server = cloud.get_server(module.params['name']) - - if not server: - server = _create_server(module, cloud) - diff['after'] = server - _exit_hostvars(module, cloud, server, diff, True) - - if server.status not in ('ACTIVE', 'SHUTOFF', 'PAUSED', 'SUSPENDED'): - module.fail_json( - msg='The instance is available but not Active state: %s' % server.status) - - if server: - diff['before'] = cloud.get_openstack_vars(server) - (changed, server) = _update_server(module, cloud, server) - if module.check_mode: - diff['after'] = server - else: - diff['after'] = cloud.get_openstack_vars(server) - - _exit_hostvars(module, cloud, server, diff, changed) - - -def _absent_server(module, cloud): - changed = False - diff = {'before': '', 'after': ''} - server = cloud.get_server(module.params['name']) - - if server: - diff['before'] = cloud.get_openstack_vars(server) - changed = _delete_server(module, cloud) - module.exit_json(changed=changed, result='deleted', diff=diff) - - module.exit_json(changed=changed, diff=diff, result='not present') - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - image=dict(default=None), - image_exclude=dict(default='(deprecated)'), - flavor=dict(default=None), - flavor_ram=dict(default=None, type='int'), - flavor_include=dict(default=None), - key_name=dict(default=None), - security_groups=dict(default=['default'], type='list'), - network=dict(default=None), - nics=dict(default=[], type='list'), - meta=dict(default=None, type='raw'), - userdata=dict(default=None, aliases=['user_data']), - config_drive=dict(default=False, type='bool'), - auto_ip=dict(default=True, type='bool', aliases=['auto_floating_ip', 'public_ip']), - floating_ips=dict(default=None, type='list'), - floating_ip_pools=dict(default=None, type='list'), - volume_size=dict(default=False, type='int'), - boot_from_volume=dict(default=False, type='bool'), - boot_volume=dict(default=None, aliases=['root_volume']), - terminate_volume=dict(default=False, type='bool'), - volumes=dict(default=[], type='list'), - scheduler_hints=dict(default=None, type='dict'), - state=dict(default='present', choices=['absent', 'present']), - delete_fip=dict(default=False, type='bool'), - reuse_ips=dict(default=True, type='bool'), - ) - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[ - ['auto_ip', 'floating_ips'], - ['auto_ip', 'floating_ip_pools'], - ['floating_ips', 'floating_ip_pools'], - ['flavor', 'flavor_ram'], - ['image', 'boot_volume'], - ['boot_from_volume', 'boot_volume'], - ['nics', 'network'], - ], - required_if=[ - ('boot_from_volume', True, ['volume_size', 'image']), - ], - ) - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - image = module.params['image'] - boot_volume = module.params['boot_volume'] - flavor = module.params['flavor'] - flavor_ram = module.params['flavor_ram'] - - if state == 'present': - if not (image or boot_volume): - module.fail_json( - msg='Parameter image or boot_volume is required if state == present' - ) - if not flavor and not flavor_ram: - module.fail_json( - msg='Parameter flavor or flavor_ram is required if state == present' - ) - - sdk, cloud = openstack_cloud_from_module(module) - try: - if state == 'present': - _present_server(module, cloud) - if state == 'absent': - _absent_server(module, cloud) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_server_action.py b/lib/ansible/modules/cloud/openstack/os_server_action.py deleted file mode 100644 index ea352013e0..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_server_action.py +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# Copyright (c) 2015, Jesse Keating <jlk@derpops.bike> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_server_action -short_description: Perform actions on Compute Instances from OpenStack -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Jesse Keating (@omgjlk)" -description: - - Perform server actions on an existing compute instance from OpenStack. - This module does not return any data other than changed true/false. - When I(action) is 'rebuild', then I(image) parameter is required. -options: - server: - description: - - Name or ID of the instance - required: true - wait: - description: - - If the module should wait for the instance action to be performed. - type: bool - default: 'yes' - timeout: - description: - - The amount of time the module should wait for the instance to perform - the requested action. - default: 180 - action: - description: - - Perform the given action. The lock and unlock actions always return - changed as the servers API does not provide lock status. - choices: [stop, start, pause, unpause, lock, unlock, suspend, resume, - rebuild] - default: present - image: - description: - - Image the server should be rebuilt with - version_added: "2.3" - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Pauses a compute instance -- os_server_action: - action: pause - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - server: vm1 - timeout: 200 -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - -_action_map = {'stop': 'SHUTOFF', - 'start': 'ACTIVE', - 'pause': 'PAUSED', - 'unpause': 'ACTIVE', - 'lock': 'ACTIVE', # API doesn't show lock/unlock status - 'unlock': 'ACTIVE', - 'suspend': 'SUSPENDED', - 'resume': 'ACTIVE', - 'rebuild': 'ACTIVE'} - -_admin_actions = ['pause', 'unpause', 'suspend', 'resume', 'lock', 'unlock'] - - -def _action_url(server_id): - return '/servers/{server_id}/action'.format(server_id=server_id) - - -def _wait(timeout, cloud, server, action, module, sdk): - """Wait for the server to reach the desired state for the given action.""" - - for count in sdk.utils.iterate_timeout( - timeout, - "Timeout waiting for server to complete %s" % action): - try: - server = cloud.get_server(server.id) - except Exception: - continue - - if server.status == _action_map[action]: - return - - if server.status == 'ERROR': - module.fail_json(msg="Server reached ERROR state while attempting to %s" % action) - - -def _system_state_change(action, status): - """Check if system state would change.""" - if status == _action_map[action]: - return False - return True - - -def main(): - argument_spec = openstack_full_argument_spec( - server=dict(required=True), - action=dict(required=True, choices=['stop', 'start', 'pause', 'unpause', - 'lock', 'unlock', 'suspend', 'resume', - 'rebuild']), - image=dict(required=False), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, supports_check_mode=True, - required_if=[('action', 'rebuild', ['image'])], - **module_kwargs) - - action = module.params['action'] - wait = module.params['wait'] - timeout = module.params['timeout'] - image = module.params['image'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - server = cloud.get_server(module.params['server']) - if not server: - module.fail_json(msg='Could not find server %s' % server) - status = server.status - - if module.check_mode: - module.exit_json(changed=_system_state_change(action, status)) - - if action == 'stop': - if not _system_state_change(action, status): - module.exit_json(changed=False) - - cloud.compute.post( - _action_url(server.id), - json={'os-stop': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - if action == 'start': - if not _system_state_change(action, status): - module.exit_json(changed=False) - - cloud.compute.post( - _action_url(server.id), - json={'os-start': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - if action == 'pause': - if not _system_state_change(action, status): - module.exit_json(changed=False) - - cloud.compute.post( - _action_url(server.id), - json={'pause': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - elif action == 'unpause': - if not _system_state_change(action, status): - module.exit_json(changed=False) - - cloud.compute.post( - _action_url(server.id), - json={'unpause': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - elif action == 'lock': - # lock doesn't set a state, just do it - cloud.compute.post( - _action_url(server.id), - json={'lock': None}) - module.exit_json(changed=True) - - elif action == 'unlock': - # unlock doesn't set a state, just do it - cloud.compute.post( - _action_url(server.id), - json={'unlock': None}) - module.exit_json(changed=True) - - elif action == 'suspend': - if not _system_state_change(action, status): - module.exit_json(changed=False) - - cloud.compute.post( - _action_url(server.id), - json={'suspend': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - elif action == 'resume': - if not _system_state_change(action, status): - module.exit_json(changed=False) - - cloud.compute.post( - _action_url(server.id), - json={'resume': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - elif action == 'rebuild': - image = cloud.get_image(image) - - if image is None: - module.fail_json(msg="Image does not exist") - - # rebuild doesn't set a state, just do it - cloud.compute.post( - _action_url(server.id), - json={'rebuild': None}) - if wait: - _wait(timeout, cloud, server, action, module, sdk) - module.exit_json(changed=True) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_server_group.py b/lib/ansible/modules/cloud/openstack/os_server_group.py deleted file mode 100644 index ef00b107f1..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_server_group.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2016 Catalyst IT Limited -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_server_group -short_description: Manage OpenStack server groups -extends_documentation_fragment: openstack -version_added: "2.2" -author: "Lingxian Kong (@kong)" -description: - - Add or remove server groups from OpenStack. -options: - state: - description: - - Indicate desired state of the resource. When I(state) is 'present', - then I(policies) is required. - choices: ['present', 'absent'] - required: false - default: present - name: - description: - - Server group name. - required: true - policies: - description: - - A list of one or more policy names to associate with the server - group. The list must contain at least one policy name. The current - valid policy names are anti-affinity, affinity, soft-anti-affinity - and soft-affinity. - required: false - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a server group with 'affinity' policy. -- os_server_group: - state: present - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: my_server_group - policies: - - affinity - -# Delete 'my_server_group' server group. -- os_server_group: - state: absent - auth: - auth_url: https://identity.example.com - username: admin - password: admin - project_name: admin - name: my_server_group -''' - -RETURN = ''' -id: - description: Unique UUID. - returned: success - type: str -name: - description: The name of the server group. - returned: success - type: str -policies: - description: A list of one or more policy names of the server group. - returned: success - type: list -members: - description: A list of members in the server group. - returned: success - type: list -metadata: - description: Metadata key and value pairs. - returned: success - type: dict -project_id: - description: The project ID who owns the server group. - returned: success - type: str -user_id: - description: The user ID who owns the server group. - returned: success - type: str -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, server_group): - if state == 'present' and not server_group: - return True - if state == 'absent' and server_group: - return True - - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - policies=dict(required=False, type='list'), - state=dict(default='present', choices=['absent', 'present']), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule( - argument_spec, - supports_check_mode=True, - **module_kwargs - ) - - name = module.params['name'] - policies = module.params['policies'] - state = module.params['state'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - server_group = cloud.get_server_group(name) - - if module.check_mode: - module.exit_json( - changed=_system_state_change(state, server_group) - ) - - changed = False - if state == 'present': - if not server_group: - if not policies: - module.fail_json( - msg="Parameter 'policies' is required in Server Group " - "Create" - ) - server_group = cloud.create_server_group(name, policies) - changed = True - - module.exit_json( - changed=changed, - id=server_group['id'], - server_group=server_group - ) - if state == 'absent': - if server_group: - cloud.delete_server_group(server_group['id']) - changed = True - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_server_info.py b/lib/ansible/modules/cloud/openstack/os_server_info.py deleted file mode 100644 index 604f4f5ee0..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_server_info.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_server_info -short_description: Retrieve information about one or more compute instances -author: Monty (@emonty) -version_added: "2.0" -description: - - Retrieve information about server instances from OpenStack. - - This module was called C(os_server_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_server_info) module no longer returns C(ansible_facts)! -notes: - - The result contains a list of servers. -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - server: - description: - - restrict results to servers with names or UUID matching - this glob expression (e.g., <web*>). - detailed: - description: - - when true, return additional detail about servers at the expense - of additional API calls. - type: bool - default: 'no' - filters: - description: - - restrict results to servers matching a dictionary of - filters - version_added: "2.8" - availability_zone: - description: - - Ignored. Present for backwards compatibility - all_projects: - description: - - Whether to list servers from all projects or just the current auth - scoped project. - type: bool - default: 'no' - version_added: "2.8" -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -# Gather information about all servers named <web*> that are in an active state: -- os_server_info: - cloud: rax-dfw - server: web* - filters: - vm_state: active - register: result -- debug: - msg: "{{ result.openstack_servers }}" -''' - -import fnmatch - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - server=dict(required=False), - detailed=dict(required=False, type='bool', default=False), - filters=dict(required=False, type='dict', default=None), - all_projects=dict(required=False, type='bool', default=False), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) - is_old_facts = module._name == 'os_server_facts' - if is_old_facts: - module.deprecate("The 'os_server_facts' module has been renamed to 'os_server_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, cloud = openstack_cloud_from_module(module) - try: - openstack_servers = cloud.search_servers( - detailed=module.params['detailed'], filters=module.params['filters'], - all_projects=module.params['all_projects']) - - if module.params['server']: - # filter servers by name - pattern = module.params['server'] - # TODO(mordred) This is handled by sdk now - openstack_servers = [server for server in openstack_servers - if fnmatch.fnmatch(server['name'], pattern) or fnmatch.fnmatch(server['id'], pattern)] - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_servers=openstack_servers)) - else: - module.exit_json(changed=False, openstack_servers=openstack_servers) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_server_metadata.py b/lib/ansible/modules/cloud/openstack/os_server_metadata.py deleted file mode 100644 index 5478354655..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_server_metadata.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# Copyright (c) 2016, Mario Santos <mario.rf.santos@gmail.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'community', - 'metadata_version': '1.1'} - -DOCUMENTATION = ''' ---- -module: os_server_metadata -short_description: Add/Update/Delete Metadata in Compute Instances from OpenStack -extends_documentation_fragment: openstack -version_added: "2.6" -author: "Mario Santos (@ruizink)" -description: - - Add, Update or Remove metadata in compute instances from OpenStack. -options: - server: - description: - - Name of the instance to update the metadata - required: true - aliases: ['name'] - meta: - description: - - 'A list of key value pairs that should be provided as a metadata to - the instance or a string containing a list of key-value pairs. - Eg: meta: "key1=value1,key2=value2"' - required: true - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Availability zone in which to create the snapshot. - required: false -requirements: - - "python >= 2.7" - - "openstack" -''' - -EXAMPLES = ''' -# Creates or updates hostname=test1 as metadata of the server instance vm1 -- name: add metadata to compute instance - hosts: localhost - tasks: - - name: add metadata to instance - os_server_metadata: - state: present - auth: - auth_url: https://openstack-api.example.com:35357/v2.0/ - username: admin - password: admin - project_name: admin - name: vm1 - meta: - hostname: test1 - group: group1 - -# Removes the keys under meta from the instance named vm1 -- name: delete metadata from compute instance - hosts: localhost - tasks: - - name: delete metadata from instance - os_server_metadata: - state: absent - auth: - auth_url: https://openstack-api.example.com:35357/v2.0/ - username: admin - password: admin - project_name: admin - name: vm1 - meta: - hostname: - group: -''' - -RETURN = ''' -server_id: - description: The compute instance id where the change was made - returned: success - type: str - sample: "324c4e91-3e03-4f62-9a4d-06119a8a8d16" -metadata: - description: The metadata of compute instance after the change - returned: success - type: dict - sample: {'key1': 'value1', 'key2': 'value2'} -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import (openstack_full_argument_spec, - openstack_module_kwargs, - openstack_cloud_from_module) - - -def _needs_update(server_metadata=None, metadata=None): - if server_metadata is None: - server_metadata = {} - if metadata is None: - metadata = {} - return len(set(metadata.items()) - set(server_metadata.items())) != 0 - - -def _get_keys_to_delete(server_metadata_keys=None, metadata_keys=None): - if server_metadata_keys is None: - server_metadata_keys = [] - if metadata_keys is None: - metadata_keys = [] - return set(server_metadata_keys) & set(metadata_keys) - - -def main(): - argument_spec = openstack_full_argument_spec( - server=dict(required=True, aliases=['name']), - meta=dict(required=True, type='dict'), - state=dict(default='present', choices=['absent', 'present']), - ) - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - server_param = module.params['server'] - meta_param = module.params['meta'] - changed = False - - sdk, cloud = openstack_cloud_from_module(module) - try: - server = cloud.get_server(server_param) - if not server: - module.fail_json( - msg='Could not find server {0}'.format(server_param)) - - if state == 'present': - # check if it needs update - if _needs_update(server_metadata=server.metadata, - metadata=meta_param): - if not module.check_mode: - cloud.set_server_metadata(server_param, meta_param) - changed = True - elif state == 'absent': - # remove from params the keys that do not exist in the server - keys_to_delete = _get_keys_to_delete(server.metadata.keys(), - meta_param.keys()) - if len(keys_to_delete) > 0: - if not module.check_mode: - cloud.delete_server_metadata(server_param, keys_to_delete) - changed = True - - if changed: - server = cloud.get_server(server_param) - - module.exit_json( - changed=changed, server_id=server.id, metadata=server.metadata) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=e.message, extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_server_volume.py b/lib/ansible/modules/cloud/openstack/os_server_volume.py deleted file mode 100644 index 2caec55777..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_server_volume.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_server_volume -short_description: Attach/Detach Volumes from OpenStack VM's -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Attach or Detach volumes from OpenStack VM's -options: - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - required: false - server: - description: - - Name or ID of server you want to attach a volume to - required: true - volume: - description: - - Name or id of volume you want to attach to a server - required: true - device: - description: - - Device you want to attach. Defaults to auto finding a device name. - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Attaches a volume to a compute host -- name: attach a volume - hosts: localhost - tasks: - - name: attach volume to host - os_server_volume: - state: present - cloud: mordred - server: Mysql-server - volume: mysql-data - device: /dev/vdb -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, device): - """Check if system state would change.""" - if state == 'present': - if device: - return False - return True - if state == 'absent': - if device: - return True - return False - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - server=dict(required=True), - volume=dict(required=True), - device=dict(default=None), # None == auto choose device name - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - wait = module.params['wait'] - timeout = module.params['timeout'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - server = cloud.get_server(module.params['server']) - volume = cloud.get_volume(module.params['volume']) - - if not volume: - module.fail_json(msg='volume %s is not found' % module.params['volume']) - - dev = cloud.get_volume_attach_device(volume, server.id) - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, dev)) - - if state == 'present': - changed = False - if not dev: - changed = True - cloud.attach_volume(server, volume, module.params['device'], - wait=wait, timeout=timeout) - - server = cloud.get_server(module.params['server']) # refresh - volume = cloud.get_volume(module.params['volume']) # refresh - hostvars = cloud.get_openstack_vars(server) - - module.exit_json( - changed=changed, - id=volume['id'], - attachments=volume['attachments'], - openstack=hostvars - ) - - elif state == 'absent': - if not dev: - # Volume is not attached to this server - module.exit_json(changed=False) - - cloud.detach_volume(server, volume, wait=wait, timeout=timeout) - module.exit_json( - changed=True, - result='Detached volume from server' - ) - - except (sdk.exceptions.OpenStackCloudException, sdk.exceptions.ResourceTimeout) as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_stack.py b/lib/ansible/modules/cloud/openstack/os_stack.py deleted file mode 100644 index 617d5093c3..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_stack.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# (c) 2016, Mathieu Bultel <mbultel@redhat.com> -# (c) 2016, Steve Baker <sbaker@redhat.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_stack -short_description: Add/Remove Heat Stack -extends_documentation_fragment: openstack -version_added: "2.2" -author: - - "Mathieu Bultel (@matbu)" - - "Steve Baker (@steveb)" -description: - - Add or Remove a Stack to an OpenStack Heat -options: - state: - description: - - Indicate desired state of the resource - choices: ['present', 'absent'] - default: present - name: - description: - - Name of the stack that should be created, name could be char and digit, no space - required: true - tag: - description: - - Tag for the stack that should be created, name could be char and digit, no space - version_added: "2.5" - template: - description: - - Path of the template file to use for the stack creation - environment: - description: - - List of environment files that should be used for the stack creation - parameters: - description: - - Dictionary of parameters for the stack creation - rollback: - description: - - Rollback stack creation - type: bool - default: 'yes' - timeout: - description: - - Maximum number of seconds to wait for the stack creation - default: 3600 - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' -EXAMPLES = ''' ---- -- name: create stack - ignore_errors: True - register: stack_create - os_stack: - name: "{{ stack_name }}" - tag: "{{ tag_name }}" - state: present - template: "/path/to/my_stack.yaml" - environment: - - /path/to/resource-registry.yaml - - /path/to/environment.yaml - parameters: - bmc_flavor: m1.medium - bmc_image: CentOS - key_name: default - private_net: "{{ private_net_param }}" - node_count: 2 - name: undercloud - image: CentOS - my_flavor: m1.large - external_net: "{{ external_net_param }}" -''' - -RETURN = ''' -id: - description: Stack ID. - type: str - sample: "97a3f543-8136-4570-920e-fd7605c989d6" - returned: always - -stack: - description: stack info - type: complex - returned: always - contains: - action: - description: Action, could be Create or Update. - type: str - sample: "CREATE" - creation_time: - description: Time when the action has been made. - type: str - sample: "2016-07-05T17:38:12Z" - description: - description: Description of the Stack provided in the heat template. - type: str - sample: "HOT template to create a new instance and networks" - id: - description: Stack ID. - type: str - sample: "97a3f543-8136-4570-920e-fd7605c989d6" - name: - description: Name of the Stack - type: str - sample: "test-stack" - identifier: - description: Identifier of the current Stack action. - type: str - sample: "test-stack/97a3f543-8136-4570-920e-fd7605c989d6" - links: - description: Links to the current Stack. - type: list - elements: dict - sample: "[{'href': 'http://foo:8004/v1/7f6a/stacks/test-stack/97a3f543-8136-4570-920e-fd7605c989d6']" - outputs: - description: Output returned by the Stack. - type: list - elements: dict - sample: "{'description': 'IP address of server1 in private network', - 'output_key': 'server1_private_ip', - 'output_value': '10.1.10.103'}" - parameters: - description: Parameters of the current Stack - type: dict - sample: "{'OS::project_id': '7f6a3a3e01164a4eb4eecb2ab7742101', - 'OS::stack_id': '97a3f543-8136-4570-920e-fd7605c989d6', - 'OS::stack_name': 'test-stack', - 'stack_status': 'CREATE_COMPLETE', - 'stack_status_reason': 'Stack CREATE completed successfully', - 'status': 'COMPLETE', - 'template_description': 'HOT template to create a new instance and networks', - 'timeout_mins': 60, - 'updated_time': null}" -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module -from ansible.module_utils._text import to_native - - -def _create_stack(module, stack, cloud, sdk, parameters): - try: - stack = cloud.create_stack(module.params['name'], - template_file=module.params['template'], - environment_files=module.params['environment'], - timeout=module.params['timeout'], - wait=True, - rollback=module.params['rollback'], - **parameters) - - stack = cloud.get_stack(stack.id, None) - if stack.stack_status == 'CREATE_COMPLETE': - return stack - else: - module.fail_json(msg="Failure in creating stack: {0}".format(stack)) - except sdk.exceptions.OpenStackCloudException as e: - if hasattr(e, 'response'): - module.fail_json(msg=to_native(e), response=e.response.json()) - else: - module.fail_json(msg=to_native(e)) - - -def _update_stack(module, stack, cloud, sdk, parameters): - try: - stack = cloud.update_stack( - module.params['name'], - template_file=module.params['template'], - environment_files=module.params['environment'], - timeout=module.params['timeout'], - rollback=module.params['rollback'], - wait=module.params['wait'], - **parameters) - - if stack['stack_status'] == 'UPDATE_COMPLETE': - return stack - else: - module.fail_json(msg="Failure in updating stack: %s" % - stack['stack_status_reason']) - except sdk.exceptions.OpenStackCloudException as e: - if hasattr(e, 'response'): - module.fail_json(msg=to_native(e), response=e.response.json()) - else: - module.fail_json(msg=to_native(e)) - - -def _system_state_change(module, stack, cloud): - state = module.params['state'] - if state == 'present': - if not stack: - return True - if state == 'absent' and stack: - return True - return False - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - tag=dict(required=False, default=None), - template=dict(default=None), - environment=dict(default=None, type='list'), - parameters=dict(default={}, type='dict'), - rollback=dict(default=False, type='bool'), - timeout=dict(default=3600, type='int'), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - state = module.params['state'] - name = module.params['name'] - # Check for required parameters when state == 'present' - if state == 'present': - for p in ['template']: - if not module.params[p]: - module.fail_json(msg='%s required with present state' % p) - - sdk, cloud = openstack_cloud_from_module(module) - try: - stack = cloud.get_stack(name) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, stack, cloud)) - - if state == 'present': - parameters = module.params['parameters'] - if module.params['tag']: - parameters['tags'] = module.params['tag'] - from distutils.version import StrictVersion - min_version = '0.28.0' - if StrictVersion(sdk.version.__version__) < StrictVersion(min_version) and stack: - module.warn("To update tags using os_stack module, the" - "installed version of the openstacksdk" - "library MUST be >={min_version}" - "".format(min_version=min_version)) - if not stack: - stack = _create_stack(module, stack, cloud, sdk, parameters) - else: - stack = _update_stack(module, stack, cloud, sdk, parameters) - module.exit_json(changed=True, - stack=stack, - id=stack.id) - elif state == 'absent': - if not stack: - changed = False - else: - changed = True - if not cloud.delete_stack(name, wait=module.params['wait']): - module.fail_json(msg='delete stack failed for stack: %s' % name) - module.exit_json(changed=changed) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=to_native(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_subnet.py b/lib/ansible/modules/cloud/openstack/os_subnet.py deleted file mode 100644 index a4ac68047e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_subnet.py +++ /dev/null @@ -1,360 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# (c) 2013, Benno Joy <benno@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_subnet -short_description: Add/Remove subnet to an OpenStack network -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Add or Remove a subnet to an OpenStack network -options: - state: - description: - - Indicate desired state of the resource - choices: ['present', 'absent'] - default: present - network_name: - description: - - Name of the network to which the subnet should be attached - - Required when I(state) is 'present' - name: - description: - - The name of the subnet that should be created. Although Neutron - allows for non-unique subnet names, this module enforces subnet - name uniqueness. - required: true - cidr: - description: - - The CIDR representation of the subnet that should be assigned to - the subnet. Required when I(state) is 'present' and a subnetpool - is not specified. - ip_version: - description: - - The IP version of the subnet 4 or 6 - default: 4 - enable_dhcp: - description: - - Whether DHCP should be enabled for this subnet. - type: bool - default: 'yes' - gateway_ip: - description: - - The ip that would be assigned to the gateway for this subnet - no_gateway_ip: - description: - - The gateway IP would not be assigned for this subnet - type: bool - default: 'no' - version_added: "2.2" - dns_nameservers: - description: - - List of DNS nameservers for this subnet. - allocation_pool_start: - description: - - From the subnet pool the starting address from which the IP should - be allocated. - allocation_pool_end: - description: - - From the subnet pool the last IP that should be assigned to the - virtual machines. - host_routes: - description: - - A list of host route dictionaries for the subnet. - ipv6_ra_mode: - description: - - IPv6 router advertisement mode - choices: ['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'] - ipv6_address_mode: - description: - - IPv6 address mode - choices: ['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'] - use_default_subnetpool: - description: - - Use the default subnetpool for I(ip_version) to obtain a CIDR. - type: bool - default: 'no' - project: - description: - - Project name or ID containing the subnet (name admin-only) - version_added: "2.1" - availability_zone: - description: - - Ignored. Present for backwards compatibility - extra_specs: - description: - - Dictionary with extra key/value pairs passed to the API - required: false - default: {} - version_added: "2.7" -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a new (or update an existing) subnet on the specified network -- os_subnet: - state: present - network_name: network1 - name: net1subnet - cidr: 192.168.0.0/24 - dns_nameservers: - - 8.8.8.7 - - 8.8.8.8 - host_routes: - - destination: 0.0.0.0/0 - nexthop: 12.34.56.78 - - destination: 192.168.0.0/24 - nexthop: 192.168.0.1 - -# Delete a subnet -- os_subnet: - state: absent - name: net1subnet - -# Create an ipv6 stateless subnet -- os_subnet: - state: present - name: intv6 - network_name: internal - ip_version: 6 - cidr: 2db8:1::/64 - dns_nameservers: - - 2001:4860:4860::8888 - - 2001:4860:4860::8844 - ipv6_ra_mode: dhcpv6-stateless - ipv6_address_mode: dhcpv6-stateless -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _can_update(subnet, module, cloud, filters=None): - """Check for differences in non-updatable values""" - network_name = module.params['network_name'] - ip_version = int(module.params['ip_version']) - ipv6_ra_mode = module.params['ipv6_ra_mode'] - ipv6_a_mode = module.params['ipv6_address_mode'] - - if network_name: - network = cloud.get_network(network_name, filters) - if network: - netid = network['id'] - else: - module.fail_json(msg='No network found for %s' % network_name) - if netid != subnet['network_id']: - module.fail_json(msg='Cannot update network_name in existing \ - subnet') - if ip_version and subnet['ip_version'] != ip_version: - module.fail_json(msg='Cannot update ip_version in existing subnet') - if ipv6_ra_mode and subnet.get('ipv6_ra_mode', None) != ipv6_ra_mode: - module.fail_json(msg='Cannot update ipv6_ra_mode in existing subnet') - if ipv6_a_mode and subnet.get('ipv6_address_mode', None) != ipv6_a_mode: - module.fail_json(msg='Cannot update ipv6_address_mode in existing \ - subnet') - - -def _needs_update(subnet, module, cloud, filters=None): - """Check for differences in the updatable values.""" - - # First check if we are trying to update something we're not allowed to - _can_update(subnet, module, cloud, filters) - - # now check for the things we are allowed to update - enable_dhcp = module.params['enable_dhcp'] - subnet_name = module.params['name'] - pool_start = module.params['allocation_pool_start'] - pool_end = module.params['allocation_pool_end'] - gateway_ip = module.params['gateway_ip'] - no_gateway_ip = module.params['no_gateway_ip'] - dns = module.params['dns_nameservers'] - host_routes = module.params['host_routes'] - curr_pool = subnet['allocation_pools'][0] - - if subnet['enable_dhcp'] != enable_dhcp: - return True - if subnet_name and subnet['name'] != subnet_name: - return True - if pool_start and curr_pool['start'] != pool_start: - return True - if pool_end and curr_pool['end'] != pool_end: - return True - if gateway_ip and subnet['gateway_ip'] != gateway_ip: - return True - if dns and sorted(subnet['dns_nameservers']) != sorted(dns): - return True - if host_routes: - curr_hr = sorted(subnet['host_routes'], key=lambda t: t.keys()) - new_hr = sorted(host_routes, key=lambda t: t.keys()) - if curr_hr != new_hr: - return True - if no_gateway_ip and subnet['gateway_ip']: - return True - return False - - -def _system_state_change(module, subnet, cloud, filters=None): - state = module.params['state'] - if state == 'present': - if not subnet: - return True - return _needs_update(subnet, module, cloud, filters) - if state == 'absent' and subnet: - return True - return False - - -def main(): - ipv6_mode_choices = ['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'] - argument_spec = openstack_full_argument_spec( - name=dict(type='str', required=True), - network_name=dict(type='str'), - cidr=dict(type='str'), - ip_version=dict(type='str', default='4', choices=['4', '6']), - enable_dhcp=dict(type='bool', default=True), - gateway_ip=dict(type='str'), - no_gateway_ip=dict(type='bool', default=False), - dns_nameservers=dict(type='list', default=None), - allocation_pool_start=dict(type='str'), - allocation_pool_end=dict(type='str'), - host_routes=dict(type='list', default=None), - ipv6_ra_mode=dict(type='str', choices=ipv6_mode_choices), - ipv6_address_mode=dict(type='str', choices=ipv6_mode_choices), - use_default_subnetpool=dict(type='bool', default=False), - extra_specs=dict(type='dict', default=dict()), - state=dict(type='str', default='present', choices=['absent', 'present']), - project=dict(type='str'), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - required_together=[ - ['allocation_pool_end', 'allocation_pool_start'], - ], - **module_kwargs) - - state = module.params['state'] - network_name = module.params['network_name'] - cidr = module.params['cidr'] - ip_version = module.params['ip_version'] - enable_dhcp = module.params['enable_dhcp'] - subnet_name = module.params['name'] - gateway_ip = module.params['gateway_ip'] - no_gateway_ip = module.params['no_gateway_ip'] - dns = module.params['dns_nameservers'] - pool_start = module.params['allocation_pool_start'] - pool_end = module.params['allocation_pool_end'] - host_routes = module.params['host_routes'] - ipv6_ra_mode = module.params['ipv6_ra_mode'] - ipv6_a_mode = module.params['ipv6_address_mode'] - use_default_subnetpool = module.params['use_default_subnetpool'] - project = module.params.pop('project') - extra_specs = module.params['extra_specs'] - - # Check for required parameters when state == 'present' - if state == 'present': - if not module.params['network_name']: - module.fail_json(msg='network_name required with present state') - if (not module.params['cidr'] and not use_default_subnetpool and - not extra_specs.get('subnetpool_id', False)): - module.fail_json(msg='cidr or use_default_subnetpool or ' - 'subnetpool_id required with present state') - - if pool_start and pool_end: - pool = [dict(start=pool_start, end=pool_end)] - else: - pool = None - - if no_gateway_ip and gateway_ip: - module.fail_json(msg='no_gateway_ip is not allowed with gateway_ip') - - sdk, cloud = openstack_cloud_from_module(module) - try: - if project is not None: - proj = cloud.get_project(project) - if proj is None: - module.fail_json(msg='Project %s could not be found' % project) - project_id = proj['id'] - filters = {'tenant_id': project_id} - else: - project_id = None - filters = None - - subnet = cloud.get_subnet(subnet_name, filters=filters) - - if module.check_mode: - module.exit_json(changed=_system_state_change(module, subnet, - cloud, filters)) - - if state == 'present': - if not subnet: - kwargs = dict( - cidr=cidr, - ip_version=ip_version, - enable_dhcp=enable_dhcp, - subnet_name=subnet_name, - gateway_ip=gateway_ip, - disable_gateway_ip=no_gateway_ip, - dns_nameservers=dns, - allocation_pools=pool, - host_routes=host_routes, - ipv6_ra_mode=ipv6_ra_mode, - ipv6_address_mode=ipv6_a_mode, - tenant_id=project_id) - dup_args = set(kwargs.keys()) & set(extra_specs.keys()) - if dup_args: - raise ValueError('Duplicate key(s) {0} in extra_specs' - .format(list(dup_args))) - if use_default_subnetpool: - kwargs['use_default_subnetpool'] = use_default_subnetpool - kwargs = dict(kwargs, **extra_specs) - subnet = cloud.create_subnet(network_name, **kwargs) - changed = True - else: - if _needs_update(subnet, module, cloud, filters): - cloud.update_subnet(subnet['id'], - subnet_name=subnet_name, - enable_dhcp=enable_dhcp, - gateway_ip=gateway_ip, - disable_gateway_ip=no_gateway_ip, - dns_nameservers=dns, - allocation_pools=pool, - host_routes=host_routes) - changed = True - else: - changed = False - module.exit_json(changed=changed, - subnet=subnet, - id=subnet['id']) - - elif state == 'absent': - if not subnet: - changed = False - else: - changed = True - cloud.delete_subnet(subnet_name) - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_subnets_info.py b/lib/ansible/modules/cloud/openstack/os_subnets_info.py deleted file mode 100644 index fe0c307cc7..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_subnets_info.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_subnets_info -short_description: Retrieve information about one or more OpenStack subnets. -version_added: "2.0" -author: "Davide Agnello (@dagnello)" -description: - - Retrieve information about one or more subnets from OpenStack. - - This module was called C(os_subnets_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_subnets_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - name: - description: - - Name or ID of the subnet. - - Alias 'subnet' added in version 2.8. - required: false - aliases: ['subnet'] - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - required: false - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -extends_documentation_fragment: openstack -''' - -EXAMPLES = ''' -- name: Gather information about previously created subnets - os_subnets_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - register: result - -- name: Show openstack subnets - debug: - msg: "{{ result.openstack_subnets }}" - -- name: Gather information about a previously created subnet by name - os_subnets_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - name: subnet1 - register: result - -- name: Show openstack subnets - debug: - msg: "{{ result.openstack_subnets }}" - -- name: Gather information about a previously created subnet with filter - # Note: name and filters parameters are not mutually exclusive - os_subnets_info: - auth: - auth_url: https://identity.example.com - username: user - password: password - project_name: someproject - filters: - tenant_id: 55e2ce24b2a245b09f181bf025724cbe - register: result - -- name: Show openstack subnets - debug: - msg: "{{ result.openstack_subnets }}" -''' - -RETURN = ''' -openstack_subnets: - description: has all the openstack information about the subnets - returned: always, but can be null - type: complex - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Name given to the subnet. - returned: success - type: str - network_id: - description: Network ID this subnet belongs in. - returned: success - type: str - cidr: - description: Subnet's CIDR. - returned: success - type: str - gateway_ip: - description: Subnet's gateway ip. - returned: success - type: str - enable_dhcp: - description: DHCP enable flag for this subnet. - returned: success - type: bool - ip_version: - description: IP version for this subnet. - returned: success - type: int - tenant_id: - description: Tenant id associated with this subnet. - returned: success - type: str - dns_nameservers: - description: DNS name servers for this subnet. - returned: success - type: list - elements: str - allocation_pools: - description: Allocation pools associated with this subnet. - returned: success - type: list - elements: dict -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None, aliases=['subnet']), - filters=dict(required=False, type='dict', default=None) - ) - module = AnsibleModule(argument_spec) - is_old_facts = module._name == 'os_subnets_facts' - if is_old_facts: - module.deprecate("The 'os_subnets_facts' module has been renamed to 'os_subnets_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, cloud = openstack_cloud_from_module(module) - try: - subnets = cloud.search_subnets(module.params['name'], - module.params['filters']) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_subnets=subnets)) - else: - module.exit_json(changed=False, openstack_subnets=subnets) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_user.py b/lib/ansible/modules/cloud/openstack/os_user.py deleted file mode 100644 index 93e0351b93..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_user.py +++ /dev/null @@ -1,296 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_user -short_description: Manage OpenStack Identity Users -extends_documentation_fragment: openstack -author: David Shrewsbury (@Shrews) -version_added: "2.0" -description: - - Manage OpenStack Identity users. Users can be created, - updated or deleted using this module. A user will be updated - if I(name) matches an existing user and I(state) is present. - The value for I(name) cannot be updated without deleting and - re-creating the user. -options: - name: - description: - - Username for the user - required: true - password: - description: - - Password for the user - update_password: - required: false - choices: ['always', 'on_create'] - version_added: "2.3" - description: - - C(always) will attempt to update password. C(on_create) will only - set the password for newly created users. - email: - description: - - Email address for the user - description: - description: - - Description about the user - version_added: "2.4" - default_project: - description: - - Project name or ID that the user should be associated with by default - domain: - description: - - Domain to create the user in if the cloud supports domains - enabled: - description: - - Is the user enabled - type: bool - default: 'yes' - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a user -- os_user: - cloud: mycloud - state: present - name: demouser - password: secret - email: demo@example.com - domain: default - default_project: demo - -# Delete a user -- os_user: - cloud: mycloud - state: absent - name: demouser - -# Create a user but don't update password if user exists -- os_user: - cloud: mycloud - state: present - name: demouser - password: secret - update_password: on_create - email: demo@example.com - domain: default - default_project: demo - -# Create a user without password -- os_user: - cloud: mycloud - state: present - name: demouser - email: demo@example.com - domain: default - default_project: demo -''' - - -RETURN = ''' -user: - description: Dictionary describing the user. - returned: On success when I(state) is 'present' - type: complex - contains: - default_project_id: - description: User default project ID. Only present with Keystone >= v3. - type: str - sample: "4427115787be45f08f0ec22a03bfc735" - domain_id: - description: User domain ID. Only present with Keystone >= v3. - type: str - sample: "default" - email: - description: User email address - type: str - sample: "demo@example.com" - id: - description: User ID - type: str - sample: "f59382db809c43139982ca4189404650" - name: - description: User name - type: str - sample: "demouser" -''' -from distutils.version import StrictVersion - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(params_dict, user): - for k in params_dict: - if k not in ('password', 'update_password') and user[k] != params_dict[k]: - return True - - # We don't get password back in the user object, so assume any supplied - # password is a change. - if (params_dict['password'] is not None and - params_dict['update_password'] == 'always'): - return True - - return False - - -def _get_domain_id(cloud, domain): - try: - # We assume admin is passing domain id - domain_id = cloud.get_domain(domain)['id'] - except Exception: - # If we fail, maybe admin is passing a domain name. - # Note that domains have unique names, just like id. - try: - domain_id = cloud.search_domains(filters={'name': domain})[0]['id'] - except Exception: - # Ok, let's hope the user is non-admin and passing a sane id - domain_id = domain - - return domain_id - - -def _get_default_project_id(cloud, default_project, domain_id, module): - project = cloud.get_project(default_project, domain_id=domain_id) - if not project: - module.fail_json(msg='Default project %s is not valid' % default_project) - - return project['id'] - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - password=dict(required=False, default=None, no_log=True), - email=dict(required=False, default=None), - default_project=dict(required=False, default=None), - description=dict(type='str'), - domain=dict(required=False, default=None), - enabled=dict(default=True, type='bool'), - state=dict(default='present', choices=['absent', 'present']), - update_password=dict(default=None, choices=['always', 'on_create']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule( - argument_spec, - **module_kwargs) - - name = module.params['name'] - password = module.params.get('password') - email = module.params['email'] - default_project = module.params['default_project'] - domain = module.params['domain'] - enabled = module.params['enabled'] - state = module.params['state'] - update_password = module.params['update_password'] - description = module.params['description'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - domain_id = None - if domain: - domain_id = _get_domain_id(cloud, domain) - user = cloud.get_user(name, domain_id=domain_id) - else: - user = cloud.get_user(name) - - if state == 'present': - if update_password in ('always', 'on_create'): - if not password: - msg = "update_password is %s but a password value is missing" % update_password - module.fail_json(msg=msg) - default_project_id = None - if default_project: - default_project_id = _get_default_project_id(cloud, default_project, domain_id, module) - - if user is None: - if description is not None: - user = cloud.create_user( - name=name, password=password, email=email, - default_project=default_project_id, domain_id=domain_id, - enabled=enabled, description=description) - else: - user = cloud.create_user( - name=name, password=password, email=email, - default_project=default_project_id, domain_id=domain_id, - enabled=enabled) - changed = True - else: - params_dict = {'email': email, 'enabled': enabled, - 'password': password, - 'update_password': update_password} - if description is not None: - params_dict['description'] = description - if domain_id is not None: - params_dict['domain_id'] = domain_id - if default_project_id is not None: - params_dict['default_project_id'] = default_project_id - - if _needs_update(params_dict, user): - if update_password == 'always': - if description is not None: - user = cloud.update_user( - user['id'], password=password, email=email, - default_project=default_project_id, - domain_id=domain_id, enabled=enabled, description=description) - else: - user = cloud.update_user( - user['id'], password=password, email=email, - default_project=default_project_id, - domain_id=domain_id, enabled=enabled) - else: - if description is not None: - user = cloud.update_user( - user['id'], email=email, - default_project=default_project_id, - domain_id=domain_id, enabled=enabled, description=description) - else: - user = cloud.update_user( - user['id'], email=email, - default_project=default_project_id, - domain_id=domain_id, enabled=enabled) - changed = True - else: - changed = False - module.exit_json(changed=changed, user=user) - - elif state == 'absent': - if user is None: - changed = False - else: - if domain: - cloud.delete_user(user['id'], domain_id=domain_id) - else: - cloud.delete_user(user['id']) - changed = True - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_user_group.py b/lib/ansible/modules/cloud/openstack/os_user_group.py deleted file mode 100644 index 77373d4fe0..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_user_group.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_user_group -short_description: Associate OpenStack Identity users and groups -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Add and remove users from groups -options: - user: - description: - - Name or id for the user - required: true - group: - description: - - Name or id for the group. - required: true - state: - description: - - Should the user be present or absent in the group - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility - required: false -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Add the demo user to the demo group -- os_user_group: - cloud: mycloud - user: demo - group: demo -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, in_group): - if state == 'present' and not in_group: - return True - if state == 'absent' and in_group: - return True - return False - - -def main(): - argument_spec = openstack_full_argument_spec( - user=dict(required=True), - group=dict(required=True), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - user = module.params['user'] - group = module.params['group'] - state = module.params['state'] - - sdk, cloud = openstack_cloud_from_module(module) - try: - in_group = cloud.is_user_in_group(user, group) - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, in_group)) - - changed = False - if state == 'present': - if not in_group: - cloud.add_user_to_group(user, group) - changed = True - - elif state == 'absent': - if in_group: - cloud.remove_user_from_group(user, group) - changed = True - - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e), extra_data=e.extra_data) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_user_info.py b/lib/ansible/modules/cloud/openstack/os_user_info.py deleted file mode 100644 index 758b041938..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_user_info.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 Hewlett-Packard Enterprise Corporation -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_user_info -short_description: Retrieve information about one or more OpenStack users -extends_documentation_fragment: openstack -version_added: "2.1" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -description: - - Retrieve information about a one or more OpenStack users - - This module was called C(os_user_facts) before Ansible 2.9, returning C(ansible_facts). - Note that the M(os_user_info) module no longer returns C(ansible_facts)! -requirements: - - "python >= 2.7" - - "openstacksdk" -options: - name: - description: - - Name or ID of the user - required: true - domain: - description: - - Name or ID of the domain containing the user if the cloud supports domains - filters: - description: - - A dictionary of meta data to use for further filtering. Elements of - this dictionary may be additional dictionaries. - availability_zone: - description: - - Ignored. Present for backwards compatibility -''' - -EXAMPLES = ''' -# Gather information about previously created users -- os_user_info: - cloud: awesomecloud - register: result -- debug: - msg: "{{ result.openstack_users }}" - -# Gather information about a previously created user by name -- os_user_info: - cloud: awesomecloud - name: demouser - register: result -- debug: - msg: "{{ result.openstack_users }}" - -# Gather information about a previously created user in a specific domain -- os_user_info: - cloud: awesomecloud - name: demouser - domain: admindomain - register: result -- debug: - msg: "{{ result.openstack_users }}" - -# Gather information about a previously created user in a specific domain with filter -- os_user_info: - cloud: awesomecloud - name: demouser - domain: admindomain - filters: - enabled: False - register: result -- debug: - msg: "{{ result.openstack_users }}" -''' - - -RETURN = ''' -openstack_users: - description: has all the OpenStack information about users - returned: always, but can be null - type: complex - contains: - id: - description: Unique UUID. - returned: success - type: str - name: - description: Name given to the user. - returned: success - type: str - enabled: - description: Flag to indicate if the user is enabled - returned: success - type: bool - domain_id: - description: Domain ID containing the user - returned: success - type: str - default_project_id: - description: Default project ID of the user - returned: success - type: str - email: - description: Email of the user - returned: success - type: str - username: - description: Username of the user - returned: success - type: str -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def main(): - - argument_spec = openstack_full_argument_spec( - name=dict(required=False, default=None), - domain=dict(required=False, default=None), - filters=dict(required=False, type='dict', default=None), - ) - - module = AnsibleModule(argument_spec) - is_old_facts = module._name == 'os_user_facts' - if is_old_facts: - module.deprecate("The 'os_user_facts' module has been renamed to 'os_user_info', " - "and the renamed one no longer returns ansible_facts", version='2.13') - - sdk, opcloud = openstack_cloud_from_module(module) - try: - name = module.params['name'] - domain = module.params['domain'] - filters = module.params['filters'] - - if domain: - try: - # We assume admin is passing domain id - dom = opcloud.get_domain(domain)['id'] - domain = dom - except Exception: - # If we fail, maybe admin is passing a domain name. - # Note that domains have unique names, just like id. - dom = opcloud.search_domains(filters={'name': domain}) - if dom: - domain = dom[0]['id'] - else: - module.fail_json(msg='Domain name or ID does not exist') - - if not filters: - filters = {} - - filters['domain_id'] = domain - - users = opcloud.search_users(name, filters) - if is_old_facts: - module.exit_json(changed=False, ansible_facts=dict( - openstack_users=users)) - else: - module.exit_json(changed=False, openstack_users=users) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_user_role.py b/lib/ansible/modules/cloud/openstack/os_user_role.py deleted file mode 100644 index 936ccb2bbd..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_user_role.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 IBM -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_user_role -short_description: Associate OpenStack Identity users and roles -extends_documentation_fragment: openstack -author: "Monty Taylor (@emonty), David Shrewsbury (@Shrews)" -version_added: "2.1" -description: - - Grant and revoke roles in either project or domain context for - OpenStack Identity Users. -options: - role: - description: - - Name or ID for the role. - required: true - user: - description: - - Name or ID for the user. If I(user) is not specified, then - I(group) is required. Both may not be specified. - group: - description: - - Name or ID for the group. Valid only with keystone version 3. - If I(group) is not specified, then I(user) is required. Both - may not be specified. - project: - description: - - Name or ID of the project to scope the role association to. - If you are using keystone version 2, then this value is required. - domain: - description: - - Name or ID of the domain to scope the role association to. Valid only - with keystone version 3, and required if I(project) is not specified. - state: - description: - - Should the roles be present or absent on the user. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Grant an admin role on the user admin in the project project1 -- os_user_role: - cloud: mycloud - user: admin - role: admin - project: project1 - -# Revoke the admin role from the user barney in the newyork domain -- os_user_role: - cloud: mycloud - state: absent - user: barney - role: admin - domain: newyork -''' - -RETURN = ''' -# -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, assignment): - if state == 'present' and not assignment: - return True - elif state == 'absent' and assignment: - return True - return False - - -def _build_kwargs(user, group, project, domain): - kwargs = {} - if user: - kwargs['user'] = user - if group: - kwargs['group'] = group - if project: - kwargs['project'] = project - if domain: - kwargs['domain'] = domain - return kwargs - - -def main(): - argument_spec = openstack_full_argument_spec( - role=dict(required=True), - user=dict(required=False), - group=dict(required=False), - project=dict(required=False), - domain=dict(required=False), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs( - required_one_of=[ - ['user', 'group'] - ]) - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - role = module.params.get('role') - user = module.params.get('user') - group = module.params.get('group') - project = module.params.get('project') - domain = module.params.get('domain') - state = module.params.get('state') - - sdk, cloud = openstack_cloud_from_module(module) - try: - filters = {} - - r = cloud.get_role(role) - if r is None: - module.fail_json(msg="Role %s is not valid" % role) - filters['role'] = r['id'] - - if domain: - d = cloud.get_domain(name_or_id=domain) - if d is None: - module.fail_json(msg="Domain %s is not valid" % domain) - filters['domain'] = d['id'] - if user: - if domain: - u = cloud.get_user(user, domain_id=filters['domain']) - else: - u = cloud.get_user(user) - - if u is None: - module.fail_json(msg="User %s is not valid" % user) - filters['user'] = u['id'] - if group: - g = cloud.get_group(group) - if g is None: - module.fail_json(msg="Group %s is not valid" % group) - filters['group'] = g['id'] - domain_id = None - if project: - if domain: - p = cloud.get_project(project, domain_id=filters['domain']) - # OpenStack won't allow us to use both a domain and project as - # filter. Once we identified the project (using the domain as - # a filter criteria), we need to remove the domain itself from - # the filters list. - domain_id = filters.pop('domain') - else: - p = cloud.get_project(project) - - if p is None: - module.fail_json(msg="Project %s is not valid" % project) - filters['project'] = p['id'] - - assignment = cloud.list_role_assignments(filters=filters) - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, assignment)) - - changed = False - - if state == 'present': - if not assignment: - kwargs = _build_kwargs(user, group, project, domain_id) - cloud.grant_role(role, **kwargs) - changed = True - - elif state == 'absent': - if assignment: - kwargs = _build_kwargs(user, group, project, domain_id) - cloud.revoke_role(role, **kwargs) - changed = True - - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_volume.py b/lib/ansible/modules/cloud/openstack/os_volume.py deleted file mode 100644 index ffd885f744..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_volume.py +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_volume -short_description: Create/Delete Cinder Volumes -extends_documentation_fragment: openstack -version_added: "2.0" -author: "Monty Taylor (@emonty)" -description: - - Create or Remove cinder block storage volumes -options: - size: - description: - - Size of volume in GB. This parameter is required when the - I(state) parameter is 'present'. - display_name: - description: - - Name of volume - required: true - display_description: - description: - - String describing the volume - volume_type: - description: - - Volume type for volume - image: - description: - - Image name or id for boot from volume - snapshot_id: - description: - - Volume snapshot id to create from - volume: - description: - - Volume name or id to create from - version_added: "2.3" - bootable: - description: - - Bootable flag for volume. - type: bool - default: False - version_added: "2.10" - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility - scheduler_hints: - description: - - Scheduler hints passed to volume API in form of dict - version_added: "2.4" - metadata: - description: - - Metadata for the volume - version_added: "2.8" -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Creates a new volume -- name: create a volume - hosts: localhost - tasks: - - name: create 40g test volume - os_volume: - state: present - cloud: mordred - availability_zone: az2 - size: 40 - display_name: test_volume - scheduler_hints: - same_host: 243e8d3c-8f47-4a61-93d6-7215c344b0c0 -''' - -RETURNS = ''' -id: - description: Cinder's unique ID for this volume - returned: always - type: str - sample: fcc4ac1c-e249-4fe7-b458-2138bfb44c06 - -volume: - description: Cinder's representation of the volume object - returned: always - type: dict - sample: {'...'} -''' -from distutils.version import StrictVersion - - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _needs_update(module, volume): - ''' - check for differences in updatable values, at the moment - openstacksdk only supports extending the volume size, this - may change in the future. - :returns: bool - ''' - compare_simple = ['size'] - - for k in compare_simple: - if module.params[k] is not None and module.params[k] != volume.get(k): - return True - - return False - - -def _modify_volume(module, cloud): - ''' - modify volume, the only modification to an existing volume - available at the moment is extending the size, this is - limited by the openstacksdk and may change whenever the - functionality is extended. - ''' - volume = cloud.get_volume(module.params['display_name']) - diff = {'before': volume, 'after': ''} - size = module.params['size'] - - if size < volume.get('size'): - module.fail_json( - msg='Cannot shrink volumes, size: {0} < {1}'.format(size, volume.get('size')) - ) - - if not _needs_update(module, volume): - diff['after'] = volume - module.exit_json(changed=False, id=volume['id'], volume=volume, diff=diff) - - if module.check_mode: - diff['after'] = volume - module.exit_json(changed=True, id=volume['id'], volume=volume, diff=diff) - - cloud.volume.extend_volume( - volume.id, - size - ) - diff['after'] = cloud.get_volume(module.params['display_name']) - module.exit_json(changed=True, id=volume['id'], volume=volume, diff=diff) - - -def _present_volume(module, cloud): - if cloud.volume_exists(module.params['display_name']): - v = cloud.get_volume(module.params['display_name']) - if not _needs_update(module, v): - module.exit_json(changed=False, id=v['id'], volume=v) - _modify_volume(module, cloud) - - diff = {'before': '', 'after': ''} - - volume_args = dict( - size=module.params['size'], - volume_type=module.params['volume_type'], - display_name=module.params['display_name'], - display_description=module.params['display_description'], - snapshot_id=module.params['snapshot_id'], - bootable=module.params['bootable'], - availability_zone=module.params['availability_zone'], - ) - if module.params['image']: - image_id = cloud.get_image_id(module.params['image']) - volume_args['imageRef'] = image_id - - if module.params['volume']: - volume_id = cloud.get_volume_id(module.params['volume']) - if not volume_id: - module.fail_json(msg="Failed to find volume '%s'" % module.params['volume']) - volume_args['source_volid'] = volume_id - - if module.params['scheduler_hints']: - volume_args['scheduler_hints'] = module.params['scheduler_hints'] - - if module.params['metadata']: - volume_args['metadata'] = module.params['metadata'] - - if module.check_mode: - diff['after'] = volume_args - module.exit_json(changed=True, id=None, volume=volume_args, diff=diff) - - volume = cloud.create_volume( - wait=module.params['wait'], timeout=module.params['timeout'], - **volume_args) - diff['after'] = volume - module.exit_json(changed=True, id=volume['id'], volume=volume, diff=diff) - - -def _absent_volume(module, cloud, sdk): - changed = False - diff = {'before': '', 'after': ''} - - if cloud.volume_exists(module.params['display_name']): - volume = cloud.get_volume(module.params['display_name']) - diff['before'] = volume - - if module.check_mode: - module.exit_json(changed=True, diff=diff) - - try: - changed = cloud.delete_volume(name_or_id=module.params['display_name'], - wait=module.params['wait'], - timeout=module.params['timeout']) - except sdk.exceptions.ResourceTimeout: - diff['after'] = volume - module.exit_json(changed=changed, diff=diff) - - module.exit_json(changed=changed, diff=diff) - - -def main(): - argument_spec = openstack_full_argument_spec( - size=dict(default=None, type='int'), - volume_type=dict(default=None), - display_name=dict(required=True, aliases=['name']), - display_description=dict(default=None, aliases=['description']), - image=dict(default=None), - snapshot_id=dict(default=None), - volume=dict(default=None), - state=dict(default='present', choices=['absent', 'present']), - scheduler_hints=dict(default=None, type='dict'), - metadata=dict(default=None, type='dict'), - bootable=dict(type='bool', default=False) - ) - module_kwargs = openstack_module_kwargs( - mutually_exclusive=[ - ['image', 'snapshot_id', 'volume'], - ], - ) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, **module_kwargs) - - state = module.params['state'] - - if state == 'present' and not module.params['size']: - module.fail_json(msg="Size is required when state is 'present'") - - sdk, cloud = openstack_cloud_from_module(module) - try: - if state == 'present': - _present_volume(module, cloud) - if state == 'absent': - _absent_volume(module, cloud, sdk) - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_volume_snapshot.py b/lib/ansible/modules/cloud/openstack/os_volume_snapshot.py deleted file mode 100644 index 29fae78a5e..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_volume_snapshot.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/python -# coding: utf-8 -*- - -# Copyright (c) 2016, Mario Santos <mario.rf.santos@gmail.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'community', - 'metadata_version': '1.1'} - -DOCUMENTATION = ''' ---- -module: os_volume_snapshot -short_description: Create/Delete Cinder Volume Snapshots -extends_documentation_fragment: openstack -version_added: "2.6" -author: "Mario Santos (@ruizink)" -description: - - Create or Delete cinder block storage volume snapshots -options: - display_name: - description: - - Name of the snapshot - required: true - aliases: ['name'] - display_description: - description: - - String describing the snapshot - aliases: ['description'] - volume: - description: - - The volume name or id to create/delete the snapshot - required: True - force: - description: - - Allows or disallows snapshot of a volume to be created when the volume - is attached to an instance. - type: bool - default: 'no' - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Availability zone in which to create the snapshot. -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Creates a snapshot on volume 'test_volume' -- name: create and delete snapshot - hosts: localhost - tasks: - - name: create snapshot - os_volume_snapshot: - state: present - cloud: mordred - availability_zone: az2 - display_name: test_snapshot - volume: test_volume - - name: delete snapshot - os_volume_snapshot: - state: absent - cloud: mordred - availability_zone: az2 - display_name: test_snapshot - volume: test_volume -''' - -RETURN = ''' -snapshot: - description: The snapshot instance after the change - returned: success - type: dict - sample: - id: 837aca54-c0ee-47a2-bf9a-35e1b4fdac0c - name: test_snapshot - volume_id: ec646a7c-6a35-4857-b38b-808105a24be6 - size: 2 - status: available - display_name: test_snapshot -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import (openstack_full_argument_spec, - openstack_module_kwargs, - openstack_cloud_from_module) - - -def _present_volume_snapshot(module, cloud): - volume = cloud.get_volume(module.params['volume']) - snapshot = cloud.get_volume_snapshot(module.params['display_name'], - filters={'volume_id': volume.id}) - if not snapshot: - snapshot = cloud.create_volume_snapshot(volume.id, - force=module.params['force'], - wait=module.params['wait'], - timeout=module.params[ - 'timeout'], - name=module.params['display_name'], - description=module.params.get( - 'display_description') - ) - module.exit_json(changed=True, snapshot=snapshot) - else: - module.exit_json(changed=False, snapshot=snapshot) - - -def _absent_volume_snapshot(module, cloud): - volume = cloud.get_volume(module.params['volume']) - snapshot = cloud.get_volume_snapshot(module.params['display_name'], - filters={'volume_id': volume.id}) - if not snapshot: - module.exit_json(changed=False) - else: - cloud.delete_volume_snapshot(name_or_id=snapshot.id, - wait=module.params['wait'], - timeout=module.params['timeout'], - ) - module.exit_json(changed=True, snapshot_id=snapshot.id) - - -def _system_state_change(module, cloud): - volume = cloud.get_volume(module.params['volume']) - snapshot = cloud.get_volume_snapshot(module.params['display_name'], - filters={'volume_id': volume.id}) - state = module.params['state'] - - if state == 'present': - return snapshot is None - if state == 'absent': - return snapshot is not None - - -def main(): - argument_spec = openstack_full_argument_spec( - display_name=dict(required=True, aliases=['name']), - display_description=dict(default=None, aliases=['description']), - volume=dict(required=True), - force=dict(required=False, default=False, type='bool'), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - sdk, cloud = openstack_cloud_from_module(module) - - state = module.params['state'] - - try: - if cloud.volume_exists(module.params['volume']): - if module.check_mode: - module.exit_json(changed=_system_state_change(module, cloud)) - if state == 'present': - _present_volume_snapshot(module, cloud) - if state == 'absent': - _absent_volume_snapshot(module, cloud) - else: - module.fail_json( - msg="No volume with name or id '{0}' was found.".format( - module.params['volume'])) - except (sdk.exceptions.OpenStackCloudException, sdk.exceptions.ResourceTimeout) as e: - module.fail_json(msg=e.message) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/cloud/openstack/os_zone.py b/lib/ansible/modules/cloud/openstack/os_zone.py deleted file mode 100644 index 2103130d0b..0000000000 --- a/lib/ansible/modules/cloud/openstack/os_zone.py +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2016 Hewlett-Packard Enterprise -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: os_zone -short_description: Manage OpenStack DNS zones -extends_documentation_fragment: openstack -version_added: "2.2" -author: "Ricardo Carrillo Cruz (@rcarrillocruz)" -description: - - Manage OpenStack DNS zones. Zones can be created, deleted or - updated. Only the I(email), I(description), I(ttl) and I(masters) values - can be updated. -options: - name: - description: - - Zone name - required: true - zone_type: - description: - - Zone type - choices: [primary, secondary] - email: - description: - - Email of the zone owner (only applies if zone_type is primary) - description: - description: - - Zone description - ttl: - description: - - TTL (Time To Live) value in seconds - masters: - description: - - Master nameservers (only applies if zone_type is secondary) - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present - availability_zone: - description: - - Ignored. Present for backwards compatibility -requirements: - - "python >= 2.7" - - "openstacksdk" -''' - -EXAMPLES = ''' -# Create a zone named "example.net" -- os_zone: - cloud: mycloud - state: present - name: example.net. - zone_type: primary - email: test@example.net - description: Test zone - ttl: 3600 - -# Update the TTL on existing "example.net." zone -- os_zone: - cloud: mycloud - state: present - name: example.net. - ttl: 7200 - -# Delete zone named "example.net." -- os_zone: - cloud: mycloud - state: absent - name: example.net. -''' - -RETURN = ''' -zone: - description: Dictionary describing the zone. - returned: On success when I(state) is 'present'. - type: complex - contains: - id: - description: Unique zone ID - type: str - sample: "c1c530a3-3619-46f3-b0f6-236927b2618c" - name: - description: Zone name - type: str - sample: "example.net." - type: - description: Zone type - type: str - sample: "PRIMARY" - email: - description: Zone owner email - type: str - sample: "test@example.net" - description: - description: Zone description - type: str - sample: "Test description" - ttl: - description: Zone TTL value - type: int - sample: 3600 - masters: - description: Zone master nameservers - type: list - sample: [] -''' - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module - - -def _system_state_change(state, email, description, ttl, masters, zone): - if state == 'present': - if not zone: - return True - if email is not None and zone.email != email: - return True - if description is not None and zone.description != description: - return True - if ttl is not None and zone.ttl != ttl: - return True - if masters is not None and zone.masters != masters: - return True - if state == 'absent' and zone: - return True - return False - - -def _wait(timeout, cloud, zone, state, module, sdk): - """Wait for a zone to reach the desired state for the given state.""" - - for count in sdk.utils.iterate_timeout( - timeout, - "Timeout waiting for zone to be %s" % state): - - if (state == 'absent' and zone is None) or (state == 'present' and zone and zone.status == 'ACTIVE'): - return - - try: - zone = cloud.get_zone(zone.id) - except Exception: - continue - - if zone and zone.status == 'ERROR': - module.fail_json(msg="Zone reached ERROR state while waiting for it to be %s" % state) - - -def main(): - argument_spec = openstack_full_argument_spec( - name=dict(required=True), - zone_type=dict(required=False, choices=['primary', 'secondary']), - email=dict(required=False, default=None), - description=dict(required=False, default=None), - ttl=dict(required=False, default=None, type='int'), - masters=dict(required=False, default=None, type='list'), - state=dict(default='present', choices=['absent', 'present']), - ) - - module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, - supports_check_mode=True, - **module_kwargs) - - name = module.params.get('name') - state = module.params.get('state') - wait = module.params.get('wait') - timeout = module.params.get('timeout') - - sdk, cloud = openstack_cloud_from_module(module) - try: - zone = cloud.get_zone(name) - - if state == 'present': - zone_type = module.params.get('zone_type') - email = module.params.get('email') - description = module.params.get('description') - ttl = module.params.get('ttl') - masters = module.params.get('masters') - - if module.check_mode: - module.exit_json(changed=_system_state_change(state, email, - description, ttl, - masters, zone)) - - if zone is None: - zone = cloud.create_zone( - name=name, zone_type=zone_type, email=email, - description=description, ttl=ttl, masters=masters) - changed = True - else: - if masters is None: - masters = [] - - pre_update_zone = zone - changed = _system_state_change(state, email, - description, ttl, - masters, pre_update_zone) - if changed: - zone = cloud.update_zone( - name, email=email, - description=description, - ttl=ttl, masters=masters) - - if wait: - _wait(timeout, cloud, zone, state, module, sdk) - - module.exit_json(changed=changed, zone=zone) - - elif state == 'absent': - if module.check_mode: - module.exit_json(changed=_system_state_change(state, None, - None, None, - None, zone)) - - if zone is None: - changed = False - else: - cloud.delete_zone(name) - changed = True - - if wait: - _wait(timeout, cloud, zone, state, module, sdk) - - module.exit_json(changed=changed) - - except sdk.exceptions.OpenStackCloudException as e: - module.fail_json(msg=str(e)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/plugins/doc_fragments/openstack.py b/lib/ansible/plugins/doc_fragments/openstack.py deleted file mode 100644 index 746c1fed8c..0000000000 --- a/lib/ansible/plugins/doc_fragments/openstack.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2014, Hewlett-Packard Development Company, L.P. -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -class ModuleDocFragment(object): - - # Standard openstack documentation fragment - DOCUMENTATION = r''' -options: - cloud: - description: - - Named cloud or cloud config to operate against. - If I(cloud) is a string, it references a named cloud config as defined - in an OpenStack clouds.yaml file. Provides default values for I(auth) - and I(auth_type). This parameter is not needed if I(auth) is provided - or if OpenStack OS_* environment variables are present. - If I(cloud) is a dict, it contains a complete cloud configuration like - would be in a section of clouds.yaml. - type: raw - auth: - description: - - Dictionary containing auth information as needed by the cloud's auth - plugin strategy. For the default I(password) plugin, this would contain - I(auth_url), I(username), I(password), I(project_name) and any - information about domains (for example, I(os_user_domain_name) or I(os_project_domain_name)) if the cloud supports them. - For other plugins, - this param will need to contain whatever parameters that auth plugin - requires. This parameter is not needed if a named cloud is provided or - OpenStack OS_* environment variables are present. - type: dict - auth_type: - description: - - Name of the auth plugin to use. If the cloud uses something other than - password authentication, the name of the plugin should be indicated here - and the contents of the I(auth) parameter should be updated accordingly. - type: str - region_name: - description: - - Name of the region. - type: str - wait: - description: - - Should ansible wait until the requested resource is complete. - type: bool - default: yes - timeout: - description: - - How long should ansible wait for the requested resource. - type: int - default: 180 - api_timeout: - description: - - How long should the socket layer wait before timing out for API calls. - If this is omitted, nothing will be passed to the requests library. - type: int - validate_certs: - description: - - Whether or not SSL API requests should be verified. - - Before Ansible 2.3 this defaulted to C(yes). - type: bool - default: no - aliases: [ verify ] - ca_cert: - description: - - A path to a CA Cert bundle that can be used as part of verifying - SSL API requests. - type: str - aliases: [ cacert ] - client_cert: - description: - - A path to a client certificate to use as part of the SSL transaction. - type: str - aliases: [ cert ] - client_key: - description: - - A path to a client key to use as part of the SSL transaction. - type: str - aliases: [ key ] - interface: - description: - - Endpoint URL type to fetch from the service catalog. - type: str - choices: [ admin, internal, public ] - default: public - aliases: [ endpoint_type ] - version_added: "2.3" -requirements: - - python >= 2.7 - - openstacksdk >= 0.12.0 -notes: - - The standard OpenStack environment variables, such as C(OS_USERNAME) - may be used instead of providing explicit values. - - Auth information is driven by openstacksdk, which means that values - can come from a yaml config file in /etc/ansible/openstack.yaml, - /etc/openstack/clouds.yaml or ~/.config/openstack/clouds.yaml, then from - standard environment variables, then finally by explicit parameters in - plays. More information can be found at - U(https://docs.openstack.org/openstacksdk/) -''' diff --git a/lib/ansible/plugins/inventory/openstack.py b/lib/ansible/plugins/inventory/openstack.py deleted file mode 100644 index 0dbbbeaa10..0000000000 --- a/lib/ansible/plugins/inventory/openstack.py +++ /dev/null @@ -1,344 +0,0 @@ -# Copyright (c) 2012, Marco Vito Moscaritolo <marco@agavee.com> -# Copyright (c) 2013, Jesse Keating <jesse.keating@rackspace.com> -# Copyright (c) 2015, Hewlett-Packard Development Company, L.P. -# Copyright (c) 2016, Rackspace Australia -# Copyright (c) 2017 Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -DOCUMENTATION = ''' - name: openstack - plugin_type: inventory - author: - - Marco Vito Moscaritolo <marco@agavee.com> - - Jesse Keating <jesse.keating@rackspace.com> - short_description: OpenStack inventory source - requirements: - - "openstacksdk >= 0.28" - extends_documentation_fragment: - - inventory_cache - - constructed - description: - - Get inventory hosts from OpenStack clouds - - Uses openstack.(yml|yaml) YAML configuration file to configure the inventory plugin - - Uses standard clouds.yaml YAML configuration file to configure cloud credentials - options: - plugin: - description: token that ensures this is a source file for the 'openstack' plugin. - required: True - choices: ['openstack'] - show_all: - description: toggles showing all vms vs only those with a working IP - type: bool - default: 'no' - inventory_hostname: - description: | - What to register as the inventory hostname. - If set to 'uuid' the uuid of the server will be used and a - group will be created for the server name. - If set to 'name' the name of the server will be used unless - there are more than one server with the same name in which - case the 'uuid' logic will be used. - Default is to do 'name', which is the opposite of the old - openstack.py inventory script's option use_hostnames) - type: string - choices: - - name - - uuid - default: "name" - expand_hostvars: - description: | - Run extra commands on each host to fill in additional - information about the host. May interrogate cinder and - neutron and can be expensive for people with many hosts. - (Note, the default value of this is opposite from the default - old openstack.py inventory script's option expand_hostvars) - type: bool - default: 'no' - private: - description: | - Use the private interface of each server, if it has one, as - the host's IP in the inventory. This can be useful if you are - running ansible inside a server in the cloud and would rather - communicate to your servers over the private network. - type: bool - default: 'no' - only_clouds: - description: | - List of clouds from clouds.yaml to use, instead of using - the whole list. - type: list - default: [] - fail_on_errors: - description: | - Causes the inventory to fail and return no hosts if one cloud - has failed (for example, bad credentials or being offline). - When set to False, the inventory will return as many hosts as - it can from as many clouds as it can contact. (Note, the - default value of this is opposite from the old openstack.py - inventory script's option fail_on_errors) - type: bool - default: 'no' - all_projects: - description: | - Lists servers from all projects - type: bool - default: 'no' - version_added: 2.10 - clouds_yaml_path: - description: | - Override path to clouds.yaml file. If this value is given it - will be searched first. The default path for the - ansible inventory adds /etc/ansible/openstack.yaml and - /etc/ansible/openstack.yml to the regular locations documented - at https://docs.openstack.org/os-client-config/latest/user/configuration.html#config-files - type: list - env: - - name: OS_CLIENT_CONFIG_FILE - compose: - description: Create vars from jinja2 expressions. - type: dictionary - default: {} - groups: - description: Add hosts to group based on Jinja2 conditionals. - type: dictionary - default: {} -''' - -EXAMPLES = ''' -# file must be named openstack.yaml or openstack.yml -# Make the plugin behave like the default behavior of the old script -plugin: openstack -expand_hostvars: yes -fail_on_errors: yes -all_projects: yes -''' - -import collections -import sys - -from ansible.errors import AnsibleParserError -from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable - -try: - # Due to the name shadowing we should import other way - import importlib - sdk = importlib.import_module('openstack') - sdk_inventory = importlib.import_module('openstack.cloud.inventory') - client_config = importlib.import_module('openstack.config.loader') - HAS_SDK = True -except ImportError: - HAS_SDK = False - - -class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): - ''' Host inventory provider for ansible using OpenStack clouds. ''' - - NAME = 'openstack' - - def parse(self, inventory, loader, path, cache=True): - - super(InventoryModule, self).parse(inventory, loader, path) - - cache_key = self._get_cache_prefix(path) - - # file is config file - self._config_data = self._read_config_data(path) - - msg = '' - if not self._config_data: - msg = 'File empty. this is not my config file' - elif 'plugin' in self._config_data and self._config_data['plugin'] != self.NAME: - msg = 'plugin config file, but not for us: %s' % self._config_data['plugin'] - elif 'plugin' not in self._config_data and 'clouds' not in self._config_data: - msg = "it's not a plugin configuration nor a clouds.yaml file" - elif not HAS_SDK: - msg = "openstacksdk is required for the OpenStack inventory plugin. OpenStack inventory sources will be skipped." - - if msg: - raise AnsibleParserError(msg) - - # The user has pointed us at a clouds.yaml file. Use defaults for - # everything. - if 'clouds' in self._config_data: - self._config_data = {} - - # update cache if the user has caching enabled and the cache is being refreshed - # will update variable below in the case of an expired cache - cache_needs_update = not cache and self.get_option('cache') - - if cache: - cache = self.get_option('cache') - source_data = None - if cache: - try: - source_data = self._cache[cache_key] - except KeyError: - # cache expired or doesn't exist yet - cache_needs_update = True - - if not source_data: - clouds_yaml_path = self._config_data.get('clouds_yaml_path') - if clouds_yaml_path: - config_files = (clouds_yaml_path + - client_config.CONFIG_FILES) - else: - config_files = None - - # Redict logging to stderr so it does not mix with output - # particular ansible-inventory JSON output - # TODO(mordred) Integrate openstack's logging with ansible's logging - sdk.enable_logging(stream=sys.stderr) - - cloud_inventory = sdk_inventory.OpenStackInventory( - config_files=config_files, - private=self._config_data.get('private', False)) - only_clouds = self._config_data.get('only_clouds', []) - if only_clouds and not isinstance(only_clouds, list): - raise ValueError( - 'OpenStack Inventory Config Error: only_clouds must be' - ' a list') - if only_clouds: - new_clouds = [] - for cloud in cloud_inventory.clouds: - if cloud.name in only_clouds: - new_clouds.append(cloud) - cloud_inventory.clouds = new_clouds - - expand_hostvars = self._config_data.get('expand_hostvars', False) - fail_on_errors = self._config_data.get('fail_on_errors', False) - all_projects = self._config_data.get('all_projects', False) - - source_data = cloud_inventory.list_hosts( - expand=expand_hostvars, fail_on_cloud_config=fail_on_errors, - all_projects=all_projects) - - if cache_needs_update: - self._cache[cache_key] = source_data - - self._populate_from_source(source_data) - - def _populate_from_source(self, source_data): - groups = collections.defaultdict(list) - firstpass = collections.defaultdict(list) - hostvars = {} - - use_server_id = ( - self._config_data.get('inventory_hostname', 'name') != 'name') - show_all = self._config_data.get('show_all', False) - - for server in source_data: - if 'interface_ip' not in server and not show_all: - continue - firstpass[server['name']].append(server) - - for name, servers in firstpass.items(): - if len(servers) == 1 and not use_server_id: - self._append_hostvars(hostvars, groups, name, servers[0]) - else: - server_ids = set() - # Trap for duplicate results - for server in servers: - server_ids.add(server['id']) - if len(server_ids) == 1 and not use_server_id: - self._append_hostvars(hostvars, groups, name, servers[0]) - else: - for server in servers: - self._append_hostvars( - hostvars, groups, server['id'], server, - namegroup=True) - - self._set_variables(hostvars, groups) - - def _set_variables(self, hostvars, groups): - - # set vars in inventory from hostvars - for host in hostvars: - - # create composite vars - self._set_composite_vars( - self._config_data.get('compose'), hostvars[host], host) - - # actually update inventory - for key in hostvars[host]: - self.inventory.set_variable(host, key, hostvars[host][key]) - - # constructed groups based on conditionals - self._add_host_to_composed_groups( - self._config_data.get('groups'), hostvars[host], host) - - # constructed groups based on jinja expressions - self._add_host_to_keyed_groups( - self._config_data.get('keyed_groups'), hostvars[host], host) - - for group_name, group_hosts in groups.items(): - gname = self.inventory.add_group(group_name) - for host in group_hosts: - self.inventory.add_child(gname, host) - - def _get_groups_from_server(self, server_vars, namegroup=True): - groups = [] - - region = server_vars['region'] - cloud = server_vars['cloud'] - metadata = server_vars.get('metadata', {}) - - # Create a group for the cloud - groups.append(cloud) - - # Create a group on region - if region: - groups.append(region) - - # And one by cloud_region - groups.append("%s_%s" % (cloud, region)) - - # Check if group metadata key in servers' metadata - if 'group' in metadata: - groups.append(metadata['group']) - - for extra_group in metadata.get('groups', '').split(','): - if extra_group: - groups.append(extra_group.strip()) - - groups.append('instance-%s' % server_vars['id']) - if namegroup: - groups.append(server_vars['name']) - - for key in ('flavor', 'image'): - if 'name' in server_vars[key]: - groups.append('%s-%s' % (key, server_vars[key]['name'])) - - for key, value in iter(metadata.items()): - groups.append('meta-%s_%s' % (key, value)) - - az = server_vars.get('az', None) - if az: - # Make groups for az, region_az and cloud_region_az - groups.append(az) - groups.append('%s_%s' % (region, az)) - groups.append('%s_%s_%s' % (cloud, region, az)) - return groups - - def _append_hostvars(self, hostvars, groups, current_host, - server, namegroup=False): - hostvars[current_host] = dict( - ansible_ssh_host=server['interface_ip'], - ansible_host=server['interface_ip'], - openstack=server) - self.inventory.add_host(current_host) - - for group in self._get_groups_from_server(server, namegroup=namegroup): - groups[group].append(current_host) - - def verify_file(self, path): - - if super(InventoryModule, self).verify_file(path): - for fn in ('openstack', 'clouds'): - for suffix in ('yaml', 'yml'): - maybe = '{fn}.{suffix}'.format(fn=fn, suffix=suffix) - if path.endswith(maybe): - return True - return False diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 6a2fa5c9ef..a5e55ffdfe 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -104,8 +104,6 @@ lib/ansible/module_utils/network/skydive/api.py future-import-boilerplate lib/ansible/module_utils/network/skydive/api.py metaclass-boilerplate lib/ansible/module_utils/network/vyos/vyos.py future-import-boilerplate lib/ansible/module_utils/network/vyos/vyos.py metaclass-boilerplate -lib/ansible/module_utils/openstack.py future-import-boilerplate -lib/ansible/module_utils/openstack.py metaclass-boilerplate lib/ansible/module_utils/ovirt.py future-import-boilerplate lib/ansible/module_utils/ovirt.py metaclass-boilerplate lib/ansible/module_utils/parsing/convert_bool.py future-import-boilerplate @@ -1028,138 +1026,6 @@ lib/ansible/modules/cloud/google/gcp_tpu_node_info.py validate-modules:parameter lib/ansible/modules/cloud/hcloud/hcloud_network_info.py validate-modules:return-syntax-error lib/ansible/modules/cloud/hcloud/hcloud_server.py validate-modules:parameter-list-no-elements lib/ansible/modules/cloud/hcloud/hcloud_server_network.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_auth.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_client_config.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_client_config.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_coe_cluster.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_coe_cluster.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_coe_cluster_template.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_coe_cluster_template.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_coe_cluster_template.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_flavor_info.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/openstack/os_flavor_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_flavor_info.py validate-modules:implied-parameter-type-mismatch -lib/ansible/modules/cloud/openstack/os_flavor_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_floating_ip.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_group.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_group_info.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_image.py validate-modules:doc-choices-do-not-match-spec -lib/ansible/modules/cloud/openstack/os_image.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/openstack/os_image.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_image.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_image_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:doc-choices-do-not-match-spec -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:nonexistent-parameter-documented -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_ironic.py validate-modules:undocumented-parameter -lib/ansible/modules/cloud/openstack/os_ironic_inspect.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_ironic_node.py validate-modules:doc-choices-do-not-match-spec -lib/ansible/modules/cloud/openstack/os_ironic_node.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/openstack/os_ironic_node.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_ironic_node.py validate-modules:implied-parameter-type-mismatch -lib/ansible/modules/cloud/openstack/os_ironic_node.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_ironic_node.py validate-modules:undocumented-parameter -lib/ansible/modules/cloud/openstack/os_keypair.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_keystone_domain.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_keystone_domain_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_keystone_domain_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_keystone_endpoint.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_keystone_endpoint.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_keystone_endpoint.py validate-modules:undocumented-parameter -lib/ansible/modules/cloud/openstack/os_keystone_role.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_keystone_service.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_listener.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_listener.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_loadbalancer.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_loadbalancer.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_loadbalancer.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_member.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_member.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_network.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_network.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_networks_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_networks_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_nova_flavor.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_nova_flavor.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_nova_flavor.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_nova_host_aggregate.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_nova_host_aggregate.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_nova_host_aggregate.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_object.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_pool.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_port.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_port.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_port.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_port.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_port_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_port_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_project.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_project_access.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_project_access.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_project_access.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_project_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_project_info.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_project_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_quota.py validate-modules:doc-choices-do-not-match-spec -lib/ansible/modules/cloud/openstack/os_quota.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_quota.py validate-modules:nonexistent-parameter-documented -lib/ansible/modules/cloud/openstack/os_quota.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_quota.py validate-modules:return-syntax-error -lib/ansible/modules/cloud/openstack/os_quota.py validate-modules:undocumented-parameter -lib/ansible/modules/cloud/openstack/os_recordset.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_recordset.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_recordset.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_recordset.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_router.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_router.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_router.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_security_group.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_security_group_rule.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_security_group_rule.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_server.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/openstack/os_server.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_server.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_server.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_server.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_server.py validate-modules:undocumented-parameter -lib/ansible/modules/cloud/openstack/os_server_action.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/openstack/os_server_action.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_server_action.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_server_group.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_server_group.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_server_group.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_server_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_server_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_server_metadata.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_server_metadata.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_server_volume.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_stack.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/openstack/os_stack.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_stack.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_stack.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_subnet.py validate-modules:doc-choices-do-not-match-spec -lib/ansible/modules/cloud/openstack/os_subnet.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_subnet.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_subnet.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_subnets_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_subnets_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_user.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_user.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_user_group.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_user_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_user_info.py validate-modules:doc-required-mismatch -lib/ansible/modules/cloud/openstack/os_user_info.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_user_role.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_volume.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_volume.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/openstack/os_volume.py validate-modules:undocumented-parameter -lib/ansible/modules/cloud/openstack/os_volume_snapshot.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_zone.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/openstack/os_zone.py validate-modules:parameter-list-no-elements -lib/ansible/modules/cloud/openstack/os_zone.py validate-modules:parameter-type-not-in-doc lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py future-import-boilerplate lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py metaclass-boilerplate lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py validate-modules:doc-required-mismatch @@ -2018,8 +1884,6 @@ lib/ansible/plugins/doc_fragments/inventory_cache.py future-import-boilerplate lib/ansible/plugins/doc_fragments/inventory_cache.py metaclass-boilerplate lib/ansible/plugins/doc_fragments/junos.py future-import-boilerplate lib/ansible/plugins/doc_fragments/junos.py metaclass-boilerplate -lib/ansible/plugins/doc_fragments/openstack.py future-import-boilerplate -lib/ansible/plugins/doc_fragments/openstack.py metaclass-boilerplate lib/ansible/plugins/doc_fragments/ovirt.py future-import-boilerplate lib/ansible/plugins/doc_fragments/ovirt.py metaclass-boilerplate lib/ansible/plugins/doc_fragments/ovirt_info.py future-import-boilerplate @@ -2288,8 +2152,6 @@ test/units/module_utils/urls/test_Request.py replace-urlopen test/units/module_utils/urls/test_fetch_url.py replace-urlopen test/units/modules/cloud/linode/conftest.py future-import-boilerplate test/units/modules/cloud/linode/conftest.py metaclass-boilerplate -test/units/modules/cloud/openstack/test_os_server.py future-import-boilerplate -test/units/modules/cloud/openstack/test_os_server.py metaclass-boilerplate test/units/modules/conftest.py future-import-boilerplate test/units/modules/conftest.py metaclass-boilerplate test/units/modules/files/test_copy.py future-import-boilerplate diff --git a/test/units/modules/cloud/openstack/test_os_server.py b/test/units/modules/cloud/openstack/test_os_server.py deleted file mode 100644 index 450e536b68..0000000000 --- a/test/units/modules/cloud/openstack/test_os_server.py +++ /dev/null @@ -1,228 +0,0 @@ -import collections -import inspect -import mock -import pytest -import yaml - -from ansible.module_utils.six import string_types -from ansible.modules.cloud.openstack import os_server - - -class AnsibleFail(Exception): - pass - - -class AnsibleExit(Exception): - pass - - -def params_from_doc(func): - '''This function extracts the docstring from the specified function, - parses it as a YAML document, and returns parameters for the os_server - module.''' - - doc = inspect.getdoc(func) - cfg = yaml.load(doc) - - for task in cfg: - for module, params in task.items(): - for k, v in params.items(): - if k in ['nics'] and isinstance(v, string_types): - params[k] = [v] - task[module] = collections.defaultdict(str, - params) - - return cfg[0]['os_server'] - - -class FakeCloud(object): - ports = [ - {'name': 'port1', 'id': '1234'}, - {'name': 'port2', 'id': '4321'}, - ] - - networks = [ - {'name': 'network1', 'id': '5678'}, - {'name': 'network2', 'id': '8765'}, - ] - - images = [ - {'name': 'cirros', 'id': '1'}, - {'name': 'fedora', 'id': '2'}, - ] - - flavors = [ - {'name': 'm1.small', 'id': '1', 'flavor_ram': 1024}, - {'name': 'm1.tiny', 'id': '2', 'flavor_ram': 512}, - ] - - def _find(self, source, name): - for item in source: - if item['name'] == name or item['id'] == name: - return item - - def get_image_id(self, name, exclude=None): - image = self._find(self.images, name) - if image: - return image['id'] - - def get_flavor(self, name): - return self._find(self.flavors, name) - - def get_flavor_by_ram(self, ram, include=None): - for flavor in self.flavors: - if flavor['ram'] >= ram and (include is None or include in - flavor['name']): - return flavor - - def get_port(self, name): - return self._find(self.ports, name) - - def get_network(self, name): - return self._find(self.networks, name) - - def get_openstack_vars(self, server): - return server - - def get_server(self, name): - return None - - create_server = mock.MagicMock() - - -class TestNetworkArgs(object): - '''This class exercises the _network_args function of the - os_server module. For each test, we parse the YAML document - contained in the docstring to retrieve the module parameters for the - test.''' - - def setup_method(self, method): - self.cloud = FakeCloud() - self.module = mock.MagicMock() - self.module.params = params_from_doc(method) - - def test_nics_string_net_id(self): - ''' - - os_server: - nics: net-id=1234 - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['net-id'] == '1234') - - def test_nics_string_net_id_list(self): - ''' - - os_server: - nics: net-id=1234,net-id=4321 - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['net-id'] == '1234') - assert(args[1]['net-id'] == '4321') - - def test_nics_string_port_id(self): - ''' - - os_server: - nics: port-id=1234 - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['port-id'] == '1234') - - def test_nics_string_net_name(self): - ''' - - os_server: - nics: net-name=network1 - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['net-id'] == '5678') - - def test_nics_string_port_name(self): - ''' - - os_server: - nics: port-name=port1 - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['port-id'] == '1234') - - def test_nics_structured_net_id(self): - ''' - - os_server: - nics: - - net-id: '1234' - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['net-id'] == '1234') - - def test_nics_structured_mixed(self): - ''' - - os_server: - nics: - - net-id: '1234' - - port-name: port1 - - 'net-name=network1,port-id=4321' - ''' - args = os_server._network_args(self.module, self.cloud) - assert(args[0]['net-id'] == '1234') - assert(args[1]['port-id'] == '1234') - assert(args[2]['net-id'] == '5678') - assert(args[3]['port-id'] == '4321') - - -class TestCreateServer(object): - def setup_method(self, method): - self.cloud = FakeCloud() - self.module = mock.MagicMock() - self.module.params = params_from_doc(method) - self.module.fail_json.side_effect = AnsibleFail() - self.module.exit_json.side_effect = AnsibleExit() - self.module.check_mode = False - - self.meta = mock.MagicMock() - self.meta.gett_hostvars_from_server.return_value = { - 'id': '1234' - } - os_server.meta = self.meta - - def test_create_server(self): - ''' - - os_server: - image: cirros - flavor: m1.tiny - nics: - - net-name: network1 - meta: - - key: value - ''' - with pytest.raises(AnsibleExit): - os_server._present_server(self.module, self.cloud) - - assert(self.cloud.create_server.call_count == 1) - assert(self.cloud.create_server.call_args[1]['image'] == self.cloud.get_image_id('cirros')) - assert(self.cloud.create_server.call_args[1]['flavor'] == self.cloud.get_flavor('m1.tiny')['id']) - assert(self.cloud.create_server.call_args[1]['nics'][0]['net-id'] == self.cloud.get_network('network1')['id']) - - def test_create_server_bad_flavor(self): - ''' - - os_server: - image: cirros - flavor: missing_flavor - nics: - - net-name: network1 - ''' - with pytest.raises(AnsibleFail): - os_server._present_server(self.module, self.cloud) - - assert('missing_flavor' in - self.module.fail_json.call_args[1]['msg']) - - def test_create_server_bad_nic(self): - ''' - - os_server: - image: cirros - flavor: m1.tiny - nics: - - net-name: missing_network - ''' - with pytest.raises(AnsibleFail): - os_server._present_server(self.module, self.cloud) - - assert('missing_network' in - self.module.fail_json.call_args[1]['msg']) diff --git a/test/units/plugins/inventory/test_openstack.py b/test/units/plugins/inventory/test_openstack.py deleted file mode 100644 index fec7ae580c..0000000000 --- a/test/units/plugins/inventory/test_openstack.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2018 Lars Kellogg-Stedman <lars@redhat.com> -# -# This file is part of Ansible -# -# Ansible 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. -# -# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>. - -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import pytest - -from ansible.plugins.inventory.openstack import InventoryModule -from ansible.inventory.data import InventoryData -from ansible.template import Templar - - -config_data = { - 'plugin': 'openstack', - 'compose': { - 'composed_var': '"testvar-" + testvar', - }, - 'groups': { - 'testgroup': '"host" in inventory_hostname', - }, - 'keyed_groups': - [{ - 'prefix': 'keyed', - 'key': 'testvar', - }] -} - -hostvars = { - 'host0': { - 'inventory_hostname': 'host0', - 'testvar': '0', - }, - 'host1': { - 'inventory_hostname': 'host1', - 'testvar': '1', - }, -} - - -@pytest.fixture(scope="module") -def inventory(): - inventory = InventoryModule() - inventory._config_data = config_data - inventory.inventory = InventoryData() - inventory.templar = Templar(loader=None) - - for host in hostvars: - inventory.inventory.add_host(host) - - return inventory - - -def test_simple_groups(inventory): - inventory._set_variables(hostvars, {}) - groups = inventory.inventory.get_groups_dict() - assert 'testgroup' in groups - assert len(groups['testgroup']) == len(hostvars) - - -def test_keyed_groups(inventory): - inventory._set_variables(hostvars, {}) - assert 'keyed_0' in inventory.inventory.groups - assert 'keyed_1' in inventory.inventory.groups - - -def test_composed_vars(inventory): - inventory._set_variables(hostvars, {}) - - for host in hostvars: - assert host in inventory.inventory.hosts - host = inventory.inventory.get_host(host) - assert host.vars['composed_var'] == 'testvar-{testvar}'.format(**hostvars[host.name]) |