Posted on 2018-03-18
Ansible 2.5 is just around the corner, perfect timing to show some of the new features I was involved with and included in this release. This is the first part of a post series What’s new in Ansible 2.5.
Vultr is a Public Cloud Service (IaaS) with a manageable feature set and datacenters in around 15 locations around the globe including North America, Europe, Asia and Australia.
The features include a.o. classical virtual servers, bare metal servers, firewall management, block storage, free DNS service, custom ISOs and predefined apps. An easy to use user interface allows to configure all of these services manually but unsurprisingly Vutlr also provides an API for a programming interface.
The modules related to Vultr included in 2.5 (Ansible docs) do not yet cover all APIs but some of the most interesting ones:
These modules allow to deploy a server with your selected plan in a chosen region with an SSH key, configure the firewall group and rules and run start scripts on the server.
So let’s get started quickly by creating a new account (You support my works by using this affiliate link).
The modules uses the API and have to authenticate. So the first thing is to allow the modules to access the account using the API. You find the API key in your Account settings in the UI.
There are several ways to pass the API key to the modules. We won’t cover every option for now, just the most common way: create a .vultr.ini
in your home directory just like the following:
[default]
key = <your api key>
Run a test, get some infos about your account:
$ ansible -m vr_account_facts localhost
The output we will get should look something like:
localhost | SUCCESS => {
"ansible_facts": {
"vultr_account_facts": {
"balance": -212.87,
"last_payment_amount": -250.0,
"last_payment_date": "2017-04-28 12:29:50",
"pending_charges": 0.06
}
},
"changed": false,
"vultr_account_facts": {
"balance": -212.87,
"last_payment_amount": -250.0,
"last_payment_date": "2017-04-28 12:29:50",
"pending_charges": 0.06
},
"vultr_api": {
"api_account": "default",
"api_endpoint": "https://api.vultr.com",
"api_retries": 5,
"api_timeout": 60
}
}
But what just happened? We run the module vr_account_facts
locally, the module itself connects to the API by HTTPs. There is one more cool thing, did you note we didn’t have to install any other dependencies other then Ansible? Pretty nice isn’t it?
When authentication was successful, we can go to the next step, deploying our first server.
But first things first, create a inventory which contains the server we want to deploy, we use a classical INI style ansible inventory named production
One server, the webserver is called web-01
and we put it in the group cloud
, this is just enough for the moment.
mkdir hosts
echo "[cloud]\nweb-01" > ./hosts/production
When we check the inventory with the command introduced in 2.4, ansible-inventory
and pass the right arguments
ansible-inventory --inventory hosts/production --list
We should see a nice json about view of our inventory:
{
"_meta": {
"hostvars": {
"web-01": {}
}
},
"all": {
"children": [
"cloud",
"ungrouped"
]
},
"cloud": {
"hosts": [
"web-01"
]
},
"ungrouped": {}
}
So far, so good.
As you may know, a playbook is usually a YAML document containing one or more plays with tasks for a target host or host group. That is just what we need:
mkdir playbooks
touch playbooks/cloud.yml
In the first play, we are going to deploy our cloud server defined in our production inventory.
- hosts: cloud
gather_facts: no
tasks:
- name: Ensure a cloud server exists
local_action:
module: vr_server
name: "{{ inventory_hostname_short }}"
os: "CentOS 7 x64"
plan: "2048 MB RAM,40 GB SSD,2.00 TB BW"
region: New Jersey
We run the module as local action, that is why we turned off facts gathering as it would fail in case the server does not yet exist.
The playbook is ready, let’s give it a shot in --check
mode:
ansible-playbook playbooks/cloud.yml --inventory hosts/production --check --diff -v
No config file found; using defaults
PLAY [cloud] *******************************************************************
TASK [Ensure a cloud server exists] ********************************************
changed: [web-01 -> localhost] => {"changed": true, "vultr_api": {"api_account": "default", "api_endpoint": "https://api.vultr.com", "api_retries": 5, "api_timeout": 60}, "vultr_server": {}}
PLAY RECAP *********************************************************************
web-01 : ok=1 changed=1 unreachable=0 failed=0
Before we continue without --check
mode, I must note, that Vultr is quite popular and especially for datacenters located in Europe, plans may run out. If this happens, the module will fail but will give a decent error message:
fatal: [web-01 -> localhost]: FAILED! => {"changed": true, "msg": "URL https://api.vultr.com/v1/server/create, method POST with data OSID=167&DCID=9&VPSPLANID=201¬ify_activate=no&label=web-01. Returned 412, with body: HTTP Error 412: Request Failed Plan is not available in the selected datacenter. This could mean you have chosen the wrong plan (for example, a storage plan in a location that does not offer them), or the location you have selected does not have any more capacity.", "vultr_api": {"api_account": "default", "api_endpoint": "https://api.vultr.com", "api_retries": 5, "api_timeout": 60}, "vultr_server": {}}
Use a Vultr CLI e.g. https://github.com/JamesClonk/vultr to get a list of available plans per region (DCID):
vultr plans -r <DCID>
Okay, back to the playbook,
$ ansible-playbook playbooks/cloud.yml --inventory hosts/production --diff -v
No config file found; using defaults
PLAY [cloud] *******************************************************************
TASK [Ensure a cloud server exists] ********************************************
changed: [web-01 -> localhost] => {"changed": true, "vultr_api": {"api_account": "default", "api_endpoint": "https://api.vultr.com", "api_retries": 5, "api_timeout": 60}, "vultr_server": {"allowed_bandwidth_gb": 2000, "auto_backup_enabled": false, "cost_per_month": 10.0, "current_bandwidth_gb": 0, "date_created": "2018-03-18 12:54:29", "default_password": "aV6=DY}U(Y)n_x3,", "disk": "Virtual 40 GB", "firewall_group": null, "id": "14294916", "internal_ip": "", "kvm_url": "https://my.vultr.com/subs/vps/novnc/api.php?data=GF3VUMSQJZWWMRKBKR2XISLKKRJXOZZZIY4GK5DZN44EO6THKY3U423YI5CU4NLTJZFES6TBNYYGKTSYNNEWMRLNIZ4FS3BTJVDUIZKJHF4XQYRWF5KWSQRYJVVFGMBXLJETMTC2HEZHK42NLFZVU4ZRKBSWIURSNZWXKV3GG52UWQRLKJZXQOKMIQVXS2KWJV3DAZSGKJRGG2SBOB3VQT3YMFXGIZTVOU2S6STFOFXEKWDEMRKVE2TPNNLGWU3QJ5RESURTJZIFA6BWM46Q", "name": "web-01", "os": "CentOS 7 x64", "pending_charges": 0.02, "plan": "2048 MB RAM,40 GB SSD,2.00 TB BW", "power_status": "running", "ram": "2048 MB", "region": "New Jersey", "server_state": "ok", "status": "active", "tag": "", "v4_gateway": "207.246.94.1", "v4_main_ip": "207.246.95.35", "v6_main_ip": "", "v6_network": "", "v6_network_size": "", "v6_networks": [], "vcpu_count": 1}}
PLAY RECAP *********************************************************************
web-01 : ok=1 changed=1 unreachable=0 failed=0
That seems to have worked!
However you may feel like what a mess of output. This is because we also added -v
to get a verbose output. You are right. I wanted to show, that the module does return a lot of data which can be used later when registered in a variable, e.g. the vultr_server.default_password
to login by SSH or the vultr_server.v4_main_ip
which can be used later for a DNS A-record.
Is this it? Well, we have a lot more things to cover but this is enough for today. Stay tuned for the next part of this series.