06ecdaa7b1
* create examples/play.yml Co-authored-by: flowerysong <junk+github@flowerysong.com>
525 lines
19 KiB
YAML
525 lines
19 KiB
YAML
#!/usr/bin/env ansible-playbook
|
|
# ^ Trick: the above line can be used to make your play an executable
|
|
# you also must add 'x' permissions to the file
|
|
#
|
|
# this file is based on phred's 'pedantically commented playbook'
|
|
# https://github.com/phred/ansible-examples/blob/master/pedantically_commented_playbook.yml
|
|
#
|
|
---
|
|
# ^^^ YAML documents can begin with the document separator "---"
|
|
# and end with the "...", neither is needed for Ansible # as it does not
|
|
# support multiple YAML documents per file, but some linters incorrectly insist
|
|
# you must have it ....
|
|
#
|
|
# The '#' is a comment character, so any line starting with it will be ignored by Ansible.
|
|
|
|
# Blank lines are ignored, so can be used # to create spacing to your taste.
|
|
|
|
# Note about YAML: like Python, cares about whitespace, it requires actual spaces, tabs won't work.
|
|
# Indent consistently throughout.
|
|
# Two-space or four space indents is what most users prefer, but do whatever you like.
|
|
#
|
|
# If you're new to YAML, keep in mind that YAML documents, like XML
|
|
# documents, represent a tree-like structure of nodes and text. More
|
|
# familiar with JSON? Think of YAML as a strict (with spaces) but also more flexible
|
|
# JSON (fewer significant characters, e.g., :, "", {}, [] and liberal quoting).
|
|
# Also, JSON is a subset of YAML, so most YAML parser can read JSON just the same.
|
|
#
|
|
# The curious may read more about YAML at:
|
|
# http://www.yaml.org/spec/1.1/current.html
|
|
# there is a 1.2, but Ansible uses pyyaml which is mostly 1.1
|
|
|
|
# the following line configures 'vim' to handle 2 space indents.
|
|
# vim:ff=unix ts=2 sw=2 ai expandtab
|
|
|
|
###
|
|
# Notice the minus (-) on the line below, this is the start of a 'list' in YAML
|
|
# In Ansible this is the 'list of plays' which starts this playbook.
|
|
# Plays map the inventory hosts to the tasks, the most minimal play you can have
|
|
# just requires 'hosts'
|
|
|
|
- hosts: all
|
|
###########
|
|
# Play keyword: hosts
|
|
# Required: yes
|
|
# Description:
|
|
# The selection of hosts (or host) that the tasks in this play play should apply to.
|
|
#
|
|
## Example values:
|
|
# hosts: all -- applies to all hosts
|
|
# hosts: host1 -- apply ONLY to the host that inventory defines as 'host1'
|
|
# hosts: group1 -- apply to all hosts in group1
|
|
# hosts: group1,group2 -- apply to hosts in group1 & group2
|
|
# hosts: group1,host1 -- hosts in group1 AND host
|
|
#
|
|
## now using host patterns (TODO: url)
|
|
# hosts: group1,!group3 -- hosts in group1 that are not in group3
|
|
# hosts: group1,&group3 -- hosts in group1 that are also in group3
|
|
# hosts: group1:&group3 -- same as above, but using : instead of , as separator
|
|
# hosts: group1:!group2:&group3 -- hosts in group1 what are not in group2 but are also in group3
|
|
#
|
|
## Using a variable value for 'hosts'
|
|
#
|
|
# You can, in fact, set hosts to a variable, for example:
|
|
#
|
|
# hosts: '{{mygroups}}' -- apply to all hosts specified in the variable 'mygroups'
|
|
#
|
|
# This is handy for testing playbooks, running the same playbook against a
|
|
# staging environment before running it against production, occasional
|
|
# maintenance tasks, and other cases where you want to run the playbook
|
|
# against just a few systems rather than a whole group.
|
|
# Note that the variable cannot be set in inventory, since we need to know the hosts
|
|
# before we can use invenotry variables. So normally 'extra vars' are used, as you can
|
|
# see below.
|
|
#
|
|
# If you set hosts as shown above, then you can specify which hosts to
|
|
# apply the playbook to on each run as so:
|
|
#
|
|
# ansible-playbook playbook.yml --extra-vars="mygroups=staging"
|
|
#
|
|
# Use --extra-vars to set the variable to any combination of groups, hostnames,
|
|
# or host patterns just like the examples in the previous section.
|
|
#
|
|
|
|
name: my heavily commented play
|
|
###########
|
|
# Play keyword: name
|
|
# Default: play###
|
|
# Required: no
|
|
# Description: Just a description to document the play
|
|
|
|
gather_facts: yes
|
|
###########
|
|
# Play keyword: gather_facts
|
|
# Default: None
|
|
# Required: no
|
|
# Description:
|
|
# This controls if the play will trigger a 'fact gathering task' (aka 'gather_facts' or 'setup' action) to get information about the remote target.
|
|
# These facts normally provide useful variables on which to base decisions and task inputs. For example `ansible_os_distribution` can tell us if
|
|
# the target is a RHEL, Ubuntu or FreeBSD machine (among others), number of CPUs, RAM, etc.
|
|
# TODO: url to fact gathering
|
|
|
|
remote_user: login_user
|
|
###########
|
|
# Play keyword: user
|
|
# Default: depends on conneciton plugin, for ssh it is 'current user executing Ansible'
|
|
# Required: no
|
|
# Description:
|
|
# Remote user to login on remote targets and 'normally' execute the tasks as
|
|
|
|
become: True
|
|
###########
|
|
# Play keyword: become
|
|
# Default: False
|
|
# Required: no
|
|
# Description:
|
|
# If True, always use privilege escalationj to run tasks from this play, just like passing the
|
|
# --become flag to ansible or ansible-playbook.
|
|
|
|
|
|
become_user: root
|
|
###########
|
|
# Play keyword: become_user
|
|
# Default: None
|
|
# Required: no
|
|
# Description:
|
|
# When using privilege escalation this is the user you 'become' after login with the remote_user
|
|
# for examplle you login to the remote as 'login_user' then you 'become' root to execute the tasks
|
|
|
|
become_method: sudo
|
|
###########
|
|
# Play keyword: become_method
|
|
# Default: sudo
|
|
# Required: no
|
|
# Description:
|
|
# When using privilege escalation this chooses the become plugin to use for privilege escalation.
|
|
# use `ansible-doc -t become -l` to list all the options.
|
|
|
|
connection: ssh
|
|
###########
|
|
# Play keyword: connection
|
|
# Default: ssh
|
|
# Required: no
|
|
# Description:
|
|
# This sets which connection plugin Asnible will use to try to communicate with the target host.
|
|
# notable options are paramiko (python implementation of ssh, mostly useful in corener cases in which the ssh cli
|
|
# does not work well with the target. Also 'local' which forces a 'local fork' to execute the task, but normally
|
|
# what you really want is `delegate_to: localhost` see examples below in 'Run things locally!' entry.
|
|
# use `ansible-doc -t connection -l` to list all the options.
|
|
|
|
vars:
|
|
###########
|
|
# Play keyword: vars
|
|
# Default: none
|
|
# Required: no
|
|
# Description:
|
|
# Mapping of variables defined for this play, normally for use in templates or as variables for tasks.
|
|
|
|
# to get the value just use {{color}} to reference that value
|
|
color: brown
|
|
|
|
# Mapping structures allow complex variables structures, to use you can reference
|
|
# the variable name with {{web['memcache']}} when using nested key value or {{web}}
|
|
# when using the whole structure..
|
|
web:
|
|
memcache: 192.168.1.2
|
|
httpd: apache
|
|
|
|
# lists use a slightly different notation {{ mylist[1] }} to get 'b', they are 0 indexed.
|
|
mylist:
|
|
- a
|
|
- b
|
|
- c
|
|
|
|
# Variables can be dynamically set via Jinja templates, to be filled when consumed.
|
|
#
|
|
# In this playbook, this will always evaluate to False, because 'color'
|
|
# is set to 'brown' above.
|
|
#
|
|
# When ansible interprets the following, it will first expand 'color' to
|
|
# 'brown' and then evaluate 'brown' == 'blue' as a Jinja expression.
|
|
is_color_blue: "{{ color == 'blue' }}"
|
|
|
|
# TODO: (url variables)
|
|
|
|
vars_files:
|
|
##########
|
|
# Play keyword: vars_files
|
|
# Required: no
|
|
# Description:
|
|
# Specifies a list of YAML files to load variables from.
|
|
#
|
|
# Always evaluated after the 'vars' section, no matter which section
|
|
# occurs first in the playbook. Examples are below.
|
|
#
|
|
# Example YAML for a file to be included by vars_files:
|
|
# ---
|
|
# monitored_by: phobos.mars.nasa.gov
|
|
# fish_sticks: "good with custard"
|
|
# ... # (END OF DOCUMENT)
|
|
#
|
|
# Remove the indentation & comments of course, the '---' should be at
|
|
# the left margin in the variables file.
|
|
#
|
|
# Include a file from this absolute path
|
|
- /srv/ansible/vars/vars_file.yml
|
|
|
|
# Include a file from a path relative to this playbook
|
|
- vars/vars_file.yml
|
|
|
|
# By the way, variables set in 'vars' or as extra vars are available here.
|
|
- vars/{{something}}.yml
|
|
|
|
# It's also possible to pass an array of files, in which case
|
|
# Ansible will loop over the array and include the first file that
|
|
# exists. If none exist, ansible-playbook will halt with an error.
|
|
#
|
|
# An excellent way to handle platform-specific differences.
|
|
- [ 'vars/{{platform}}.yml', vars/default.yml ]
|
|
|
|
# Files in vars_files process in order, so later files can
|
|
# provide more specific configuration:
|
|
- [ 'vars/{{host}}.yml' ]
|
|
|
|
# Hey, but if you're doing host-specific variable files, you might
|
|
# consider setting the variable for a group in your inventory and
|
|
# adding your host to that group. Just a thought.
|
|
|
|
|
|
vars_prompt:
|
|
##########
|
|
# Play keyword: vars_prompt
|
|
# Required: no
|
|
# Description:
|
|
# A list of variables that Ansible will prompt for manual input each time this playbook
|
|
# runs. Used for sensitive data and also things like release numbers that
|
|
# vary on each deployment.
|
|
#
|
|
# Ansible won't prompts for this value if already provided, like when
|
|
# passed through --extra-vars, but not from inventory.
|
|
#
|
|
# Also it won't prompt if it detects that it is a non interactive session.
|
|
# For example, when called from cron.
|
|
#
|
|
- name: passphrase
|
|
prompt: "Please enter the passphrase for the SSL certificate"
|
|
private: yes
|
|
# The input won't be echoed back to the terminal when private (default yes)
|
|
|
|
# Not sensitive, but something that should vary on each playbook run.
|
|
- name: release_version
|
|
prompt: "Please enter a release tag"
|
|
private: no
|
|
|
|
# you can even have a default
|
|
- name: package_version
|
|
prompt: "Please enter a package version"
|
|
default: '1.0'
|
|
|
|
# You can find more advanced features in https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html
|
|
|
|
roles:
|
|
##########
|
|
# Play keyword: roles
|
|
# Required: no
|
|
# Description: A list of roles to import and execute in this play. Executes AFTER pre_tasks and play fact gathering, but before 'tasks'.
|
|
# TODO url roles + url to 'play stages'
|
|
|
|
tasks:
|
|
##########
|
|
# Play keyword: tasks
|
|
# Required: no
|
|
# Description: A list of tasks to perform in this play. Executes AFTER roles and before post_tasks
|
|
|
|
# A simple task
|
|
# Each task must have an action. 'name' is optional but very useful to document what the task does
|
|
- name: Check that the target can execute Ansible tasks
|
|
action: ping
|
|
|
|
##########
|
|
# Ansible modules do the work!, 'action' is not needed, you can use the 'action itself' as part of the task
|
|
- file: path=/tmp/secret mode=0600 owner=root group=root
|
|
#
|
|
# Format 'action' like above:
|
|
# <modulename>: <module parameters>
|
|
#
|
|
# Test your parameters using:
|
|
# ansible -m <module> -a "<module parameters>"
|
|
#
|
|
# Documentation for the stock modules:
|
|
# http://ansible.github.com/modules.html
|
|
|
|
# normally most will want to use 'k: v' notation instead of 'k=v' used above (but useful for adhoc execution).
|
|
# while both formats are mostly interchangable, `k: v` is more explicit, 'type friendly' and simpler to escape.
|
|
- name: Ensure secret is locked down
|
|
file:
|
|
path: /tmp/secret
|
|
mode: '0600'
|
|
owner: root
|
|
group: root
|
|
|
|
# note that 'action options' are indented inside the option, while 'task keywords' stay on the top level
|
|
|
|
##########
|
|
# Use variables in the task! It expands on use.
|
|
- name: Paint the server
|
|
command: echo {{color}}
|
|
|
|
# you can also define variables at the task level
|
|
- name: Ensure secret is locked down
|
|
file:
|
|
path: '{{secret_file}}'
|
|
mode: '0600'
|
|
owner: root
|
|
group: root
|
|
vars:
|
|
secret_file: /tmp/secret
|
|
|
|
##########
|
|
# Trigger handlers when things change!
|
|
#
|
|
# Most Ansible actions can detect and report when something changed.
|
|
# Like if file permissions were not the same as requested,
|
|
# a file's content is different or a package was installed (or removed)
|
|
# When a change is reported, the task assumes the 'changed' status.
|
|
# Ansible can optionally notify one or more Handlers.
|
|
# Handlers are like normal tasks, the main difference is that they only
|
|
# run when notified.
|
|
# A common use is to restart a service after updating it's configuration file.
|
|
# https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html#handlers-running-operations-on-change
|
|
|
|
# TODO: explain handler per stage execution
|
|
|
|
# This will call the "Restart Apache" handler whenever 'copy' alters
|
|
# the remote httpd.conf.
|
|
- name: Update the Apache config
|
|
copy:
|
|
src: httpd.conf
|
|
dest: /etc/httpd/httpd.conf
|
|
notify: Restart Apache
|
|
|
|
# Here's how to specify more than one handler
|
|
- name: Update our app's configuration
|
|
copy:
|
|
src: myapp.conf
|
|
dest: /etc/myapp/production.conf
|
|
notify:
|
|
- Restart Apache
|
|
- Restart Redis
|
|
|
|
##########
|
|
# Include tasks from another file!
|
|
#
|
|
# Ansible can insert a list of tasks from another file. The file
|
|
# must represent a list of tasks, which is different than a play.
|
|
#
|
|
# Task list format:
|
|
# ---
|
|
# - name: create user
|
|
# user: name={{myuser}} color={{color}}
|
|
#
|
|
# - name: add user to group
|
|
# user: name={{myuser}} groups={{hisgroup}} append=true
|
|
# ... # (END OF DOCUMENT)
|
|
#
|
|
# A 'tasks' YAML file represents a list of tasks. Don't use playbook
|
|
# YAML for a 'tasks' file.
|
|
#
|
|
# Remove the indentation & comments of course, the '---' should be at
|
|
# the left margin in the variables file.
|
|
|
|
# TODO: point at import_playbook, includes and roles
|
|
# In this example the user will be 'sklar'
|
|
# and 'color' will be 'red' inside new_user.yml
|
|
- import_tasks: tasks/new_user.yml
|
|
vars:
|
|
myuser: sklar
|
|
color: red
|
|
|
|
# In this example the user will be 'mosh'
|
|
# and $color will be 'mauve' inside new_user.yml
|
|
- import_tasks: tasks/new_user.yml
|
|
vars:
|
|
myuser: mosh
|
|
color: mauve
|
|
|
|
|
|
##########
|
|
# Run a task on each thing in a list!
|
|
#
|
|
# Ansible provides a simple loop facility. If 'loop' is provided for
|
|
# a task, then the task will be run once for each item in the provided
|
|
# list. Each iteration will create the 'item' variable with a different value.
|
|
- name: Create a file named via variable in /tmp
|
|
file: path=/tmp/{{item}} state=touched
|
|
loop:
|
|
- tangerine
|
|
- lemon
|
|
|
|
- name: Loop using a variable
|
|
file: path=/tmp/{{item}} state=touched
|
|
loop: '{{mylist}}'
|
|
vars:
|
|
# defined here, but could be anywhere before the task runs
|
|
# also note that YAML lists can be flush with their key,
|
|
# we normally indent for clarity, but this form is also correct.
|
|
mylist:
|
|
- tangerine
|
|
- lemon
|
|
##########
|
|
# Conditionally execute tasks!
|
|
#
|
|
# Sometimes you only want to run an action when a under certain conditions.
|
|
# Ansible supports using conditional Jinja expression, executing the task only when 'True'.
|
|
#
|
|
# If you're trying to run an task only when a value changes,
|
|
# consider rewriting the task as a handler and using 'notify' (see below).
|
|
#
|
|
- name: "shutdown all ubuntu"
|
|
command: /sbin/shutdown -t now
|
|
when: '{{is_ubuntu|bool}}'
|
|
|
|
- name: "shutdown the if host is in the government"
|
|
command: /sbin/shutdown -t now
|
|
when: "{{inventory_hostname in groups['government']}}"
|
|
|
|
# another way to write the same.
|
|
- name: "shutdown the if host is in the government"
|
|
command: /sbin/shutdown -t now
|
|
when: "{{'government' in group_names}}"
|
|
|
|
# Ansible has some built in variables, you can check them here (TODO url)
|
|
# inventory_hostname is the name of the current host the task is executing for (derived from the hosts: keyword)
|
|
# group_names has the list of groups the current host (inventory_hostname) is part of
|
|
# groups is a mapping of the inventory groups with the list of hosts that belong to them
|
|
|
|
##########
|
|
# Run things as other users!
|
|
#
|
|
# Each task has optional keywords that control which
|
|
# user a task should run as and whether or not to use privilege escalation
|
|
# (like sudo or su) to switch to that user.
|
|
|
|
- name: login in as postgres and dump all postgres databases
|
|
shell: pg_dumpall -w -f /tmp/backup.psql
|
|
remote_user: postgres
|
|
become: False
|
|
|
|
- name: login normally, but sudo to postgres to dump all postgres databases
|
|
shell: pg_dumpall -w -f /tmp/backup.psql
|
|
become: true
|
|
become_user: postgres
|
|
become_method: sudo
|
|
|
|
##########
|
|
# Run things locally!
|
|
#
|
|
# Each task can also be delegated to the control host
|
|
- name: create tempfile
|
|
local_action: shell dd if=/dev/urandom of=/tmp/random.txt count=100
|
|
|
|
# which is equivalent to the following
|
|
- name: create tempfile
|
|
shell: dd if=/dev/urandom of=/tmp/random.txt count=100
|
|
delegate_to: localhost
|
|
# delegate_to can use any target, but for the case above, it is the same as using local_action
|
|
# TODO url to delegation and implicit localhost
|
|
|
|
handlers:
|
|
##########
|
|
# Play keyword: handlers
|
|
# Required: no
|
|
# Description:
|
|
# Handlers are tasks that run when another task has changed something.
|
|
# See above for examples on how to trigger them.
|
|
# The format to define a handler is exactly the same as for tasks.
|
|
# Note that if multiple tasks notify the same handler in a playbook run
|
|
# that handler will only run once for that host.
|
|
#
|
|
# Handlers are referred to by name or using the listen keyword.
|
|
# They will be run in the order declared in the playbook.
|
|
# For example: if a task were to notify the handlers in reverse order like so:
|
|
#
|
|
# - task: ensure file does not exist
|
|
# file:
|
|
# name: /tmp/lock.txt
|
|
# state: absent
|
|
# notify:
|
|
# - Restart application
|
|
# - Restart nginx
|
|
#
|
|
# The "Restart nginx" handler will still run before the "Restart application"
|
|
# handler because it is declared first in this playbook.
|
|
|
|
# this one can only be called by name
|
|
- name: Restart nginx
|
|
service:
|
|
name: nginx
|
|
state: restarted
|
|
|
|
# this one can be called by name or via any entry in the listen keyword
|
|
- name: redis restarter
|
|
service:
|
|
name: redis
|
|
state: restarted
|
|
listen:
|
|
- Restart redis
|
|
|
|
# Any module can be used for the handler action
|
|
# even though this can be triggered multiple ways and times
|
|
# it will only execute once per host
|
|
- name: restart application that should really be a service
|
|
command: /srv/myapp/restart.sh
|
|
listen:
|
|
- Restart application
|
|
- restart myapp
|
|
|
|
# It's also possible to include handlers from another file. Structure is
|
|
# the same as a tasks file, see the tasks section above for an example.
|
|
- import_tasks: handlers/site.yml
|
|
|
|
|
|
# NOTE: this is not a complete list of all possible keywords in a play or task (TODO: url playbook object and keywords), just an example of very common options.
|
|
|
|
# below is the "totally optional" YAML "End of document" marker.
|
|
...
|