Giter Club home page Giter Club logo

ansible-skeleton's Introduction

Ansible Skeleton

An opinionated skeleton that considerably simplifies setting up an Ansible project with a development environment powered by Vagrant.

Advantages include:

See also the companion projects:

If you like/use this role, please consider giving it a star. Thanks!

Installation

On the management node, make sure you have installed recent versions of:

  • VirtualBox
  • Vagrant
  • Git and for Windows hosts also Git Bash. If you install Git with default settings (i.e. always click "Next" in the installer), you should be fine.
  • Ansible (only on Mac/Linux)

You can either clone this project or use the provided initialization script.

When cloning, choose another name for the target directory.

> git clone https://github.com/bertvv/ansible-skeleton.git my-ansible-project

After cloning, it's best to remove the .git directory and initialise a new repository. The history of the skeleton code is irrelevant for your Ansible project.

You can find an initialization script in my ansible-toolbox that automates the process (including creating an empty Git repository).

> atb-init my-ansible-project

This will download the latest version of the skeleton from Github, initialize a Git repository, do the first commit, and, optionally, install any specified role.

> atb-init my-ansible-project bertvv.el7 bertvv.httpd

This will create the skeleton and install roles bertvv.el7 and bertvv.httpd from Ansible Galaxy.

Getting started

First, modify the Vagrantfile to select your favourite base box. I use a CentOS 7 base box, from the Bento project. This is probably the only time you need to edit the Vagrantfile.

The vagrant-hosts.yml file specifies the nodes that are controlled by Vagrant. You should at least specify a name:, other settings (see below) are optional. A host-only adapter is created and the given IP assigned to that interface. Other optional settings that can be specified:

VirtualBox configuration:

  • cpus: The number of CPUs assigned to this VM.
  • memory: The memory size in MB, if you want to set a size different from the base box default.
  • synced_folders: A list of dicts that specify synced folders. Two keys, src: (the directory on the host system) and dest: (the mount point in the guest) are mandatory, another one, options: is, well, optional. The possible options are the same ones as specified in the Vagrant documentation on synced folders. One caveat is that the option names should be prefixed with a colon, e.g. owner: becomes :owner:.
- name: srv002
  synced_folders:
    - src: test
      dest: /tmp/test
    - src: www
      dest: /var/www/html
      options:
        :create: true
        :owner: root
        :group: root
        :mount_options: ['dmode=0755', 'fmode=0644']

Network settings:

  • auto_config: If set to false, Vagrant will not attempt to configure the network interface.
  • forwarded_ports: A list of dicts with keys host: and guest: specifying which host port should be forwarded to which port on the VM.
  • intnet: If set to true, the network interface will be attached to an internal network rather than a host-only adapter.
  • ip: The IP address for the VM.
  • mac: The MAC address to be assigned to the NIC. Several notations are accepted, including "Linux-style" (00:11:22:33:44:55) and "Windows-style" (00-11-22-33-44-55). The separator characters can be omitted altogether (001122334455).
  • netmask: By default, the network mask is 255.255.255.0. If you want another one, it should be specified.

Provisioning:

  • playbook: On this host, execute a different playbook than the default ansible/site.yml
  • shell_always: A list of dicts that specify commands to be run after booting the VM. There is one required key, cmd: that contains the command and any options/arguments.

Adding hosts

As an example, a single host with hostname srv001 is already defined. If you want to add new nodes, you should edit the following files:

  • vagrant-hosts.yml so a Vagrant box is created. A few examples that also illustrate the optional settings.
- name: srv002
  ip: 192.168.56.11
  auto_config: false

- name: srv003
  ip: 172.16.0.3
  netmask: 255.255.0.0
  intnet: true

- name: srv004
  ip: 192.168.56.14
  mac: "00:03:DE:AD:BE:EF"
  playbook: server.yml  # defaults to site.yml
  • site.yml to assign roles to your nodes, e.g.:
- hosts: srv003
  become: true
  roles:
    - bertvv.rh-base
    - bertvv.httpd

Defining groups

Ansible allows hosts to be organized into groups. In order to use this functionality, edit the file vagrant-groups.yml. The file should contain a dict with group names as keys and lists of member hosts as values.

In this example, two groups, db and web are defined:

---
db:
  - srv001
web:
  - srv002
  - srv003

Run with custom hosts/groups file

VAGRANT_HOSTS='custom-vagrant-hosts.yml' vagrant up

or

export VAGRANT_HOSTS='custom-vagrant-hosts.yml'
vagrant up

Likewise, set the environment variable VAGRANT_GROUPS to use a custom groups file.

Worked example

Alice wants to set up an environment with several web servers, a load balancer and a database server. She first defines the groups:

# group-vars.yml
---
db:
  - db001

lb:
  - lb001

web:
  - web001
  - web002
  - web003

Next, she assigns IP addresses to each VM in vagrant-hosts.yml:

# vagrant-hosts.yml
---
- name: db001
  ip: 192.168.56.10
- name: lb001
  ip: 192.168.56.11
- name: web001
  ip: 192.168.56.21
- name: web002
  ip: 192.168.56.22
- name: web003
  ip: 192.168.56.23

Next, she starts with the following master playbook site.yml:

# ansible/site.yml
---

- hosts: all
  tasks:
    - debug:
        msg: "This is {{ ansible_hostname }} in group {{ my_group }}"

The variable ansible_hostname is initialized automatically by Ansible, but my_group is not. Therefore, Alice defines it for each group, by editing an appropriately named Yaml file in ansible/group_vars/ (only web and db are shown here):

# ansible/group_vars/web.yml
---
my_group: web
# ansible/group_vars/db.yml
---
my_group: db

Next, she can run vagrant up. The following transcript shows what you should see after running vagrant provision db001 web001:

$ vagrant provision db001 web001
==> db001: Running provisioner: ansible...
    db001: Running ansible-playbook...

PLAY [all] *********************************************************************

TASK [debug] *******************************************************************
ok: [db001] => 
  msg: This is db001 in group db

PLAY RECAP *********************************************************************
db001                     : ok=1    changed=0    unreachable=0    failed=0   

==> web001: Running provisioner: ansible...
    web001: Running ansible-playbook...

PLAY [all] *********************************************************************

TASK [debug] *******************************************************************
ok: [web001] => 
  msg: This is web001 in group web

PLAY RECAP *********************************************************************
web001                     : ok=1    changed=0    unreachable=0    failed=0   

The master playbook can the be refined further, e.g.

# ansible/site.yml
---

- hosts: web
  roles:
    - bertvv.rh-base
    - bertvv.httpd
- hosts: db
  roles:
    - bertvv.rh-base
    - bertvv.mariadb
# ...

Role variables can then be defined in ansible/group_vars/.

Running tests with BATS

There's a discussion on whether Unit tests are necessary for Ansible. Indeed, with its declarative nature, Ansible largely takes away the need to check for certain things independently from the playbook definitions. For a bit more background, be sure to read through this discussion about unit testing for Ansible on Google groups.

However, it is my opinion that playbooks don't cover everything (e.g. whether a config file generated from a template has the expected contents, given the values of variables used). I value some form of testing, independent of the configuration management system. Personally, I'm a fan of the Bash Automated Testing System (BATS). It's basically an extension of Bash, so anyone familiar with it should be able to use BATS.

Put your BATS test scripts in the test/ directory and they will become available on your guest VMs as a synced folder, mounted in /vagrant/test. Scripts that you want to run on each host should be stored in the test/ directory itself, scripts for individual hosts should be stored in subdirectories with the same name as the host (see example below). Inside the VM, run

> sudo /vagrant/test/runbats.sh

to execute all tests relevant for that host. The script will install BATS if needed.

Suppose the test/ directory is structured like the example below:

test/
├── common.bats
├── runbats.sh
├── db001
│   └── db.bats
└── web001
    └── web.bats

On host db001, the scripts common.bats and db.bats will be executed, on host web001, it's common.bats and web.bats.

Tests must be defined for each host individually. If you want to run identical tests on several hosts, it's best to create a symlink, e.g.:

$ ln -s web001 web002

Now, web.bats will also be executed on host web002.

Contributors

ansible-skeleton's People

Contributors

bertvv avatar jeroened avatar jonasverhofste avatar mathiasstadler avatar thecodesmith 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  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  avatar  avatar  avatar

ansible-skeleton's Issues

ArgumentError for network options

When running vagrant up, we get an ArgumentError about the network configuration:

