Coder Social home page Coder Social logo

ansible-vultr's Introduction

ansible-vultr

Ansible module for managing servers on Vultr. At the moment the module supports only server creation and destruction.

Installation

$ cd path-to-playbook-dir
$ mkdir library
$ git clone [email protected]:tundrax/ansible-vultr.git library/vultr

NOTE: Ansible 2.x users must set ANSIBLE_LIBRARY=./library.

Usage example

This is the main playbook for dynamic inventory provisioning using Vultr.

---
- hosts: localhost
  connection: local
  gather_facts: false

  vars:
    api_key: YOUR_API_KEY
    servers:
      # ------------------------------------------------
      # - backend
      # ------------------------------------------------
      - { label: "api.example.com",  group: "lb" }
      - { label: "app1.example.com", group: "app" }
      - { label: "app2.example.com", group: "app" }
      - { label: "mdb1.example.com", group: "db" }
      # ------------------------------------------------
      # - frontend
      # ------------------------------------------------
      - { label: "example.com", group: "web" }
  tasks:
    - name: Provision Vultr servers
      vultr:
        command: server
        api_key: "{{ api_key }}"
        state: "{{ item.state | default('present') }}"
        label: "{{ item.label }}"
        DCID: "{{ item.DCID | default(25) }}" # Tokyo
        VPSPLANID: "{{ item.VPSPLANID | default(201) }}" # 1024MB / 25GB SSD
        OSID: "{{ item.OSID | default(167) }}" # CentOS 7x64
        SSHKEYID: "{{ item.SSHKEYID | default(YOUR_SSH_KEY_ID) }}"
        enable_private_network: yes
        unique_label: yes
      register: created_servers
      with_items: servers
    # ------------------------------------------------
    # - Append servers to corresponding groups
    # ------------------------------------------------
    - name: Add Vultr hosts to inventory groups
      add_host:
        name: "{{ item.1.server.main_ip }}"
        groups: "cloud,{{ servers[item.0].group }},{{ item.1.server.label }}"
        label: "{{ item.1.server.label }}"
        internal_ip: "{{ item.1.server.internal_ip }}"
      when: item.1.server is defined
      with_indexed_items: created_servers.results

Example playbook for deploying a custom OS using a custom ISO

You will need the ISOID for any custom ISOs you've already uploaded to Vultr. These are retrievable via the following command:

$ curl -H 'API-Key: YOUR_API_KEY' https://api.vultr.com/v1/iso/list

This is the main playbook for deploying a custom OS using a custom uploaded ISO.

---
- hosts: localhost
  connection: local
  gather_facts: false

  vars:
    api_key: YOUR_API_KEY
    servers:
      - { label: "example.com", group: "web", OSID: "159", ISOID: YOUR_ISO_ID }
  tasks:
    - name: Provision Vultr servers
      vultr:
        command: server
        api_key: "{{ api_key }}"
        state: "{{ item.state | default('present') }}"
        label: "{{ item.label }}"
        DCID: "{{ item.DCID | default(25) }}" # Tokyo
        VPSPLANID: "{{ item.VPSPLANID | default(201) }}" # 1024MB / 25GB SSD
        OSID: "{{ item.OSID | default(159) }}" # Custom OS
        ISOID: "{{ item.ISOID | default(0) }}"
        SSHKEYID: "{{ item.SSHKEYID | default(YOUR_SSH_KEY_ID) }}"
        enable_private_network: yes
        unique_label: yes
      register: created_servers
      with_items: servers
    # ------------------------------------------------
    # - Append servers to corresponding groups
    # ------------------------------------------------
    - name: Add Vultr hosts to inventory groups
      add_host:
        name: "{{ item.1.server.main_ip }}"
        groups: "cloud,{{ servers[item.0].group }},{{ item.1.server.label }}"
        label: "{{ item.1.server.label }}"
        internal_ip: "{{ item.1.server.internal_ip }}"
      when: item.1.server is defined
      with_indexed_items: created_servers.results

Optional Parameters

The following optional parameters may be passed along to the server command:

  • ISOID
  • hostname
  • tag
  • snapshotid
  • reservered_ip_v4
  • auto_backups
  • ddos_protection
  • notify_activate

Known issues

When you deploy a new server on Vultr, you should wait until initialization finishes. In ansible we accomplish this using wait_for module. Below, the first task that should run on all servers is to wait for port 22 to become available. Once port 22 is active - ping all servers. At this step port 22 may have become available, but your ssh key has not been copied to authorized_keys yet. Hence you will get denied access error. Rerun the playbook 2-3 seconds later, all should go fine.

# ------------------------------------------------
# - Run below tasks on group 'cloud', which contains
# - all servers being provisioned
# ------------------------------------------------
- hosts: cloud
  remote_user: root

  tasks:
    - name: Wait for port 22 to become available
      local_action: "wait_for port=22 host={{ inventory_hostname }}"

    - name: Ping pong all hosts
      ping:

    - name: Ensure hostname is preserved in cloud-init
      lineinfile: "dest=/etc/cloud/cloud.cfg regexp='^preserve_hostname' line='preserve_hostname: true' state=present"

    - name: Set hostname in sysconfigs
      lineinfile: dest=/etc/sysconfig/network regexp="^HOSTNAME" line='HOSTNAME="{{ hostvars[inventory_hostname].label }}"' state=present
      register: hostname

    - name: Set hosts FQDN
      lineinfile: dest=/etc/hosts regexp=".*{{ hostvars[inventory_hostname].label }}$" line="{{ inventory_hostname }} {{ hostvars[inventory_hostname].label }}" state=present
      register: fqdn

    - name: Set hostname
      hostname: name={{ hostvars[inventory_hostname].label }}
      when: hostname.changed or fqdn.changed

    - name: Configure eth1 (private network)
      template: src=ifcfg-eth1.j2 dest=/etc/sysconfig/network-scripts/ifcfg-eth1
      register: ifcfg_eth1

    - name: Enable eth1 (private network)
      service: name=network state=restarted
      when: hostname.changed or fqdn.changed or ifcfg_eth1.changed

As stated in "Configure eth1 (private network)" task, below is the interface config file. This file should be located in the same folder as the playbook.

# ifcgf-eth1.j2
DEVICE="eth1"
ONBOOT="yes"
NM_CONTROLLED="no"
BOOTPROTO="static"
IPADDR="{{ hostvars[inventory_hostname].internal_ip }}"
NETMASK="255.255.0.0"
IPV6INIT="no"

ansible-vultr's People

Contributors

hedzr avatar lvnilesh avatar noplanman avatar scottjbarr avatar sergeifilippov avatar sher avatar spencersharkey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ansible-vultr's Issues

Playbook fails

Hi there,

The example playbook you posted in the README.md file no longer works. The issues are in these lines:

with_items: servers
with_indexed_items: created_servers.results

I'm still learning Ansible so I don't know the how/why/when this has changed, but these changes will work:
with_items: "{{ servers }}"
with_indexed_items: "{{ created_servers.results }}"

Hope that helps and thanks for the Vultr library.

Cheers.

Python 3

This module doesn't work as-is with Python 3, as some code isn't compatible.
From what I've seen, it's the exception handling syntax that is a bit different for Python 3, but I'm not sure that's all there is to it.

I'd be happy to PR this.

SCRIPTID support

hi! I have patch which helps to SCRIPTID working

48c48
<     def server_create(self, label, vpsplanid, osid, dcid, sshkeyid, enable_private_network, enable_backups, isoid=None, snapshotid=None, hostname=None, tag=None, reserved_ip_v4=None, auto_backups=None, ddos_protection=None, notify_activate=None):
---
>     def server_create(self, label, vpsplanid, osid, dcid, sshkeyid, enable_private_network, enable_backups, isoid=None, scriptid=None, snapshotid=None, hostname=None, tag=None, reserved_ip_v4=None, auto_backups=None, ddos_protection=None, notify_activate=None):
59a60,63
> <<<<<<< HEAD
>         if scriptid:  data['SCRIPTID'] = scriptid
> =======
> >>>>>>> 77cfc99d531a2a3e8d42f868f511040327822560
184,185c188,189
<     def add(cls, label, VPSPLANID, OSID, DCID, SSHKEYID=None, enable_private_network=False, enable_backups=False, ISOID=None, snapshotid=None, hostname=None, tag=None, reserved_ip_v4=None, auto_backups=None, ddos_protection=None, notify_activate=None):
<         json = driver.server_create(label, VPSPLANID, OSID, DCID, SSHKEYID, enable_private_network, enable_backups,ISOID,snapshotid,hostname,tag,reserved_ip_v4,auto_backups,ddos_protection,notify_activate)
---
>     def add(cls, label, VPSPLANID, OSID, DCID, SSHKEYID=None, enable_private_network=False, enable_backups=False, ISOID=None, SCRIPTID=None, snapshotid=None, hostname=None, tag=None, reserved_ip_v4=None, auto_backups=None, ddos_protection=None, notify_activate=None):
>         json = driver.server_create(label, VPSPLANID, OSID, DCID, SSHKEYID, enable_private_network, enable_backups,ISOID,SCRIPTID,snapshotid,hostname,tag,reserved_ip_v4,auto_backups,ddos_protection,notify_activate)
219a224
>                     SCRIPTID=module.params['SCRIPTID'],
268a274
>             SCRIPTID = dict(type='int'),
300c306
< main()
\ No newline at end of file
---
> main()

Parameters not working properly

EDIT: Whoops, just saw #14 which fixes exactly this issue!

Even though I have notify_activate set to no (or false), I get a notification.

Checking the code, I think the problem is that the value doesn't get added to the data parameter, because it evaluates to false to begin with.

e.g. https://github.com/tundrax/ansible-vultr/blob/efdfe8a1be0e4ad2deab74bf8b429d7ea3321a68/vultr.py#L62

if notify_activate: data['notify_activate'] = self.yn(notify_activate)

if I change that line to this:

data['notify_activate'] = self.yn(notify_activate)

it works perfectly, I get no notifications.

It seems like if notify_activate is false (because it is), so the default value (true) gets set for notify_activate.

Hope you know what I mean ๐Ÿ˜

(This will be the case for the other parameters too, but they work properly because the defaults are set in a way that it doesn't get affected.)

Setting up Reverse DNS for Vultr

Would love to see this implemented in this module, the only thing I still need to login to vultr for, would be great if it could be all done through ansible.

Library path not being detected even with ANSIBLE_LIBRARY=./library env set

Getting an error when using ANSIBLE_LIBRARY=./library ansible-playbook playbook.yml:

When directly calling the playbook it works fine, but when including it in my main playbook I get this error:

ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.

The error appears to have been in '/Users/Baldwin/Google Drive/Ansible Playbooks/deploy-ww/roles/deploy/tasks/main.yml: line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

---
- hosts: localhost
  ^ here


The error appears to have been in '/Users/Baldwin/Google Drive/Ansible Playbooks/deploy-ww/roles/deploy/tasks/main.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

---
- hosts: localhost
  ^ here

My main playbook


---
- hosts: all
  become: yes

  roles:
    - deploy

Exit with appropriate error if request comes from Unauthorized IP address

Driver.server_list fails if the source IP is unauthorized.

Actual curl output is:

< HTTP/1.1 403 Forbidden
< Server: nginx
< Date: Wed, 28 Sep 2016 02:13:58 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
<
* Connection #0 to host api.vultr.com left intact
Your IP (x.x.x.x) is not authorized to use this API key

Expected behavior
Should exit with a meaningful error message.

'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'label'

trying to launch an example playbook from readme.
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'label'\n\nThe error appears to have been in '/path/to/init.yaml': line 22, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: Provision Vultr servers\n ^ here\n"}

$ ansible-playbook --version
ansible-playbook 2.2.1.0
config file =
configured module search path = ['./library']

Error for sshkeyid

fatal: [localhost]: FAILED! => {"failed": true, "msg": "template error while templating string: unexpected char u'b' at 31. String: {{ item.SSHKEYID | default(5771b70ee1fff) }}"}

When I remove this line it works fine:
SSHKEYID: "{{ item.SSHKEYID | default(5771b70ee1fff) }}"

Migrate to ansible 2.0 inventory script

Hi!

Can you please migrate this extension to an inventory script compatible with ansible 2.0?

Current version cannot be used together with current stable ansible

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.