diff --git a/changelogs/fragments/2.8-removed-modules.yaml b/changelogs/fragments/2.8-removed-modules.yaml new file mode 100644 index 0000000000..9f5ba33c8e --- /dev/null +++ b/changelogs/fragments/2.8-removed-modules.yaml @@ -0,0 +1,6 @@ +removed_features: +- ec2_remote_facts - deprecated module removed (https://github.com/ansible/ansible/pull/44985) +- azure - deprecated module removed (https://github.com/ansible/ansible/pull/44985) +- cs_nic - deprecated module removed (https://github.com/ansible/ansible/pull/44985) +- netscaler - deprecated module removed (https://github.com/ansible/ansible/pull/44985) +- win_msi - deprecated module removed (https://github.com/ansible/ansible/pull/44985) diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.4.rst b/docs/docsite/rst/porting_guides/porting_guide_2.4.rst index e3499abe74..1ebd12fe4a 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_2.4.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_2.4.rst @@ -91,8 +91,8 @@ Deprecation notices The following modules will be removed in Ansible 2.8. Please update your playbooks accordingly. -* :ref:`azure `, use :ref:`azure_rm_virtualmachine `, which uses the new Resource Manager SDK. -* :ref:`win_msi `, use :ref:`win_package ` instead +* azure, use :ref:`azure_rm_virtualmachine `, which uses the new Resource Manager SDK. +* win_msi, use :ref:`win_package ` instead Noteworthy module changes ------------------------- diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.8.rst b/docs/docsite/rst/porting_guides/porting_guide_2.8.rst new file mode 100644 index 0000000000..1f2c4b576a --- /dev/null +++ b/docs/docsite/rst/porting_guides/porting_guide_2.8.rst @@ -0,0 +1,68 @@ +.. _porting_2.8_guide: + +************************* +Ansible 2.8 Porting Guide +************************* + +This section discusses the behavioral changes between Ansible 2.7 and Ansible 2.8. + +It is intended to assist in updating your playbooks, plugins and other parts of your Ansible infrastructure so they will work with this version of Ansible. + +We suggest you read this page along with `Ansible Changelog for 2.8 `_ to understand what updates you may need to make. + +This document is part of a collection on porting. The complete list of porting guides can be found at :ref:`porting guides `. + +.. contents:: Topics + +Playbook +======== + +No notable changes. + + +Deprecated +========== + +No notable changes. + +Modules +======= + +Major changes in popular modules are detailed here + + +Modules removed +--------------- + +The following modules no longer exist: + +* ec2_remote_facts +* azure +* cs_nic +* netscaler +* win_msi + +Deprecation notices +------------------- + +The following modules will be removed in Ansible 2.12. Please update your playbooks accordingly. + + +Noteworthy module changes +------------------------- + + +Plugins +======= + +No notable changes. + +Porting custom scripts +====================== + +No notable changes. + +Networking +========== + +No notable changes. diff --git a/docs/docsite/rst/porting_guides/porting_guides.rst b/docs/docsite/rst/porting_guides/porting_guides.rst index e99f0b62dc..868a6ec645 100644 --- a/docs/docsite/rst/porting_guides/porting_guides.rst +++ b/docs/docsite/rst/porting_guides/porting_guides.rst @@ -17,3 +17,4 @@ Please note that this is not a complete list. If you believe any extra informati porting_guide_2.5 porting_guide_2.6 porting_guide_2.7 + porting_guide_2.8 diff --git a/lib/ansible/modules/cloud/amazon/_ec2_remote_facts.py b/lib/ansible/modules/cloud/amazon/_ec2_remote_facts.py index e6b4190ab7..f390654234 100644 --- a/lib/ansible/modules/cloud/amazon/_ec2_remote_facts.py +++ b/lib/ansible/modules/cloud/amazon/_ec2_remote_facts.py @@ -7,400 +7,12 @@ __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], + 'status': ['removed'], 'supported_by': 'certified'} -DOCUMENTATION = ''' ---- -module: ec2_remote_facts -short_description: Gather facts about ec2 instances in AWS -deprecated: - removed_in: "2.8" - why: Replaced with boto3 version. - alternative: Use M(ec2_instance_facts) instead. -description: - - Gather facts about ec2 instances in AWS -version_added: "2.0" -options: - filters: - description: - - A dict of filters to apply. Each dict item consists of a filter key and a filter value. - See U(http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html) for possible filters. -author: - - "Michael Schuett (@michaeljs1990)" -extends_documentation_fragment: - - aws - - ec2 -''' - -EXAMPLES = ''' -# Note: These examples do not set authentication details, see the AWS Guide for details. - -# Gather facts about all ec2 instances -- ec2_remote_facts: - -# Gather facts about all running ec2 instances with a tag of Name:Example -- ec2_remote_facts: - filters: - instance-state-name: running - "tag:Name": Example - -# Gather facts about instance i-123456 -- ec2_remote_facts: - filters: - instance-id: i-123456 - -# Gather facts about all instances in vpc-123456 that are t2.small type -- ec2_remote_facts: - filters: - vpc-id: vpc-123456 - instance-type: t2.small - -''' - -RETURN = ''' -instances: - description: provides details about EC2 instance(s) found in AWS region - returned: when EC2 instances are found in AWS region otherwise empty - type: complex - contains: - ami_launch_index: - description: > - if more than one instance is started at the same time, this value indicates the order in which the instance was launched, - the value of the first instance launched is 0 - returned: success - type: string - sample: "0" - architecture: - description: the instance architecture - returned: success - type: string - sample: "x86_64" - block_device_mapping: - description: a structure describing the attached volumes to instance - returned: success - type: complex - contains: - attach_time: - description: the attach time for an EBS volume mapped to the instance - returned: success - type: string - sample: "2017-01-03T15:19:52.000Z" - delete_on_termination: - description: indicates whether the EBS volume is deleted on instance termination - returned: success - type: boolean - sample: "true" - device_name: - description: the device name for the EBS volume - returned: success - type: string - sample: "/dev/sda1" - status: - description: the status for the EBS volume - returned: success - type: string - sample: "attaching" - volume_id: - description: the volume id of the EBS volume - returned: success - type: string - sample: "vol-3160f90df06b24080" - client_token: - description: the idempotency token provided when instance was launched - returned: success - type: string - sample: "Sample-awsmp-DFNBSML8ZMJ9" - ebs_optimized: - description: whether instance class has EBS optimized flag turned on - returned: success - type: boolean - sample: "true" - groups: - description: a list security groups to which the network interface belongs - returned: success - type: complex - contains: - id: - description: security group id - returned: success - type: string - sample: "sg-e203cf94" - name: - descriptipn: security group name - returned: success - type: string - sample: "Sample-Common-Sg" - hypervisor: - description: the hypervisor type of the instance - returned: success - type: string - sample: "xen" - id: - description: the id of the instance - returned: success - type: string - sample: "i-09275d68c04c1a16c" - image_id: - description: the id of the image used to launch the instance - returned: success - type: string - sample: "ami-1748d2f5" - instance_profile: - description: the instance profile associated with the instance - returned: success - type: complex - contains: - arn: - description: specifies an ARN of instance profile - returned: success - type: string - sample: "arn:aws:iam::171455704129:instance-profile/Sample-IamProfile" - id: - description: instance profile id - returned: success - type: string - sample: "AIPAD5WIZGNR9TH6LBFE4" - interfaces: - description: a list of ENI associated to instance - returned: success - type: complex - contains: - id: - description: the id of ENI - returned: success - type: string - sample: "eni-cf96b081" - mac_address: - description: the MAC address of ENI - returned: success - type: string - sample: "06:c4:fd:90:dc:61" - kernel: - description: the kernel id - returned: success - type: string - sample: "null" - key_name: - description: the name of the key pair used when the instance was launched - returned: success - type: string - sample: "MyKey" - launch_time": - description: the time when the instance was launched - returned: success - type: string - sample: "2017-06-16T15:44:54.000Z" - monitoring_state: - description: indicates whether detailed monitoring is enabled - returned: success - type: string - sample: "disabled" - private_dns_name: - description: the private IPv4 DNS name of the instance - returned: success - type: string - sample: "ip-10-21-39-23.ag-net.com" - private_ip_address: - description: the private IPv4 address of the instance - returned: success - type: string - sample: "10.216.139.23" - public_dns_name: - description: the public DNS name of the instance - returned: success - type: string - sample: "ec2-54-194-252-215.eu-west-1.compute.amazonaws.com" - public_ip_address: - description: the public IPv4 address of the instance - returned: success - type: string - sample: "54.194.252.215" - ramdisk: - description: the RAM disk id - returned: success - type: string - sample: "null" - region: - description: the AWS region in which instance is running in - returned: success - type: string - sample: "eu-west-1" - requester_id: - description: the id of the entity that launched the instance on your behalf - returned: success - type: string - sample: "null" - root_device_type: - description: the type of root device that the instance uses - returned: success - type: string - sample: "ebs" - source_destination_check: - description: indicates whether the instance performs source/destination checking - returned: success - type: boolean - sample: "true" - spot_instance_request_id: - description: the id of the spot instance request - returned: success - type: string - sample: "null" - state: - description: a message that describes the state change - returned: success - type: string - sample: "running" - tags: - description: a dictionary of key/value pairs assigned to the resource - returned: success - type: complex - contains: - key: - description: the key of a tag assigned to the resource - returned: success - type: string - sample: "Environment" - virtualization_type: - description: the virtualization type of the instance - returned: success - type: string - sample: "hvm" - vpc_id: - description: the id of the VPC that the instance is running in - returned: success - type: string - sample: "vpc-12c9ae4f" -''' - -try: - import boto.ec2 - from boto.exception import BotoServerError - HAS_BOTO = True -except ImportError: - HAS_BOTO = False - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.ec2 import AnsibleAWSError, connect_to_aws, ec2_argument_spec, get_aws_connection_info - - -def get_instance_info(instance): - - # Get groups - groups = [] - for group in instance.groups: - groups.append({'id': group.id, 'name': group.name}.copy()) - - # Get interfaces - interfaces = [] - for interface in instance.interfaces: - interfaces.append({'id': interface.id, 'mac_address': interface.mac_address}.copy()) - - # If an instance is terminated, sourceDestCheck is no longer returned - try: - source_dest_check = instance.sourceDestCheck - except AttributeError: - source_dest_check = None - - # Get block device mapping - try: - bdm_dict = [] - bdm = getattr(instance, 'block_device_mapping') - for device_name in bdm.keys(): - bdm_dict.append({ - 'device_name': device_name, - 'status': bdm[device_name].status, - 'volume_id': bdm[device_name].volume_id, - 'delete_on_termination': bdm[device_name].delete_on_termination, - 'attach_time': bdm[device_name].attach_time - }) - except AttributeError: - pass - - instance_profile = dict(instance.instance_profile) if instance.instance_profile is not None else None - - instance_info = {'id': instance.id, - 'kernel': instance.kernel, - 'instance_profile': instance_profile, - 'root_device_type': instance.root_device_type, - 'private_dns_name': instance.private_dns_name, - 'public_dns_name': instance.public_dns_name, - 'ebs_optimized': instance.ebs_optimized, - 'client_token': instance.client_token, - 'virtualization_type': instance.virtualization_type, - 'architecture': instance.architecture, - 'ramdisk': instance.ramdisk, - 'tags': instance.tags, - 'key_name': instance.key_name, - 'source_destination_check': source_dest_check, - 'image_id': instance.image_id, - 'groups': groups, - 'interfaces': interfaces, - 'spot_instance_request_id': instance.spot_instance_request_id, - 'requester_id': instance.requester_id, - 'monitoring_state': instance.monitoring_state, - 'placement': { - 'tenancy': instance._placement.tenancy, - 'zone': instance._placement.zone - }, - 'ami_launch_index': instance.ami_launch_index, - 'launch_time': instance.launch_time, - 'hypervisor': instance.hypervisor, - 'region': instance.region.name, - 'persistent': instance.persistent, - 'private_ip_address': instance.private_ip_address, - 'public_ip_address': instance.ip_address, - 'state': instance._state.name, - 'vpc_id': instance.vpc_id, - 'block_device_mapping': bdm_dict, - } - - return instance_info - - -def list_ec2_instances(connection, module): - - filters = module.params.get("filters") - instance_dict_array = [] - - try: - all_instances = connection.get_only_instances(filters=filters) - except BotoServerError as e: - module.fail_json(msg=e.message) - - for instance in all_instances: - instance_dict_array.append(get_instance_info(instance)) - - module.exit_json(instances=instance_dict_array) - - -def main(): - argument_spec = ec2_argument_spec() - argument_spec.update( - dict( - filters=dict(default=None, type='dict') - ) - ) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) - - if not HAS_BOTO: - module.fail_json(msg='boto required for this module') - - region, ec2_url, aws_connect_params = get_aws_connection_info(module) - - if region: - try: - connection = connect_to_aws(boto.ec2, region, **aws_connect_params) - except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: - module.fail_json(msg=str(e)) - else: - module.fail_json(msg="region must be specified") - - list_ec2_instances(connection, module) +from ansible.module_utils.common.removed import removed_module if __name__ == '__main__': - main() + removed_module(removed_in='2.8') diff --git a/lib/ansible/modules/cloud/azure/_azure.py b/lib/ansible/modules/cloud/azure/_azure.py index 760f4ef64e..afefd8eb97 100644 --- a/lib/ansible/modules/cloud/azure/_azure.py +++ b/lib/ansible/modules/cloud/azure/_azure.py @@ -8,590 +8,12 @@ __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], + 'status': ['removed'], 'supported_by': 'community'} -DOCUMENTATION = ''' ---- -module: azure -short_description: create or terminate a virtual machine in azure -description: - - Creates or terminates azure instances. When created optionally waits for it to be 'running'. -version_added: "1.7" -deprecated: - removed_in: "2.8" - why: Replaced with various dedicated Azure modules. - alternative: M(azure_rm_virtualmachine) -options: - name: - description: - - name of the virtual machine and associated cloud service. - required: true - location: - description: - - the azure location to use (e.g. 'East US') - required: true - subscription_id: - description: - - azure subscription id. Overrides the AZURE_SUBSCRIPTION_ID environment variable. - management_cert_path: - description: - - path to an azure management certificate associated with the subscription id. Overrides the AZURE_CERT_PATH environment variable. - storage_account: - description: - - the azure storage account in which to store the data disks. - required: true - image: - description: - - system image for creating the virtual machine - (e.g., b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu_DAILY_BUILD-precise-12_04_3-LTS-amd64-server-20131205-en-us-30GB) - required: true - role_size: - description: - - azure role size for the new virtual machine (e.g., Small, ExtraLarge, A6). You have to pay attention to the fact that instances of - type G and DS are not available in all regions (locations). Make sure if you selected the size and type of instance available in your chosen location. - default: Small - endpoints: - description: - - a comma-separated list of TCP ports to expose on the virtual machine (e.g., "22,80") - default: 22 - user: - description: - - the unix username for the new virtual machine. - password: - description: - - the unix password for the new virtual machine. - ssh_cert_path: - description: - - path to an X509 certificate containing the public ssh key to install in the virtual machine. - See http://www.windowsazure.com/en-us/manage/linux/tutorials/intro-to-linux/ for more details. - - if this option is specified, password-based ssh authentication will be disabled. - virtual_network_name: - description: - - Name of virtual network. - hostname: - description: - - hostname to write /etc/hostname. Defaults to .cloudapp.net. - wait: - description: - - wait for the instance to be in state 'running' before returning - type: bool - default: 'no' - wait_timeout: - description: - - how long before wait gives up, in seconds - default: 600 - wait_timeout_redirects: - description: - - how long before wait gives up for redirects, in seconds - default: 300 - state: - description: - - create or terminate instances - choices: [ absent, present ] - default: 'present' - auto_updates: - description: - - Enable Auto Updates on Windows Machines - version_added: "2.0" - type: bool - default: 'no' - enable_winrm: - description: - - Enable winrm on Windows Machines - version_added: "2.0" - type: bool - default: 'yes' - os_type: - description: - - The type of the os that is gettings provisioned - version_added: "2.0" - default: "linux" - choices: [ "windows", "linux" ] - -requirements: - - "python >= 2.6" - - "azure >= 0.7.1" -author: "John Whitbeck (@jwhitbeck)" -''' - -EXAMPLES = ''' -# Note: None of these examples set subscription_id or management_cert_path -# It is assumed that their matching environment variables are set. - -- name: Provision virtual machine example - azure: - name: my-virtual-machine - role_size: Small - image: b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu_DAILY_BUILD-precise-12_04_3-LTS-amd64-server-20131205-en-us-30GB - location: East US - user: ubuntu - ssh_cert_path: /path/to/azure_x509_cert.pem - storage_account: my-storage-account - wait: True - state: present - delegate_to: localhost - -- name: Terminate virtual machine example - azure: - name: my-virtual-machine - state: absent - delegate_to: localhost - -- name: Create windows machine - azure: - name: ben-Winows-23 - hostname: win123 - os_type: windows - enable_winrm: True - subscription_id: '{{ azure_sub_id }}' - management_cert_path: '{{ azure_cert_path }}' - role_size: Small - image: bd507d3a70934695bc2128e3e5a255ba__RightImage-Windows-2012-x64-v13.5 - location: East Asia - password: xxx - storage_account: benooytes - user: admin - wait: True - state: present - virtual_network_name: '{{ vnet_name }}' - delegate_to: localhost -''' - -import base64 -import datetime -import os -import signal -import time -from ansible.module_utils.six.moves.urllib.parse import urlparse -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.facts.timeout import TimeoutError - -AZURE_LOCATIONS = ['South Central US', - 'Central US', - 'East US 2', - 'East US', - 'West US', - 'North Central US', - 'North Europe', - 'West Europe', - 'East Asia', - 'Southeast Asia', - 'Japan West', - 'Japan East', - 'Brazil South'] - -AZURE_ROLE_SIZES = ['ExtraSmall', - 'Small', - 'Medium', - 'Large', - 'ExtraLarge', - 'A5', - 'A6', - 'A7', - 'A8', - 'A9', - 'Basic_A0', - 'Basic_A1', - 'Basic_A2', - 'Basic_A3', - 'Basic_A4', - 'Standard_D1', - 'Standard_D2', - 'Standard_D3', - 'Standard_D4', - 'Standard_D11', - 'Standard_D12', - 'Standard_D13', - 'Standard_D14', - 'Standard_D1_v2', - 'Standard_D2_v2', - 'Standard_D3_v2', - 'Standard_D4_v2', - 'Standard_D5_v2', - 'Standard_D11_v2', - 'Standard_D12_v2', - 'Standard_D13_v2', - 'Standard_D14_v2', - 'Standard_DS1', - 'Standard_DS2', - 'Standard_DS3', - 'Standard_DS4', - 'Standard_DS11', - 'Standard_DS12', - 'Standard_DS13', - 'Standard_DS14', - 'Standard_G1', - 'Standard_G2', - 'Standard_G3', - 'Standard_G4', - 'Standard_G5'] - -from distutils.version import LooseVersion - -try: - import azure as windows_azure - - if hasattr(windows_azure, '__version__') and LooseVersion(windows_azure.__version__) <= "0.11.1": - from azure import WindowsAzureError as AzureException - from azure import WindowsAzureMissingResourceError as AzureMissingException - else: - from azure.common import AzureException as AzureException - from azure.common import AzureMissingResourceHttpError as AzureMissingException - - from azure.servicemanagement import (ServiceManagementService, OSVirtualHardDisk, SSH, PublicKeys, - PublicKey, LinuxConfigurationSet, ConfigurationSetInputEndpoints, - ConfigurationSetInputEndpoint, Listener, WindowsConfigurationSet) - - HAS_AZURE = True -except ImportError: - HAS_AZURE = False - -from types import MethodType -import json - - -def _wait_for_completion(azure, promise, wait_timeout, msg): - if not promise: - return - wait_timeout = time.time() + wait_timeout - while wait_timeout > time.time(): - operation_result = azure.get_operation_status(promise.request_id) - time.sleep(5) - if operation_result.status == "Succeeded": - return - - raise AzureException('Timed out waiting for async operation ' + msg + ' "' + str(promise.request_id) + '" to complete.') - - -def _delete_disks_when_detached(azure, wait_timeout, disk_names): - def _handle_timeout(signum, frame): - raise TimeoutError("Timeout reached while waiting for disks to become detached.") - - signal.signal(signal.SIGALRM, _handle_timeout) - signal.alarm(wait_timeout) - try: - while len(disk_names) > 0: - for disk_name in disk_names: - disk = azure.get_disk(disk_name) - if disk.attached_to is None: - azure.delete_disk(disk.name, True) - disk_names.remove(disk_name) - except AzureException as e: - raise AzureException("failed to get or delete disk %s, error was: %s" % (disk_name, str(e))) - finally: - signal.alarm(0) - - -def get_ssh_certificate_tokens(module, ssh_cert_path): - """ - Returns the sha1 fingerprint and a base64-encoded PKCS12 version of the certificate. - """ - # This returns a string such as SHA1 Fingerprint=88:60:0B:13:A9:14:47:DA:4E:19:10:7D:34:92:2B:DF:A1:7D:CA:FF - rc, stdout, stderr = module.run_command(['openssl', 'x509', '-in', ssh_cert_path, '-fingerprint', '-noout']) - if rc != 0: - module.fail_json(msg="failed to generate the key fingerprint, error was: %s" % stderr) - fingerprint = stdout.strip()[17:].replace(':', '') - - rc, stdout, stderr = module.run_command(['openssl', 'pkcs12', '-export', '-in', ssh_cert_path, '-nokeys', '-password', 'pass:']) - if rc != 0: - module.fail_json(msg="failed to generate the pkcs12 signature from the certificate, error was: %s" % stderr) - pkcs12_base64 = base64.b64encode(stdout.strip()) - - return (fingerprint, pkcs12_base64) - - -def create_virtual_machine(module, azure): - """ - Create new virtual machine - - module : AnsibleModule object - azure: authenticated azure ServiceManagementService object - - Returns: - True if a new virtual machine and/or cloud service was created, false otherwise - """ - name = module.params.get('name') - os_type = module.params.get('os_type') - hostname = module.params.get('hostname') or name + ".cloudapp.net" - endpoints = module.params.get('endpoints').split(',') - ssh_cert_path = module.params.get('ssh_cert_path') - user = module.params.get('user') - password = module.params.get('password') - location = module.params.get('location') - role_size = module.params.get('role_size') - storage_account = module.params.get('storage_account') - image = module.params.get('image') - virtual_network_name = module.params.get('virtual_network_name') - wait = module.params.get('wait') - wait_timeout = int(module.params.get('wait_timeout')) - - changed = False - - # Check if a deployment with the same name already exists - cloud_service_name_available = azure.check_hosted_service_name_availability(name) - if cloud_service_name_available.result: - # cloud service does not exist; create it - try: - result = azure.create_hosted_service(service_name=name, label=name, location=location) - _wait_for_completion(azure, result, wait_timeout, "create_hosted_service") - changed = True - except AzureException as e: - module.fail_json(msg="failed to create the new service, error was: %s" % str(e)) - - try: - # check to see if a vm with this name exists; if so, do nothing - azure.get_role(name, name, name) - except AzureMissingException: - # vm does not exist; create it - - if os_type == 'linux': - # Create linux configuration - disable_ssh_password_authentication = not password - vm_config = LinuxConfigurationSet(hostname, user, password, disable_ssh_password_authentication) - else: - # Create Windows Config - vm_config = WindowsConfigurationSet(hostname, password, None, module.params.get('auto_updates'), None, user) - vm_config.domain_join = None - if module.params.get('enable_winrm'): - listener = Listener('Http') - vm_config.win_rm.listeners.listeners.append(listener) - else: - vm_config.win_rm = None - - # Add ssh certificates if specified - if ssh_cert_path: - fingerprint, pkcs12_base64 = get_ssh_certificate_tokens(module, ssh_cert_path) - # Add certificate to cloud service - result = azure.add_service_certificate(name, pkcs12_base64, 'pfx', '') - _wait_for_completion(azure, result, wait_timeout, "add_service_certificate") - - # Create ssh config - ssh_config = SSH() - ssh_config.public_keys = PublicKeys() - authorized_keys_path = u'/home/%s/.ssh/authorized_keys' % user - ssh_config.public_keys.public_keys.append(PublicKey(path=authorized_keys_path, fingerprint=fingerprint)) - # Append ssh config to linux machine config - vm_config.ssh = ssh_config - - # Create network configuration - network_config = ConfigurationSetInputEndpoints() - network_config.configuration_set_type = 'NetworkConfiguration' - network_config.subnet_names = [] - network_config.public_ips = None - for port in endpoints: - network_config.input_endpoints.append(ConfigurationSetInputEndpoint(name='TCP-%s' % port, - protocol='TCP', - port=port, - local_port=port)) - - # First determine where to store disk - today = datetime.date.today().strftime('%Y-%m-%d') - disk_prefix = u'%s-%s' % (name, name) - media_link = u'http://%s.blob.core.windows.net/vhds/%s-%s.vhd' % (storage_account, disk_prefix, today) - # Create system hard disk - os_hd = OSVirtualHardDisk(image, media_link) - - # Spin up virtual machine - try: - result = azure.create_virtual_machine_deployment(service_name=name, - deployment_name=name, - deployment_slot='production', - label=name, - role_name=name, - system_config=vm_config, - network_config=network_config, - os_virtual_hard_disk=os_hd, - role_size=role_size, - role_type='PersistentVMRole', - virtual_network_name=virtual_network_name) - _wait_for_completion(azure, result, wait_timeout, "create_virtual_machine_deployment") - changed = True - except AzureException as e: - module.fail_json(msg="failed to create the new virtual machine, error was: %s" % str(e)) - - try: - deployment = azure.get_deployment_by_name(service_name=name, deployment_name=name) - return (changed, urlparse(deployment.url).hostname, deployment) - except AzureException as e: - module.fail_json(msg="failed to lookup the deployment information for %s, error was: %s" % (name, str(e))) - - -def terminate_virtual_machine(module, azure): - """ - Terminates a virtual machine - - module : AnsibleModule object - azure: authenticated azure ServiceManagementService object - - Returns: - True if a new virtual machine was deleted, false otherwise - """ - - # Whether to wait for termination to complete before returning - wait = module.params.get('wait') - wait_timeout = int(module.params.get('wait_timeout')) - name = module.params.get('name') - delete_empty_services = module.params.get('delete_empty_services') - - changed = False - - deployment = None - public_dns_name = None - disk_names = [] - try: - deployment = azure.get_deployment_by_name(service_name=name, deployment_name=name) - except AzureMissingException as e: - pass # no such deployment or service - except AzureException as e: - module.fail_json(msg="failed to find the deployment, error was: %s" % str(e)) - - # Delete deployment - if deployment: - changed = True - try: - # gather disk info - results = [] - for role in deployment.role_list: - role_props = azure.get_role(name, deployment.name, role.role_name) - if role_props.os_virtual_hard_disk.disk_name not in disk_names: - disk_names.append(role_props.os_virtual_hard_disk.disk_name) - except AzureException as e: - module.fail_json(msg="failed to get the role %s, error was: %s" % (role.role_name, str(e))) - - try: - result = azure.delete_deployment(name, deployment.name) - _wait_for_completion(azure, result, wait_timeout, "delete_deployment") - except AzureException as e: - module.fail_json(msg="failed to delete the deployment %s, error was: %s" % (deployment.name, str(e))) - - # It's unclear when disks associated with terminated deployment get detached. - # Thus, until the wait_timeout is reached, we continue to delete disks as they - # become detached by polling the list of remaining disks and examining the state. - try: - _delete_disks_when_detached(azure, wait_timeout, disk_names) - except (AzureException, TimeoutError) as e: - module.fail_json(msg=str(e)) - - try: - # Now that the vm is deleted, remove the cloud service - result = azure.delete_hosted_service(service_name=name) - _wait_for_completion(azure, result, wait_timeout, "delete_hosted_service") - except AzureException as e: - module.fail_json(msg="failed to delete the service %s, error was: %s" % (name, str(e))) - public_dns_name = urlparse(deployment.url).hostname - - return changed, public_dns_name, deployment - - -def get_azure_creds(module): - # Check module args for credentials, then check environment vars - subscription_id = module.params.get('subscription_id') - if not subscription_id: - subscription_id = os.environ.get('AZURE_SUBSCRIPTION_ID', None) - if not subscription_id: - module.fail_json(msg="No subscription_id provided. Please set 'AZURE_SUBSCRIPTION_ID' or use the 'subscription_id' parameter") - - management_cert_path = module.params.get('management_cert_path') - if not management_cert_path: - management_cert_path = os.environ.get('AZURE_CERT_PATH', None) - if not management_cert_path: - module.fail_json(msg="No management_cert_path provided. Please set 'AZURE_CERT_PATH' or use the 'management_cert_path' parameter") - - return subscription_id, management_cert_path - - -def main(): - module = AnsibleModule( - argument_spec=dict( - ssh_cert_path=dict(), - name=dict(), - hostname=dict(), - os_type=dict(default='linux', choices=['linux', 'windows']), - location=dict(choices=AZURE_LOCATIONS), - role_size=dict(choices=AZURE_ROLE_SIZES), - subscription_id=dict(no_log=True), - storage_account=dict(), - management_cert_path=dict(), - endpoints=dict(default='22'), - user=dict(), - password=dict(no_log=True), - image=dict(), - virtual_network_name=dict(default=None), - state=dict(default='present'), - wait=dict(type='bool', default=False), - wait_timeout=dict(default=600), - wait_timeout_redirects=dict(default=300), - auto_updates=dict(type='bool', default=False), - enable_winrm=dict(type='bool', default=True), - ) - ) - if not HAS_AZURE: - module.fail_json(msg='azure python module required for this module') - # create azure ServiceManagementService object - subscription_id, management_cert_path = get_azure_creds(module) - - wait_timeout_redirects = int(module.params.get('wait_timeout_redirects')) - - if hasattr(windows_azure, '__version__') and LooseVersion(windows_azure.__version__) <= "0.8.0": - # wrapper for handling redirects which the sdk <= 0.8.0 is not following - azure = Wrapper(ServiceManagementService(subscription_id, management_cert_path), wait_timeout_redirects) - else: - azure = ServiceManagementService(subscription_id, management_cert_path) - - cloud_service_raw = None - if module.params.get('state') == 'absent': - (changed, public_dns_name, deployment) = terminate_virtual_machine(module, azure) - - elif module.params.get('state') == 'present': - # Changed is always set to true when provisioning new instances - if not module.params.get('name'): - module.fail_json(msg='name parameter is required for new instance') - if not module.params.get('image'): - module.fail_json(msg='image parameter is required for new instance') - if not module.params.get('user'): - module.fail_json(msg='user parameter is required for new instance') - if not module.params.get('location'): - module.fail_json(msg='location parameter is required for new instance') - if not module.params.get('storage_account'): - module.fail_json(msg='storage_account parameter is required for new instance') - if not (module.params.get('password') or module.params.get('ssh_cert_path')): - module.fail_json(msg='password or ssh_cert_path parameter is required for new instance') - (changed, public_dns_name, deployment) = create_virtual_machine(module, azure) - - module.exit_json(changed=changed, public_dns_name=public_dns_name, deployment=json.loads(json.dumps(deployment, default=lambda o: o.__dict__))) - - -class Wrapper(object): - def __init__(self, obj, wait_timeout): - self.other = obj - self.wait_timeout = wait_timeout - - def __getattr__(self, name): - if hasattr(self.other, name): - func = getattr(self.other, name) - return lambda *args, **kwargs: self._wrap(func, args, kwargs) - raise AttributeError(name) - - def _wrap(self, func, args, kwargs): - if isinstance(func, MethodType): - result = self._handle_temporary_redirects(lambda: func(*args, **kwargs)) - else: - result = self._handle_temporary_redirects(lambda: func(self.other, *args, **kwargs)) - return result - - def _handle_temporary_redirects(self, f): - wait_timeout = time.time() + self.wait_timeout - while wait_timeout > time.time(): - try: - return f() - except AzureException as e: - if not str(e).lower().find("temporary redirect") == -1: - time.sleep(5) - else: - raise e +from ansible.module_utils.common.removed import removed_module if __name__ == '__main__': - main() + removed_module(removed_in='2.8') diff --git a/lib/ansible/modules/cloud/cloudstack/_cs_nic.py b/lib/ansible/modules/cloud/cloudstack/_cs_nic.py index 9bc433de46..b446c3618d 100644 --- a/lib/ansible/modules/cloud/cloudstack/_cs_nic.py +++ b/lib/ansible/modules/cloud/cloudstack/_cs_nic.py @@ -8,274 +8,12 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], + 'status': ['removed'], 'supported_by': 'community'} -DOCUMENTATION = ''' ---- -module: cs_nic -short_description: Manages NICs and secondary IPs of an instance on Apache CloudStack based clouds -description: - - Add and remove secondary IPs to and from a NIC. -version_added: "2.3" -author: -- René Moser (@resmo) -deprecated: - removed_in: "2.8" - why: New module created. - alternative: Use M(cs_instance_nic_secondaryip) instead. -options: - vm: - description: - - Name of instance. - required: true - aliases: [ name ] - network: - description: - - Name of the network. - - Required to find the NIC if instance has multiple networks assigned. - vm_guest_ip: - description: - - Secondary IP address to be added to the instance nic. - - If not set, the API always returns a new IP address and idempotency is not given. - aliases: [ secondary_ip ] - vpc: - description: - - Name of the VPC the C(vm) is related to. - domain: - description: - - Domain the instance is related to. - account: - description: - - Account the instance is related to. - project: - description: - - Name of the project the instance is deployed in. - zone: - description: - - Name of the zone in which the instance is deployed in. - - If not set, default zone is used. - state: - description: - - State of the ipaddress. - choices: [ absent, present ] - default: present - poll_async: - description: - - Poll async jobs until job has finished. - type: bool - default: 'yes' -extends_documentation_fragment: cloudstack -''' -EXAMPLES = ''' -- name: Assign a specific IP to the default NIC of the VM - local_action: - module: cs_nic - vm: customer_xy - vm_guest_ip: 10.10.10.10 - -# Note: If vm_guest_ip is not set, you will get a new IP address on every run. -- name: Assign an IP to the default NIC of the VM - local_action: - module: cs_nic - vm: customer_xy - -- name: Remove a specific IP from the default NIC - local_action: - module: cs_nic - vm: customer_xy - vm_guest_ip: 10.10.10.10 - state: absent -''' - -RETURN = ''' ---- -id: - description: UUID of the nic. - returned: success - type: string - sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 -vm: - description: Name of the VM. - returned: success - type: string - sample: web-01 -ip_address: - description: Primary IP of the NIC. - returned: success - type: string - sample: 10.10.10.10 -netmask: - description: Netmask of the NIC. - returned: success - type: string - sample: 255.255.255.0 -mac_address: - description: MAC address of the NIC. - returned: success - type: string - sample: 02:00:33:31:00:e4 -vm_guest_ip: - description: Secondary IP of the NIC. - returned: success - type: string - sample: 10.10.10.10 -network: - description: Name of the network if not default. - returned: success - type: string - sample: sync network -domain: - description: Domain the VM is related to. - returned: success - type: string - sample: example domain -account: - description: Account the VM is related to. - returned: success - type: string - sample: example account -project: - description: Name of project the VM is related to. - returned: success - type: string - sample: Production -''' -try: - from cs import CloudStackException -except ImportError: - pass # Handled in AnsibleCloudStack.__init__ - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together - - -class AnsibleCloudStackNic(AnsibleCloudStack): - - def __init__(self, module): - super(AnsibleCloudStackNic, self).__init__(module) - self.vm_guest_ip = self.module.params.get('vm_guest_ip') - self.nic = None - self.returns = { - 'ipaddress': 'ip_address', - 'macaddress': 'mac_address', - 'netmask': 'netmask', - } - - def get_nic(self): - if self.nic: - return self.nic - args = { - 'virtualmachineid': self.get_vm(key='id'), - 'networkid': self.get_network(key='id'), - } - nics = self.cs.listNics(**args) - if nics: - self.nic = nics['nic'][0] - return self.nic - self.module.fail_json(msg="NIC for VM %s in network %s not found" % (self.get_vm(key='name'), self.get_network(key='name'))) - - def get_secondary_ip(self): - nic = self.get_nic() - if self.vm_guest_ip: - secondary_ips = nic.get('secondaryip') or [] - for secondary_ip in secondary_ips: - if secondary_ip['ipaddress'] == self.vm_guest_ip: - return secondary_ip - return None - - def present_nic(self): - nic = self.get_nic() - if not self.get_secondary_ip(): - self.result['changed'] = True - args = { - 'nicid': nic['id'], - 'ipaddress': self.vm_guest_ip, - } - - if not self.module.check_mode: - res = self.cs.addIpToNic(**args) - - if 'errortext' in res: - self.module.fail_json(msg="Failed: '%s'" % res['errortext']) - - poll_async = self.module.params.get('poll_async') - if poll_async: - nic = self.poll_job(res, 'nicsecondaryip') - # Save result for RETURNS - self.vm_guest_ip = nic['ipaddress'] - return nic - - def absent_nic(self): - nic = self.get_nic() - secondary_ip = self.get_secondary_ip() - if secondary_ip: - self.result['changed'] = True - if not self.module.check_mode: - res = self.cs.removeIpFromNic(id=secondary_ip['id']) - if 'errortext' in res: - self.module.fail_json(msg="Failed: '%s'" % nic['errortext']) - - poll_async = self.module.params.get('poll_async') - if poll_async: - self.poll_job(res, 'nicsecondaryip') - return nic - - def get_result(self, nic): - super(AnsibleCloudStackNic, self).get_result(nic) - if nic and not self.module.params.get('network'): - self.module.params['network'] = nic.get('networkid') - self.result['network'] = self.get_network(key='name') - self.result['vm'] = self.get_vm(key='name') - self.result['vm_guest_ip'] = self.vm_guest_ip - self.result['domain'] = self.get_domain(key='path') - self.result['account'] = self.get_account(key='name') - self.result['project'] = self.get_project(key='name') - return self.result - - -def main(): - argument_spec = cs_argument_spec() - argument_spec.update(dict( - vm=dict(type='str', required=True, aliases=['name']), - vm_guest_ip=dict(type='str', aliases=['secondary_ip']), - network=dict(type='str',), - vpc=dict(type='str'), - state=dict(type='str', default='present', choices=['absent', 'present']), - domain=dict(type='str'), - account=dict(type='str'), - project=dict(type='str'), - zone=dict(type='str'), - poll_async=dict(type='bool', default=True), - )) - - module = AnsibleModule( - argument_spec=argument_spec, - required_together=cs_required_together(), - supports_check_mode=True, - required_if=([ - ('state', 'absent', ['vm_guest_ip']) - ]) - ) - - try: - acs_nic = AnsibleCloudStackNic(module) - - state = module.params.get('state') - - if state == 'absent': - nic = acs_nic.absent_nic() - else: - nic = acs_nic.present_nic() - - result = acs_nic.get_result(nic) - - except CloudStackException as e: - module.fail_json(msg='CloudStackException: %s' % str(e)) - - module.exit_json(**result) +from ansible.module_utils.common.removed import removed_module if __name__ == '__main__': - main() + removed_module(removed_in='2.8') diff --git a/lib/ansible/modules/network/citrix/_netscaler.py b/lib/ansible/modules/network/citrix/_netscaler.py index e5347ce51a..d884d3c3ec 100644 --- a/lib/ansible/modules/network/citrix/_netscaler.py +++ b/lib/ansible/modules/network/citrix/_netscaler.py @@ -8,180 +8,12 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], + 'status': ['removed'], 'supported_by': 'community'} -DOCUMENTATION = ''' ---- -module: netscaler -version_added: "1.1" -short_description: Manages Citrix NetScaler entities -description: - - Manages Citrix NetScaler server and service entities. -deprecated: - removed_in: "2.8" - why: Replaced with Citrix maintained version. - alternative: Use M(netscaler_service) and M(netscaler_server) instead. -options: - nsc_host: - description: - - Hostname or ip of your netscaler. - required: true - nsc_protocol: - description: - - Protocol used to access netscaler. - default: https - user: - description: - - Username. - required: true - password: - description: - - Password. - required: true - action: - description: - - The action you want to perform on the entity. - choices: [ disable, enable ] - default: disable - name: - description: - - Name of the entity. - required: true - default: hostname - type: - description: - - Type of the entity. - choices: [ server, service ] - default: server - validate_certs: - description: - - If C(no), SSL certificates for the target url will not be validated. - - This should only be used on personally controlled sites using self-signed certificates. - type: bool - default: 'yes' -author: -- Nandor Sivok (@dominis) -''' -EXAMPLES = ''' -- name: Disable the server - netscaler: - nsc_host: nsc.example.com - user: apiuser - password: apipass - -- name: Enable the server - netscaler: - nsc_host: nsc.example.com - user: apiuser - password: apipass - action: enable - -- name: Disable the service local:8080 - netscaler: - nsc_host: nsc.example.com - user: apiuser - password: apipass - name: local:8080 - type: service - action: disable -''' - -import json -import socket -import traceback -import base64 - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six.moves.urllib.parse import urlencode -from ansible.module_utils._text import to_native, to_bytes -from ansible.module_utils.urls import fetch_url - - -class netscaler(object): - - _nitro_base_url = '/nitro/v1/' - - def __init__(self, module): - self.module = module - - def http_request(self, api_endpoint, data_json=None): - data_josn = {} if data_json is None else data_json - - request_url = self._nsc_protocol + '://' + self._nsc_host + self._nitro_base_url + api_endpoint - - data_json = urlencode(data_json) - if not len(data_json): - data_json = None - - auth = base64.b64encode(to_bytes('%s:%s' % (self._nsc_user, self._nsc_pass)).replace('\n', '').strip()) - headers = { - 'Authorization': 'Basic %s' % auth, - 'Content-Type': 'application/x-www-form-urlencoded', - } - - response, info = fetch_url(self.module, request_url, data=data_json, headers=headers) - - return json.load(response) - - def prepare_request(self, action): - resp = self.http_request( - 'config', - { - "object": - { - "params": {"action": action}, - self._type: {"name": self._name} - } - } - ) - - return resp - - -def core(module): - n = netscaler(module) - n._nsc_host = module.params.get('nsc_host') - n._nsc_user = module.params.get('user') - n._nsc_pass = module.params.get('password') - n._nsc_protocol = module.params.get('nsc_protocol') - n._name = module.params.get('name') - n._type = module.params.get('type') - action = module.params.get('action') - - r = n.prepare_request(action) - - return r['errorcode'], r - - -def main(): - - module = AnsibleModule( - argument_spec=dict( - nsc_host=dict(type='str', required=True), - nsc_protocol=dict(type='str', default='https'), - user=dict(type='str', required=True), - password=dict(type='str', required=True, no_log=True), - action=dict(type='str', default='enable', choices=['disable', 'enable']), - name=dict(type='str', default=socket.gethostname()), - type=dict(type='str', default='server', choices=['server', 'service']), - validate_certs=dict(type='bool', default=True), - ), - ) - - rc = 0 - try: - rc, result = core(module) - except Exception as e: - module.fail_json(msg=to_native(e), exception=traceback.format_exc()) - - if rc != 0: - module.fail_json(rc=rc, msg=result) - else: - result['changed'] = True - module.exit_json(**result) +from ansible.module_utils.common.removed import removed_module if __name__ == '__main__': - main() + removed_module(removed_in='2.8') diff --git a/lib/ansible/modules/windows/_win_msi.py b/lib/ansible/modules/windows/_win_msi.py index 1d25940524..bbf1fb53a7 100644 --- a/lib/ansible/modules/windows/_win_msi.py +++ b/lib/ansible/modules/windows/_win_msi.py @@ -8,80 +8,12 @@ # file of the same name ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['deprecated'], + 'status': ['removed'], 'supported_by': 'community'} -DOCUMENTATION = r''' ---- -module: win_msi -version_added: '1.7' -deprecated: - removed_in: "2.8" - why: The win_msi module has a number of issues, the M(win_package) module is easier to maintain and use. - alternative: Use M(win_package) instead. -short_description: Installs and uninstalls Windows MSI files -description: - - Installs or uninstalls a Windows MSI file that is already located on the - target server. -options: - path: - description: - - File system path to the MSI file to install. - required: yes - type: path - extra_args: - description: - - Additional arguments to pass to the msiexec.exe command. - state: - description: - - Whether the MSI file should be installed or uninstalled. - choices: [ absent, present ] - default: present - creates: - description: - - Path to a file created by installing the MSI to prevent from - attempting to reinstall the package on every run. - type: path - removes: - description: - - Path to a file removed by uninstalling the MSI to prevent from - attempting to re-uninstall the package on every run. - type: path - version_added: '2.4' - wait: - description: - - Specify whether to wait for install or uninstall to complete before continuing. - type: bool - default: 'no' - version_added: '2.1' -notes: -- This module is not idempotent and will report a change every time. - Use the C(creates) and C(removes) options to your advantage. -- Please look into M(win_package) instead, this package will be deprecated in the future. -author: -- Matt Martz (@sivel) -''' -EXAMPLES = r''' -- name: Install an MSI file - win_msi: - path: C:\7z920-x64.msi +from ansible.module_utils.common.removed import removed_module -- name: Install an MSI, and wait for it to complete before continuing - win_msi: - path: C:\7z920-x64.msi - wait: yes -- name: Uninstall an MSI file - win_msi: - path: C:\7z920-x64.msi - state: absent -''' - -RETURN = r''' -log: - description: The logged output from the installer - returned: always - type: string - sample: N/A -''' +if __name__ == '__main__': + removed_module(removed_in='2.8') diff --git a/test/sanity/ansible-doc/skip.txt b/test/sanity/ansible-doc/skip.txt index 1ad6285365..1074959e08 100644 --- a/test/sanity/ansible-doc/skip.txt +++ b/test/sanity/ansible-doc/skip.txt @@ -13,3 +13,8 @@ ec2_facts ec2_vpc nxos_mtu s3 +azure +cs_nic +ec2_remote_facts +netscaler +win_msi diff --git a/test/sanity/validate-modules/ignore.txt b/test/sanity/validate-modules/ignore.txt index 122b32b0f0..28dc616820 100644 --- a/test/sanity/validate-modules/ignore.txt +++ b/test/sanity/validate-modules/ignore.txt @@ -139,8 +139,6 @@ lib/ansible/modules/cloud/amazon/s3_website.py E324 lib/ansible/modules/cloud/amazon/sns_topic.py E325 lib/ansible/modules/cloud/amazon/sts_assume_role.py E317 lib/ansible/modules/cloud/atomic/atomic_container.py E317 -lib/ansible/modules/cloud/azure/_azure.py E324 -lib/ansible/modules/cloud/azure/_azure.py E326 lib/ansible/modules/cloud/centurylink/clc_alert_policy.py E317 lib/ansible/modules/cloud/centurylink/clc_firewall_policy.py E317 lib/ansible/modules/cloud/centurylink/clc_firewall_policy.py E324 @@ -647,7 +645,6 @@ lib/ansible/modules/network/aos/_aos_blueprint_param.py E325 lib/ansible/modules/network/asa/asa_config.py E324 lib/ansible/modules/network/bigswitch/bigmon_policy.py E324 lib/ansible/modules/network/bigswitch/bigmon_policy.py E326 -lib/ansible/modules/network/citrix/_netscaler.py E324 lib/ansible/modules/network/cloudengine/ce_aaa_server.py E322 lib/ansible/modules/network/cloudengine/ce_aaa_server_host.py E322 lib/ansible/modules/network/cloudengine/ce_acl.py E322