$ vagrant up
/opt/vagrant/embedded/gems/gems/vagrant-2.3.7/plugins/kernel_v2/config/vm.rb:319:in `network': wrong number of arguments (given 2, expected 1) (ArgumentError)
        from /home/thomas/source/infra-auto/infra-2223-thomasaelbrecht/vmlab/Vagrantfile:151:in `block (3 levels) in <top (required)>'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/config/v2/loader.rb:37:in `load'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/config/loader.rb:126:in `block (2 levels) in load'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/config/loader.rb:119:in `each'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/config/loader.rb:119:in `block in load'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/config/loader.rb:116:in `each'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/config/loader.rb:116:in `load'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/vagrantfile.rb:174:in `machine_config'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/environment.rb:983:in `block in find_configured_plugins'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/environment.rb:981:in `each'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/environment.rb:981:in `find_configured_plugins'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/environment.rb:1008:in `process_configured_plugins'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/lib/vagrant/environment.rb:189:in `initialize'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/bin/vagrant:211:in `new'
        from /opt/vagrant/embedded/gems/gems/vagrant-2.3.7/bin/vagrant:211:in `<main>'

The solution for this is changing this line:

node.vm.network :private_network, network_options(host)

into:

node.vm.network :private_network, **network_options(host)

[Question] Thoughts on "ansible_local" instead of custom script

Hi @bertvv,

Thank you for an amazing project! I am currently reviewing and noticed that for Windows you are using a custom script because Ansible is not supported on a Windows hosts. I recently discovered that there is a Ansible Local Provisioner that you can use to run Ansible locally.

What are your thoughts on this? I know this project has been out for a while and might have been before the provisioner so I wanted to know if that was the reason or there is another factor that made you chose a custom script.

Again thank you for making this available.

Wrong version ansible installed

My host OS is windows, so I have to run ansible on the vm I am setting up. This gives me problems when setting up a fedora 24 client, because the version of ansible that gets installed is 2.2.0, which means that your other ansible roles don't fully work anymore

Vagrantfile module for Ansible based on your work with modifications that may interest you

Hello!

Needing to control Vagrant from Ansible roles or playbooks (for cluster testing purpose), I had to write a collection of modules to handle Vagrant commands and Vagrantfile. For this second part, your work is the best I found during my tech monitoring so I integrated some of it in mine.

Here is my collection repo: https://github.com/jclaveau/ansible-vagrant-modules

To be les opiniated as you, I had to modify some parts of your code:

  • Support of multiple provisionners with all their possible parameters
  • Support of all possible parameters for forwarded_ports (makes overwriting of ssh ports possible)
  • Optional vagrant-groups.yml file
  • Warning removal due to Ruby's ** splat operator
  • Tests with ansible-test and continuous integration with Github Actions

You can find these modifications here: https://github.com/jclaveau/ansible-vagrant-modules/blob/main/plugins/module_utils/Vagrantfile

It diverged quite a lot so I cannot really make a PR but I wanted to notice you of my work so you may take value from it. Thus I open this bug.

I kept the MIT licensed only for the Vagrantfile so you can use it as much as you want. The rest of my collection is in GPLv3+ as the Ansible module development guidelines requires. Obviously, I listed your contributors in the credits of my README.

Thanks a lot for your work!

Here is an example of use (You can see how Ansible yaml fits well with your yaml config):

- name: Add a vm to the Vagrantfile
  jclaveau.vagrant.config:
  args:
    state: "present"
    name: "{{ item }}"
    config:
      box: boxomatic/debian-11
      ansible:
        playbook: "glusterfs_provisionning_playbook.yml"
      shell:
        inline: 'echo "provisionning done"'
      forwarded_ports:
        - host: "808{{ i }}"
          guest: 80
        - host: "8{{ i }}43"
          guest: 443
    loop:
     - srv001
     - srv002
  loop_control:
    index_var: "i"

Thanks a lot for your work

Split up variables into separate environments

E.g directory structure like:

ansible/roles/
  environments/
    common/      -> don't know if this will work since it's not an inventory directory
      group_vars/
      host_vars/
    development/
      group_vars/
        all.yml
        webservers.yml
      host_vars/
        srv001.yml
        srv002.yml
      inventory     -> link to Vagrant inventory?
    production/
      group_vars/
        all.yml
        webservers.yml
      host_vars/
        srv001.yml
        srv002.yml
      inventory

See http://www.geedew.com/setting-up-ansible-for-multiple-environment-deployments/

Generic ansible-playbook script

There are now two script for running a playbook, one for Windows hosts (script runs on the guest, and installs Ansible when necessary), one for Unix-hosts (script runs on host system).

Maybe it would be better to unify this.

In VirtualBox, create a group for VMs within the same project

In VirtualBox, create a group for VMs within the same project.

In Vagrantfile:

PROJECT_NAME = '/' + File.basename(Dir.getwd)
[...]
  hosts.each do |host|
    config.vm.provider 'virtualbox' do |vb|
      vb.customize ['modifyvm', :id, '--groups', PROJECT_NAME]
    end
[...]

Pull Bats from bats-core not unmaintained sstephenson ?

I noticed while using runbats.sh that it is pulling an older version, there are new active maintainers at bats-core while the original repository it is pulling from appears to not have merged anything in quite a while.

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.