Example projects showing how to do test-driven development of Ansible roles and running those tests on multiple Cloud providers at the same time
This project build on top of molecule-ansible-docker-vagrant, where all the basics on how to do test-driven development of Ansible roles with Molecule is described. Have a look into the blog series so far:
- Test-driven infrastructure development with Ansible & Molecule
- Continuous Infrastructure with Ansible, Molecule & TravisCI
- Continuous cloud infrastructure with Ansible, Molecule & TravisCI on AWS
Developing infrastructure code according to prinicples like test-driven development and continuous integration is really great! But what about pushing this to the next level? As Molecule is able to handle everything Ansible is albe to access, why not run our test automatically on all major cloud platforms at the same time?
With this, we would not only have a security net for our infrastructure code, but would also be safe regarding a switch of our current cloud or data center provider. Lot's of people talk about the unclear costs of this switch. **** If our infrastructure code would be able to run on every cloud platform possible, we would simply be able to switch to whatever platform we want - and all with just the virtually no expenses.Why not just reduce these to zero?!
Let's start with AWS by just forking molecule-ansible-google-cloud, since there should be mostly everything needed to use Molecule with a Cloud provider.
First, you'll need a valid Azure account, which happens to be a Microsoft account (you could also use that to access Office 365 and other things). If everything is fine with your account, you should be able to access the Azure Portal at https://portal.azure.com/#home:
According to the Molecule docs about the Azure driver, we then we need to install Azure support for Molecule:
pip3 install ansible[azure]
Compared to AWS and GCE this time we install pip's Ansible package with Azure support, not Molecule itself.
Now let's initialize a new Molecule scenario calles azure-ubuntu
inside our Ansible role:
cd molecule-ansible-azure/docker
molecule init scenario --driver-name azure --role-name docker --scenario-name azure-ubuntu
That should create a new directory azure-ubuntu
inside the docker/molecule
folder. We'll integrate the results into our multi scenario project in a second.
Now let's dig into the generated molecule.yml:
scenario:
name: azure-ubuntu
driver:
name: azure
platforms:
- name: azure-ubuntu
provisioner:
name: ansible
lint:
name: ansible-lint
enabled: false
playbooks:
converge: ../playbook.yml
lint:
name: yamllint
enabled: false
verifier:
name: testinfra
directory: ../tests/
env:
# get rid of the DeprecationWarning messages of third-party libs,
# see https://docs.pytest.org/en/latest/warnings.html#deprecationwarning-and-pendingdeprecationwarning
PYTHONWARNINGS: "ignore:.*U.*mode is deprecated:DeprecationWarning"
lint:
name: flake8
options:
# show which tests where executed in test output
v: 1
As we already tuned the molecule.yml
files for our other scenarios like aws-ec2-ubuntu
, we know what to change here. provisioner.playbook.converge
needs to be configured, so the one playbook.yml
could be found.
Also the verifier
section has to be enhanced to gain all the described advantages like supressed deprecation warnings and the better test result overview.
As you may noticed, the driver now uses azure
and the platform is pre-configured with only a concrete name
. Here we just tune the instance name to azure-ubuntu
.
Compared to the AWS and GCE Molecule drivers, these are only one configuration parameters. But there have to be more, just think about region or image configuration! Therefore we need to dive into the create.yml:
- name: Create
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not (lookup('env', 'MOLECULE_DEBUG') | bool or molecule_yml.provisioner.log|default(false) | bool) }}"
vars:
resource_group_name: molecule
location: westus
ssh_user: molecule
ssh_port: 22
virtual_network_name: molecule_vnet
subnet_name: molecule_subnet
keypair_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key"
tasks:
...
- name: Create molecule instance(s)
azure_rm_virtualmachine:
resource_group: "{{ resource_group_name }}"
name: "{{ item.name }}"
vm_size: Standard_A0
admin_username: "{{ ssh_user }}"
public_ip_allocation_method: Dynamic
ssh_password_enabled: false
ssh_public_keys:
- path: "/home/{{ ssh_user }}/.ssh/authorized_keys"
key_data: "{{ keypair.ssh_public_key }}"
image:
offer: CentOS
publisher: OpenLogic
sku: '7.4'
version: latest
register: server
with_items: "{{ molecule_yml.platforms }}"
async: 7200
poll: 0
...
And there we are! Molecule makes heavy usage of Ansible's azure_rm_virtualmachine module.
Now as we chose to implement the use case of a standard Ubuntu Docker installation, we need to switch the image.offer
to another fitting one. So let's adhere to the docs' standard way and use Azure CLI to list available image configurations for our location.
Therefore Azure CLI needs to be available on your machine. On my Mac I use brew install azure-cli
to install it. Now we can do:
$ az vm image list --output table
You are viewing an offline list of images, use --all to retrieve an up-to-date list
Offer Publisher Sku Urn UrnAlias Version
------------- ---------------------- ------------------ -------------------------------------------------------------- ------------------- ---------
CentOS OpenLogic 7.5 OpenLogic:CentOS:7.5:latest CentOS latest
CoreOS CoreOS Stable CoreOS:CoreOS:Stable:latest CoreOS latest
Debian credativ 9 credativ:Debian:9:latest Debian latest
openSUSE-Leap SUSE 42.3 SUSE:openSUSE-Leap:42.3:latest openSUSE-Leap latest
RHEL RedHat 7-RAW RedHat:RHEL:7-RAW:latest RHEL latest
SLES SUSE 15 SUSE:SLES:15:latest SLES latest
UbuntuServer Canonical 18.04-LTS Canonical:UbuntuServer:18.04-LTS:latest UbuntuLTS latest
WindowsServer MicrosoftWindowsServer 2019-Datacenter MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest Win2019Datacenter latest
WindowsServer MicrosoftWindowsServer 2016-Datacenter MicrosoftWindowsServer:WindowsServer:2016-Datacenter:latest Win2016Datacenter latest
WindowsServer MicrosoftWindowsServer 2012-R2-Datacenter MicrosoftWindowsServer:WindowsServer:2012-R2-Datacenter:latest Win2012R2Datacenter latest
WindowsServer MicrosoftWindowsServer 2012-Datacenter MicrosoftWindowsServer:WindowsServer:2012-Datacenter:latest Win2012Datacenter latest
WindowsServer MicrosoftWindowsServer 2008-R2-SP1 MicrosoftWindowsServer:WindowsServer:2008-R2-SP1:latest Win2008R2SP1 latest
As there we can spot a fitting Ubuntu 18.04 image inside the list, we should be able to configure Molecule. As we already saw inside the generated create.yml, the azure_rm_virtualmachine
module uses a with_items: "{{ molecule_yml.platforms }}"
configuration, so we only need to change the create.yml
sligthly:
...
- name: Create molecule instance(s)
azure_rm_virtualmachine:
...
image: "{{ item.image }}"
register: server
with_items: "{{ molecule_yml.platforms }}"
async: 7200
poll: 0
...
With this, we can now move to our molecule.yml and configure the Azure image:
scenario:
name: gcp-gce-ubuntu
driver:
name: azure
platforms:
- name: azure-ubuntu
image:
offer: UbuntuServer
publisher: Canonical
sku: 18.04-LTS
version: latest
...
We shouldn't forget the configuration of our Azure location (compare with GCP's zone and AWS' region). To find out the correct location, we can leverage the Azure CLI again. As the docs state, there is az account list-locations
to list the configured location for your account. Running the command will maybe result in the following error:
$ az account list-locations
Please run 'az login' to setup account.
Now to interact with the az account
commands, you'll need a valid Azure subscription. You can start with the free 12 month subscription for example. If you entered everything, the subscription should be available inside the Azure Portal and the azure login
command should work like this:
$ az login
Note, we have launched a browser for you to login. For old experience with device code, use "az login --use-device-code"
You have logged in. Now let us find all the subscriptions to which you have access...
[
{
"cloudName": "AzureCloud",
"id": "1f0021b3-xxx-xxxx-xxxx-xxxxxxxxxxx",
"isDefault": true,
"name": "Free Trial",
"state": "Enabled",
"tenantId": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
"user": {
"name": "jonas.hecht@codecentric.de",
"type": "user"
}
}
]
Having the Azure CLI successfully logged in, we should try to run az account list-locations
again. Just pick a location, which suits you best. I took westeurope
for example and change the create.yml:
- name: Create
...
vars:
resource_group_name: molecule
location: westeurope
ssh_user: molecule
ssh_port: 22
Now we should have everything prepared. Let's try to run our first Molecule test on Azure (including --debug
so that we see what's going on):
molecule --debug create --scenario-name azure-ubuntu
Open your Google Cloud Compute Engine dashboard and you should see the instance beeing created by Molecule: