Configuration

class molecule.config.Config

Molecule searches the current directory for molecule.yml files by globbing molecule/*/molecule.yml. The files are instantiated into a list of Molecule Config objects, and each Molecule subcommand operates on this list.

The directory in which the molecule.yml resides is the Scenario’s directory. Molecule performs most functions within this directory.

The Config object instantiates Dependency, Driver, Lint, Platforms, Provisioner, Verifier, Scenario, and State references.

Variable Substitution

class molecule.interpolation.Interpolator

Configuration options may contain environment variables. For example, suppose the shell contains VERIFIER_NAME=testinfra and the following molecule.yml is supplied.

verifier:
  - name: ${VERIFIER_NAME}

Molecule will substitute $VERIFIER_NAME with the value of the VERIFIER_NAME environment variable.

Warning

If an environment variable is not set, Molecule substitutes with an empty string.

Both $VARIABLE and ${VARIABLE} syntax are supported. Extended shell-style features, such as ${VARIABLE-default} and ${VARIABLE:-default} are also supported.

If a literal dollar sign is needed in a configuration, use a double dollar sign ($$).

Molecule will substitute special MOLECULE_ environment variables defined in molecule.yml.

Important

Remember, the MOLECULE_ namespace is reserved for Molecule. Do not prefix your own variables with MOLECULE_.

A file may be placed in the root of the project as env.yml, and Molecule will read variables when rendering molecule.yml. See command usage.

Dependency

Testing roles may rely upon additional dependencies. Molecule handles managing these dependencies by invoking configurable dependency managers.

Ansible Galaxy

class molecule.dependency.ansible_galaxy.AnsibleGalaxy

Ansible Galaxy is the default dependency manager.

Additional options can be passed to ansible-galaxy install through the options dict. Any option set in this section will override the defaults.

Note

Molecule will remove any options matching ‘^[v]+$’, and pass -vvv to the underlying ansible-galaxy command when executing molecule –debug.

dependency:
  name: galaxy
  options:
    ignore-certs: True
    ignore-errors: True
    role-file: requirements.yml

The dependency manager can be disabled by setting enabled to False.

dependency:
  name: galaxy
  enabled: False

Environment variables can be passed to the dependency.

dependency:
  name: galaxy
  env:
    FOO: bar

Gilt

class molecule.dependency.gilt.Gilt

Gilt is an alternate dependency manager.

Additional options can be passed to gilt overlay through the options dict. Any option set in this section will override the defaults.

dependency:
  name: gilt
  options:
    debug: True

The dependency manager can be disabled by setting enabled to False.

dependency:
  name: gilt
  enabled: False

Environment variables can be passed to the dependency.

dependency:
  name: gilt
  env:
    FOO: bar

Shell

class molecule.dependency.shell.Shell

Shell is an alternate dependency manager. It is intended to run a command in situations where Ansible Galaxy and Gilt don’t suffice.

The command to execute is required, and is relative to Molecule’s project directory when referencing a script not in $PATH.

Note

Unlike the other dependency managers, options are ignored and not passed to shell. Additional flags/subcommands should simply be added to the command.

dependency:
  name: shell
  command: path/to/command --flag1 subcommand --flag2

The dependency manager can be disabled by setting enabled to False.

dependency:
  name: shell
  command: path/to/command --flag1 subcommand --flag2
  enabled: False

Environment variables can be passed to the dependency.

dependency:
  name: shell
  command: path/to/command --flag1 subcommand --flag2
  env:
    FOO: bar

Driver

Molecule uses Ansible to manage instances to operate on. Molecule supports any provider Ansible supports. This work is offloaded to the provisioner.

The driver’s name is specified in molecule.yml, and can be overriden on the command line. Molecule will remember the last successful driver used, and

continue to use the driver for all subsequent subcommands, or until the instances are destroyed by Molecule.

Important

The verifier must support the Ansible provider for proper Molecule integration.

The driver’s python package requires installation.

Azure

class molecule.driver.azure.Azure

The class responsible for managing Azure instances. Azure is not the default driver used in Molecule.

Molecule leverages Ansible’s azure_module, by mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: azure
platforms:
  - name: instance
$ pip install 'ansible[azure]'

Change the options passed to the ssh client.

driver:
  name: azure
  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.

driver:
  name: azure
  safe_files:
    - foo

Delegated

class molecule.driver.delegated.Delegated

The class responsible for managing delegated instances. Delegated is not the default driver used in Molecule.

Under this driver, it is the developers responsibility to implement the create and destroy playbooks. Managed is the default behaviour of all drivers.

driver:
  name: delegated

However, the developer must adhere to the instance-config API. The developer’s create playbook must provide the following instance-config data, and the developer’s destroy playbook must reset the instance-config.

- address: ssh_endpoint
  identity_file: ssh_identity_file  # mutually exclusive with password
  instance: instance_name
  port: ssh_port_as_string
  user: ssh_user
  password: ssh_password  # mutually exclusive with identity_file
  become_method: valid_ansible_become_method  # optional
  become_pass: password_if_required  # optional

- address: winrm_endpoint
  instance: instance_name
  connection: 'winrm'
  port: winrm_port_as_string
  user: winrm_user
  password: winrm_password
  winrm_transport: ntlm/credssp/kerberos
  winrm_cert_pem: <path to the credssp public certificate key>
  winrm_cert_key_pem: <path to the credssp private certificate key>
  winrm_server_cert_validation: True/False

This article covers how to configure and use WinRM with Ansible: https://docs.ansible.com/ansible/latest/user_guide/windows_winrm.html

Molecule can also skip the provisioning/deprovisioning steps. It is the developers responsibility to manage the instances, and properly configure Molecule to connect to said instances.

driver:
  name: delegated
  options:
    managed: False
    login_cmd_template: 'docker exec -ti {instance} bash'
    ansible_connection_options:
      ansible_connection: docker
platforms:
  - name: instance-docker
$ docker run \
    -d \
    --name instance-docker \
    --hostname instance-docker \
    -it molecule_local/ubuntu:latest sleep infinity & wait

Use Molecule with delegated instances, which are accessible over ssh.

Important

It is the developer’s responsibility to configure the ssh config file.

driver:
  name: delegated
  options:
    managed: False
    login_cmd_template: 'ssh {instance} -F /tmp/ssh-config'
    ansible_connection_options:
      ansible_connection: ssh
      ansible_ssh_common_args: '-F /path/to/ssh-config'
platforms:
  - name: instance-vagrant

Provide the files Molecule will preserve post destroy action.

driver:
  name: delegated
  safe_files:
    - foo

And in order to use localhost as molecule’s target:

driver:
  name: delegated
  options:
    managed: False
    ansible_connection_options:
      ansible_connection: local

DigitalOcean

class molecule.driver.digitalocean.DigitalOcean

This class is responsible for managing DigitalOcean instances. DigitalOcean is not the default driver used in Molecule.

Molecule leverages Ansible’s digital_ocean_module, by mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: digitalocean
platforms:
  - name: instance
$ pip install 'molecule[digitalocean]'

Change the options passed to the ssh client.

driver:
  name: digitalocean
  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 the files Molecule will preserve upon each subcommand execution.

driver:
  name: digitalocean
  safe_files:
    - foo

Docker

class molecule.driver.docker.Docker

The class responsible for managing Docker containers. Docker is the default driver used in Molecule.

Molecule leverages Ansible’s docker_container module, by mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: docker
platforms:
  - name: instance
    hostname: instance
    image: image_name:tag
    dockerfile: Dockerfile.j2
    pull: True|False
    pre_build_image: True|False
    registry:
      url: registry.example.com
      credentials:
        username: $USERNAME
        password: $PASSWORD
        email: user@example.com
        user: root
    override_command: True|False
    command: sleep infinity
    tty: True|False
    pid_mode: host
    privileged: True|False
    security_opts:
      - seccomp=unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    keep_volumes: True|False
    tmpfs:
      - /tmp
      - /run
    capabilities:
      - SYS_ADMIN
    sysctls:
      net.core.somaxconn: 1024
      net.ipv4.tcp_syncookies: 0
    exposed_ports:
      - 53/udp
      - 53/tcp
    published_ports:
      - 0.0.0.0:8053:53/udp
      - 0.0.0.0:8053:53/tcp
    ulimits:
      - nofile:262144:262144
    dns_servers:
      - 8.8.8.8
    etc_hosts: "{'host1.example.com': '10.3.1.5'}"
    networks:
      - name: foo
      - name: bar
    network_mode: host
    purge_networks: true
    docker_host: tcp://localhost:12376
    cacert_path: /foo/bar/ca.pem
    cert_path: /foo/bar/cert.pem
    key_path: /foo/bar/key.pem
    tls_verify: true
    env:
      FOO: bar
    restart_policy: on-failure
    restart_retries: 1
    buildargs:
        http_proxy: http://proxy.example.com:8080/

If specifying the CMD directive in your Dockerfile.j2 or consuming a built image which declares a CMD directive, then you must set override_command: False. Otherwise, Molecule takes care to honour the value of the command key or uses the default of bash -c "while true; do sleep 10000; done" to run the container until it is provisioned.

When attempting to utilize a container image with systemd as your init system inside the container to simulate a real machine, make sure to set the privileged, volumes, command, and environment values. An example using the centos:7 image is below:

Note

Do note that running containers in privileged mode is considerably less secure. For details, please reference Docker Security Configuration

platforms:
- name: instance
  image: centos:7
  privileged: true
  volumes:
    - "/sys/fs/cgroup:/sys/fs/cgroup:rw"
  command: "/usr/sbin/init"
  tty: True
  environment:
    container: docker
$ pip install molecule[docker]

When pulling from a private registry, it is the user’s discretion to decide whether to use hard-code strings or environment variables for passing credentials to molecule.

Important

Hard-coded credentials in molecule.yml should be avoided, instead use variable substitution.

Provide a list of files Molecule will preserve, relative to the scenario ephemeral directory, after any destroy subcommand execution.

driver:
  name: docker
  safe_files:
    - foo

EC2

class molecule.driver.ec2.EC2

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.

driver:
  name: ec2
platforms:
  - name: instance

Some configuration examples:

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:

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

Use wildcards for getting the latest image. For example, the latest Ubuntu bionic image:

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
$ pip install 'molecule[ec2]'

Change the options passed to the ssh client.

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.

driver:
  name: ec2
  safe_files:
    - foo

GCE

class molecule.driver.gce.GCE

The class responsible for managing GCE instances. GCE is not the default driver used in Molecule.

GCE is somewhat different than other cloud providers. There is not an Ansible module for managing ssh keys. This driver assumes the developer has deployed project wide ssh key.

Molecule leverages Ansible’s gce_module, by mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: gce
platforms:
  - name: instance
$ pip install molecule[gce]

Change the options passed to the ssh client.

driver:
  name: gce
  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.

driver:
  name: gce
  safe_files:
    - foo

Hetzner Cloud

class molecule.driver.hetznercloud.HetznerCloud

The class responsible for managing Hetzner Cloud instances. Hetzner Cloud is not the default driver used in Molecule.

Molecule leverages Ansible’s hcloud_server module, by mapping variables from molecule.yml into create.yml and destroy.yml.

Important

The hcloud_server module is only available in Ansible >= 2.8.

driver:
  name: hetznercloud
platforms:
  - name: instance
    server_type: cx11
    image: debian-9
$ pip install 'molecule[hetznercloud]'

Change the options passed to the ssh client.

driver:
  name: hetznercloud
  ssh_connection_options:
    - '-o ControlPath=~/.ansible/cp/%r@%h-%p'

Important

The Hetzner Cloud driver implementation uses the Parmiko transport provided by Ansible to avoid issues of connection hanging and indefinite polling as experienced with the default OpenSSh based transport.

Important

Molecule does not merge lists, when overriding the developer must provide all options.

Provide the files Molecule will preserve upon each subcommand execution.

driver:
  name: hetznercloud
  safe_files:
    - foo

Linode

class molecule.driver.linode.Linode

The class responsible for managing Linode instances. Linode is not the default driver used in Molecule.

Molecule leverages Ansible’s linode_module, by mapping variables from molecule.yml into create.yml and destroy.yml.

Important

Please note, the Ansible Linode module is currently using the deprecated API and there are a number of outstanding usability issues with the module. However, there is ongoing work to migrate to the new API (v4) and migrate this driver when that time comes. In the mean time, this driver can be considered at somewhat of an Alpha status quality.

driver:
  name: linode
platforms:
  - name: instance
    plan: 1
    datacenter: 7
    distribution: 129
$ pip install 'molecule[linode]'

Change the options passed to the ssh client.

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.

driver:
  name: linode
  safe_files:
    - foo

LXC

class molecule.driver.lxc.LXC

The class responsible for managing LXC containers. LXC is not the default driver used in Molecule.

Molecule leverages Ansible’s lxc_container module, by mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: lxc
$ pip install molecule[lxc]

Provide a list of files Molecule will preserve, relative to the scenario ephemeral directory, after any destroy subcommand execution.

driver:
  name: lxc
  safe_files:
    - foo

LXD

class molecule.driver.lxd.LXD

The class responsible for managing LXD containers. LXD is not the default driver used in Molecule.

Molecule leverages Ansible’s lxd_container module, by mapping variables from molecule.yml into create.yml and destroy.yml. The lxd_container module leverages the LXD API. Usefull information about, for example the source variable can be found in the LXD API documentation.

driver:
  name: lxd
platforms:
  - name: instance
    url: https://127.0.0.1:8443
    cert_file: /root/.config/lxc/client.crt
    key_file: /root/.config/lxc/client.key
    trust_password: password
    source:
      type: image
      mode: pull
      server: https://images.linuxcontainers.org
      protocol: lxd|simplestreams
      alias: ubuntu/xenial/amd64
    architecture: x86_64|i686
    config:
      limits.cpu: 2
    devices:
      kvm:
        path: /dev/kvm
        type: unix-char
    profiles:
      - default
    force_stop: True|False

Provide a list of files Molecule will preserve, relative to the scenario ephemeral directory, after any destroy subcommand execution.

driver:
  name: lxd
  safe_files:
    - foo

Openstack

class molecule.driver.openstack.Openstack

The class responsible for managing OpenStack instances. OpenStack is not the default driver used in Molecule.

Molecule leverages Ansible’s openstack_module, by mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: openstack
platforms:
  - name: instance
$ pip install molecule[openstack]

Change the options passed to the ssh client.

driver:
  name: openstack
  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.

driver:
  name: openstack
  safe_files:
    - foo

Podman

class molecule.driver.podman.Podman

The class responsible for managing Podman containers. Podman is not default driver used in Molecule.

Molecule uses Podman ansible connector and podman CLI while mapping variables from molecule.yml into create.yml and destroy.yml.

driver:
  name: podman
platforms:
  - name: instance
    hostname: instance
    image: image_name:tag
    dockerfile: Dockerfile.j2
    pull: True|False
    pre_build_image: True|False
    registry:
      url: registry.example.com
      credentials:
        username: $USERNAME
        password: $PASSWORD
    override_command: True|False
    command: sleep infinity
    tty: True|False
    pid_mode: host
    privileged: True|False
    security_opts:
      - seccomp=unconfined
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    tmpfs:
      - /tmp
      - /run
    capabilities:
      - SYS_ADMIN
    exposed_ports:
      - 53/udp
      - 53/tcp
    published_ports:
      - 0.0.0.0:8053:53/udp
      - 0.0.0.0:8053:53/tcp
    ulimits:
      - nofile=1024:1028
    dns_servers:
      - 8.8.8.8
    network: host
    etc_hosts: {'host1.example.com': '10.3.1.5'}
    cert_path: /foo/bar/cert.pem
    tls_verify: true
    env:
      FOO: bar
    restart_policy: on-failure
    restart_retries: 1
    buildargs:
      http_proxy: http://proxy.example.com:8080/

If specifying the CMD directive in your Dockerfile.j2 or consuming a built image which declares a CMD directive, then you must set override_command: False. Otherwise, Molecule takes care to honour the value of the command key or uses the default of bash -c "while true; do sleep 10000; done" to run the container until it is provisioned.

When attempting to utilize a container image with systemd as your init system inside the container to simulate a real machine, make sure to set the privileged, volumes, command, and environment values. An example using the centos:7 image is below:

Note

Do note that running containers in privileged mode is considerably less secure.

platforms:
- name: instance
  image: centos:7
  privileged: true
  volumes:
    - "/sys/fs/cgroup:/sys/fs/cgroup:rw"
  command: "/usr/sbin/init"
  tty: True
$ pip install molecule[podman]

When pulling from a private registry, it is the user’s discretion to decide whether to use hard-code strings or environment variables for passing credentials to molecule.

Important

Hard-coded credentials in molecule.yml should be avoided, instead use variable substitution.

Provide a list of files Molecule will preserve, relative to the scenario ephemeral directory, after any destroy subcommand execution.

driver:
  name: podman
  safe_files:
    - foo

Vagrant

class molecule.driver.vagrant.Vagrant

The class responsible for managing Vagrant instances. Vagrant is not the default driver used in Molecule.

Molecule leverages Molecule’s own Molecule Vagrant Module, by mapping variables from molecule.yml into create.yml and destroy.yml.

Important

This driver is alpha quality software. Do not perform any additonal tasks inside the create playbook. Molecule does not know about the Vagrant instances’ configuration until the converge playbook is executed.

The create playbook boots instances, then the instance data is written to disk. The instance data is then added to Molecule’s Ansible inventory on the next execution of molecule.command.create, which happens to be the converge playbook.

This is an area needing improvement. Gluing togher Ansible playbook return data and molecule is clunky. Moving the playbook execution from sh to python is less than ideal, since the playbook’s return data needs handled by an internal callback plugin.

Operating this far inside Ansible’s internals doesn’t feel right. Nor does orchestrating Ansible’s CLI with Molecule. Ansible is throwing pieces over the wall, which Molecule is picking up and reconstructing.

driver:
  name: vagrant
platforms:
  - name: instance-1
    instance_raw_config_args:
      - "vm.network 'forwarded_port', guest: 80, host: 8080"
    interfaces:
      - auto_config: true
        network_name: private_network
        type: dhcp
    config_options:
      synced_folder: True
    box: debian/jessie64
    box_version: 10.1
    box_url: http://repo.example.com/images/postmerge/debian.json
    memory: 1024
    cpus: 1
    provider_options:
      gui: True
    provider_raw_config_args:
      - "customize ['modifyvm', :id, '--cpuexecutioncap', '50']"
    provider_override_args:
      - "vm.synced_folder './', '/vagrant', disabled: true, type: 'nfs'"
    provision: True
$ pip install molecule[vagrant]

Change the provider passed to Vagrant.

driver:
  name: vagrant
  provider:
    name: parallels

Change the options passed to the ssh client.

driver:
  name: vagrant
  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.

driver:
  name: vagrant
  safe_files:
    - foo

Molecule Vagrant Module

Molecule manages Vagrant via an internal Ansible module. The following belongs in the appropriate create or destroy playbooks, and uses the default provider.

Supported Providers:

  • VirtualBox (default)

  • VMware (vmware_fusion, vmware_workstation and vmware_desktop)

  • Parallels

  • Libvirt (requires vagrant-libvirt plugin)

Create instances.

- hosts: localhost
  connection: local
  tasks:
    - name: Create instances
      molecule_vagrant:
        instance_name: "{{ item }}"
        platform_box: ubuntu/trusty64
        state: up
      with_items:
        - instance-1
        - instance-2

Destroy instances.

- hosts: localhost
  connection: local
  tasks:
    - name: Destroy instances
      molecule_vagrant:
        instance_name: "{{ item }}"
        platform_box: ubuntu/trusty64
        state: destroy
      with_items:
        - instance-1
        - instance-2

Halt instances (shutdown without destroy).

- hosts: localhost
  connection: local
  tasks:
    - name: Halt instances
      molecule_vagrant:
        instance_name: "{{ item }}"
        platform_box: ubuntu/trusty64
        state: halt
      with_items:
        - instance-1
        - instance-2

Create instances with interfaces.

- hosts: localhost
  connection: local
  tasks:
    - name: Create instance with interfaces
      molecule_vagrant:
        instance_name: instance-1
        instance_interfaces:
          - auto_config: true
            network_name: private_network
            type: dhcp
          - auto_config: false
            network_name: private_network
            type: dhcp
          - auto_config: true
            ip: 192.168.11.3
            network_name: private_network
            type: static
        platform_box: ubuntu/trusty64
        state: up

Create instances with additional provider options.

- hosts: localhost
  connection: local
  tasks:
    - name: Create instances
      molecule_vagrant:
        instance_name: "{{ item }}"
        platform_box: ubuntu/trusty64
        provider_name: virtualbox
        provider_memory: 1024
        provider_cpus: 4
        provider_raw_config_args:
          - "customize ['modifyvm', :id, '--cpuexecutioncap', '50']"
        provider_options:
          gui: true
        provision: true
        state: up
      with_items:
        - instance-1
        - instance-2

Create instances with additional instance options.

- hosts: localhost
  connection: local
  tasks:
    - name: Create instances
      molecule_vagrant:
        instance_name: "{{ item }}"
        platform_box: ubuntu/trusty64
        instance_raw_config_args:
          - "vm.network 'forwarded_port', guest: 80, host: 8080"
        state: up
      with_items:
        - instance-1
        - instance-2

Create instances on a remote Libvirt node using default create/destroy templates.

- hosts: localhost
  connection: local
  tasks:
    - name: Create instances
      molecule_vagrant:
        instance_name: "{{ item }}"
        platform_box: ubuntu/trusty64
        provider_raw_config_args:
          - 'host = "remote-node.example.com"'
          - 'connect_via_ssh = "True"'
          - 'username = "sshuser"'
          - 'driver = "kvm"'
          - 'cpu_mode = "host-passthrough"'
        state: up
      with_items:
        - instance-1
        - instance-2

Lint

Molecule handles project linting by invoking configurable linters.

Yaml Lint

class molecule.lint.yamllint.Yamllint

yamllint is the default projet linter.

yamllint is a linter for YAML files. In addition to checking for syntax validity it also checks for key repetition as well as cosmetic problems such as line length, trailing spaces, and indentation.

The default yamllint settings that ship with molecule can be found in the cookiecutter template.

Additional options can be passed to yamllint through the options dict. Any option set in this section will override the defaults. See the yamllint rules for more options.

lint:
  name: yamllint
  options:
    config-file: foo/bar

The project linting can be disabled by setting enabled to False.

lint:
  name: yamllint
  enabled: False

Environment variables can be passed to lint.

lint:
  name: yamllint
  env:
    FOO: bar

Paths can be ignored.

lint:
  name: yamllint
  options:
    config-data:
      ignore: path_to_ignore

Platforms

class molecule.platforms.Platforms

Platforms define the instances to be tested, and the groups to which the instances belong.

platforms:
  - name: instance-1

Multiple instances can be provided.

platforms:
  - name: instance-1
  - name: instance-2

Mapping instances to groups. These groups will be used by the Provisioner for orchestration purposes.

platforms:
  - name: instance-1
    groups:
      - group1
      - group2

Children allow the creation of groups of groups.

platforms:
  - name: instance-1
    groups:
      - group1
      - group2
    children:
      - child_group1

Provisioner

Molecule handles provisioning and converging the role.

Ansible

class molecule.provisioner.ansible.Ansible

Ansible is the default provisioner. No other provisioner will be supported.

Molecule’s provisioner manages the instances lifecycle. However, the user must provide the create, destroy, and converge playbooks. Molecule’s init subcommand will provide the necessary files for convenience.

Molecule will skip tasks which are tagged with either molecule-notest or notest. With the tag molecule-idempotence-notest tasks are only skipped during the idempotence action step.

Important

Reserve the create and destroy playbooks for provisioning. Do not attempt to gather facts or perform operations on the provisioned nodes inside these playbooks. Due to the gymnastics necessary to sync state between Ansible and Molecule, it is best to perform these tasks in the prepare or converge playbooks.

It is the developers responsiblity to properly map the modules’s fact data into the instance_conf_dict fact in the create playbook. This allows Molecule to properly configure Ansible inventory.

Additional options can be passed to ansible-playbook through the options dict. Any option set in this section will override the defaults.

Important

Options do not affect the create and destroy actions.

Note

Molecule will remove any options matching ‘^[v]+$’, and pass -vvv to the underlying ansible-playbook command when executing molecule –debug.

Molecule will silence log output, unless invoked with the --debug flag. However, this results in quite a bit of output. To enable Ansible log output, add the following to the provisioner section of molecule.yml.

provisioner:
  name: ansible
  log: True

The create/destroy playbooks for Docker and Vagrant are bundled with Molecule. These playbooks have a clean API from molecule.yml, and are the most commonly used. The bundled playbooks can still be overriden.

The playbook loading order is:

  1. provisioner.playbooks.$driver_name.$action

  2. provisioner.playbooks.$action

  3. bundled_playbook.$driver_name.$action

provisioner:
  name: ansible
  options:
    vvv: True
  playbooks:
    create: create.yml
    converge: playbook.yml
    destroy: destroy.yml

Share playbooks between roles.

provisioner:
  name: ansible
  playbooks:
    create: ../default/create.yml
    destroy: ../default/destroy.yml
    converge: playbook.yml

Multiple driver playbooks. In some situations a developer may choose to test the same role against different backends. Molecule will choose driver specific create/destroy playbooks, if the determined driver has a key in the playbooks section of the provisioner’s dict.

Important

If the determined driver has a key in the playbooks dict, Molecule will use this dict to resolve all provisioning playbooks (create/destroy).

provisioner:
  name: ansible
  playbooks:
    docker:
      create: create.yml
      destroy: destroy.yml
    create: create.yml
    destroy: destroy.yml
    converge: playbook.yml

Important

Paths in this section are converted to absolute paths, where the relative parent is the $scenario_directory.

The side effect playbook executes actions which produce side effects to the instances(s). Intended to test HA failover scenarios or the like. It is not enabled by default. Add the following to the provisioner’s playbooks section to enable.

provisioner:
  name: ansible
  playbooks:
    side_effect: side_effect.yml

Important

This feature should be considered experimental.

The prepare playbook executes actions which bring the system to a given state prior to converge. It is executed after create, and only once for the duration of the instances life.

This can be used to bring instances into a particular state, prior to testing.

provisioner:
  name: ansible
  playbooks:
    prepare: prepare.yml

The cleanup playbook is for cleaning up test infrastructure that may not be present on the instance that will be destroyed. The primary use-case is for “cleaning up” changes that were made outside of Molecule’s test environment. For example, remote database connections or user accounts. Intended to be used in conjunction with prepare to modify external resources when required.

The cleanup step is executed directly before every destroy step. Just like the destroy step, it will be run twice. An initial clean before converge and then a clean before the last destroy step. This means that the cleanup playbook must handle failures to cleanup resources which have not been created yet.

Add the following to the provisioner’s playbooks section to enable.

provisioner:
  name: ansible
  playbooks:
    cleanup: cleanup.yml

Important

This feature should be considered experimental.

Environment variables. Molecule does its best to handle common Ansible paths. The defaults are as follows.

ANSIBLE_ROLES_PATH:
  $ephemeral_directory/roles/:$project_directory/../
ANSIBLE_LIBRARY:
  $ephemeral_directory/library/:$project_directory/library/
ANSIBLE_FILTER_PLUGINS:
  $ephemeral_directory/plugins/filters/:$project_directory/filter/plugins/

Environment variables can be passed to the provisioner. Variables in this section which match the names above will be appened to the above defaults, and converted to absolute paths, where the relative parent is the $scenario_directory.

Important

Paths in this section are converted to absolute paths, where the relative parent is the $scenario_directory.

provisioner:
  name: ansible
  env:
    FOO: bar

Modifying ansible.cfg.

provisioner:
  name: ansible
  config_options:
    defaults:
      fact_caching: jsonfile
    ssh_connection:
      scp_if_ssh: True

Important

The following keys are disallowed to prevent Molecule from improperly functioning. They can be specified through the provisioner’s env setting described above, with the exception of the privilege_escalation.

provisioner:
  name: ansible
  config_options:
    defaults:
      roles_path: /path/to/roles_path
      library: /path/to/library
      filter_plugins: /path/to/filter_plugins
    privilege_escalation: {}

Roles which require host/groups to have certain variables set. Molecule uses the same variables defined in a playbook syntax as Ansible.

provisioner:
  name: ansible
  inventory:
    group_vars:
      foo1:
        foo: bar
      foo2:
        foo: bar
        baz:
          qux: zzyzx
    host_vars:
      foo1-01:
        foo: bar

Molecule automatically generates the inventory based on the hosts defined under Platforms. Using the hosts key allows to add extra hosts to the inventory that are not managed by Molecule.

A typical use case is if you want to access some variables from another host in the inventory (using hostvars) without creating it.

Note

The content of hosts should follow the YAML based inventory syntax: start with the all group and have hosts/vars/children entries.

provisioner:
  name: ansible
  inventory:
    hosts:
      all:
        extra_host:
          foo: hello

Important

The extra hosts added to the inventory using this key won’t be created/destroyed by Molecule. It is the developers responsibility to target the proper hosts in the playbook. Only the hosts defined under Platforms should be targetted instead of all.

An alternative to the above is symlinking. Molecule creates symlinks to the specified directory in the inventory directory. This allows ansible to converge utilizing its built in host/group_vars resolution. These two forms of inventory management are mutually exclusive.

Like above, it is possible to pass an additional inventory file (or even dynamic inventory script), using the hosts key. Ansible will automatically merge this inventory with the one generated by molecule. This can be useful if you want to define extra hosts that are not managed by Molecule.

Important

Again, it is the developers responsibility to target the proper hosts in the playbook. Only the hosts defined under Platforms should be targetted instead of all.

Note

The source directory linking is relative to the scenario’s directory.

The only valid keys are hosts, group_vars and host_vars. Molecule’s schema validator will enforce this.

provisioner:
  name: ansible
  inventory:
    links:
      hosts: ../../../inventory/hosts
      group_vars: ../../../inventory/group_vars/
      host_vars: ../../../inventory/host_vars/

Override connection options:

provisioner:
  name: ansible
  connection_options:
    ansible_ssh_user: foo
    ansible_ssh_common_args: -o IdentitiesOnly=no

Add arguments to ansible-playbook when running converge:

provisioner:
  name: ansible
  ansible_args:
    - --inventory=mygroups.yml
    - --limit=host1,host2

Lint

Molecule handles provisioner linting by invoking configurable linters.

class molecule.provisioner.lint.ansible_lint.AnsibleLint

Ansible Lint is the default role linter.

Ansible Lint checks playbooks for practices, and behaviour that could potentially be improved.

Additional options can be passed to ansible-lint through the options dict. Any option set in this section will override the defaults.

provisioner:
  name: ansible
  lint:
    name: ansible-lint
    options:
      exclude:
        - path/exclude1
        - path/exclude2
      x: ["ANSIBLE0011,ANSIBLE0012"]
      force-color: True

The x option has to be passed like this due to a bug in Ansible Lint.

The role linting can be disabled by setting enabled to False.

provisioner:
  name: ansible
  lint:
    name: ansible-lint
    enabled: False

Environment variables can be passed to lint.

provisioner:
  name: ansible
  lint:
    name: ansible-lint
    env:
      FOO: bar

Scenario

Molecule treats scenarios as a first-class citizens, with a top-level configuration syntax.

class molecule.scenario.Scenario

A scenario allows Molecule test a role in a particular way, this is a fundamental change from Molecule v1.

A scenario is a self-contained directory containing everything necessary for testing the role in a particular way. The default scenario is named default, and every role should contain a default scenario.

Unless mentioned explicitly, the scenario name will be the directory name hosting the files.

Any option set in this section will override the defaults.

scenario:
  name: default  # optional
  create_sequence:
    - dependency
    - create
    - prepare
  check_sequence:
    - dependency
    - cleanup
    - destroy
    - create
    - prepare
    - converge
    - check
    - destroy
  converge_sequence:
    - dependency
    - create
    - prepare
    - converge
  destroy_sequence:
    - dependency
    - cleanup
    - destroy
  test_sequence:
    - lint
    - dependency
    - cleanup
    - destroy
    - syntax
    - create
    - prepare
    - converge
    - idempotence
    - side_effect
    - verify
    - cleanup
    - destroy

State

An internal bookkeeping mechanism.

class molecule.state.State

A class which manages the state file. Intended to be used as a singleton throughout a given Molecule config. The initial state is serialized to disk if the file does not exist, otherwise is deserialized from the existing state file. Changes made to the object are immediately serialized.

State is not a top level option in Molecule’s config. It’s purpose is for bookkeeping, and each Config object has a reference to a State object.

Note

Currently, it’s use is significantly smaller than it was in v1 of Molecule.

Verifier

Molecule handles role testing by invoking configurable verifiers.

Ansible

class molecule.verifier.ansible.Ansible

Ansible is not the default test runner.

Molecule executes a playbook (verify.yml) located in the role’s scenario.directory.

verifier:
  name: ansible
  lint:
    name: ansible-lint

The testing can be disabled by setting enabled to False.

verifier:
  name: ansible
  enabled: False

Environment variables can be passed to the verifier.

verifier:
  name: ansible
  env:
    FOO: bar

Lint

class molecule.verifier.lint.ansible_lint.AnsibleLint

Ansible Lint is not the default verifier linter.

Ansible Lint checks playbooks for practices, and behaviour that could potentially be improved.

Additional options can be passed to ansible-lint through the options dict. Any option set in this section will override the defaults.

verifier:
  name: ansible
  lint:
    name: ansible-lint
    options:
      exclude:
        - path/exclude1
        - path/exclude2
      x: ["ANSIBLE0011,ANSIBLE0012"]
      force-color: True

The x option must be passed like this due to a bug in Ansible Lint.

The role linting can be disabled by setting enabled to False.

verifier:
  name: ansible
  lint:
    name: ansible-lint
    enabled: False

Environment variables can be passed to lint.

verifier:
  name: ansible
  lint:
    name: ansible-lint
    env:
      FOO: bar

Goss

class molecule.verifier.goss.Goss

Goss is not the default test runner.

Goss is a YAML based serverspec-like tool for validating a server’s configuration. Goss is not the default verifier used in Molecule.

Molecule executes a playbook (verify.yml) located in the role’s scenario.directory. This playbook will copy YAML files to the instances, and execute Goss using a community written Goss Ansible module bundled with Molecule.

Additional options can be passed to goss validate by modifying the verify playbook.

verifier:
  name: goss
  lint:
    name: yamllint

The testing can be disabled by setting enabled to False.

verifier:
  name: goss
  enabled: False

Environment variables can be passed to the verifier.

verifier:
  name: goss
  env:
    FOO: bar

Change path to the test directory.

verifier:
  name: goss
  directory: /foo/bar/

All files starting with test_* will be copied to all molecule hosts. Files matching the regular expression test_host_$instance_name[-.w].yml will only run on $instance_name. If you have 2 molecule instances, instance1 and instance2, your test files could look like this:

test_default.yml (will run on all hosts)
test_host_instance1.yml (will run only on instance1)
test_host_instance2.yml (will run only on instance2)

Important

Due to the nature of this verifier. Molecule does not perform options handling in the same fashion as Testinfra.

Lint

The Goss verifier does not utilize a linter.

Inspec

class molecule.verifier.inspec.Inspec

Inspec is not the default test runner.

InSpec is Chef’s open-source language for describing security & compliance rules that can be shared between software engineers, operations, and security engineers. Your compliance, security, and other policy requirements become automated tests throughout all stages of the software delivery process. Inspec is not the default verifier used in Molecule.

Molecule executes a playbook (verify.yml) located in the role’s scenario.directory. This playbook will copy test files to the instances, and execute Inspec locally over Ansible. Molecule executes Inspec over an Ansible transport, in an attempt to provide Inspec support across all Molecule drivers.

Additional options can be passed to inspec exec by modifying the verify playbook.

The testing can be disabled by setting enabled to False.

verifier:
  name: inspec
  enabled: False

Environment variables can be passed to the verifier.

verifier:
  name: inspec
  env:
    FOO: bar

Change path to the test directory.

verifier:
  name: inspec
  directory: /foo/bar/

Important

Due to the nature of this verifier. Molecule does not perform options handling in the same fashion as Testinfra.

Lint

class molecule.verifier.lint.rubocop.RuboCop

RuboCop is not the default verifier linter.

RuboCop is a linter for ruby files.

Additional options can be passed to rubocop through the options dict. Any option set in this section will override the defaults.

verifier:
  name: inspec
  lint:
    name: rubocop
    options:
      auto-correct: True

Test file linting can be disabled by setting enabled to False.

verifier:
  name: inspec
  lint:
    name: rubocop
    enabled: False

Environment variables can be passed to lint.

verifier:
  name: inspec
  lint:
    name: rubocop
    env:
      FOO: bar

Testinfra

class molecule.verifier.testinfra.Testinfra

Testinfra is the default test runner.

Additional options can be passed to testinfra through the options dict. Any option set in this section will override the defaults.

Note

Molecule will remove any options matching ‘^[v]+$’, and pass -vvv to the underlying pytest command when executing molecule --debug.

verifier:
  name: testinfra
  options:
    n: 1

The testing can be disabled by setting enabled to False.

verifier:
  name: testinfra
  enabled: False

Environment variables can be passed to the verifier.

verifier:
  name: testinfra
  env:
    FOO: bar

Change path to the test directory.

verifier:
  name: testinfra
  directory: /foo/bar/

Additional tests from another file or directory relative to the scenario’s tests directory (supports regexp).

verifier:
  name: testinfra
  additional_files_or_dirs:
    - ../path/to/test_1.py
    - ../path/to/test_2.py
    - ../path/to/directory/*

Lint

class molecule.verifier.lint.flake8.Flake8

Flake8 is the default verifier linter.

Flake8 is a linter for python files.

Additional options can be passed to flake8 through the options dict. Any option set in this section will override the defaults.

verifier:
  name: testinfra
  lint:
    name: flake8
    options:
      benchmark: True

Test file linting can be disabled by setting enabled to False.

verifier:
  name: testinfra
  lint:
    name: flake8
    enabled: False

Environment variables can be passed to lint.

verifier:
  name: testinfra
  lint:
    name: flake8
    env:
      FOO: bar
class molecule.verifier.lint.precommit.PreCommit

Pre-commit tool verifier wrapper.

This class is used to lint files by executing the pre-commit command line tool for files in the test folder with a prefix of test_.

Pre-Commit is not the default verifier linter.

Pre-Commit is a linter for python files and more.

Additional options can be passed to pre-commit through the options dict. Any option set in this section will override the defaults.

verifier:
  name: testinfra
  lint:
    name: pre-commit
    options:
      remove-tabs:

Test file linting can be disabled by setting enabled to False.

verifier:
  name: testinfra
  lint:
    name: pre-commit
    enabled: False

Environment variables can be passed to lint.

verifier:
  name: testinfra
  lint:
    name: pre-commit
    env:
      FOO: bar

Example pre-commit configuration file (.pre-commit-config.yaml) to run flake8.

repos:
  - repo: local
    hooks:
      - id: flake8
        name: flake8
        entry: python -m flake8 --max-line-length=120
        language: system
        types: [python]