From 25818cef0ac025b671b3903f7bc2414156347320 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 21 Dec 2016 16:05:03 +0100 Subject: [PATCH] Various files from ansible-roles --- .gitignore | 1 + CONVENTIONS.md | 158 +++++++++++++++++++++++++++++++++++++++++ README.md | 18 +++++ playbooks/evolinux.yml | 5 +- playbooks/httpd.yml | 5 +- test/Vagrantfile | 30 ++++++++ test/vagrant.yml | 36 ++++++++++ vars/global.yml | 3 - 8 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 CONVENTIONS.md create mode 100644 test/Vagrantfile create mode 100644 test/vagrant.yml delete mode 100644 vars/global.yml diff --git a/.gitignore b/.gitignore index a8b42eb..c0b71d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +/test/.vagrant *.retry diff --git a/CONVENTIONS.md b/CONVENTIONS.md new file mode 100644 index 0000000..6de69e5 --- /dev/null +++ b/CONVENTIONS.md @@ -0,0 +1,158 @@ +# Conventions + +## Roles + +We can use the `ansible-galaxy init` command to bootstrap a new role : + + $ ansible-galaxy init foo + - foo was created successfully + $ tree foo + foo + ├── defaults + │   └── main.yml + ├── files + ├── handlers + │   └── main.yml + ├── meta + │   └── main.yml + ├── README.md + ├── tasks + │   └── main.yml + ├── templates + ├── tests + │   ├── inventory + │   └── test.yml + └── vars + └── main.yml + +All `main.yml` file will be picked up by Ansible automatically, with respect to their own responsibility. + +The main directory is `tasks`. It will contains tasks, either all in the `main.yml` file, or grouped in files that can be included in the main file. + +`defaults/main.yml` is the place to put the list of all variables for the role with a default value. + +`vars` will hold files with variables definitions. Those differ from the defaults because of a much higher precedence (see below). + +`files` is the directory where we'll put files to copy on hosts. They will be copied "as-is". When a role has multiple logical groups of tasks, it's best to create a sub-directory for each group that needs files. The name of files in these directories doesn't have to be the same as the destination name. Example : + + copy: + src: apt/jessie_backports_preferences + dest: /etc/apt/apt.conf.d/backports + +`templates` is the twin brother of `files`, but differs in that it contains files that can be pre-processed by the Jinja2 templating language. It can contain variables that will be extrapolated before copying the file to its destination. + +`handlers` is the place to put special tasks that can be triggered by the `notify` argument of modules. For example an `nginx -s reload` command. + +`meta/main.yml` contains … well … "meta" information. There we can define role dependencies, but also some "galaxy" information like the desired Ansible version, supported OS and distributions, a description, author/ownership, license… + +`tests` and `.travis.yml` are here to help testing with a test matrix, a test inventory and a test playbook. + +We can delete parts we don't need. + +### How much goes into a role + +We create roles (instead of a plain tasks files) when it makes sense as a whole, and it is more that a series of tasks. It often has variables, files/templates, handlers… + +## Syntax + +### Pure YAML + +It's possible to use a compact (Ansible specific) syntax, + + - name: Add evomaintenance trap for '{{ user.name }}' + lineinfile: state=present dest='/home/{{ user.name }}/.profile' insertafter=EOF line='trap "sudo /usr/share/scripts/evomaintenance.sh" 0' + when: evomaintenance_script.stat.exists + +but we prefer the pure-YAML syntax + + - name: Add evomaintenance trap for '{{ user.name }}' + lineinfile: + state: present + dest: '/home/{{ user.name }}/.profile' + insertafter: EOF + line: 'trap "sudo /usr/share/scripts/evomaintenance.sh" 0' + when: evomaintenance_script.stat.exists + +Here are some reasons : + +* when lines get long, it's easier to read ; +* it's a pure YAML syntax, so there is no Ansible-specific preprocessing +* … which means that IDE can show the proper syntax highlighting ; +* each argument stands on its own. + +## Variables + +### defaults + +When a role is using variables, they must be defined (for example in the `defaults/main.yml`) with a default value (possibly Null). That way, there will never be a "foo is undefined" situation. + +### progressive specificity + +In many roles, we use a *progressive specificity* pattern for some variables. +The most common is for "alert_email" ; we want to have a default email address where all alerts or messages will be sent, but it can be customized globally, and also customized per task/role. + +For the *evolinux-base* role we have those defaults : + + general_alert_email: "root@localhost" + reboot_alert_email: Null + log2mail_alert_email: Null + raid_alert_email: Null + +In the *log2mail* template, we set the email address like this : + + mailto = {{ log2mail_alert_email or general_alert_email | mandatory }} + +If nothing is customized, the mail will be sent to root@localhost, if general_alert_email is changed, it will be used, but if log2mail_alert_email is set to a non-null value, it will have precedence. + +## precedence + +There are multiple places where we can define variables and there is a specific precedence order for the resolution. Here is [the (ascending) order](http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable) : + +* role defaults +* inventory vars +* inventory group_vars +* inventory host_vars +* playbook group_vars +* playbook host_vars +* host facts +* play vars +* play vars_prompt +* play vars_files +* registered vars +* set_facts +* role and include vars +* block vars (only for tasks in block) +* task vars (only for the task) +* extra vars (always win precedence) + +## Configuration patterns + +### lineinfile vs. blockinfile vs. copy/template + +When possible, we prefer using the [lineinfile](http://docs.ansible.com/ansible/lineinfile_module.html) module to make very specific changes. +If a `regexp` argument is specified, every line that matches the pattern will be updated. It's a good way to comment/uncomment variable, or add a piece inside a line. + +When it's not possible (multi-line changes, for example), we can use the [blockinfile](http://docs.ansible.com/ansible/blockinfile_module.html) module. It manages blocks of text with begin/end markers. The marker can be customized, mostly to use the proper comment syntax, but also to prevent collisions within a file. + +If none of the previous can be used, we can use [copy](http://docs.ansible.com/ansible/copy_module.html) or [template](http://docs.ansible.com/ansible/template_module.html) modules to copy an entire file. + +### defaults and custom files + +We try not to alter configuration files managed by packages. It makes upgrading easier, so when a piece of software has a "foo.d" configuration directory, we add custom files there. + +We usually put a `z-evolinux-defaults` with our core configuration. This file can be changed later via Ansible and must not be edited by hand. Example : + + copy: + src: evolinux-defaults.cnf + dest: /etc/mysql/conf.d/z-evolinux-defaults.cnf + force: yes + + +We also create a blank `zzz-evolinux-custom` file, with commented examples, to allow custom configuration that will never be reverted by Ansible. Example : + + copy: + src: evolinux-custom.cnf + dest: /etc/mysql/conf.d/zzz-evolinux-custom.cnf + force: no + +The source file or template shouldn't to be prefixed for ordering (eg. `z-` or `zzz-`). It's the task's responsibility to choose how destination files must be ordered. diff --git a/README.md b/README.md index 2a7fd65..4dfb2ae 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,21 @@ ``` $ ansible-playbook playbooks/evolinux.yml -i inventory/hosts -K ``` + +## Tests + +It's possible to use the `vagrant.yml` playbook locally, to test and debug the roles on a virtual machine. + +It works with a Virtualbox VM, driven by Vagrant. + +To install Virtualbox and Vagrant (version 1.8 is not available on Debian repositories yet) : + +``` +$ apt install virtualbox +$ curl -O https://releases.hashicorp.com/vagrant/1.8.5/vagrant_1.8.5_x86_64.deb /tmp/ +$ dpkg -i /tmp /vagrant_1.8.5_x86_64.deb +``` + +To bring the VM up and run the playbook, simply run `$ vagrant up` from the root of this repository. + +To destroy the VM and start again from scratch : `$ vagrant destroy && vagrant up`. diff --git a/playbooks/evolinux.yml b/playbooks/evolinux.yml index f1049df..75778ab 100644 --- a/playbooks/evolinux.yml +++ b/playbooks/evolinux.yml @@ -1,8 +1,9 @@ - hosts: ansible-test gather_facts: yes become: yes - vars_files: - - "../vars/global.yml" + vars: + roles: ../../ansible-roles + tasks: ../tasks roles: - "{{ roles }}/etc-git" diff --git a/playbooks/httpd.yml b/playbooks/httpd.yml index 68e7225..b18a82b 100644 --- a/playbooks/httpd.yml +++ b/playbooks/httpd.yml @@ -1,8 +1,9 @@ - hosts: ansible-test gather_facts: yes become: yes - vars_files: - - "../vars/global.yml" + vars: + roles: ../../ansible-roles + tasks: ../tasks vars: - evolinux_default_www_nginx_enabled: True diff --git a/test/Vagrantfile b/test/Vagrantfile new file mode 100644 index 0000000..70dab1d --- /dev/null +++ b/test/Vagrantfile @@ -0,0 +1,30 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + config.vm.box = "debian/jessie64" + + config.vm.synced_folder "./vagrant_share/", "/vagrant", disabled: true + + config.vm.provider :virtualbox do |v| + v.memory = 2048 + v.cpus = 2 + v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] + v.customize ["modifyvm", :id, "--ioapic", "on"] + end + + # Master + config.vm.define :default do |default| + default.vm.hostname = "default" + default.vm.network :private_network, ip: "192.168.33.33" + default.vm.provision :ansible, run: "always" do |ansible| + ansible.limit = "default" + ansible.playbook = "vagrant.yml" + # ansible.tags = "mysql" + ansible.raw_arguments = ["-b"] + end + end + +end diff --git a/test/vagrant.yml b/test/vagrant.yml new file mode 100644 index 0000000..be5afb1 --- /dev/null +++ b/test/vagrant.yml @@ -0,0 +1,36 @@ +--- +- hosts: default + gather_facts: yes + become: yes + vars: + roles: ../../ansible-roles + + roles: + # - apt-upgrade + # - { role: apt-upgrade, apt_upgrade_mode: safe } + # - evolinux-base + # - listupgrade + # - etc-git + - "{{ roles }}/evolinux-base" + # - minifirewall + # - squid + # - evomaintenance + # - munin + # - monit + # - redis + # - { role: rbenv, username: 'vagrant' } + # - mysql + # - { role: mysql, mysql_custom_tmpdir: '/home/mysql-tmpdir' } + # - { + # role: "nginx", + # nginx_private_ipaddr_whitelist_present: ["192.168.0.2"], + # nginx_private_ipaddr_whitelist_absent: ["127.0.0.1"], + # nginx_private_htpasswd_present: ["qsdfqsdf:dsfgdfsdf"], + # nginx_private_htpasswd_absent: ["toto:dsfgdfsdf"] + # } + # - apache + # - { role: elastic-stack, + # elasticsearch_jvm_xms: "256m", + # elasticsearch_jvm_xmx: "256m" + # } + # - filebeat diff --git a/vars/global.yml b/vars/global.yml deleted file mode 100644 index be611ea..0000000 --- a/vars/global.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -roles: ../../ansible-roles -tasks: ../tasks