From 953756b65bd7036274663ce54edcaee67cebaa53 Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea Date: Fri, 25 Oct 2019 21:20:24 +0100 Subject: [PATCH] Moved ec2 driver to molecule-ec2 The driver has its own repository now: https://github.com/pycontribs/molecule-ec2 Fixes: #2313 Signed-off-by: Sorin Sbarnea --- Dockerfile | 4 +- docs/configuration.rst | 8 - docs/getting-started.rst | 4 +- .../molecule.yml | 5 - .../scenario/driver/ec2/cookiecutter.json | 5 - .../INSTALL.rst | 22 -- .../{{cookiecutter.scenario_name}}/create.yml | 202 ------------- .../destroy.yml | 49 ---- .../playbook.yml | 7 - .../prepare.yml | 11 - molecule/driver/ec2.py | 267 ------------------ molecule/test/functional/conftest.py | 10 - molecule/test/functional/test_command.py | 44 +-- .../resources/playbooks/delegated/create.yml | 1 - .../playbooks/delegated/create/ec2.yml | 53 ---- .../resources/playbooks/delegated/destroy.yml | 1 - .../playbooks/delegated/destroy/ec2.yml | 21 -- .../inventory/group_vars/all/all.yml | 7 - .../test/resources/playbooks/ec2/create.yml | 147 ---------- .../test/resources/playbooks/ec2/destroy.yml | 49 ---- .../driver/ec2/molecule/default/molecule.yml | 33 --- .../driver/ec2/molecule/default/playbook.yml | 7 - .../driver/ec2/molecule/default/prepare.yml | 9 - .../molecule/default/tests/test_default.py | 31 -- .../ec2/molecule/multi-node/molecule.yml | 44 --- .../ec2/molecule/multi-node/playbook.yml | 28 -- .../ec2/molecule/multi-node/prepare.yml | 9 - .../ec2/molecule/multi-node/tests/__init__.py | 0 .../molecule/multi-node/tests/test_default.py | 31 -- .../test/unit/command/init/test_scenario.py | 26 -- .../test/unit/cookiecutter/test_molecule.py | 2 +- molecule/test/unit/driver/test_ec2.py | 233 --------------- .../test/unit/model/v2/test_driver_section.py | 6 - molecule/test/unit/test_config.py | 5 - setup.cfg | 4 - tox.ini | 1 - 36 files changed, 6 insertions(+), 1380 deletions(-) delete mode 100644 molecule/cookiecutter/scenario/driver/ec2/cookiecutter.json delete mode 100644 molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst delete mode 100644 molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml delete mode 100644 molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml delete mode 100644 molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/playbook.yml delete mode 100644 molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/prepare.yml delete mode 100644 molecule/driver/ec2.py delete mode 100644 molecule/test/resources/playbooks/delegated/create/ec2.yml delete mode 100644 molecule/test/resources/playbooks/delegated/destroy/ec2.yml delete mode 100644 molecule/test/resources/playbooks/ec2/create.yml delete mode 100644 molecule/test/resources/playbooks/ec2/destroy.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/default/molecule.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/default/playbook.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/default/prepare.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/default/tests/test_default.py delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/multi-node/molecule.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/multi-node/playbook.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/multi-node/prepare.yml delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/__init__.py delete mode 100644 molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/test_default.py delete mode 100644 molecule/test/unit/driver/test_ec2.py diff --git a/Dockerfile b/Dockerfile index 563d99f98..77fd7083d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,7 +51,7 @@ ENV PACKAGES="\ " RUN apk add --update --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ ${PACKAGES} -ENV MOLECULE_EXTRAS="azure,docker,docs,ec2,openstack,vagrant,windows" +ENV MOLECULE_EXTRAS="azure,docker,docs,openstack,vagrant,windows" # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917006 RUN pip3 install -U wheel @@ -132,7 +132,7 @@ ENV GEM_PACKAGES="\ etc \ " -ENV MOLECULE_EXTRAS="azure,docker,docs,ec2,lxc,openstack,vagrant,windows" +ENV MOLECULE_EXTRAS="azure,docker,docs,lxc,openstack,vagrant,windows" RUN \ apk add --update --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ ${BUILD_DEPS} ${PACKAGES} \ diff --git a/docs/configuration.rst b/docs/configuration.rst index 6c486e0e4..aa4004e48 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -75,14 +75,6 @@ Docker .. autoclass:: molecule.driver.docker.Docker() :undoc-members: -.. _ec2-driver: - -EC2 -^^^ - -.. autoclass:: molecule.driver.ec2.EC2() - :undoc-members: - Openstack ^^^^^^^^^ diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 6a8cbb38b..ba37855c3 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -99,9 +99,7 @@ keys represent the high level components that Molecule provides. These are: dependencies. * The :ref:`driver` provider. Molecule uses `Docker`_ by default. Molecule uses - the driver to delegate the task of creating instances. There are many - providers such as :ref:`ec2-driver`. Under the hood, - it's all Ansible modules. + the driver to delegate the task of creating instances. * The :ref:`linters` provider. Molecule uses :std:doc:`Yamllint ` by default to ensure that best practices are encouraged diff --git a/molecule/cookiecutter/molecule/{{cookiecutter.role_name}}/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/molecule.yml b/molecule/cookiecutter/molecule/{{cookiecutter.role_name}}/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/molecule.yml index 8b10c876d..387a05adf 100644 --- a/molecule/cookiecutter/molecule/{{cookiecutter.role_name}}/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/molecule.yml +++ b/molecule/cookiecutter/molecule/{{cookiecutter.role_name}}/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/molecule.yml @@ -13,11 +13,6 @@ platforms: {%- if cookiecutter.driver_name == 'docker' %} - name: instance image: docker.io/centos:7 -{%- elif cookiecutter.driver_name == 'ec2' %} - - name: instance - image: ami-a5b196c0 - instance_type: t2.micro - vpc_subnet_id: subnet-6456fd1f {%- elif cookiecutter.driver_name == 'openstack' %} - name: instance image: Ubuntu-16.04 diff --git a/molecule/cookiecutter/scenario/driver/ec2/cookiecutter.json b/molecule/cookiecutter/scenario/driver/ec2/cookiecutter.json deleted file mode 100644 index 2ec6fb298..000000000 --- a/molecule/cookiecutter/scenario/driver/ec2/cookiecutter.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "molecule_directory": "molecule", - "role_name": "OVERRIDDEN", - "scenario_name": "OVERRIDDEN" -} diff --git a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst b/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst deleted file mode 100644 index f305f0b20..000000000 --- a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst +++ /dev/null @@ -1,22 +0,0 @@ -******* -Amazon Web Services driver installation guide -******* - -Requirements -============ - -* An AWS credentials rc file - -Install -======= - -Please refer to the `Virtual environment`_ documentation for installation best -practices. If not using a virtual environment, please consider passing the -widely recommended `'--user' flag`_ when invoking ``pip``. - -.. _Virtual environment: https://virtualenv.pypa.io/en/latest/ -.. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site - -.. code-block:: bash - - $ pip install 'molecule[ec2]' diff --git a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml b/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml deleted file mode 100644 index 4fba277d1..000000000 --- a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml +++ /dev/null @@ -1,202 +0,0 @@ ---- -{% raw -%} -- name: Create - hosts: localhost - connection: local - gather_facts: false - no_log: "{{ molecule_no_log }}" - vars: - ssh_user: ubuntu - ssh_port: 22 - - security_group_name: molecule - security_group_description: Security group for testing Molecule - security_group_rules: - - proto: tcp - from_port: "{{ ssh_port }}" - to_port: "{{ ssh_port }}" - cidr_ip: "{{ molecule_yml.driver.cidr_ip | - default('0.0.0.0/0') }}" - - proto: icmp - from_port: 8 - to_port: -1 - cidr_ip: "{{ molecule_yml.driver.cidr_ip | - default('0.0.0.0/0') }}" - security_group_rules_egress: - - proto: -1 - from_port: 0 - to_port: 0 - cidr_ip: '0.0.0.0/0' - - keypair_name: molecule_key - molecule_keypair_path: "{{ - lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key" - keypair_path: "{{ - molecule_yml.driver.keypair_path | default(molecule_keypair_path) }}" - tasks: - - name: Get current public IP - ipify_facts: - - - name: Set allowed ingress Security Group IP from current public IP - set_fact: - allowed_ip_cidr: "{{ ipify_public_ip }}/32" - when: (item.auto_public_ip is defined) and (item.auto_public_ip == True) - loop: "{{ molecule_yml.platforms }}" - - - name: Set allowed ingress Security Group IP - set_fact: - allowed_ip_cidr: "{{ item.allowed_ip_cidr }}" - when: item.allowed_ip_cidr is defined - loop: "{{ molecule_yml.platforms }}" - - - name: Set Security Group Rules for allowed ingress IP - set_fact: - security_group_rules: - - proto: tcp - from_port: "{{ ssh_port }}" - to_port: "{{ ssh_port }}" - cidr_ip: "{{ allowed_ip_cidr }}" - - proto: icmp - from_port: 8 - to_port: -1 - cidr_ip: "{{ allowed_ip_cidr }}" - when: allowed_ip_cidr is defined - - - name: Gather facts about VPC from vpc_subnet_id - ec2_vpc_subnet_facts: - subnet_ids: "{{ item.vpc_subnet_id }}" - loop: "{{ molecule_yml.platforms }}" - register: subnet_facts - - - name: Create security group - ec2_group: - name: "{{ security_group_name }}" - description: "{{ security_group_name }}" - rules: "{{ security_group_rules }}" - rules_egress: "{{ security_group_rules_egress }}" - vpc_id: "{{ subnet_facts.vpc_id }}" - - - name: Test for presence of local keypair - stat: - path: "{{ keypair_path }}" - register: keypair_local - - - name: Delete remote keypair - ec2_key: - name: "{{ keypair_name }}" - state: absent - when: not keypair_local.stat.exists - - - name: Test for presence of local keypair public key - stat: - path: "{{ keypair_path }}.pub" - register: keypair_public_local - when: keypair_local.stat.exists - - - name: Upload selected keypair - ec2_key: - name: "{{ keypair_name }}" - key_material: "{{ lookup('file', '{{ keypair_path }}.pub') }}" - register: keypair - when: - - keypair_local.stat.exists - - keypair_public_local.stat.exists - - - name: Create keypair - ec2_key: - name: "{{ keypair_name }}" - register: keypair - when: not keypair_public_local.stat.exists - - - name: Persist the keypair - copy: - dest: "{{ keypair_path }}" - content: "{{ keypair.key.private_key }}" - mode: 0600 - when: - - keypair.changed - - not keypair_public_local.stat.exists - - - name: Get the ec2 ami(s) by owner and name, if image not set - ec2_ami_facts: - owners: "{{ item.image_owner }}" - filters: - name: "{{ item.image_name }}" - loop: "{{ molecule_yml.platforms }}" - when: item.image is not defined - register: ami_facts - - - name: Create molecule instance(s) - ec2: - key_name: "{{ keypair_name }}" - image: "{{ item.image - if item.image is defined - else (ami_facts.results[index].images | sort(attribute='creation_date', reverse=True))[0].image_id }}" - instance_type: "{{ item.instance_type }}" - vpc_subnet_id: "{{ item.vpc_subnet_id }}" - group: "{{ security_group_name }}" - instance_tags: "{{ item.instance_tags | combine({'instance': item.name}) - if item.instance_tags is defined - else {'instance': item.name} }}" - wait: true - assign_public_ip: true - instance_profile_name: "{{ item.instance_profile_name | default(omit) }}" - exact_count: 1 - count_tag: - instance: "{{ item.name }}" - register: server - loop: "{{ molecule_yml.platforms }}" - loop_control: - index_var: index - async: 7200 - poll: 0 - - - name: Wait for instance(s) creation to complete - async_status: - jid: "{{ item.ansible_job_id }}" - register: ec2_jobs - until: ec2_jobs.finished - retries: 300 - with_items: "{{ server.results }}" - - # Mandatory configuration for Molecule to function. - - - name: Populate instance config dict - set_fact: - instance_conf_dict: { - 'instance': "{{ item.instances[0].tags.instance }}", - 'address': "{{ item.instances[0].private_ip - if molecule_yml.driver.cidr_ip is defined - else item.instances[0].public_ip }}", - 'user': "{{ ssh_user }}", - 'port': "{{ ssh_port }}", - 'identity_file': "{{ keypair_path }}", - 'instance_ids': "{{ item.instance_ids }}", } - with_items: "{{ ec2_jobs.results }}" - register: instance_config_dict - when: server.changed | bool - - - name: Convert instance config dict to a list - set_fact: - instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}" - when: server.changed | bool - - - name: Dump instance config - copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" - dest: "{{ molecule_instance_config }}" - when: server.changed | bool - - - name: Wait for SSH - wait_for: - port: "{{ ssh_port }}" - host: "{{ item.address }}" - search_regex: SSH - delay: 10 - timeout: 320 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" - - - name: Wait for boot process to finish - pause: - minutes: 2 -{%- endraw %} diff --git a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml b/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml deleted file mode 100644 index 8840746a4..000000000 --- a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -{% raw -%} -- name: Destroy - hosts: localhost - connection: local - gather_facts: false - no_log: "{{ molecule_no_log }}" - tasks: - - block: - - name: Populate instance config - set_fact: - instance_conf: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" - skip_instances: false - rescue: - - name: Populate instance config when file missing - set_fact: - instance_conf: {} - skip_instances: true - - - name: Destroy molecule instance(s) - ec2: - state: absent - instance_ids: "{{ item.instance_ids }}" - register: server - with_items: "{{ instance_conf }}" - when: not skip_instances - async: 7200 - poll: 0 - - - name: Wait for instance(s) deletion to complete - async_status: - jid: "{{ item.ansible_job_id }}" - register: ec2_jobs - until: ec2_jobs.finished - retries: 300 - with_items: "{{ server.results }}" - - # Mandatory configuration for Molecule to function. - - - name: Populate instance config - set_fact: - instance_conf: {} - - - name: Dump instance config - copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" - dest: "{{ molecule_instance_config }}" - when: server.changed | bool -{%- endraw %} diff --git a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/playbook.yml b/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/playbook.yml deleted file mode 100644 index fecf1c843..000000000 --- a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/playbook.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Converge - hosts: all - tasks: - - name: "Include {{ cookiecutter.role_name }}" - include_role: - name: "{{ cookiecutter.role_name }}" diff --git a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/prepare.yml b/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/prepare.yml deleted file mode 100644 index babe22509..000000000 --- a/molecule/cookiecutter/scenario/driver/ec2/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/prepare.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -{% raw -%} -- name: Prepare - hosts: all - gather_facts: false - tasks: - - name: Install python for Ansible - raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal python-zipstream) - become: true - changed_when: false -{%- endraw %} diff --git a/molecule/driver/ec2.py b/molecule/driver/ec2.py deleted file mode 100644 index 466aa0416..000000000 --- a/molecule/driver/ec2.py +++ /dev/null @@ -1,267 +0,0 @@ -# Copyright (c) 2015-2018 Cisco Systems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -from base64 import b64decode -import sys - -try: - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 - from cryptography.hazmat.primitives.serialization import load_pem_private_key - - HAS_CRYPTOGRAPHY = True -except ImportError: - HAS_CRYPTOGRAPHY = False - -try: - import boto3 - - HAS_BOTO3 = True -except ImportError: - HAS_BOTO3 = False - -from molecule import logger -from molecule.api import Driver - -from molecule import util - -LOG = logger.get_logger(__name__) - - -class EC2(Driver): - """ - The class responsible for managing `EC2`_ instances. `EC2`_ - is ``not`` the default driver used in Molecule. - - Molecule leverages Ansible's `ec2_module`_, by mapping variables from - ``molecule.yml`` into ``create.yml`` and ``destroy.yml``. - - .. _`ec2_module`: https://docs.ansible.com/ansible/latest/ec2_module.html - - .. code-block:: yaml - - driver: - name: ec2 - platforms: - - name: instance - - Some configuration examples: - - .. code-block:: yaml - - driver: - name: ec2 - platforms: - - name: instance - image: ami-0311dc90a352b25f4 - instance_type: t2.micro - vpc_subnet_id: subnet-1cb17175 - - If you don't know the AMI code or want to avoid hardcoding it: - - .. code-block:: yaml - - driver: - name: ec2 - platforms: - - name: instance - image_owner: 099720109477 - image_name: ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-20190320 - instance_type: t2.micro - vpc_subnet_id: subnet-1cb17175 - - If you want to attach an IAM role to the Molecule instance: - - .. code-block:: yaml - - driver: - name: ec2 - platforms: - - name: instance - image_owner: 099720109477 - image_name: ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-20190320 - instance_type: t2.micro - vpc_subnet_id: subnet-1cb17175 - instance_profile_name: example-iam-role - - Use wildcards for getting the latest image. For example, the latest Ubuntu bionic image: - - .. code-block:: yaml - - driver: - name: ec2 - platforms: - - name: instance - image_owner: 099720109477 - image_name: ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-* - instance_type: t2.micro - vpc_subnet_id: subnet-1cb17175 - - Windows EC2 instances can be used as well: - - .. code-block:: yaml - - driver: - name: ec2 - platforms: - - name: instance - image: ami-06a0d33fc8d328de0 - instance_type: t3a.medium - vpc_subnet_id: subnet-1cb17175 - connection_options: - sudo: False - ansible_user: Administrator - # Specify a password to override the automatic lookup - # or omit to retrieve automatically - # (requires boto3 & cryptography packages) - # ansible_password: hunter2 - ansible_port: 5986 - ansible_connection: winrm - ansible_winrm_scheme: https - ansible_winrm_server_cert_validation: ignore - - .. code-block:: bash - - $ pip install 'molecule[ec2]' - - Change the options passed to the ssh client. - - .. code-block:: yaml - - driver: - name: ec2 - ssh_connection_options: - - '-o ControlPath=~/.ansible/cp/%r@%h-%p' - - .. important:: - - Molecule does not merge lists, when overriding the developer must - provide all options. - - Provide a list of files Molecule will preserve, relative to the scenario - ephemeral directory, after any ``destroy`` subcommand execution. - - .. code-block:: yaml - - driver: - name: ec2 - safe_files: - - foo - - .. _`EC2`: https://aws.amazon.com/ec2/ - """ # noqa - - def __init__(self, config=None): - super(EC2, self).__init__(config) - self._name = "ec2" - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - self._name = value - - @property - def login_cmd_template(self): - connection_options = " ".join(self.ssh_connection_options) - - return ( - "ssh {{address}} " - "-l {{user}} " - "-p {{port}} " - "-i {{identity_file}} " - "{}" - ).format(connection_options) - - @property - def default_safe_files(self): - return [self.instance_config] - - @property - def default_ssh_connection_options(self): - return self._get_ssh_connection_options() - - def login_options(self, instance_name): - d = {"instance": instance_name} - - return util.merge_dicts(d, self._get_instance_config(instance_name)) - - def ansible_connection_options(self, instance_name): - try: - d = self._get_instance_config(instance_name) - plat_conn_opts = next( - ( - item - for item in self._config.config.get("platforms", []) - if item["name"] == instance_name - ), - {}, - ).get("connection_options", {}) - conn_opts = util.merge_dicts( - { - "ansible_user": d["user"], - "ansible_host": d["address"], - "ansible_port": d["port"], - "ansible_private_key_file": d["identity_file"], - "connection": "ssh", - "ansible_ssh_common_args": " ".join(self.ssh_connection_options), - }, - plat_conn_opts, - ) - if conn_opts.get("ansible_connection") == "winrm" and ( - not conn_opts.get("ansible_password") - ): - conn_opts["ansible_password"] = self._get_windows_instance_pass( - d["instance_ids"][0], d["identity_file"] - ) - return conn_opts - except StopIteration: - return {} - except IOError: - # Instance has yet to be provisioned , therefore the - # instance_config is not on disk. - return {} - - def _get_instance_config(self, instance_name): - instance_config_dict = util.safe_load_file(self._config.driver.instance_config) - - return next( - item for item in instance_config_dict if item["instance"] == instance_name - ) - - def _get_windows_instance_pass(self, instance_id, key_file): - if not HAS_BOTO3: - LOG.error("boto3 required when using Windows instances") - sys.exit(1) - if not HAS_CRYPTOGRAPHY: - LOG.error("cryptography package required when using Windows instances") - sys.exit(1) - ec2_client = boto3.client("ec2") - data_response = ec2_client.get_password_data(InstanceId=instance_id) - decoded = b64decode(data_response["PasswordData"]) - with open(key_file, "rb") as f: - key = load_pem_private_key(f.read(), None, default_backend()) - return key.decrypt(decoded, PKCS1v15()) - - def sanity_checks(self): - # FIXME(decentral1se): Implement sanity checks - pass diff --git a/molecule/test/functional/conftest.py b/molecule/test/functional/conftest.py index d6d5ce4c5..5c8b5722f 100644 --- a/molecule/test/functional/conftest.py +++ b/molecule/test/functional/conftest.py @@ -74,7 +74,6 @@ def skip_test(request, driver_name): ) support_checks_map = { 'docker': supports_docker, - 'ec2': supports_ec2, 'podman': lambda: min_ansible("2.8.6"), 'openstack': supports_openstack, 'vagrant': supports_vagrant_virtualbox, @@ -282,15 +281,6 @@ def demands_delegated(): return pytest.config.getoption('--delegated') -@pytest.helpers.register -def supports_ec2(): - from ansible.module_utils.ec2 import HAS_BOTO3 - - env_vars = ('AWS_ACCESS_KEY', 'AWS_SECRET_ACCESS_KEY') - - return _env_vars_exposed(env_vars) and HAS_BOTO3 - - @pytest.helpers.register def supports_openstack(): pytest.importorskip('shade') # Ansible provides no import diff --git a/molecule/test/functional/test_command.py b/molecule/test/functional/test_command.py index 2a63a3644..f66b1b29e 100644 --- a/molecule/test/functional/test_command.py +++ b/molecule/test/functional/test_command.py @@ -47,7 +47,6 @@ def driver_name(request): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -65,7 +64,6 @@ def test_command_check(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -83,7 +81,6 @@ def test_command_cleanup(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -101,7 +98,6 @@ def test_command_converge(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -122,7 +118,6 @@ def test_command_create(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('dependency', 'docker', 'ansible-galaxy'), - ('dependency', 'ec2', 'ansible-galaxy'), ('dependency', 'openstack', 'ansible-galaxy'), ('dependency', 'vagrant', 'ansible-galaxy'), ('dependency', 'podman', 'ansible-galaxy'), @@ -150,7 +145,6 @@ def test_command_dependency_ansible_galaxy( 'scenario_to_test, driver_name, scenario_name', [ ('dependency', 'docker', 'gilt'), - ('dependency', 'ec2', 'gilt'), ('dependency', 'openstack', 'gilt'), ('dependency', 'vagrant', 'gilt'), ('dependency', 'podman', 'gilt'), @@ -174,7 +168,6 @@ def test_command_dependency_gilt( 'scenario_to_test, driver_name, scenario_name', [ ('dependency', 'docker', 'shell'), - ('dependency', 'ec2', 'shell'), ('dependency', 'openstack', 'shell'), ('dependency', 'vagrant', 'shell'), ('dependency', 'podman', 'shell'), @@ -198,7 +191,6 @@ def test_command_dependency_shell( 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -216,7 +208,6 @@ def test_command_destroy(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -230,7 +221,7 @@ def test_command_idempotence(scenario_to_test, with_scenario, scenario_name): @pytest.mark.parametrize( 'driver_name', - [('docker'), ('ec2'), ('openstack'), ('vagrant'), ('podman')], + [('docker'), ('openstack'), ('vagrant'), ('podman')], indirect=['driver_name'], ) def test_command_init_role(temp_dir, driver_name, skip_test): @@ -239,7 +230,7 @@ def test_command_init_role(temp_dir, driver_name, skip_test): @pytest.mark.parametrize( 'driver_name', - [('docker'), ('ec2'), ('openstack'), ('vagrant'), ('podman')], + [('docker'), ('openstack'), ('vagrant'), ('podman')], indirect=['driver_name'], ) def test_command_init_scenario(temp_dir, driver_name, skip_test): @@ -250,7 +241,6 @@ def test_command_init_scenario(temp_dir, driver_name, skip_test): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -277,17 +267,6 @@ def test_command_lint(scenario_to_test, with_scenario, scenario_name): instance docker ansible default false false instance-1 docker ansible multi-node false false instance-2 docker ansible multi-node false false -""".strip(), - ), # noqa - ( - 'driver/ec2', - 'ec2', - """ -Instance Name Driver Name Provisioner Name Scenario Name Created Converged ---------------- ------------- ------------------ --------------- --------- ----------- -instance ec2 ansible default false false -instance-1 ec2 ansible multi-node false false -instance-2 ec2 ansible multi-node false false """.strip(), ), # noqa ( @@ -351,15 +330,6 @@ def test_command_list(scenario_to_test, with_scenario, expected): instance docker ansible default false false instance-1 docker ansible multi-node false false instance-2 docker ansible multi-node false false -""".strip(), - ), - ( - 'driver/ec2', - 'ec2', - """ -instance ec2 ansible default false false -instance-1 ec2 ansible multi-node false false -instance-2 ec2 ansible multi-node false false """.strip(), ), ( @@ -414,12 +384,6 @@ def test_command_list_with_format_plain(scenario_to_test, with_scenario, expecte [['instance-1', '.*instance-1.*'], ['instance-2', '.*instance-2.*']], 'multi-node', ), - ( - 'driver/ec2', - 'ec2', - [['instance-1', '.*ip-.*'], ['instance-2', '.*ip-.*']], - 'multi-node', - ), ( 'driver/openstack', 'openstack', @@ -455,7 +419,6 @@ def test_command_login(scenario_to_test, with_scenario, login_args, scenario_nam 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -477,7 +440,6 @@ def test_command_prepare(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -495,7 +457,6 @@ def test_command_side_effect(scenario_to_test, with_scenario, scenario_name): 'scenario_to_test, driver_name, scenario_name', [ ('driver/docker', 'docker', 'default'), - ('driver/ec2', 'ec2', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -515,7 +476,6 @@ def test_command_syntax(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'default'), ('driver/docker', 'docker', 'ansible-verifier'), ('driver/docker', 'docker', 'multi-node'), - ('driver/ec2', 'ec2', None), ('driver/openstack', 'openstack', None), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', None), diff --git a/molecule/test/resources/playbooks/delegated/create.yml b/molecule/test/resources/playbooks/delegated/create.yml index 55c4df9e9..8ec356b90 100644 --- a/molecule/test/resources/playbooks/delegated/create.yml +++ b/molecule/test/resources/playbooks/delegated/create.yml @@ -5,6 +5,5 @@ gather_facts: false tasks: - include: create/docker.yml - - include: create/ec2.yml - include: create/openstack.yml # - include: create/vagrant.yml diff --git a/molecule/test/resources/playbooks/delegated/create/ec2.yml b/molecule/test/resources/playbooks/delegated/create/ec2.yml deleted file mode 100644 index 398c413bb..000000000 --- a/molecule/test/resources/playbooks/delegated/create/ec2.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -- name: Test for presence of local keypair - stat: - path: "{{ ec2.key_path }}" - register: keypair_local - -- name: Delete remote keypair - ec2_key: - name: "{{ ec2.key_name }}" - state: absent - when: not keypair_local.stat.exists - -- name: Create keypair - ec2_key: - name: "{{ ec2.key_name }}" - register: keypair - -- name: Persist the keypair - copy: - dest: "{{ ec2.key_path }}" - content: "{{ keypair.key.private_key }}" - mode: 0600 - when: keypair.changed - -- name: Create molecule instance(s) - ec2: - key_name: "{{ ec2.key_name }}" - image: ami-a5b196c0 - instance_type: t2.micro - vpc_subnet_id: subnet-6456fd1f - group: molecule - instance_tags: - name: "{{ ec2.name }}" - wait: true - assign_public_ip: true - exact_count: 1 - count_tag: - name: "{{ ec2.name }}" - register: server - -- name: Persist ssh config - copy: - dest: "{{ ec2.ssh_config_path }}" - content: | - Host "{{ ec2.name }}" - HostName "{{ server.instances[0].public_ip }}" - User "{{ ec2.ssh_user }}" - IdentityFile "{{ ec2.key_path }}" - UserKnownHostsFile=/dev/null - IdentitiesOnly=yes - StrictHostKeyChecking=no - CheckHostIP=no - when: server.changed diff --git a/molecule/test/resources/playbooks/delegated/destroy.yml b/molecule/test/resources/playbooks/delegated/destroy.yml index 3dae59892..07998d765 100644 --- a/molecule/test/resources/playbooks/delegated/destroy.yml +++ b/molecule/test/resources/playbooks/delegated/destroy.yml @@ -5,6 +5,5 @@ gather_facts: false tasks: - include: destroy/docker.yml - - include: destroy/ec2.yml - include: destroy/openstack.yml # - include: create/vagrant.yml diff --git a/molecule/test/resources/playbooks/delegated/destroy/ec2.yml b/molecule/test/resources/playbooks/delegated/destroy/ec2.yml deleted file mode 100644 index f5c3a86f2..000000000 --- a/molecule/test/resources/playbooks/delegated/destroy/ec2.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -- name: Get instance ec2 facts - ec2_remote_facts: - filters: - instance-state-name: running - tag:name: "{{ ec2.name }}" - register: ec2_facts - -- name: Destroy molecule instance(s) - ec2: - state: absent - instance_ids: "{{ ec2_facts.instances[0].id }}" - when: ec2_facts.instances | length | int > 0 - -- name: Cleanup temporary files - file: - path: "{{ item }}" - state: absent - with_items: - - "{{ ec2.key_path }}" - - "{{ ec2.ssh_config_path }}" diff --git a/molecule/test/resources/playbooks/delegated/inventory/group_vars/all/all.yml b/molecule/test/resources/playbooks/delegated/inventory/group_vars/all/all.yml index f2059c077..f1801cdbc 100644 --- a/molecule/test/resources/playbooks/delegated/inventory/group_vars/all/all.yml +++ b/molecule/test/resources/playbooks/delegated/inventory/group_vars/all/all.yml @@ -1,13 +1,6 @@ --- base_dir: /tmp -ec2: - name: delegated-instance-ec2 - key_name: molecule - key_path: "{{ base_dir }}/ssh-key-ec2" - ssh_config_path: "{{ base_dir }}/ssh-config-ec2" - ssh_user: ubuntu - openstack: name: delegated-instance-openstack key_name: molecule diff --git a/molecule/test/resources/playbooks/ec2/create.yml b/molecule/test/resources/playbooks/ec2/create.yml deleted file mode 100644 index a265fedc8..000000000 --- a/molecule/test/resources/playbooks/ec2/create.yml +++ /dev/null @@ -1,147 +0,0 @@ ---- -- name: Create - hosts: localhost - connection: local - gather_facts: false - no_log: "{{ molecule_no_log }}" - vars: - ssh_user: ubuntu - ssh_port: 22 - - security_group_name: molecule - security_group_description: Security group for testing Molecule - security_group_rules: - - proto: tcp - from_port: "{{ ssh_port }}" - to_port: "{{ ssh_port }}" - cidr_ip: '0.0.0.0/0' - - proto: icmp - from_port: 8 - to_port: -1 - cidr_ip: '0.0.0.0/0' - security_group_rules_egress: - - proto: -1 - from_port: 0 - to_port: 0 - cidr_ip: '0.0.0.0/0' - - keypair_name: molecule_key - keypair_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key" - tasks: - - name: Find the vpc for the subnet - ec2_vpc_subnet_facts: - subnet_ids: "{{ item.vpc_subnet_id }}" - loop: "{{ molecule_yml.platforms }}" - register: subnet_facts - - - name: Create security groups - ec2_group: - vpc_id: "{{ item.subnets[0].vpc_id }}" - name: "{{ security_group_name }}" - description: "{{ security_group_name }}" - rules: "{{ security_group_rules }}" - rules_egress: "{{ security_group_rules_egress }}" - loop: "{{ subnet_facts.results }}" - - - name: Test for presence of local keypair - stat: - path: "{{ keypair_path }}" - register: keypair_local - - - name: Delete remote keypair - ec2_key: - name: "{{ keypair_name }}" - state: absent - when: not keypair_local.stat.exists - - - name: Create keypair - ec2_key: - name: "{{ keypair_name }}" - register: keypair - - - name: Persist the keypair - copy: - dest: "{{ keypair_path }}" - content: "{{ keypair.key.private_key }}" - mode: 0600 - when: keypair.changed - - - name: Get the ec2 ami(s) by owner and name, if image not set - ec2_ami_facts: - owners: "{{ item.image_owner }}" - filters: - name: "{{ item.image_name }}" - loop: "{{ molecule_yml.platforms }}" - when: item.image is not defined - register: ami_facts - - - name: Create molecule instance(s) - ec2: - key_name: "{{ keypair_name }}" - image: "{{ item.image - if item.image is defined - else (ami_facts.results[index].images | sort(attribute='creation_date', reverse=True))[0].image_id }}" - instance_type: "{{ item.instance_type }}" - vpc_subnet_id: "{{ item.vpc_subnet_id }}" - group: "{{ security_group_name }}" - instance_tags: - instance: "{{ item.name }}" - wait: true - assign_public_ip: true - instance_profile_name: "{{ item.instance_profile_name | default(omit) }}" - exact_count: 1 - count_tag: - instance: "{{ item.name }}" - register: server - loop: "{{ molecule_yml.platforms }}" - loop_control: - index_var: index - async: 7200 - poll: 0 - - - name: Wait for instance(s) creation to complete - async_status: - jid: "{{ item.ansible_job_id }}" - register: ec2_jobs - until: ec2_jobs.finished - retries: 300 - with_items: "{{ server.results }}" - - # Mandatory configuration for Molecule to function. - - - name: Populate instance config dict - set_fact: - instance_conf_dict: { - 'instance': "{{ item.instances[0].tags.instance }}", - 'address': "{{ item.instances[0].public_ip }}", - 'user': "{{ ssh_user }}", - 'port': "{{ ssh_port }}", - 'identity_file': "{{ keypair_path }}", - 'instance_ids': "{{ item.instance_ids }}", } - with_items: "{{ ec2_jobs.results }}" - register: instance_config_dict - when: server.changed | bool - - - name: Convert instance config dict to a list - set_fact: - instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}" - when: server.changed | bool - - - name: Dump instance config - copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" - dest: "{{ molecule_instance_config }}" - when: server.changed | bool - - - name: Wait for SSH - wait_for: - port: "{{ ssh_port }}" - host: "{{ item.address }}" - search_regex: SSH - delay: 10 - timeout: 320 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" - - - name: Wait for boot process to finish - pause: - minutes: 2 diff --git a/molecule/test/resources/playbooks/ec2/destroy.yml b/molecule/test/resources/playbooks/ec2/destroy.yml deleted file mode 100644 index 79773c27e..000000000 --- a/molecule/test/resources/playbooks/ec2/destroy.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -- name: Destroy - hosts: localhost - connection: local - gather_facts: false - no_log: "{{ molecule_no_log }}" - vars: - resource_group_name: molecule - tasks: - - block: - - name: Populate instance config - set_fact: - instance_conf: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" - skip_instances: false - rescue: - - name: Populate instance config when file missing - set_fact: - instance_conf: {} - skip_instances: true - - - name: Destroy molecule instance(s) - ec2: - state: absent - instance_ids: "{{ item.instance_ids }}" - register: server - with_items: "{{ instance_conf }}" - when: not skip_instances - async: 7200 - poll: 0 - - - name: Wait for instance(s) deletion to complete - async_status: - jid: "{{ item.ansible_job_id }}" - register: ec2_jobs - until: ec2_jobs.finished - retries: 300 - with_items: "{{ server.results }}" - - # Mandatory configuration for Molecule to function. - - - name: Populate instance config - set_fact: - instance_conf: {} - - - name: Dump instance config - copy: - content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" - dest: "{{ molecule_instance_config }}" - when: server.changed | bool diff --git a/molecule/test/scenarios/driver/ec2/molecule/default/molecule.yml b/molecule/test/scenarios/driver/ec2/molecule/default/molecule.yml deleted file mode 100644 index e47c94f41..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/default/molecule.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -dependency: - name: galaxy -driver: - name: ec2 -lint: - name: yamllint - options: - config-file: ../../../resources/.yamllint -platforms: - - name: instance - image: ami-a5b196c0 - instance_type: t2.micro - vpc_subnet_id: subnet-6456fd1f - instance_profile_name: instance-profile -provisioner: - name: ansible - config_options: - defaults: - callback_whitelist: profile_roles,profile_tasks,timer - playbooks: - create: ../../../../../resources/playbooks/ec2/create.yml - destroy: ../../../../../resources/playbooks/ec2/destroy.yml - env: - ANSIBLE_ROLES_PATH: ../../../../../resources/roles/ - lint: - name: ansible-lint -scenario: - name: default -verifier: - name: testinfra - lint: - name: flake8 diff --git a/molecule/test/scenarios/driver/ec2/molecule/default/playbook.yml b/molecule/test/scenarios/driver/ec2/molecule/default/playbook.yml deleted file mode 100644 index 2d0e971e3..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/default/playbook.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Converge - hosts: all - gather_facts: false - become: true - roles: - - molecule diff --git a/molecule/test/scenarios/driver/ec2/molecule/default/prepare.yml b/molecule/test/scenarios/driver/ec2/molecule/default/prepare.yml deleted file mode 100644 index ddb01fbf9..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/default/prepare.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -- name: Prepare - hosts: all - gather_facts: false - tasks: - - name: Install python for Ansible - raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal python-zipstream) - become: true - changed_when: false diff --git a/molecule/test/scenarios/driver/ec2/molecule/default/tests/test_default.py b/molecule/test/scenarios/driver/ec2/molecule/default/tests/test_default.py deleted file mode 100644 index 7421539d7..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/default/tests/test_default.py +++ /dev/null @@ -1,31 +0,0 @@ -import os - -import testinfra.utils.ansible_runner - -testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ['MOLECULE_INVENTORY_FILE'] -).get_hosts('all') - - -# EC2 provides unique random hostnames. -def test_hostname(host): - pass - - -def test_etc_molecule_directory(host): - f = host.file('/etc/molecule') - - assert f.is_directory - assert f.user == 'root' - assert f.group == 'root' - assert f.mode == 0o755 - - -def test_etc_molecule_ansible_hostname_file(host): - filename = '/etc/molecule/{}'.format(host.check_output('hostname -s')) - f = host.file(filename) - - assert f.is_file - assert f.user == 'root' - assert f.group == 'root' - assert f.mode == 0o644 diff --git a/molecule/test/scenarios/driver/ec2/molecule/multi-node/molecule.yml b/molecule/test/scenarios/driver/ec2/molecule/multi-node/molecule.yml deleted file mode 100644 index 369d49a92..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/multi-node/molecule.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- -dependency: - name: galaxy -driver: - name: ec2 -lint: - name: yamllint - options: - config-file: ../../../resources/.yamllint -platforms: - - name: instance-1 - image: ami-a5b196c0 - instance_type: t2.micro - vpc_subnet_id: subnet-6456fd1f - instance_profile_name: instance-profile - groups: - - foo - - bar - - name: instance-2 - image: ami-a5b196c0 - instance_type: t2.micro - vpc_subnet_id: subnet-6456fd1f - instance_profile_name: instance-profile - groups: - - foo - - baz -provisioner: - name: ansible - config_options: - defaults: - callback_whitelist: profile_roles,profile_tasks,timer - playbooks: - create: ../../../../../resources/playbooks/ec2/create.yml - destroy: ../../../../../resources/playbooks/ec2/destroy.yml - env: - ANSIBLE_ROLES_PATH: ../../../../../resources/roles/ - lint: - name: ansible-lint -scenario: - name: multi-node -verifier: - name: testinfra - lint: - name: flake8 diff --git a/molecule/test/scenarios/driver/ec2/molecule/multi-node/playbook.yml b/molecule/test/scenarios/driver/ec2/molecule/multi-node/playbook.yml deleted file mode 100644 index 8fe4807ff..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/multi-node/playbook.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- -- name: Converge - hosts: all - gather_facts: false - become: true - roles: - - molecule - -- name: Converge - hosts: bar - gather_facts: false - become: true - roles: - - molecule - -- name: Converge - hosts: foo - gather_facts: false - become: true - roles: - - molecule - -- name: Converge - hosts: baz - gather_facts: false - become: true - roles: - - molecule diff --git a/molecule/test/scenarios/driver/ec2/molecule/multi-node/prepare.yml b/molecule/test/scenarios/driver/ec2/molecule/multi-node/prepare.yml deleted file mode 100644 index ddb01fbf9..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/multi-node/prepare.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -- name: Prepare - hosts: all - gather_facts: false - tasks: - - name: Install python for Ansible - raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal python-zipstream) - become: true - changed_when: false diff --git a/molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/__init__.py b/molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/test_default.py b/molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/test_default.py deleted file mode 100644 index 7421539d7..000000000 --- a/molecule/test/scenarios/driver/ec2/molecule/multi-node/tests/test_default.py +++ /dev/null @@ -1,31 +0,0 @@ -import os - -import testinfra.utils.ansible_runner - -testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ['MOLECULE_INVENTORY_FILE'] -).get_hosts('all') - - -# EC2 provides unique random hostnames. -def test_hostname(host): - pass - - -def test_etc_molecule_directory(host): - f = host.file('/etc/molecule') - - assert f.is_directory - assert f.user == 'root' - assert f.group == 'root' - assert f.mode == 0o755 - - -def test_etc_molecule_ansible_hostname_file(host): - filename = '/etc/molecule/{}'.format(host.check_output('hostname -s')) - f = host.file(filename) - - assert f.is_file - assert f.user == 'root' - assert f.group == 'root' - assert f.mode == 0o644 diff --git a/molecule/test/unit/command/init/test_scenario.py b/molecule/test/unit/command/init/test_scenario.py index f77720c8b..98834c614 100644 --- a/molecule/test/unit/command/init/test_scenario.py +++ b/molecule/test/unit/command/init/test_scenario.py @@ -139,32 +139,6 @@ def test_execute_with_absent_custom_template( patched_logger_critical.assert_called_once() -def test_execute_with_absent_driver_in_custom_template( - temp_dir, _command_args, custom_template_dir, patched_logger_warn -): - _command_args['driver_name'] = 'ec2' - _command_args['driver_template'] = custom_template_dir - - absent_driver_instance = scenario.Scenario(_command_args) - absent_driver_instance.execute() - - patched_logger_warn.assert_called_once_with( - "Driver not found in custom template directory" - "({driver_template}/{driver_name}), " - "using the default template instead".format(**_command_args) - ) - - assert os.path.isdir('./molecule/test-scenario') - assert os.path.isdir('./molecule/test-scenario/tests') - - install_file = os.path.join( - temp_dir.strpath, 'molecule', 'test-scenario', 'INSTALL.rst' - ) - with open(install_file) as f: - content = f.read() - assert "Amazon Web Services driver installation guide" in content - - def test_execute_with_incorrect_template( temp_dir, invalid_template_dir, _command_args, patched_logger_critical ): diff --git a/molecule/test/unit/cookiecutter/test_molecule.py b/molecule/test/unit/cookiecutter/test_molecule.py index e9a302216..06bf29202 100644 --- a/molecule/test/unit/cookiecutter/test_molecule.py +++ b/molecule/test/unit/cookiecutter/test_molecule.py @@ -93,7 +93,7 @@ def test_vagrant_driver( @pytest.mark.parametrize( - 'driver', [('docker'), ('ec2'), ('openstack'), ('vagrant')] + 'driver', [('docker'), ('openstack'), ('vagrant')] ) def test_drivers( driver, temp_dir, _molecule_file, _role_directory, _command_args, _instance diff --git a/molecule/test/unit/driver/test_ec2.py b/molecule/test/unit/driver/test_ec2.py deleted file mode 100644 index 1b4ab0a41..000000000 --- a/molecule/test/unit/driver/test_ec2.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright (c) 2015-2018 Cisco Systems, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -import os - -import pytest - -from molecule import config -from molecule.driver import ec2 - - -# NOTE(retr0h): The use of the `patched_config_validate` fixture, disables -# config.Config._validate from executing. Thus preventing odd side-effects -# throughout patched.assert_called unit tests. -@pytest.fixture -def _instance(patched_config_validate, config_instance): - return ec2.EC2(config_instance) - - -def test_config_private_member(_instance): - assert isinstance(_instance._config, config.Config) - - -def test_testinfra_options_property(_instance): - assert { - 'connection': 'ansible', - 'ansible-inventory': _instance._config.provisioner.inventory_file, - } == _instance.testinfra_options - - -def test_name_property(_instance): - assert 'ec2' == _instance.name - - -def test_options_property(_instance): - x = {'managed': True} - - assert x == _instance.options - - -def test_login_cmd_template_property(_instance): - x = ( - 'ssh {address} -l {user} -p {port} -i {identity_file} ' - '-o UserKnownHostsFile=/dev/null ' - '-o ControlMaster=auto ' - '-o ControlPersist=60s ' - '-o IdentitiesOnly=yes ' - '-o StrictHostKeyChecking=no' - ) - - assert x == _instance.login_cmd_template - - -def test_safe_files_property(_instance): - x = [ - os.path.join( - _instance._config.scenario.ephemeral_directory, 'instance_config.yml' - ) - ] - - assert x == _instance.safe_files - - -def test_default_safe_files_property(_instance): - x = [ - os.path.join( - _instance._config.scenario.ephemeral_directory, 'instance_config.yml' - ) - ] - - assert x == _instance.default_safe_files - - -def test_delegated_property(_instance): - assert not _instance.delegated - - -def test_managed_property(_instance): - assert _instance.managed - - -def test_default_ssh_connection_options_property(_instance): - x = [ - '-o UserKnownHostsFile=/dev/null', - '-o ControlMaster=auto', - '-o ControlPersist=60s', - '-o IdentitiesOnly=yes', - '-o StrictHostKeyChecking=no', - ] - - assert x == _instance.default_ssh_connection_options - - -def test_login_options(mocker, _instance): - m = mocker.patch('molecule.driver.ec2.EC2._get_instance_config') - m.return_value = { - 'instance': 'foo', - 'address': '172.16.0.2', - 'user': 'cloud-user', - 'port': 22, - 'identity_file': '/foo/bar', - } - - x = { - 'instance': 'foo', - 'address': '172.16.0.2', - 'user': 'cloud-user', - 'port': 22, - 'identity_file': '/foo/bar', - } - assert x == _instance.login_options('foo') - - -def test_ansible_connection_options(mocker, _instance): - m = mocker.patch('molecule.driver.ec2.EC2._get_instance_config') - m.return_value = { - 'instance': 'foo', - 'address': '172.16.0.2', - 'user': 'cloud-user', - 'port': 22, - 'identity_file': '/foo/bar', - } - - x = { - 'ansible_host': '172.16.0.2', - 'ansible_port': 22, - 'ansible_user': 'cloud-user', - 'ansible_private_key_file': '/foo/bar', - 'connection': 'ssh', - 'ansible_ssh_common_args': ( - '-o UserKnownHostsFile=/dev/null ' - '-o ControlMaster=auto ' - '-o ControlPersist=60s ' - '-o IdentitiesOnly=yes ' - '-o StrictHostKeyChecking=no' - ), - } - assert x == _instance.ansible_connection_options('foo') - - -def test_ansible_connection_options_handles_missing_instance_config(mocker, _instance): - m = mocker.patch('molecule.util.safe_load_file') - m.side_effect = IOError - - assert {} == _instance.ansible_connection_options('foo') - - -def test_ansible_connection_options_handles_missing_results_key(mocker, _instance): - m = mocker.patch('molecule.util.safe_load_file') - m.side_effect = StopIteration - - assert {} == _instance.ansible_connection_options('foo') - - -def test_instance_config_property(_instance): - x = os.path.join( - _instance._config.scenario.ephemeral_directory, 'instance_config.yml' - ) - - assert x == _instance.instance_config - - -def test_ssh_connection_options_property(_instance): - x = [ - '-o UserKnownHostsFile=/dev/null', - '-o ControlMaster=auto', - '-o ControlPersist=60s', - '-o IdentitiesOnly=yes', - '-o StrictHostKeyChecking=no', - ] - - assert x == _instance.ssh_connection_options - - -def test_status(mocker, _instance): - result = _instance.status() - - assert 2 == len(result) - - assert result[0].instance_name == 'instance-1' - assert result[0].driver_name == 'ec2' - assert result[0].provisioner_name == 'ansible' - assert result[0].scenario_name == 'default' - assert result[0].created == 'false' - assert result[0].converged == 'false' - - assert result[1].instance_name == 'instance-2' - assert result[1].driver_name == 'ec2' - assert result[1].provisioner_name == 'ansible' - assert result[1].scenario_name == 'default' - assert result[1].created == 'false' - assert result[1].converged == 'false' - - -def test_get_instance_config(mocker, _instance): - m = mocker.patch('molecule.util.safe_load_file') - m.return_value = [{'instance': 'foo'}, {'instance': 'bar'}] - - x = {'instance': 'foo'} - assert x == _instance._get_instance_config('foo') - - -def test_get_instance_profile(mocker, _instance): - m = mocker.patch('molecule.util.safe_load_file') - m.return_value = [{'instance': 'foo', 'instance_profile_name': 'instance-profile'}] - - x = {'instance': 'foo', 'instance_profile_name': 'instance-profile'} - assert x == _instance._get_instance_config('foo') - - -def test_created(_instance): - assert 'false' == _instance._created() - - -def test_converged(_instance): - assert 'false' == _instance._converged() diff --git a/molecule/test/unit/model/v2/test_driver_section.py b/molecule/test/unit/model/v2/test_driver_section.py index a9b3f7def..f283c8938 100644 --- a/molecule/test/unit/model/v2/test_driver_section.py +++ b/molecule/test/unit/model/v2/test_driver_section.py @@ -171,11 +171,6 @@ def _model_driver_allows_docker_section_data(): return {'driver': {'name': 'docker'}} -@pytest.fixture -def _model_driver_allows_ec2_section_data(): - return {'driver': {'name': 'ec2'}} - - @pytest.fixture def _model_driver_allows_openstack_section_data(): return {'driver': {'name': 'openstack'}} @@ -192,7 +187,6 @@ def _model_driver_allows_vagrant_section_data(): [ ('_model_driver_allows_delegated_section_data'), ('_model_driver_allows_docker_section_data'), - ('_model_driver_allows_ec2_section_data'), ('_model_driver_allows_openstack_section_data'), ('_model_driver_allows_vagrant_section_data'), ], diff --git a/molecule/test/unit/test_config.py b/molecule/test/unit/test_config.py index 471c90134..ce13f95fc 100644 --- a/molecule/test/unit/test_config.py +++ b/molecule/test/unit/test_config.py @@ -122,11 +122,6 @@ def _config_driver_delegated_section_data(): return {'driver': {'name': 'delegated', 'options': {'managed': False}}} -@pytest.fixture -def _config_driver_ec2_section_data(): - return {'driver': {'name': 'ec2'}} - - @pytest.fixture def _config_driver_openstack_section_data(): return {'driver': {'name': 'openstack'}} diff --git a/setup.cfg b/setup.cfg index 848ad1ec1..436863bc0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -106,9 +106,6 @@ docker = # system selinux libraries but it will provide a clear message when user # has to do that. selinux; sys_platform=="linux2" -ec2 = - boto - boto3 openstack = shade vagrant = @@ -133,7 +130,6 @@ console_scripts = molecule.driver = docker = molecule.driver.docker:Docker delegated = molecule.driver.delegated:Delegated - ec2 = molecule.driver.ec2:EC2 openstack = molecule.driver.openstack:Openstack podman = molecule.driver.podman:Podman vagrant = molecule.driver.vagrant:Vagrant diff --git a/tox.ini b/tox.ini index 3a139e58e..827001951 100644 --- a/tox.ini +++ b/tox.ini @@ -34,7 +34,6 @@ deps = extras = docker podman - ec2 openstack vagrant windows