diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ba25fa4c1..c7dc0c41f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,7 +10,6 @@ Unreleased * MAJOR: Dockerfile templates are now embedded in molecule. * MINOR: Fixed typo with OVERRIDDEN placeholder in templates * Supported Ansible versions are now 2.9, 2.8, 2.7 -* The Linode driver now uses the ``linode_v4`` module. * Removed goss verifier * dependency now runs before lint on default test and lint sequences * ANSIBLE_ROLES_PATH, ANSIBLE_LIBRARY, ANSIBLE_FILTER_PLUGINS now include the default Ansible lookup paths diff --git a/Dockerfile b/Dockerfile index d7069162b..b5ada732d 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,gce,linode,openstack,vagrant,windows" +ENV MOLECULE_EXTRAS="azure,docker,docs,ec2,gce,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,gce,linode,lxc,openstack,vagrant,windows" +ENV MOLECULE_EXTRAS="azure,docker,docs,ec2,gce,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 e23b72b44..f34dffe44 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -91,14 +91,6 @@ GCE .. autoclass:: molecule.driver.gce.GCE() :undoc-members: -.. _linode-driver: - -Linode -^^^^^^ - -.. autoclass:: molecule.driver.linode.Linode() - :undoc-members: - Openstack ^^^^^^^^^ diff --git a/docs/getting-started.rst b/docs/getting-started.rst index ec2ba30f4..c705685e4 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -100,8 +100,8 @@ keys represent the high level components that Molecule provides. These are: * 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`, :ref:`gce-driver` - and :ref:`linode-driver`. Under the hood, it's all Ansible modules. + providers such as :ref:`ec2-driver`, :ref:`gce-driver`. Under the hood, + it's all Ansible modules. * 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 f353b265c..2dc5083b5 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 @@ -23,12 +23,6 @@ platforms: zone: us-west1-a machine_type: f1-micro image: debian-8 -{%- elif cookiecutter.driver_name == 'linode' %} - - name: instance - type: g6-nanode-1 - state: present - region: eu-west - image: linode/debian9 {%- elif cookiecutter.driver_name == 'openstack' %} - name: instance image: Ubuntu-16.04 diff --git a/molecule/cookiecutter/scenario/driver/linode/cookiecutter.json b/molecule/cookiecutter/scenario/driver/linode/cookiecutter.json deleted file mode 100644 index 2ec6fb298..000000000 --- a/molecule/cookiecutter/scenario/driver/linode/cookiecutter.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "molecule_directory": "molecule", - "role_name": "OVERRIDDEN", - "scenario_name": "OVERRIDDEN" -} diff --git a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst b/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst deleted file mode 100644 index a01b35f64..000000000 --- a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/INSTALL.rst +++ /dev/null @@ -1,23 +0,0 @@ -******************************** -Linode driver installation guide -******************************** - -Requirements -============ - -* Ansible >= 2.8 -* ``LINODE_ACCESS_TOKEN`` exposed in your environment - -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[linode]' diff --git a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml b/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml deleted file mode 100644 index 09eab019a..000000000 --- a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/create.yml +++ /dev/null @@ -1,77 +0,0 @@ ---- -{% raw -%} -- name: Create - hosts: localhost - connection: local - gather_facts: false - no_log: "{{ molecule_no_log }}" - vars: - ssh_user: root - ssh_port: 22 - ssh_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key" - tasks: - - name: Create SSH key - user: - name: "{{ lookup('env', 'USER') }}" - generate_ssh_key: true - ssh_key_file: "{{ ssh_path }}" - register: generated_ssh_key - - - name: Create molecule instance(s) - linode_v4: - label: "{{ item.name }}" - region: "{{ item.region }}" - image: "{{ item.image }}" - type: "{{ item.type }}" - group: "{{ item.group | default(omit) }}" - tags: "{{ item.tags | default(omit) }}" - authorized_keys: - - "{{ generated_ssh_key.ssh_public_key }}" - state: present - access_token: "{{ lookup('env', 'LINODE_ACCESS_TOKEN', errors='strict') }}" - register: server - with_items: "{{ molecule_yml.platforms }}" - async: 7200 - poll: 0 - - - name: Wait for instance(s) creation to complete - async_status: - jid: "{{ item.ansible_job_id }}" - register: linode_jobs - until: linode_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.instance.label }}", - 'address': "{{ item.instance.ipv4[0] }}", - 'user': "{{ ssh_user }}", - 'port': "{{ ssh_port }}", - 'identity_file': "{{ ssh_path }}", } - with_items: "{{ linode_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 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" -{%- endraw %} diff --git a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml b/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml deleted file mode 100644 index e2da0abc6..000000000 --- a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/destroy.yml +++ /dev/null @@ -1,50 +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) - linode_v4: - label: "{{ item.instance }}" - state: absent - access_token: "{{ lookup('env', 'LINODE_ACCESS_TOKEN', errors='strict') }}" - 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: linode_jobs - until: linode_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 | molecule_to_yaml | molecule_header }}" - dest: "{{ molecule_instance_config }}" - when: server.changed | bool -{%- endraw %} diff --git a/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/playbook.yml b/molecule/cookiecutter/scenario/driver/linode/{{cookiecutter.molecule_directory}}/{{cookiecutter.scenario_name}}/playbook.yml deleted file mode 100644 index fecf1c843..000000000 --- a/molecule/cookiecutter/scenario/driver/linode/{{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/driver/linode.py b/molecule/driver/linode.py deleted file mode 100644 index 563d2b81e..000000000 --- a/molecule/driver/linode.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (c) 2018-2019 Red Hat, 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 - -from molecule.api import Driver - -from molecule import logger, util -from molecule.util import lru_cache - -log = logger.get_logger(__name__) - - -class Linode(Driver): - """ - The class responsible for managing `Linode`_ instances. `Linode`_ - is `not` the default driver used in Molecule. - - Molecule leverages Ansible's `linode_v4 module`_, by mapping variables - from ``molecule.yml`` into ``create.yml`` and ``destroy.yml``. - - .. code-block:: yaml - - driver: - name: linode - platforms: - - name: instance - type: g6-nanode-1 - state: present - region: eu-west - image: linode/debian9 - - .. _`linode_v4 module`: https://docs.ansible.com/ansible/latest/modules/linode_v4_module.html - - .. code-block:: bash - - $ pip install 'molecule[linode]' - - Change the options passed to the ssh client. - - .. code-block:: yaml - - driver: - name: linode - 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: linode - safe_files: - - foo - - .. _`Linode`: https://www.linode.com/ - """ # noqa - - def __init__(self, config=None): - super(Linode, self).__init__(config) - self._name = 'linode' - - @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) - - return { - '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), - } - 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 - ) - - @lru_cache() - def sanity_checks(self): - log.info("Sanity checks: '{}'".format(self._name)) - - try: - from linode_api4 import LinodeClient # noqa - except ImportError: - msg = ( - 'Missing Linode driver dependency. Please ' - "install via 'molecule[linode]' or refer to " - 'your INSTALL.rst driver documentation file' - ) - util.sysexit_with_message(msg) - - if 'LINODE_ACCESS_TOKEN' not in os.environ: - msg = ( - 'Missing Linode access token. Please expose ' - 'the LINODE_ACCESS_TOKEN environment variable with ' - 'your account access token value' - ) - util.sysexit_with_message(msg) diff --git a/molecule/model/schema_v2.py b/molecule/model/schema_v2.py index a77dcfe4e..e4ed8cff2 100644 --- a/molecule/model/schema_v2.py +++ b/molecule/model/schema_v2.py @@ -487,21 +487,6 @@ def pre_validate_base_schema(env, keep_string): } } -platforms_linode_schema = { - 'platforms': { - 'type': 'list', - 'schema': { - 'type': 'dict', - 'schema': { - 'region': {'type': 'string', 'required': True}, - 'image': {'type': 'string', 'required': True}, - 'type': {'type': 'string', 'required': True}, - 'group': {'type': 'string'}, - 'tags': {'type': 'list', 'schema': {'type': 'string'}}, - }, - }, - } -} dependency_command_nullable_schema = { 'dependency': { @@ -591,8 +576,6 @@ def validate(c): elif c['driver']['name'] == 'vagrant': util.merge_dicts(schema, driver_vagrant_provider_section_schema) util.merge_dicts(schema, platforms_vagrant_schema) - elif c['driver']['name'] == 'linode': - util.merge_dicts(schema, platforms_linode_schema) # Verifier util.merge_dicts(schema, api.verifiers()[c['verifier']['name']].schema()) diff --git a/molecule/test/functional/conftest.py b/molecule/test/functional/conftest.py index 145f6cd19..be614322a 100644 --- a/molecule/test/functional/conftest.py +++ b/molecule/test/functional/conftest.py @@ -76,7 +76,6 @@ def skip_test(request, driver_name): 'docker': supports_docker, 'ec2': supports_ec2, 'gce': supports_gce, - 'linode': lambda: min_ansible("2.8") and supports_linode(), 'podman': lambda: min_ansible("2.8.6"), 'openstack': supports_openstack, 'vagrant': supports_vagrant_virtualbox, @@ -274,15 +273,6 @@ def min_ansible(version): return False -@pytest.helpers.register -def supports_linode(): - from ansible.modules.cloud.linode.linode_v4 import HAS_LINODE_DEPENDENCY - - env_vars = ('LINODE_ACCESS_TOKEN',) - - return _env_vars_exposed(env_vars) and HAS_LINODE_DEPENDENCY - - @pytest.helpers.register def supports_vagrant_virtualbox(): return get_vagrant_executable() or get_virtualbox_executable() diff --git a/molecule/test/functional/test_command.py b/molecule/test/functional/test_command.py index 87c5b92fa..5e27d58c6 100644 --- a/molecule/test/functional/test_command.py +++ b/molecule/test/functional/test_command.py @@ -49,7 +49,6 @@ def driver_name(request): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -69,7 +68,6 @@ def test_command_check(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -108,7 +106,6 @@ def test_command_converge(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -131,7 +128,6 @@ def test_command_create(scenario_to_test, with_scenario, scenario_name): ('dependency', 'docker', 'ansible-galaxy'), ('dependency', 'ec2', 'ansible-galaxy'), ('dependency', 'gce', 'ansible-galaxy'), - ('dependency', 'linode', 'ansible-galaxy'), ('dependency', 'openstack', 'ansible-galaxy'), ('dependency', 'vagrant', 'ansible-galaxy'), ('dependency', 'podman', 'ansible-galaxy'), @@ -161,7 +157,6 @@ def test_command_dependency_ansible_galaxy( ('dependency', 'docker', 'gilt'), ('dependency', 'ec2', 'gilt'), ('dependency', 'gce', 'gilt'), - ('dependency', 'linode', 'gilt'), ('dependency', 'openstack', 'gilt'), ('dependency', 'vagrant', 'gilt'), ('dependency', 'podman', 'gilt'), @@ -187,7 +182,6 @@ def test_command_dependency_gilt( ('dependency', 'docker', 'shell'), ('dependency', 'ec2', 'shell'), ('dependency', 'gce', 'shell'), - ('dependency', 'linode', 'shell'), ('dependency', 'openstack', 'shell'), ('dependency', 'vagrant', 'shell'), ('dependency', 'podman', 'shell'), @@ -213,7 +207,6 @@ def test_command_dependency_shell( ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -233,7 +226,6 @@ def test_command_destroy(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -247,7 +239,7 @@ def test_command_idempotence(scenario_to_test, with_scenario, scenario_name): @pytest.mark.parametrize( 'driver_name', - [('docker'), ('ec2'), ('gce'), ('linode'), ('openstack'), ('vagrant'), ('podman')], + [('docker'), ('ec2'), ('gce'), ('openstack'), ('vagrant'), ('podman')], indirect=['driver_name'], ) def test_command_init_role(temp_dir, driver_name, skip_test): @@ -256,7 +248,7 @@ def test_command_init_role(temp_dir, driver_name, skip_test): @pytest.mark.parametrize( 'driver_name', - [('docker'), ('ec2'), ('gce'), ('linode'), ('openstack'), ('vagrant'), ('podman')], + [('docker'), ('ec2'), ('gce'), ('openstack'), ('vagrant'), ('podman')], indirect=['driver_name'], ) def test_command_init_scenario(temp_dir, driver_name, skip_test): @@ -269,7 +261,6 @@ def test_command_init_scenario(temp_dir, driver_name, skip_test): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -318,17 +309,6 @@ def test_command_lint(scenario_to_test, with_scenario, scenario_name): instance gce ansible default false false instance-1 gce ansible multi-node false false instance-2 gce ansible multi-node false false -""".strip(), - ), # noqa - ( - 'driver/linode', - 'linode', - """ -Instance Name Driver Name Provisioner Name Scenario Name Created Converged ---------------- ------------- ------------------ --------------- --------- ----------- -instance linode ansible default false false -instance-1 linode ansible multi-node false false -instance-2 linode ansible multi-node false false """.strip(), ), # noqa ( @@ -410,15 +390,6 @@ def test_command_list(scenario_to_test, with_scenario, expected): instance gce ansible default false false instance-1 gce ansible multi-node false false instance-2 gce ansible multi-node false false -""".strip(), - ), - ( - 'driver/linode', - 'linode', - """ -instance linode ansible default false false -instance-1 linode ansible multi-node false false -instance-2 linode ansible multi-node false false """.strip(), ), ( @@ -485,13 +456,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/linode', 'linode', [['instance', '.*instance.*']], 'default'), - ( - 'driver/linode', - 'linode', - [['instance-1', '.*instance-1.*'], ['instance-2', '.*instance-2.*']], - 'multi-node', - ), ( 'driver/openstack', 'openstack', @@ -529,7 +493,6 @@ def test_command_login(scenario_to_test, with_scenario, login_args, scenario_nam ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -553,7 +516,6 @@ def test_command_prepare(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -573,7 +535,6 @@ def test_command_side_effect(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'default'), ('driver/ec2', 'ec2', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), @@ -595,7 +556,6 @@ def test_command_syntax(scenario_to_test, with_scenario, scenario_name): ('driver/docker', 'docker', 'multi-node'), ('driver/ec2', 'ec2', None), ('driver/gce', 'gce', None), - ('driver/linode', 'linode', None), ('driver/openstack', 'openstack', None), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', None), @@ -612,7 +572,6 @@ def test_command_test(scenario_to_test, with_scenario, scenario_name, driver_nam [ ('driver/docker', 'docker', 'default'), ('driver/gce', 'gce', 'default'), - ('driver/linode', 'linode', 'default'), ('driver/openstack', 'openstack', 'default'), ('driver/delegated', 'delegated', 'docker'), ('driver/vagrant', 'vagrant', 'default'), diff --git a/molecule/test/resources/playbooks/linode/create.yml b/molecule/test/resources/playbooks/linode/create.yml deleted file mode 100644 index 466616503..000000000 --- a/molecule/test/resources/playbooks/linode/create.yml +++ /dev/null @@ -1,75 +0,0 @@ ---- -- name: Create - hosts: localhost - connection: local - gather_facts: false - no_log: "{{ molecule_no_log }}" - vars: - ssh_user: root - ssh_port: 22 - ssh_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key" - tasks: - - name: Create SSH key - user: - name: "{{ lookup('env', 'USER') }}" - generate_ssh_key: true - ssh_key_file: "{{ ssh_path }}" - register: generated_ssh_key - - - name: Create molecule instance(s) - linode_v4: - label: "{{ item.name }}" - region: "{{ item.region }}" - image: "{{ item.image }}" - type: "{{ item.type }}" - group: "{{ item.group | default(omit) }}" - tags: "{{ item.tags | default(omit) }}" - authorized_keys: - - "{{ generated_ssh_key.ssh_public_key }}" - state: present - access_token: "{{ lookup('env', 'LINODE_ACCESS_TOKEN', errors='strict') }}" - register: server - with_items: "{{ molecule_yml.platforms }}" - async: 7200 - poll: 0 - - - name: Wait for instance(s) creation to complete - async_status: - jid: "{{ item.ansible_job_id }}" - register: linode_jobs - until: linode_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.instance.label }}", - 'address': "{{ item.instance.ipv4[0] }}", - 'user': "{{ ssh_user }}", - 'port': "{{ ssh_port }}", - 'identity_file': "{{ ssh_path }}", } - with_items: "{{ linode_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 - with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" diff --git a/molecule/test/resources/playbooks/linode/destroy.yml b/molecule/test/resources/playbooks/linode/destroy.yml deleted file mode 100644 index 01d2d8d62..000000000 --- a/molecule/test/resources/playbooks/linode/destroy.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -- 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) - linode_v4: - label: "{{ item.instance }}" - state: absent - access_token: "{{ lookup('env', 'LINODE_ACCESS_TOKEN', errors='strict') }}" - 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: linode_jobs - until: linode_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 | molecule_to_yaml | molecule_header }}" - dest: "{{ molecule_instance_config }}" - when: server.changed | bool diff --git a/molecule/test/scenarios/driver/linode/molecule/default/molecule.yml b/molecule/test/scenarios/driver/linode/molecule/default/molecule.yml deleted file mode 100644 index 1efd1524a..000000000 --- a/molecule/test/scenarios/driver/linode/molecule/default/molecule.yml +++ /dev/null @@ -1,36 +0,0 @@ ---- -dependency: - name: galaxy - -driver: - name: linode - -lint: - name: yamllint - options: - config-file: ../../../resources/.yamllint - -platforms: - - name: instance - type: g6-nanode-1 - state: present - region: eu-west - image: linode/debian9 - -provisioner: - name: ansible - playbooks: - create: ../../../../../resources/playbooks/linode/create.yml - destroy: ../../../../../resources/playbooks/linode/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/linode/molecule/default/playbook.yml b/molecule/test/scenarios/driver/linode/molecule/default/playbook.yml deleted file mode 100644 index 6cbb76ebf..000000000 --- a/molecule/test/scenarios/driver/linode/molecule/default/playbook.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -- name: Converge - hosts: all - roles: - - molecule diff --git a/molecule/test/scenarios/driver/linode/molecule/default/tests/test_default.py b/molecule/test/scenarios/driver/linode/molecule/default/tests/test_default.py deleted file mode 100644 index f7150631e..000000000 --- a/molecule/test/scenarios/driver/linode/molecule/default/tests/test_default.py +++ /dev/null @@ -1,34 +0,0 @@ -import os - -import pytest - -import testinfra.utils.ansible_runner - -testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ['MOLECULE_INVENTORY_FILE'] -).get_hosts('all') - - -@pytest.mark.skip(reason='Scenario tests not implemented yet') -def test_hostname(host): - assert 'instance' == host.check_output('hostname -s') - - -@pytest.mark.skip(reason='Scenario tests not implemented yet') -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 - - -@pytest.mark.skip(reason='Scenario tests not implemented yet') -def test_etc_molecule_ansible_hostname_file(host): - f = host.file('/etc/molecule/instance') - - assert f.is_file - assert f.user == 'root' - assert f.group == 'root' - assert f.mode == 0o644 diff --git a/molecule/test/scenarios/driver/linode/molecule/multi-node/molecule.yml b/molecule/test/scenarios/driver/linode/molecule/multi-node/molecule.yml deleted file mode 100644 index ae5eaf532..000000000 --- a/molecule/test/scenarios/driver/linode/molecule/multi-node/molecule.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- -dependency: - name: galaxy - -driver: - name: linode - -lint: - name: yamllint - options: - config-file: ../../../resources/.yamllint - -platforms: - - name: instance-1 - type: g6-nanode-1 - state: present - region: eu-west - image: linode/debian9 - - name: instance-2 - type: g6-nanode-1 - state: present - region: eu-west - image: linode/debian9 - -provisioner: - name: ansible - config_options: - defaults: - callback_whitelist: profile_roles,profile_tasks,timer - playbooks: - create: ../../../../../resources/playbooks/linode/create.yml - destroy: ../../../../../resources/playbooks/linode/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/linode/molecule/multi-node/playbook.yml b/molecule/test/scenarios/driver/linode/molecule/multi-node/playbook.yml deleted file mode 100644 index b85ef1146..000000000 --- a/molecule/test/scenarios/driver/linode/molecule/multi-node/playbook.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -- name: Converge - hosts: all - gather_facts: false - roles: - - molecule - -- name: Converge - hosts: bar - gather_facts: false - roles: - - molecule - -- name: Converge - hosts: foo - gather_facts: false - roles: - - molecule - -- name: Converge - hosts: baz - gather_facts: false - roles: - - molecule diff --git a/molecule/test/scenarios/driver/linode/molecule/multi-node/tests/test_default.py b/molecule/test/scenarios/driver/linode/molecule/multi-node/tests/test_default.py deleted file mode 100644 index f83de56f0..000000000 --- a/molecule/test/scenarios/driver/linode/molecule/multi-node/tests/test_default.py +++ /dev/null @@ -1,36 +0,0 @@ -import os -import re - -import pytest - -import testinfra.utils.ansible_runner - -testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( - os.environ['MOLECULE_INVENTORY_FILE'] -).get_hosts('all') - - -@pytest.mark.skip(reason='Scenario tests not implemented yet') -def test_hostname(host): - assert re.search(r'instance-[12]', host.check_output('hostname -s')) - - -@pytest.mark.skip(reason='Scenario tests not implemented yet') -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 - - -@pytest.mark.skip(reason='Scenario tests not implemented yet') -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/cookiecutter/test_molecule.py b/molecule/test/unit/cookiecutter/test_molecule.py index ad6a24732..c261fcd07 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'), ('gce'), ('linode'), ('openstack'), ('vagrant')] + 'driver', [('docker'), ('ec2'), ('gce'), ('openstack'), ('vagrant')] ) def test_drivers( driver, temp_dir, _molecule_file, _role_directory, _command_args, _instance diff --git a/molecule/test/unit/driver/test_linode.py b/molecule/test/unit/driver/test_linode.py deleted file mode 100644 index 8c568e4b3..000000000 --- a/molecule/test/unit/driver/test_linode.py +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright (c) 2018-2019 Red Hat, 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 linode - - -@pytest.fixture -def linode_instance(patched_config_validate, config_instance): - return linode.Linode(config_instance) - - -def test_linode_config_gives_config_object(linode_instance): - assert isinstance(linode_instance._config, config.Config) - - -def test_linode_testinfra_options_property(linode_instance): - assert { - 'connection': 'ansible', - 'ansible-inventory': linode_instance._config.provisioner.inventory_file, - } == linode_instance.testinfra_options - - -def test_linode_name_property(linode_instance): - assert 'linode' == linode_instance.name - - -def test_linode_options_property(linode_instance): - assert {'managed': True} == linode_instance.options - - -def test_linode_login_cmd_template_property(linode_instance): - template = 'ssh {address} -l {user} -p {port} -i {identity_file}' - assert template in linode_instance.login_cmd_template - - -def test_linode_safe_files_property(linode_instance): - expected_safe_files = [ - os.path.join( - linode_instance._config.scenario.ephemeral_directory, 'instance_config.yml' - ) - ] - - assert expected_safe_files == linode_instance.safe_files - - -def test_linode_default_safe_files_property(linode_instance): - expected_default_safe_files = [ - os.path.join( - linode_instance._config.scenario.ephemeral_directory, 'instance_config.yml' - ) - ] - assert expected_default_safe_files == linode_instance.default_safe_files - - -def test_linode_delegated_property(linode_instance): - assert not linode_instance.delegated - - -def test_linode_managed_property(linode_instance): - assert linode_instance.managed - - -def test_linode_default_ssh_connection_options_property(linode_instance): - expected_options = [ - '-o UserKnownHostsFile=/dev/null', - '-o ControlMaster=auto', - '-o ControlPersist=60s', - '-o IdentitiesOnly=yes', - '-o StrictHostKeyChecking=no', - ] - - assert expected_options == linode_instance.default_ssh_connection_options - - -def test_linode_login_options(linode_instance, mocker): - target = 'molecule.driver.linode.Linode._get_instance_config' - get_instance_config_patch = mocker.patch(target) - - get_instance_config_patch.return_value = { - 'instance': 'linode', - 'address': '172.16.0.2', - 'user': 'linode-admin', - 'port': 22, - 'identity_file': '/foo/bar', - } - - get_instance_config_patch = { - 'instance': 'linode', - 'address': '172.16.0.2', - 'user': 'linode-admin', - 'port': 22, - 'identity_file': '/foo/bar', - } - - assert get_instance_config_patch == linode_instance.login_options('linode') - - -def test_linode_ansible_connection_options(linode_instance, mocker): - target = 'molecule.driver.linode.Linode._get_instance_config' - get_instance_config_patch = mocker.patch(target) - - get_instance_config_patch.return_value = { - 'instance': 'linode', - 'address': '172.16.0.2', - 'user': 'linode-admin', - 'port': 22, - 'identity_file': '/foo/bar', - } - - get_instance_config_patch = { - 'ansible_host': '172.16.0.2', - 'ansible_port': 22, - 'ansible_user': 'linode-admin', - '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' - ), - } - - connection_options = linode_instance.ansible_connection_options('linode') - assert get_instance_config_patch == connection_options - - -def test_linode_instance_config_property(linode_instance): - instance_config_path = os.path.join( - linode_instance._config.scenario.ephemeral_directory, 'instance_config.yml' - ) - - assert instance_config_path == linode_instance.instance_config - - -def test_linode_ssh_connection_options_property(linode_instance): - expected_options = [ - '-o UserKnownHostsFile=/dev/null', - '-o ControlMaster=auto', - '-o ControlPersist=60s', - '-o IdentitiesOnly=yes', - '-o StrictHostKeyChecking=no', - ] - - assert expected_options == linode_instance.ssh_connection_options - - -def test_linode_status(mocker, linode_instance): - linode_status = linode_instance.status() - - assert 2 == len(linode_status) - - assert linode_status[0].instance_name == 'instance-1' - assert linode_status[0].driver_name == 'linode' - assert linode_status[0].provisioner_name == 'ansible' - assert linode_status[0].scenario_name == 'default' - assert linode_status[0].created == 'false' - assert linode_status[0].converged == 'false' - - assert linode_status[1].instance_name == 'instance-2' - assert linode_status[1].driver_name == 'linode' - assert linode_status[1].provisioner_name == 'ansible' - assert linode_status[1].scenario_name == 'default' - assert linode_status[1].created == 'false' - assert linode_status[1].converged == 'false' - - -def test_created(linode_instance): - assert 'false' == linode_instance._created() - - -def test_converged(linode_instance): - assert 'false' == linode_instance._converged() diff --git a/molecule/test/unit/model/v2/test_platforms_section.py b/molecule/test/unit/model/v2/test_platforms_section.py index 2fd8629b2..417c5889d 100644 --- a/molecule/test/unit/model/v2/test_platforms_section.py +++ b/molecule/test/unit/model/v2/test_platforms_section.py @@ -325,71 +325,3 @@ def test_platforms_driver_name_required(_config): x = {'platforms': [{0: [{'name': ['required field']}]}]} assert x == schema_v2.validate(_config) - - -@pytest.fixture -def _model_platform_linode_section_data(): - return { - 'driver': {'name': 'linode'}, - 'platforms': [ - { - 'name': '', - 'region': '', - 'image': '', - 'type': '', - 'group': '', - 'tags': [''], - } - ], - } - - -@pytest.mark.parametrize( - '_config', ['_model_platform_linode_section_data'], indirect=True -) -def test_platforms_linode(_config): - assert {} == schema_v2.validate(_config) - - -@pytest.fixture -def _model_platforms_linode_errors_section_data(): - return { - 'driver': {'name': 'linode'}, - 'platforms': [ - {'name': 0, 'region': 0, 'image': 0, 'type': 0, 'group': 0, 'tags': ''} - ], - } - - -@pytest.mark.parametrize( - '_config', ['_model_platforms_linode_errors_section_data'], indirect=True -) -def test_platforms_linode_has_errors(_config): - expected_config = { - 'platforms': [ - { - 0: [ - { - 'name': ['must be of string type'], - 'region': ['must be of string type'], - 'group': ['must be of string type'], - 'type': ['must be of string type'], - 'image': ['must be of string type'], - 'tags': ['must be of list type'], - } - ] - } - ] - } - - assert expected_config == schema_v2.validate(_config) - - -@pytest.mark.parametrize( - '_config', ['_model_platform_linode_section_data'], indirect=True -) -@pytest.mark.parametrize('_required_field', ('region', 'image', 'type')) -def test_platforms_linode_fields_required(_config, _required_field): - del _config['platforms'][0][_required_field] - expected_config = {'platforms': [{0: [{_required_field: ['required field']}]}]} - assert expected_config == schema_v2.validate(_config) diff --git a/setup.cfg b/setup.cfg index 32f79906a..887bd602c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -111,8 +111,6 @@ ec2 = boto3 gce = apache-libcloud -linode = - linode_api4 >= 2.0.0, < 3.0 openstack = shade vagrant = @@ -139,7 +137,6 @@ molecule.driver = delegated = molecule.driver.delegated:Delegated ec2 = molecule.driver.ec2:EC2 gce = molecule.driver.gce:GCE - linode = molecule.driver.linode:Linode openstack = molecule.driver.openstack:Openstack podman = molecule.driver.podman:Podman vagrant = molecule.driver.vagrant:Vagrant diff --git a/tox.ini b/tox.ini index 4cd2ce542..eec53cb36 100644 --- a/tox.ini +++ b/tox.ini @@ -36,7 +36,6 @@ extras = podman ec2 gce - linode openstack vagrant windows