├── .drone.yml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── README.md ├── advanced ├── chapter_00.yml ├── chapter_01.yml ├── chapter_02.yml ├── chapter_03.yml ├── chapter_04.yml ├── chapter_05.yml ├── chapter_06.yml ├── chapter_07.yml ├── chapter_08.yml ├── chapter_09.yml ├── chapter_10.yml ├── chapter_11.yml ├── resources │ ├── chapter06 │ │ └── shot1.png │ └── hosts │ │ ├── hosts.graphml │ │ ├── hosts.png │ │ └── hosts.svg └── root.yml ├── advanced_lab ├── .advanced_lab ├── chapter_05 │ └── variable_override.yml ├── chapter_07 │ ├── secrets.yml │ └── vault-test.yml ├── chapter_08 │ ├── lab.yml │ └── lamp_haproxy │ │ ├── README.md │ │ ├── group_vars │ │ ├── all │ │ ├── dbservers │ │ ├── lbservers │ │ └── webservers │ │ ├── hosts │ │ ├── roles │ │ ├── base-apache │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── common │ │ │ ├── files │ │ │ │ ├── RPM-GPG-KEY-EPEL-6 │ │ │ │ └── epel.repo │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ ├── iptables.j2 │ │ │ │ └── ntp.conf.j2 │ │ ├── haproxy │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── haproxy.cfg.j2 │ │ ├── nagios │ │ │ ├── files │ │ │ │ ├── ansible-managed-services.cfg │ │ │ │ ├── localhost.cfg │ │ │ │ └── nagios.cfg │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ ├── dbservers.cfg.j2 │ │ │ │ ├── lbservers.cfg.j2 │ │ │ │ └── webservers.cfg.j2 │ │ └── web │ │ │ └── tasks │ │ │ └── main.yml │ │ ├── rolling_update.yml │ │ └── site.yml ├── chapter_09 │ └── mysql-users.yml └── chapter_11 │ ├── iptables.yml │ └── templates │ └── iptables.j2 ├── build.yml ├── build_single.py ├── builder.sh ├── chapter_template.yml ├── development ├── chapter_0.yml ├── chapter_1.yml ├── chapter_2.yml ├── chapter_3.yml ├── chapter_4.yml └── root.yml ├── fundamentals ├── chapter_0.yml ├── chapter_1.yml ├── chapter_2.yml ├── chapter_3.yml ├── chapter_4.yml └── root.yml ├── operational ├── chapter_0.yml ├── chapter_1.yml ├── chapter_2.yml ├── chapter_3.yml ├── chapter_4.yml ├── chapter_5.yml ├── chapter_6.yml ├── chapter_7.yml ├── chapter_8.yml └── root.yml ├── operational_lab ├── adhoc_commands.sh ├── group_vars │ └── all ├── lab3-7.yml ├── labs.yml ├── labs1_2.yml ├── nginx.repo └── templates │ ├── nginx.conf │ └── vhost.conf └── syntax_check.py /.drone.yml: -------------------------------------------------------------------------------- 1 | image: linuturk/ubuntu-devel 2 | script: 3 | - apt-get install python-yaml -y 4 | - bash builder.sh 5 | publish: 6 | swift: 7 | username: {{rax_username}} 8 | password: {{rax_apikey}} 9 | auth_url: https://identity.api.rackspacecloud.com/v2.0 10 | region: IAD 11 | container: ansible-slides 12 | source: output 13 | branch: master 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /revelator 2 | /reveal_* 3 | /output 4 | /.yml 5 | 6 | *.swp 7 | 8 | *.py[co] 9 | 10 | # Packages 11 | *.egg 12 | *.egg-info 13 | dist 14 | build 15 | eggs 16 | parts 17 | bin 18 | var 19 | sdist 20 | develop-eggs 21 | .installed.cfg 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | 30 | #Translations 31 | *.mo 32 | 33 | #Mr Developer 34 | .mr.developer.cfg 35 | 36 | .DS_Store 37 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "revelator"] 2 | path = revelator 3 | url = https://github.com/mpdehaan/revelator.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | 4 | python: 5 | - 2.7 6 | 7 | install: 8 | - pip install PyYAML 9 | 10 | before_script: 11 | - git clone https://github.com/mpdehaan/revelator.git 12 | 13 | script: 14 | - python syntax_check.py fundamentals/*.yml 15 | - python build_single.py fundamentals/ > fundamentals.yml && cd revelator && ./write_it ../fundamentals.yml fundamentals/ 16 | - cd .. && python syntax_check.py operational/*.yml 17 | - python build_single.py operational/ > operational.yml && cd revelator && ./write_it ../operational.yml operational/ 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansible-sprint 2 | 3 | ## Build Instructions 4 | 5 | Build instructions can be found in build.yml. 6 | 7 | ### Dependencies 8 | 9 | * PyYAML 10 | 11 | ## Syntax Checking 12 | 13 | ``` 14 | python syntax_check.py *.yml 15 | ``` 16 | -------------------------------------------------------------------------------- /advanced/chapter_00.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Justin Phelps 4 | title: Advanced Ansible 5 | description: Advanced Ansible Course 6 | 7 | slides: 8 | - 9 | - nested: 10 | - 11 | - h1: Advanced Ansible 12 | 13 | - 14 | - h2: Learning Objectives 15 | - p: Students will be able to understand 16 | - p: | 17 | 27 | -------------------------------------------------------------------------------- /advanced/chapter_01.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Foo 4 | title: Advanced Ansible 5 | description: Advanced Ansible Course 6 | 7 | slides: 8 | - 9 | - nested: 10 | - 11 | - h1: Assessment Questions 12 | - link: 13 | - http://bit.ly/ansible_advanced 14 | - http://bit.ly/ansible_advanced 15 | -------------------------------------------------------------------------------- /advanced/chapter_02.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Paul Durivage 4 | title: "Chapter 1, Understanding configuration files and environment variables" 5 | description: Ansible Advanced Course 6 | 7 | slides: 8 | 9 | - set_global: 10 | transition: rotate 11 | background: '#007777' 12 | #background: 'black' 13 | 14 | - 15 | - nested: 16 | - 17 | - h1: Configuration Files 18 | - class_notes: | 19 | Configuration files accept configuration directives to modify 20 | the way Ansible runs, for example: configuring a specific 21 | connection type, or to set the number of forks. 22 | - 23 | - h3: File locations 24 | - ul: 25 | - "ansible.cfg (in the current directory)" 26 | - ".ansible.cfg (in the home directory)" 27 | - "/etc/ansible/ansible.cfg" 28 | - class_notes: | 29 | These are the three locations where configuration files are kept. 30 | The configuration files in these locations are read and evaluated 31 | in an order of precedence. The system file in /etc/ansible/ansible.cfg 32 | has the lowest precedence, the "~/.ansible.cfg" is next highest, and 33 | "./ansible.cfg" is the highest precedence. 34 | 35 | - 36 | - h3: Environment Variables 37 | - code: | 38 | ANSIBLE_KEEP_ALL_FILES=True ansible -i hosts ... 39 | - class_notes: | 40 | Environment variables have the highest precedence of all, and work similarly 41 | to configuration directives in config files 42 | 43 | - 44 | - h3: Environment Variables 45 | - ul: 46 | - Highest precedence 47 | - "Enviroment variables & configuration directives" 48 | - constants.py 49 | - class_notes: | 50 | An enviroment variable is going to squash configuration directives 51 | at all levels. Important to note: enviroment variables do not always 52 | have an equivalent configuration directive. 53 | Enviroment variables are not well documented, and are, for the most part 54 | documented only in code, in the "constants.py" file inside Ansible 55 | 56 | - 57 | - h3: Configuration Sections 58 | - ul: 59 | - defaults 60 | - paramiko 61 | - ssh_connection 62 | - accelerate 63 | - class_notes: | 64 | Each of the bullets are a "section" under which their respective directives 65 | should be used. The config file uses INI format. 66 | 67 | - 68 | - h3: Configuration Sections 69 | - code: | 70 | $ cat ansible.cfg 71 | [defaults] 72 | ... 73 | - class_notes: | 74 | Sections are literally section headers for INI files. Configuration 75 | directives for each section are placed under their appropriate, 76 | respective section header. 77 | 78 | - 79 | - h3: Configuration Options 80 | - p: Each section has its own directives 81 | - code: | 82 | [defaults] 83 | hostfile = hosts 84 | private_key_file = ~/.ssh/id_rsa 85 | ... 86 | - class_notes: | 87 | The directives are defined under their respective section. 88 | The Ansible documentation provides all the configuration directives 89 | for each section. 90 | - 91 | - h3: Configuration Options 92 | - link: [ 'http://docs.ansible.com/intro_configuration.html', 'http://docs.ansible.com/intro_configuration.html' ] 93 | 94 | - 95 | - h3: Example Configuration 96 | - code: | 97 | [defaults] 98 | hostfile = hosts 99 | private_key_file = /Users/username/.ssh/id_rsa 100 | nocows = 1 101 | forks = 50 102 | transport = ssh 103 | remote_user = ansibleuser 104 | ask_sudo_pass = True 105 | ask_vault_pass = True 106 | roles_path = roles 107 | 108 | [ssh_connection] 109 | pipelining = True 110 | scp_if_ssh = True 111 | - class_notes: | 112 | This is configuration file that was made to ensure Ansible complies 113 | with the local environment configuration. For example, it explictly 114 | forces ssh, asks for a sudo pass, sets forks to 50, etc. 115 | 116 | - 117 | - h3: Config File Tour 118 | - class_notes: | 119 | Students check their config files 120 | 121 | -------------------------------------------------------------------------------- /advanced/chapter_03.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: DF and TG 4 | title: Connection Types 5 | description: Connection to Remote Machines 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: "Connection Types" 13 | - class_notes: Title slide. Ansible has a number of ways to connect to remote machines. SSH is the default, and there are two SSH mechanisms. This chapter will cover the differences between the two, as well as other connection mechanisms. 14 | 15 | - 16 | - h1: "Smart (SSH auto-detected)" 17 | - p: placeholder for diagram to show smart, openssh, and paramiko? 18 | - class_notes: By default, Ansible auto-detects the right SSH-based connection mechanism to use. There are two, Paramiko and OpenSSH. Paramiko is used when your version of OpenSSH on the control machine is too old to support "Control Persist/Control Master", which greatly improve connection performance. Ubuntu has a modern version of OpenSSH, but CentOS/RHEL6 do not. 19 | 20 | - 21 | - h1: "OpenSSH" 22 | - class_notes: With the OpenSSH connection type, you can use regular SSH configuration use things like jump hosts to bounce from one host to another, Kerberos authentication, and any other SSH configuration that you need. OpenSSH also supports control master/control persist which improves the performance of multiple connections to the same machine, which is useful for Ansible. 23 | 24 | - 25 | - h1: "Pipelining" 26 | - class_notes: If you're using OpenSSH, you can enable pipelining, which greatly increases SSH performance. It is enabled in the ansible.cfg configuration file. Pipelining is disabled by default because it requires a little bit of target machine configuration for sudo. You must disable ‘requiretty’ in /etc/sudoers on all managed hosts. 27 | 28 | 29 | - 30 | - h1: "Paramiko" 31 | - class_notes: Paramiko is a very simple Python implementation of an SSH client. Ansible uses it as a fallback when the version of OpenSSH on the control machine is not suitable. It doesn't support the advanced OpenSSH configuration like jump hosts, etc. 32 | 33 | - 34 | - h1: "Accelerated Mode" 35 | - p: "http://docs.ansible.com/playbooks_acceleration.html" 36 | 37 | 38 | - class_notes: Accelerated mode is a special kind of connection that sets up a temporary listener on the target server and then bypasses SSH using a special encrypted connection to run the rest of the tasks without having to establish a new SSH connection every time. It is about as fast as pipelined SSH, but it can have some additional performance benefits if you are transferring a lot of large files to the target systems. 39 | 40 | - 41 | - h1: "Local Connections" 42 | 43 | - 44 | - h1: "Connection Plugins" 45 | -------------------------------------------------------------------------------- /advanced/chapter_04.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Matt Martz 4 | title: jinja2 templates 5 | description: Some jinja2 stuff 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Jinja2 Templates 13 | - p: I mustache you a question. 14 | 15 | - 16 | - h2: Jinja2 Templates 17 | - ul: 18 | - Delimiters 19 | - Control Structures 20 | - Jinja2 Environment 21 | - Python Data Types 22 | - Filters and Tests 23 | 24 | - 25 | - h2: Delimiters 26 | - code: | 27 | {{ variable }} 28 | - code: | 29 | {% for server in groups.webservers %} 30 | - class_notes: There are 2 (default) delimiters in jinja2. The first prints the result of the expression. The latter is used to execute statements such as for loops or assigning values. 31 | 32 | - 33 | - h2: Control Structures 34 | - p: | 35 | 47 | - class_notes: This is a list of all control strucutres as mentioned in the jinja2 docs. The ones most people need to know about are "for" and "if". Point students to http://jinja.pocoo.org/docs/templates/ for additional information about the other types. 48 | 49 | - 50 | - h2: For Loop 51 | - code: | 52 | {% for server in groups.webservers %} 53 | {{ hostvars[server].ansible_default_ipv4.address }} 54 | {% endfor %} 55 | - class_notes: Ending a control structure in jinja2 is generally done with endTYPE, where TYPE in the above case is "for". 56 | 57 | - 58 | - h2: If Statement 59 | - code: | 60 | {% if server == inventory_hostname %} 61 | {{ 127.0.0.1 }} 62 | {% else if server in groups.database %} 63 | {{ hostvars[server].ansible_eth1.address }} 64 | {% else %} 65 | {{ hostvars[server].ansible_default_ipv4.address }} 66 | {% endif %} 67 | - class_notes: This is an example of an if/else if/else statement, nothing too special here. 68 | 69 | - 70 | - h2: Accessing Variables from Other Hosts 71 | - p: The "hostvars" variable contains facts for all hosts that have had facts gathered. 72 | - code: 73 | hostvars['web01'].ansible_eth1.address 74 | - class_notes: Group variables are not held independent of the hosts. During inventory parsing, group vars are merged into the individual hosts facts. 75 | 76 | - 77 | - h2: Manipulating Jinja2 Environment 78 | - p: Ansible configures jinja2 with a set of sane defaults. In some cases these defaults are not optimal, usually in the case of variable_start_string or trim_blocks. The first line of a jinja2 template can include a jinja2 environment configuration line 79 | - code: | 80 | #jinja2:variable_start_string:'[%' , variable_end_string:'%]' 81 | - class_notes: This example shows changing "{{ ... }}" to "[% ... %]". This is valuable in the case where you may need to use the "{{" or "}}" strings in your template that are not part of jinja2. http://jinja.pocoo.org/docs/api/#jinja2.Environment 82 | 83 | - 84 | - h2: Jinja2 Variables are Python Data Types 85 | - p: In some cases there will not be Jinja2 filters that do what you want, such as a lack of a "split" filter. This can be achieved using the ".split()" method on a python string object. 86 | - code: | 87 | {% set servers = "server1,server2,server3" %} 88 | {% for server in servers.split(",") %} 89 | {{ server }} 90 | {% endfor %} 91 | 92 | - 93 | - h2: Filters and Tests 94 | - p: Jinja2 provides you with a number of filters and tests to manipulate and test data. Ansible also provides a number of filters. 95 | - link: 96 | - http://docs.ansible.com/playbooks_variables.html#jinja2-filters 97 | - http://docs.ansible.com/playbooks_variables.html#jinja2-filters 98 | 99 | - 100 | - h2: Filters 101 | - p: Filters are invoked similarly to unix shell pipes and manipulate variables and return the results 102 | - code: | 103 | variable | replace("-", "_") 104 | - class_notes: Additional details can be found at http://jinja.pocoo.org/docs/templates/#filters 105 | 106 | - 107 | - h2: Tests 108 | - p: Tests can be used to test a variable against a common expression 109 | - code: | 110 | {% if variable is defined %} 111 | - class_notes: Additional details can be found at http://jinja.pocoo.org/docs/templates/#tests 112 | -------------------------------------------------------------------------------- /advanced/chapter_06.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Paul Durivage 4 | title: "Chapter 4, Dynamic Inventory" 5 | description: "" 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Dynamic Inventories 13 | 14 | - 15 | - h3: What is Dynamic Inventory? 16 | - ul: 17 | - Executable script 18 | - Queries a service that holds data about servers 19 | - Returns the data to Ansible (as JSON) 20 | - class_notes: | 21 | Dynamic inventory is a script that queries a service, like a cloud 22 | provider API or a management application like Spacewalk. This data 23 | is formatted in an Ansible-specific JSON data structure and is used in 24 | lieu of hardcoded, static inventory files. 25 | 26 | - 27 | - h3: Why Dynamic Inventory? 28 | - ul: 29 | - Time 30 | - Accuracy 31 | - class_notes: | 32 | Ideally, the source of data for our dynamic inventory scripts is 100% 33 | correct, and is automatically updated as infrastructure changes. This 34 | is especially useful in environments where machines are coming on and offline 35 | all the time, like a cloud or virtual environment. 36 | 37 | - 38 | - h3: Manual Invocation 39 | - code: | 40 | $ ./docker.py (--list | --host) 41 | - class_notes: | 42 | Manual invocation of a dynamic inventory script is straight forward. 43 | Dynamic inventory scripts must be executable, so calling them explictly will 44 | invoke the script and return JSON as output. 45 | All inventory scripts must accept two optional arguments, list and host. 'List' 46 | lists hosts, and 'host' accepts a hostname as an argument and returns data on the host. 47 | Note, '--host' is functionally optional because of the '_meta' hash returned in the 48 | '--list' results. More on that later. 49 | 50 | - 51 | - h3: Results 52 | - image: "https://raw.githubusercontent.com/Linuturk/ansible-sprint/master/advanced/resources/chapter06/shot1.png" 53 | - class_notes: | 54 | The output of this command is returned as JSON, in an Ansible-specific structure. 55 | This image shows the invocation of the Docker inventory script. The script queries 56 | a Docker host and requests information about containers. The script creates groups, 57 | which we see as arrays of hostnames. 58 | The '_meta' hash has data about hosts -- essentially this data becomes hostvars for 59 | eac host.SSH host, port information plus additional host variables are returned by 60 | the script which can later be used in plays. 61 | 62 | - 63 | - h3: Ansible with Dynamic Inventory 64 | - code: | 65 | $ ansible -i ./docker.py --list-hosts running 66 | suspicious_ptolemy 67 | ecstatic_albattani 68 | - class_notes: | 69 | This is an example of an ad-hoc command using the inventory script. 70 | We use the -i argument just as we would with any other inventory script, however 71 | we use a path to a dynamic inventory script with this argument rather 72 | than a path to a static inventory file. 73 | You can see from this command we have asked to list hosts that the limit matches. In 74 | this example, we are matching the group "running". 75 | 76 | - 77 | - h3: Combining Inventory Types 78 | - code: | 79 | $ tree 80 | . 81 | ├── common.yml 82 | ├── prod 83 | │   ├── docker.py 84 | │   └── servers 85 | └── site.yml 86 | 87 | 1 directory, 4 files 88 | 89 | $ ansible-playbook -i prod site.yml 90 | - class_notes: | 91 | One can combine inventory types, both static and dynamic inventories, by 92 | placing them in a directory and referencing the directory as the value of the 93 | optional '-i' argument. 94 | In the example in this slide, you can see a static inventory file called 'servers', 95 | a dynamic inventory script called 'docker.py', in a directory called 'prod'. Notice 96 | that the value passed to the '-i' argument is the name of the directory, 'prod'. 97 | - 98 | - h3: Lab 99 | - p: | 100 | Using the dynamic inventory script for today's infrastructure, provision several 101 | instances. Manually run the inventory script to query information on 102 | the instances. Then, run the inventory script using an Ansible command to 103 | list and then ping the instances. 104 | -------------------------------------------------------------------------------- /advanced/chapter_07.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: TG 4 | title: Advanced Ansible 5 | description: Encrypting Sensitive Data with Vault 6 | 7 | slides: 8 | 9 | - set_global: 10 | transition: rotate 11 | background: '#007777' 12 | #background: 'black' 13 | 14 | - 15 | - nested: 16 | - 17 | - h1: Ansible Vault 18 | - p: What are you trying to hide? 19 | - 20 | - h1: Ansible Vault 21 | - p: "Ansible Vault is a tool to encrypt YAML variables files that may contain sensitive data." 22 | - ul: 23 | - Password-based 24 | - Separate command line tool 25 | - Encrypts YAML files 26 | - class_notes: Ansible Vault is a command line tool that can be used to encrypt files that may contain sensitive data. it's usually used to encrypt variables files, but it can encrypt entire playbooks as well. When Ansible is operating on a playbook that refers to an encrypted file, it can either prompt for the password or be fed a password via file. 'Question ideas; what kinds of information should be encrypted?' 27 | 28 | - 29 | - h2: Vault Operations 30 | - ul: 31 | - create 32 | - edit 33 | - rekey 34 | - encrypt 35 | - decrypt 36 | - class_notes: ansible-vault is the CLI tool, and it has several operations. 37 | 38 | - 39 | - h2: Vault Operations 40 | - code: ansible-vault create secrets.yml 41 | - class_notes: Create a new file and open it in $EDITOR. When it's saved, it will be encrypted. 42 | 43 | - 44 | - h2: Vault Operations 45 | - code: ansible-vault edit secrets.yml 46 | - class_notes: Edit an existing file in $EDITOR. Ansible will decrypt it to a temporary location and open it in an editor, and then when saved, re-encrypt it. 47 | 48 | - 49 | - h2: Vault Operations 50 | - code: ansible-vault rekey secrets.yml 51 | - class_notes: Change the password on an encrypted file. 52 | 53 | - 54 | - h2: Vault Operations 55 | - code: ansible-vault encrypt secrets.yml 56 | - class_notes: Encrypt an existing file. 57 | 58 | - 59 | - h2: Vault Operations 60 | - code: ansible-vault decrypt secrets.yml 61 | - class_notes: Permanently decrypt an encrypted file. 62 | 63 | - 64 | - h2: Running a Playbook 65 | - code: ansible-playbook --ask-vault-pass vault-test.yml 66 | - code: ansible-playbook --vault-password-file ../vault-pw vault-test.yml 67 | - class_notes: There are two ways to run a playbook that refers to encrypted content. The first one prompts at runtime. The second method is to refer to a file on disk that contains the password. 68 | 69 | - 70 | - h2: 'Lab: Vault' 71 | - ul: 72 | - Create a new encrypted file 73 | - Edit that file 74 | - Re-key the file 75 | - Use an encrypted file in a playbook 76 | - h6: 'Objective: Create a vault-encrypted vars file for a subsequent lab.' 77 | -------------------------------------------------------------------------------- /advanced/chapter_08.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: DF and TG 4 | title: Roles 5 | description: Ansible Roles and Content Organization 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: "Roles" 13 | - p: Reusing and sharing Ansible content. 14 | - class_notes: Title slide. Roles are a way to organize and reuse Ansible content in a standard way. 15 | 16 | - 17 | - h2: "Filesystem Structure" 18 | - p: Roles use specific file structures. 19 | - class_notes: Roles search for variables, files and templates in specific places. We'll discuss the file structure over the next few slides. 20 | 21 | - 22 | - h3: "Example Role Structure in a Project Folder:" 23 | - code: | 24 | site.yml 25 | roles/ 26 | role1/ 27 | files/ 28 | templates/ 29 | tasks/ 30 | handlers/ 31 | vars/ 32 | meta/ 33 | 34 | - 35 | - h3: "Calling a role in a playbook example:" 36 | - code: | 37 | --- 38 | - hosts: webservers 39 | roles: 40 | - common 41 | - webservers 42 | 43 | - 44 | - h3: "Behavior examples of role X:" 45 | - ul: 46 | - If roles/x/tasks/main.yml exists, tasks listed therein will be added to the play 47 | - If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play 48 | - If roles/x/vars/main.yml exists, variables listed therein will be added to the play 49 | - If roles/x/meta/main.yml exists, any role dependencies listed therein will be added to the list of roles 50 | - Any copy tasks can reference files in roles/x/files/ 51 | - Any script tasks can reference scripts in roles/x/files/ 52 | - Any template tasks can reference files in roles/x/templates/ 53 | - Any include tasks can reference files in roles/x/tasks/ 54 | 55 | - 56 | - h3: "Parameterize Your Roles:" 57 | - code: | 58 | --- 59 | - hosts: webservers 60 | roles: 61 | - common 62 | - { role: foo, dir: '/opt/a', port: 5000 } 63 | - { role: foo, dir: '/opt/b', port: 5001 } 64 | 65 | - 66 | - h3: "Call Roles Conditionally:" 67 | - code: | 68 | --- 69 | - hosts: webservers 70 | roles: 71 | - { role: foo, when: "ansible_os_family == 'RedHat'" } 72 | 73 | - 74 | - h3: "Pre and Post Tasks, Use of roles in a top level playbook:" 75 | - code: | 76 | --- 77 | - hosts: webservers 78 | 79 | pre_tasks: 80 | - shell: echo 'Hello.' 81 | 82 | roles: 83 | - { role: some_role } 84 | 85 | tasks: 86 | - shell: echo 'I called a role!' 87 | 88 | post_tasks: 89 | - shell: echo 'Goodbye.' 90 | 91 | - 92 | - h2: "Variables Defaults" 93 | - p: It is possible to set default variables for your roles. 94 | - class_notes: Role default variables allow you to set default variables for included or dependent roles. To create defaults, simply add a defaults/main.yml file in your role directory. These variables will have the lowest priority of any variables available, and can be easily overridden by any other variable, including inventory variables. 95 | 96 | - 97 | - h2: "Role Dependencies" 98 | - p: Role Dependencies allow for roles to automatically pull in other roles. 99 | - class_notes: Role dependencies allow you to automatically pull in other roles when using a role. Role dependencies are stored in the meta/main.yml file contained within the role directory. This file should contain a list of roles and parameters to insert before the specified role. 100 | 101 | - 102 | - h3: Example role dependency entry in the meta/main.yml file 103 | - code: | 104 | --- 105 | dependencies: 106 | - { role: common, some_parameter: 3 } 107 | - { role: apache, port: 80 } 108 | - { role: postgres, dbname: blarg, other_parameter: 12 } 109 | - 110 | - h3: Duplicate Role Dependiencies 111 | - p: You can call a role dependency multiple times with various parameters. 112 | - code: | 113 | --- 114 | allow_duplicates: yes 115 | dependencies: 116 | - { role: apache, port: 80 } 117 | - { role: apache, port: 8080 } 118 | - class_notes: Not a common use case, but you can parameterize role dependencies in a repeated way. Such as having multiple runs of apache based on the dependencies of another role. This could get you multiple versions of a stack of apache, tomcat and a database with different parameters. The order of execution would be the order of the duplicates and repeat the roles that depend on it. For example, this could be tomcat, apache with port 80, then tomcat, apache with port 8080, and so on. They will rerun against the same inventory, of course. 119 | 120 | - 121 | - h2: "Embedding Custom Modules" 122 | - p: Role-specific custom modules can be packaged with the role. 123 | - class_notes: This is an advanced topic that should not be relevant for most users. If you write a custom module you may wish to distribute it as part of a role. Generally speaking, Ansible as a project is very interested in taking high-quality modules into ansible core for inclusion, so this shouldn’t be the norm, but it’s quite easy to do. 124 | 125 | - 126 | - h3: "Examples of embedding a custom module in a role:" 127 | - code: | 128 | roles/ 129 | my_role/ 130 | library/ 131 | module1 132 | module2 133 | - class_notes: Alongside the ‘tasks’ and ‘handlers’ structure of a role, add a directory named ‘library’. In this ‘library’ directory, then include the module directly inside of it. 134 | 135 | - 136 | - h3: "Calling the role with a custom module in a playbook:" 137 | - code: | 138 | - hosts: webservers 139 | roles: 140 | - my_role 141 | - class_notes: As you can see, we call a role with a custom module just as we would a role without one. This is because our custom module also follows the file structure as previously described. 142 | 143 | - 144 | - h2: "Ansible Galaxy" 145 | - p: Sharing is caring. visit http://galaxy.ansible.com 146 | - class_notes: Ansible Galaxy is a free site for finding, downloading, rating, and reviewing all kinds of community developed Ansible roles and can be a great way to get a jumpstart on your automation projects. You can sign up with social auth, and the download client ‘ansible-galaxy’ is included in Ansible 1.4.2 and later. 147 | 148 | - 149 | - h3: "One last trick: Galaxy has you covered." 150 | - code: | 151 | ansible-galaxy init mynewrole 152 | - class_notes: the ansible-galaxy command doesn't just download an install roles from the public service, it will also initialize an empty role with the role name of your choosing. This means it will place all the folders, skeleton files and file structure as needed. Use this to write roles without having to remember to create every file or folder. 153 | -------------------------------------------------------------------------------- /advanced/chapter_09.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Jesse K 4 | title: Delegation 5 | description: "How delegation can be used to redirect tasks to a different host." 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Delegation 13 | - p: I like things done my way but by somebody else. 14 | - class_notes: | 15 | In this chapter we discuss delegation, how tasks in a play 16 | can be redirected to an alternate host for execution. 17 | What use cases can you think of for looping over hosts to 18 | execute a task, but have that task execute somewhere else? 19 | 20 | - 21 | - h2: Delegation 22 | - ul: 23 | - Local actions and actions on other hosts 24 | - Delegation to a host in inventory 25 | - Delegation to a host not in inventory 26 | - Task execution concurrency with delegation 27 | - class_notes: | 28 | Actions can be done locally, or on another system in your 29 | inventory, or out of your inventory. Execution concurrency 30 | is a concern as well. 31 | 32 | - 33 | - h2: Local actions and actions on other hosts 34 | - p: "Task control keyword: delegate_to" 35 | - code: | 36 | - name: take out of load balancer pool 37 | command: /usr/bin/take_out_of_pool {{ inventory_hostname }} 38 | delegate_to: localhost 39 | 40 | - name: update packages 41 | yum: name=acme-web-stack state=latest 42 | 43 | - name: add back to load balancer pool 44 | command: /usr/bin/add_back_to_pool {{ inventory_hostname }} 45 | delegate_to: localhost 46 | - class_notes: | 47 | The delegate_to keyword is what tells Ansible to redirect the 48 | task to the system listed. The variables you reference are 49 | attached to the host in the loop, not the host you are 50 | delegating to. So the task has the context of the host in the 51 | loop but it just gets executed on the host you delegate to. 52 | 53 | Is there another way to indicate that an action needs to 54 | happen locally? 55 | 56 | - 57 | - h2: Delegation to a host in inventory 58 | - p: Delegation most often targets another host in your inventory 59 | - p: Uses connection variable data from delegate target 60 | - ul: 61 | - ansible_connection 62 | - ansible_ssh_host 63 | - ansible_ssh_port 64 | - ansible_ssh_user 65 | - etc... 66 | - class_notes: | 67 | When delegating to a host listed in your inventory, data 68 | from your delegation target will be used when creating the 69 | connection to the delegation target, but only the connection 70 | related variables. The rest will be read from the host in the 71 | loop. 72 | 73 | - 74 | - h2: Delegation to a host not in inventory 75 | - p: "Delegation: not just limited to hosts in your inventory" 76 | - p: Make use of add_host to adjust connection details 77 | - code: | 78 | - name: add delegation host 79 | add_host: name=hubert ansible_ssh_host=192.168.10.2 80 | ansible_ssh_user=fred 81 | - class_notes: | 82 | You can also delegate to a host that doesn't exist in your 83 | inventory. In this case, ansible will use the string provided 84 | verbatim and attempt to connect to it with the current connection 85 | type and details. If you need to adjust the connection details, 86 | make use of the add_host task to create an ephemeral host in your 87 | inventory with connection data defined. 88 | 89 | - 90 | - h2: 'Lab: ephemeral host task delegation' 91 | - p: Create an ephemeral host and delegate a task to it 92 | - ul: 93 | - Create a play for localhost 94 | - Create a host using add_host with detailed connection variables 95 | - Create a simple task that is delegated to the added host 96 | - Run playbook with -vvvv to observe the connection details 97 | - class_notes: | 98 | This is a simple contrived lab that will exercise making use of 99 | add_host to create an ephemeral host to delegate a task to. This 100 | host doesn't have to actually exist, a connection failure on the 101 | task will suffice to see the connection details to observe the 102 | delegation. Feel free to play with values and observe how they 103 | reflect in running the lab. 104 | - h6: 'Objective: Using an ephemeral host to delegate a single task to' 105 | 106 | - 107 | - h2: Sample Play 108 | - code: | 109 | --- 110 | - name: test play 111 | hosts: localhost 112 | 113 | tasks: 114 | - name: add delegation host 115 | add_host: name=hubert ansible_ssh_host=192.168.10.2 116 | ansible_ssh_user=fred 117 | 118 | - name: silly echo 119 | command: echo {{ inventory_hostname }} 120 | delegate_to: hubert 121 | 122 | - code: | 123 | $ ansible-playbook test-play.yml -vvvv 124 | 125 | - 126 | - h2: Task execution concurrency with delegation 127 | - p: Delegated tasks will run for every host in the loop 128 | - p: Tasks will run with configured forks / serial 129 | - p: Be aware of race conditions and concurrency issues 130 | - class_notes: | 131 | Delegated tasks will run for every host in the hosts: , but this 132 | can create issues with race conditions, particularly when using 133 | conditionals in the task, as the forks count will be used to create 134 | multiple concurrent tasks. This can also create a thundering 135 | herd problem of too many connections opening at once to a single 136 | host. SSH servers have a MaxStartups config option that can limit 137 | how many concurrent connections it'll allow. Easy to overflow. 138 | 139 | What happens when you have five hosts in your set, five or more 140 | forks, a task that is conditional on the existence of a file, and 141 | the task creates the file. All five tasks will run at once, racing 142 | to create the file. 143 | 144 | - 145 | - h2: 'Lab: multi-host task delegation' 146 | - ul: 147 | - Create a play to loop over 'webservers' group 148 | - Create a task to use mysql_user module to add a user 149 | - Use host specific mysql user / password data 150 | - delegate_to should be used to execute on the first 'databases' server 151 | - h6: 'Objective: Add mysql users to a database for a set of hosts' 152 | 153 | - 154 | - h2: Sample Play 155 | - code: | 156 | --- 157 | - name: MySQL Users 158 | hosts: webservers 159 | 160 | tasks: 161 | - name: add a mysql user for the server 162 | mysql_user: name={{ db_username }} host={{ inventory_hostname }} 163 | password='{{ db_password }}' priv='ansible.*:ALL' 164 | state=present 165 | delegate_to: databases[0] 166 | - p: | 167 | When ran with -vvvv one can clearly see the connection debugging 168 | output which will show the delegation in action. 169 | -------------------------------------------------------------------------------- /advanced/chapter_10.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Matt Martz 4 | title: jinja2 template labs 5 | description: Some jinja2 stuff 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Jinja2 Templates Labs 13 | 14 | - 15 | - h2: Lab 16 | - p: Create playbook and a jinja2 template to achieve the following results 17 | - ul: 18 | - Template out /etc/sysconfig/iptables 19 | - Only allow access to MySQL (tcp/3306) from servers in the webservers group 20 | - A play to create this file from the template 21 | - The play should have a handler to reload iptables when the file changes 22 | - iptables should be enabled and configured to start on boot 23 | 24 | - 25 | - h2: Sample template 26 | - code: | 27 | *filter 28 | :INPUT ACCEPT [0:0] 29 | :FORWARD ACCEPT [0:0] 30 | :OUTPUT ACCEPT [0:0] 31 | 32 | {% for server in groups['webservers'] %} 33 | -A INPUT -p tcp -s {{ hostvars[server].ansible_eth1.ipv4.address }} -i eth1 -d {{ ansible_eth1.ipv4.address }} --dport 3306 -j ACCEPT 34 | {% endfor %} 35 | 36 | {% for server in groups['databases'] %} 37 | {% if server != inventory_hostname %} 38 | -A INPUT -p tcp -s {{ hostvars[server].ansible_eth1.ipv4.address }} -i eth1 -d {{ ansible_eth1.ipv4.address }} --dport 3306 -j ACCEPT 39 | {% endif %} 40 | {% endfor %} 41 | 42 | -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 43 | -A INPUT -p icmp -j ACCEPT 44 | -A INPUT -i lo -j ACCEPT 45 | -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT 46 | -A INPUT -j REJECT --reject-with icmp-host-prohibited 47 | -A FORWARD -j REJECT --reject-with icmp-host-prohibited 48 | COMMIT 49 | 50 | - 51 | - h2: Sample play 52 | - code: | 53 | --- 54 | - hosts: webservers 55 | gather_facts: true 56 | 57 | - hosts: databases 58 | handlers: 59 | - name: Reload iptables 60 | service: name=iptables state=reloaded 61 | 62 | tasks: 63 | - name: Template /etc/sysconfig/iptables 64 | template: src=templates/iptables.j2 dest=/etc/sysconfig/iptables 65 | notify: Reload iptables 66 | 67 | - name: Ensure iptables is started and enabled 68 | service: name=iptables state=started enabled=yes 69 | 70 | -------------------------------------------------------------------------------- /advanced/chapter_11.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Foo 4 | title: Advanced Ansible 5 | description: Advanced Ansible Course 6 | 7 | slides: 8 | - 9 | - nested: 10 | - 11 | - h1: Assessment Questions 12 | - link: 13 | - http://bit.ly/ansible_advanced 14 | - http://bit.ly/ansible_advanced 15 | -------------------------------------------------------------------------------- /advanced/resources/chapter06/shot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/training-content/a5e45373d919d90738afa64350d5303a69022147/advanced/resources/chapter06/shot1.png -------------------------------------------------------------------------------- /advanced/resources/hosts/hosts.graphml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | web01 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | db01 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ansible 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | <?xml version="1.0" encoding="utf-8"?> 117 | <svg version="1.1" 118 | xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 119 | x="0px" y="0px" width="36px" height="57px" viewBox="0 -0.741 36 57" enable-background="new 0 -0.741 36 57" 120 | xml:space="preserve"> 121 | <defs> 122 | </defs> 123 | <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="230.1768" y1="798.6021" x2="180.3346" y2="798.6021" gradientTransform="matrix(1 0 0 1 -195.2002 -770.8008)"> 124 | <stop offset="0" style="stop-color:#4D4D4D"/> 125 | <stop offset="1" style="stop-color:#8D8D8D"/> 126 | </linearGradient> 127 | <rect y="0.943" fill="url(#SVGID_1_)" width="34.977" height="53.716"/> 128 | <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="224.6807" y1="798.6021" x2="200.6973" y2="798.6021" gradientTransform="matrix(1 0 0 1 -195.2002 -770.8008)"> 129 | <stop offset="0.0319" style="stop-color:#848484"/> 130 | <stop offset="0.1202" style="stop-color:#8C8C8C"/> 131 | <stop offset="0.308" style="stop-color:#969696"/> 132 | <stop offset="0.5394" style="stop-color:#999999"/> 133 | <stop offset="0.5501" style="stop-color:#9C9C9C"/> 134 | <stop offset="0.6256" style="stop-color:#B0B0B0"/> 135 | <stop offset="0.7118" style="stop-color:#BEBEBE"/> 136 | <stop offset="0.8178" style="stop-color:#C7C7C7"/> 137 | <stop offset="1" style="stop-color:#C9C9C9"/> 138 | </linearGradient> 139 | <path fill="url(#SVGID_2_)" d="M5.497,0.943c7.945-1.258,16.04-1.258,23.983,0c0,17.905,0,35.811,0,53.716 140 | c-7.943,1.258-16.039,1.258-23.983,0C5.497,36.753,5.497,18.848,5.497,0.943z"/> 141 | <path fill="#515151" d="M5.497,14.621c7.995,0,15.989,0,23.983,0c0,13.346,0,26.693,0,40.037c-7.943,1.258-16.039,1.258-23.983,0 142 | C5.497,41.314,5.497,27.967,5.497,14.621z"/> 143 | <path opacity="0.43" fill="#565656" d="M5.497,4.745c7.982-0.628,16.001-0.628,23.983,0c0,2.707,0,5.413,0,8.12 144 | c-7.994,0-15.989,0-23.983,0C5.497,10.158,5.497,7.452,5.497,4.745z"/> 145 | <path opacity="0.43" fill="none" stroke="#4D4D4D" stroke-width="0.0999" stroke-miterlimit="10" d="M5.497,4.745 146 | c7.982-0.628,16.001-0.628,23.983,0c0,2.707,0,5.413,0,8.12c-7.994,0-15.989,0-23.983,0C5.497,10.158,5.497,7.452,5.497,4.745z"/> 147 | <polygon opacity="0.43" fill="#565656" stroke="#4D4D4D" stroke-width="0.0135" stroke-miterlimit="10" enable-background="new " points=" 148 | 6.496,5.746 9.869,5.606 9.869,6.661 6.496,6.799 "/> 149 | <rect x="31.307" y="2.517" fill="#E7ED00" stroke="#717171" stroke-width="0.1926" stroke-miterlimit="10" width="3.692" height="1.505"/> 150 | <rect x="31.307" y="5.8" fill="#C8FF00" stroke="#717171" stroke-width="0.1926" stroke-miterlimit="10" width="3.692" height="1.507"/> 151 | <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="29.4414" y1="35.1235" x2="5.4995" y2="35.1235"> 152 | <stop offset="0" style="stop-color:#808080"/> 153 | <stop offset="0.1907" style="stop-color:#828282"/> 154 | <stop offset="0.2955" style="stop-color:#8A8A8A"/> 155 | <stop offset="0.3795" style="stop-color:#989898"/> 156 | <stop offset="0.4524" style="stop-color:#ACACAC"/> 157 | <stop offset="0.5175" style="stop-color:#C5C5C5"/> 158 | <stop offset="0.5273" style="stop-color:#C9C9C9"/> 159 | <stop offset="0.5914" style="stop-color:#C9C9C9"/> 160 | <stop offset="0.9681" style="stop-color:#C9C9C9"/> 161 | </linearGradient> 162 | <path fill="url(#SVGID_3_)" d="M5.5,14.822c0,13.22,0,26.438,0,39.66c7.931,1.256,16.012,1.256,23.941,0c0-13.222,0-26.439,0-39.66 163 | C21.461,14.822,13.48,14.822,5.5,14.822z M28.396,18.703c-0.74,0.01-1.482,0.02-2.225,0.029c0-0.951,0-1.901-0.001-2.85 164 | c0.742-0.003,1.483-0.005,2.224-0.008C28.396,16.817,28.396,17.76,28.396,18.703z M16.354,42.496c0-0.961,0-1.924,0-2.885 165 | c0.744,0.006,1.489,0.006,2.233,0c0,0.961,0,1.924,0,2.885C17.843,42.503,17.098,42.503,16.354,42.496z M18.587,43.568 166 | c0,0.955,0,1.91,0,2.866c-0.744,0.009-1.489,0.009-2.234,0c0-0.956,0-1.911,0-2.866C17.098,43.574,17.843,43.574,18.587,43.568z 167 | M18.586,27.742c0,0.961,0,1.922,0,2.886c-0.744,0.004-1.488,0.004-2.231,0c0-0.964,0-1.925,0-2.886 168 | C17.099,27.746,17.842,27.746,18.586,27.742z M16.354,26.671c0-0.955,0-1.91,0-2.865c0.743,0.002,1.487,0.002,2.23,0 169 | c0,0.955,0,1.91,0,2.865C17.842,26.675,17.099,26.675,16.354,26.671z M16.354,34.583c0-0.961,0-1.924,0-2.885 170 | c0.744,0.004,1.488,0.004,2.231,0c0,0.961,0,1.924,0,2.885C17.842,34.588,17.099,34.588,16.354,34.583z M18.586,35.656 171 | c0,0.961,0,1.924,0.001,2.885c-0.745,0.008-1.489,0.008-2.233,0c0-0.961,0-1.924,0-2.885C17.099,35.66,17.842,35.66,18.586,35.656z 172 | M15.307,30.619c-0.742-0.01-1.484-0.021-2.227-0.039c0-0.957,0-1.916,0-2.875c0.742,0.014,1.485,0.023,2.226,0.029 173 | C15.307,28.695,15.307,29.656,15.307,30.619z M15.307,31.689c0,0.961,0,1.924,0,2.885c-0.742-0.012-1.485-0.025-2.227-0.047 174 | c0-0.959,0.001-1.92,0.001-2.877C13.822,31.667,14.565,31.68,15.307,31.689z M15.307,35.644c0,0.959,0,1.922-0.001,2.883 175 | c-0.742-0.012-1.485-0.031-2.228-0.056c0-0.959,0.001-1.918,0.001-2.877C13.821,35.617,14.564,35.633,15.307,35.644z M15.306,39.597 176 | c0,0.96,0,1.922,0,2.883c-0.742-0.016-1.486-0.037-2.228-0.064c0-0.959,0-1.916,0.001-2.877 177 | C13.82,39.564,14.563,39.585,15.306,39.597z M19.637,39.597c0.742-0.012,1.484-0.033,2.227-0.059c0,0.959,0,1.918,0,2.875 178 | c-0.741,0.029-1.483,0.052-2.227,0.064C19.637,41.519,19.637,40.559,19.637,39.597z M19.637,38.527c0-0.961,0-1.924,0-2.883 179 | c0.74-0.012,1.482-0.027,2.225-0.05c0,0.959,0,1.918,0.002,2.876C21.121,38.496,20.377,38.515,19.637,38.527z M19.637,34.572 180 | c0-0.961,0-1.922-0.002-2.883c0.741-0.01,1.483-0.021,2.225-0.039c0.002,0.957,0.002,1.916,0.002,2.875 181 | C21.119,34.547,20.376,34.564,19.637,34.572z M19.635,30.619c0-0.963,0-1.924,0-2.885c0.74-0.006,1.483-0.017,2.225-0.029 182 | c0,0.959,0,1.916,0,2.875C21.118,30.599,20.376,30.609,19.635,30.619z M19.633,26.666c0-0.955,0-1.909,0-2.864 183 | c0.741-0.005,1.483-0.013,2.227-0.021c0,0.951,0,1.903,0,2.856C21.118,26.65,20.375,26.66,19.633,26.666z M19.633,22.732 184 | c-0.001-0.963-0.001-1.924-0.001-2.885c0.741-0.002,1.483-0.006,2.226-0.012c0,0.959,0.002,1.918,0.002,2.877 185 | C21.116,22.72,20.374,22.728,19.633,22.732z M18.586,22.736c-0.744,0.002-1.487,0.002-2.23,0c0-0.963,0-1.924,0-2.887 186 | c0.743,0.002,1.487,0.002,2.23,0C18.586,20.813,18.586,21.773,18.586,22.736z M15.309,22.732c-0.742-0.004-1.483-0.012-2.226-0.02 187 | c0-0.959,0.001-1.918,0.001-2.877c0.742,0.006,1.484,0.01,2.226,0.012C15.31,20.808,15.309,21.769,15.309,22.732z M15.309,23.801 188 | c0,0.955,0,1.91,0,2.864c-0.742-0.006-1.483-0.016-2.227-0.027c0-0.953,0-1.906,0-2.859C13.825,23.789,14.566,23.796,15.309,23.801z 189 | M12.036,26.617c-0.742-0.017-1.483-0.033-2.225-0.055c0-0.947,0-1.895,0.001-2.841c0.741,0.019,1.483,0.031,2.225,0.042 190 | C12.037,24.716,12.036,25.666,12.036,26.617z M12.035,27.683c0,0.957,0,1.916,0,2.873c-0.742-0.021-1.483-0.047-2.225-0.076 191 | c0-0.953,0-1.904,0-2.857C10.552,27.646,11.293,27.667,12.035,27.683z M12.035,31.621c0,0.957-0.001,1.914-0.001,2.871 192 | c-0.742-0.023-1.483-0.055-2.224-0.092c0-0.953,0-1.906,0-2.859C10.551,31.572,11.292,31.6,12.035,31.621z M12.033,35.56 193 | c0,0.956-0.001,1.914-0.001,2.871c-0.742-0.031-1.484-0.066-2.225-0.111c0-0.953,0.001-1.906,0.001-2.858 194 | C10.549,35.5,11.291,35.533,12.033,35.56z M12.031,39.498c0,0.955,0,1.914-0.001,2.869c-0.742-0.035-1.484-0.078-2.225-0.129 195 | c0-0.953,0-1.904,0.001-2.857C10.547,39.426,11.289,39.465,12.031,39.498z M12.03,43.435c0,0.951-0.001,1.901-0.001,2.854 196 | c-0.742-0.041-1.484-0.09-2.225-0.149c0-0.944,0.001-1.892,0.001-2.838C10.546,43.353,11.288,43.4,12.03,43.435z M13.077,43.482 197 | c0.743,0.031,1.486,0.053,2.228,0.067c0,0.956,0,1.91,0,2.864c-0.742-0.016-1.486-0.041-2.229-0.074 198 | C13.077,45.389,13.077,44.435,13.077,43.482z M15.305,47.486c0,0.961,0,1.922,0,2.883c-0.743-0.019-1.487-0.047-2.23-0.084 199 | c0-0.959,0-1.918,0.001-2.875C13.818,47.443,14.562,47.468,15.305,47.486z M16.353,47.504c0.745,0.009,1.49,0.009,2.234,0 200 | c0.001,0.96,0.001,1.924,0.001,2.883c-0.745,0.011-1.49,0.011-2.235,0C16.353,49.427,16.353,48.464,16.353,47.504z M19.639,47.486 201 | c0.741-0.018,1.483-0.043,2.227-0.076c0,0.957,0.002,1.916,0.002,2.875c-0.742,0.037-1.486,0.065-2.229,0.084 202 | C19.639,49.406,19.639,48.447,19.639,47.486z M19.637,46.414c0-0.954,0-1.908,0-2.864c0.742-0.015,1.484-0.036,2.229-0.067 203 | c0,0.953,0,1.905,0,2.857C21.122,46.373,20.379,46.398,19.637,46.414z M22.911,43.435c0.741-0.035,1.483-0.082,2.224-0.135 204 | c0,0.945,0,1.895,0.002,2.838c-0.74,0.059-1.482,0.107-2.226,0.15C22.911,45.336,22.911,44.386,22.911,43.435z M22.911,42.369 205 | c-0.001-0.957-0.001-1.914-0.002-2.871c0.741-0.032,1.483-0.069,2.225-0.117c0,0.954,0.001,1.906,0.001,2.857 206 | C24.395,42.289,23.652,42.333,22.911,42.369z M22.909,38.431c0-0.957-0.001-1.915-0.001-2.871c0.742-0.027,1.482-0.061,2.224-0.098 207 | c0.001,0.951,0.001,1.904,0.001,2.857C24.393,38.363,23.65,38.4,22.909,38.431z M22.908,34.494c0-0.957-0.002-1.916-0.002-2.871 208 | c0.742-0.021,1.482-0.051,2.225-0.079c0,0.952,0,1.903,0.001,2.856C24.391,34.437,23.648,34.468,22.908,34.494z M22.906,30.556 209 | c0-0.957,0-1.916-0.002-2.873c0.742-0.016,1.484-0.037,2.226-0.061c0,0.953,0.001,1.904,0.001,2.857 210 | C24.391,30.509,23.648,30.535,22.906,30.556z M22.904,26.617c0-0.951,0-1.901,0-2.854c0.74-0.011,1.482-0.025,2.224-0.042 211 | c0,0.946,0.001,1.894,0.001,2.841C24.389,26.583,23.646,26.601,22.904,26.617z M22.902,22.699c0-0.957,0-1.916,0-2.874 212 | c0.742-0.007,1.482-0.014,2.225-0.023c0.001,0.953,0.001,1.906,0.001,2.859C24.387,22.676,23.646,22.689,22.902,22.699z 213 | M22.902,18.76C22.9,17.802,22.9,16.845,22.9,15.887c0.742,0,1.481-0.003,2.225-0.004c0.001,0.953,0.001,1.906,0.002,2.858 214 | C24.385,18.75,23.643,18.756,22.902,18.76z M21.855,18.767c-0.742,0.004-1.482,0.007-2.225,0.009c0-0.961,0-1.922,0-2.884 215 | c0.741,0,1.482-0.001,2.225-0.002C21.855,16.849,21.855,17.808,21.855,18.767z M18.585,18.779c-0.743,0.001-1.486,0.001-2.229,0 216 | c0-0.961,0-1.923,0-2.885c0.742,0,1.486,0,2.229,0C18.585,16.855,18.585,17.817,18.585,18.779z M15.31,18.777 217 | c-0.742-0.002-1.483-0.005-2.225-0.009c0-0.959,0-1.918,0-2.877c0.742,0,1.483,0.001,2.225,0.002 218 | C15.31,16.854,15.31,17.815,15.31,18.777z M12.039,18.76c-0.742-0.005-1.483-0.011-2.225-0.019c0-0.953,0-1.905,0.001-2.858 219 | c0.742,0.001,1.483,0.004,2.224,0.004C12.039,16.845,12.039,17.803,12.039,18.76z M12.039,19.827c0,0.957-0.001,1.915-0.001,2.872 220 | c-0.741-0.01-1.483-0.021-2.224-0.035c0-0.953,0-1.906,0-2.859C10.555,19.813,11.296,19.819,12.039,19.827z M8.768,22.64 221 | c-0.741-0.018-1.482-0.035-2.223-0.057c0-0.943,0-1.887,0-2.831c0.741,0.013,1.482,0.025,2.223,0.036 222 | C8.768,20.739,8.768,21.689,8.768,22.64z M8.767,23.697c0,0.944,0,1.89,0,2.832c-0.741-0.024-1.482-0.053-2.223-0.084 223 | c0-0.938,0-1.873,0-2.811C7.284,23.658,8.026,23.679,8.767,23.697z M8.766,27.587c0,0.949-0.001,1.898-0.001,2.85 224 | c-0.74-0.033-1.481-0.068-2.222-0.111c0-0.942,0-1.887,0-2.83C7.284,27.529,8.025,27.56,8.766,27.587z M8.765,31.494 225 | c0,0.951-0.001,1.9-0.001,2.852c-0.74-0.04-1.481-0.087-2.221-0.139c0-0.943,0-1.887,0-2.831C7.283,31.42,8.023,31.459,8.765,31.494 226 | z M8.763,35.404c0,0.949,0,1.899,0,2.851c-0.741-0.052-1.481-0.104-2.22-0.168c0-0.942,0-1.886,0-2.829 227 | C7.282,35.31,8.022,35.361,8.763,35.404z M8.762,39.312c0,0.949,0,1.899-0.001,2.852c-0.741-0.059-1.48-0.123-2.219-0.195 228 | c0-0.943,0-1.889,0-2.83C7.281,39.203,8.021,39.26,8.762,39.312z M8.76,43.219c0,0.944,0,1.888-0.001,2.832 229 | c-0.74-0.065-1.479-0.14-2.218-0.224c0-0.938,0-1.875,0-2.812C7.281,43.092,8.02,43.16,8.76,43.219z M8.759,47.109 230 | c0,0.951,0,1.9,0,2.851c-0.741-0.073-1.48-0.158-2.219-0.253c0-0.942,0-1.887,0-2.828C7.279,46.964,8.019,47.039,8.759,47.109z 231 | M9.804,47.201c0.741,0.06,1.483,0.111,2.224,0.154c0,0.955,0,1.912,0,2.868c-0.742-0.045-1.484-0.103-2.225-0.166 232 | C9.804,49.107,9.804,48.154,9.804,47.201z M12.027,51.291c0,0.957,0,1.916,0,2.873c-0.742-0.053-1.484-0.114-2.225-0.188 233 | c0-0.951,0.001-1.904,0.001-2.857C10.544,51.187,11.285,51.244,12.027,51.291z M13.075,51.353c0.743,0.039,1.486,0.067,2.229,0.086 234 | c0,0.961,0,1.922,0,2.885c-0.743-0.021-1.487-0.053-2.229-0.094C13.075,53.269,13.075,52.312,13.075,51.353z M16.353,51.459 235 | c0.745,0.009,1.49,0.009,2.235,0c0,0.961,0,1.924,0,2.885c-0.745,0.013-1.491,0.013-2.235,0 236 | C16.353,53.382,16.353,52.42,16.353,51.459z M19.639,51.439c0.741-0.019,1.485-0.049,2.229-0.086c0,0.959,0,1.92,0.001,2.877 237 | c-0.743,0.041-1.485,0.072-2.229,0.094C19.639,53.361,19.639,52.4,19.639,51.439z M22.913,51.291 238 | c0.743-0.047,1.483-0.104,2.226-0.172c0,0.953,0,1.906,0,2.857c-0.74,0.073-1.481,0.135-2.224,0.188 239 | C22.914,53.205,22.914,52.248,22.913,51.291z M22.913,50.224c-0.001-0.956-0.001-1.912-0.001-2.869 240 | c0.742-0.043,1.484-0.095,2.225-0.154c0,0.953,0,1.906,0.002,2.857C24.396,50.123,23.654,50.179,22.913,50.224z M26.184,47.109 241 | c0.739-0.066,1.479-0.145,2.217-0.229c0,0.942,0,1.887,0,2.83c-0.736,0.092-1.478,0.177-2.217,0.252 242 | C26.184,49.009,26.184,48.06,26.184,47.109z M26.184,46.051c-0.002-0.944-0.002-1.888-0.002-2.832 243 | c0.739-0.06,1.48-0.127,2.219-0.202c0,0.938,0,1.873,0,2.811C27.662,45.912,26.923,45.986,26.184,46.051z M26.182,42.162 244 | c0-0.95-0.002-1.9-0.002-2.85c0.74-0.052,1.48-0.109,2.219-0.176c0.002,0.943,0.002,1.887,0.002,2.83 245 | C27.662,42.039,26.921,42.105,26.182,42.162z M26.18,38.253c0-0.95,0-1.9-0.002-2.852c0.742-0.041,1.482-0.093,2.221-0.146 246 | c0,0.942,0,1.887,0,2.829C27.66,38.15,26.92,38.203,26.18,38.253z M26.178,34.345c0-0.949,0-1.898,0-2.852 247 | c0.74-0.034,1.481-0.073,2.221-0.117c0,0.943,0,1.887,0,2.83C27.659,34.258,26.918,34.305,26.178,34.345z M26.177,30.437 248 | c0-0.949,0-1.9-0.001-2.85c0.741-0.027,1.481-0.059,2.221-0.092c0,0.943,0.002,1.888,0.002,2.83 249 | C27.659,30.367,26.918,30.404,26.177,30.437z M26.176,26.529c-0.001-0.942-0.001-1.888-0.001-2.832 250 | c0.742-0.018,1.482-0.039,2.222-0.063c0,0.938,0,1.873,0,2.811C27.657,26.476,26.917,26.503,26.176,26.529z M26.174,22.64 251 | c0-0.951-0.001-1.901-0.001-2.851c0.741-0.01,1.483-0.022,2.224-0.035c0,0.943,0,1.886,0,2.831 252 | C27.657,22.605,26.915,22.623,26.174,22.64z M8.769,15.881c0,0.95,0,1.9-0.001,2.85c-0.741-0.008-1.482-0.018-2.223-0.028 253 | c0-0.943,0-1.887,0-2.83C7.286,15.876,8.028,15.878,8.769,15.881z M6.54,50.758c0.738,0.097,1.478,0.183,2.218,0.258 254 | c0,0.95,0,1.901,0,2.853c-0.741-0.084-1.48-0.178-2.218-0.28C6.54,52.646,6.54,51.701,6.54,50.758z M26.184,53.869 255 | c0-0.95,0-1.899,0-2.853c0.739-0.075,1.479-0.163,2.217-0.259c0.002,0.941,0.002,1.889,0.002,2.83 256 | C27.663,53.693,26.925,53.785,26.184,53.869z"/> 257 | <path id="highlight_2_" opacity="0.17" fill="#FFFFFF" enable-background="new " d="M0,0.943h5.497c0,0,6.847-0.943,11.974-0.943 258 | C22.6,0,29.48,0.943,29.48,0.943h5.496v41.951c0,0-12.076-0.521-18.623-2.548C9.807,38.32,0,30.557,0,30.557V0.943z"/> 259 | </svg> 260 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /advanced/resources/hosts/hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/training-content/a5e45373d919d90738afa64350d5303a69022147/advanced/resources/hosts/hosts.png -------------------------------------------------------------------------------- /advanced/root.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Rackspace and Ansible 4 | title: Ansible Fundamentals 5 | description: Ansible Fundamentals 6 | slides: [] 7 | -------------------------------------------------------------------------------- /advanced_lab/.advanced_lab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ansible/training-content/a5e45373d919d90738afa64350d5303a69022147/advanced_lab/.advanced_lab -------------------------------------------------------------------------------- /advanced_lab/chapter_05/variable_override.yml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | connection: local 3 | vars: 4 | - local_var: "override me" 5 | tasks: 6 | - name: print out the variable 7 | debug: msg="This should not output 'override me' - {{ local_var }}" 8 | -------------------------------------------------------------------------------- /advanced_lab/chapter_07/secrets.yml: -------------------------------------------------------------------------------- 1 | --- 2 | password: thisisasecret 3 | 4 | -------------------------------------------------------------------------------- /advanced_lab/chapter_07/vault-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | connection: local 4 | 5 | vars_files: 6 | - secrets.yml 7 | 8 | tasks: 9 | - debug: msg="I know a secret! {{ password }}" 10 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lab.yml: -------------------------------------------------------------------------------- 1 | You'll be creating a role named "db" in install mysql alongside the rest of the roles provided to ultimately create a full LAMP stack install. 2 | 3 | For guidance, you may consult https://github.com/ansible/ansible-examples. -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/README.md: -------------------------------------------------------------------------------- 1 | LAMP Stack + HAProxy: Example Playbooks 2 | ----------------------------------------------------------------------------- 3 | 4 | - Requires Ansible 1.2 5 | - Expects CentOS/RHEL 6 hosts 6 | 7 | This example is an extension of the simple LAMP deployment. Here we'll install 8 | and configure a web server with an HAProxy load balancer in front, and deploy 9 | an application to the web servers. This set of playbooks also have the 10 | capability to dynamically add and remove web server nodes from the deployment. 11 | It also includes examples to do a rolling update of a stack without affecting 12 | the service. 13 | 14 | You can also optionally configure a Nagios monitoring node. 15 | 16 | ### Initial Site Setup 17 | 18 | First we configure the entire stack by listing our hosts in the 'hosts' 19 | inventory file, grouped by their purpose: 20 | 21 | [webservers] 22 | webserver1 23 | webserver2 24 | 25 | [dbservers] 26 | dbserver 27 | 28 | [lbservers] 29 | lbserver 30 | 31 | [monitoring] 32 | nagios 33 | 34 | After which we execute the following command to deploy the site: 35 | 36 | ansible-playbook -i hosts site.yml 37 | 38 | The deployment can be verified by accessing the IP address of your load 39 | balancer host in a web browser: http://:8888. Reloading the page 40 | should have you hit different webservers. 41 | 42 | ### Removing and Adding a Node 43 | 44 | Removal and addition of nodes to the cluster is as simple as editing the 45 | hosts inventory and re-running: 46 | 47 | ansible-playbook -i hosts site.yml 48 | 49 | ### Rolling Update 50 | 51 | Rolling updates are the preferred way to update the web server software or 52 | deployed application, since the load balancer can be dynamically configured 53 | to take the hosts to be updated out of the pool. This will keep the service 54 | running on other servers so that the users are not interrupted. 55 | 56 | In this example the hosts are updated in serial fashion, which means that 57 | only one server will be updated at one time. If you have a lot of web server 58 | hosts, this behaviour can be changed by setting the 'serial' keyword in 59 | webservers.yml file. 60 | 61 | Once the code has been updated in the source repository for your application 62 | which can be defined in the group_vars/all file, execute the following 63 | command: 64 | 65 | ansible-playbook -i hosts rolling_update.yml 66 | 67 | You can optionally pass: -e webapp_version=xxx to the rolling_update 68 | playbook to specify a specific version of the example webapp to deploy. 69 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | # Variables here are applicable to all host groups 3 | 4 | httpd_port: 80 5 | ntpserver: 192.168.1.2 6 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/group_vars/dbservers: -------------------------------------------------------------------------------- 1 | --- 2 | # The variables file used by the playbooks in the dbservers group. 3 | # These don't have to be explicitly imported by vars_files: they are autopopulated. 4 | 5 | mysqlservice: mysqld 6 | mysql_port: 3306 7 | dbuser: root 8 | dbname: foodb 9 | upassword: abc 10 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/group_vars/lbservers: -------------------------------------------------------------------------------- 1 | --- 2 | # Variables for the HAproxy configuration 3 | 4 | # HAProxy supports "http" and "tcp". For SSL, SMTP, etc, use "tcp". 5 | mode: http 6 | 7 | # Port on which HAProxy should listen 8 | listenport: 8888 9 | 10 | # A name for the proxy daemon, this wil be the suffix in the logs. 11 | daemonname: myapplb 12 | 13 | # Balancing Algorithm. Available options: 14 | # roundrobin, source, leastconn, source, uri 15 | # (if persistance is required use, "source") 16 | balance: roundrobin 17 | 18 | # Ethernet interface on which the load balancer should listen 19 | # Defaults to the first interface. Change this to: 20 | # 21 | # iface: eth1 22 | # 23 | # ...to override. 24 | # 25 | iface: '{{ ansible_default_ipv4.interface }}' 26 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/group_vars/webservers: -------------------------------------------------------------------------------- 1 | --- 2 | # Variables for the web server configuration 3 | 4 | # Ethernet interface on which the web server should listen. 5 | # Defaults to the first interface. Change this to: 6 | # 7 | # iface: eth1 8 | # 9 | # ...to override. 10 | # 11 | iface: '{{ ansible_default_ipv4.interface }}' 12 | 13 | # this is the repository that holds our sample webapp 14 | repository: http://github.com/bennojoy/mywebapp.git 15 | 16 | # this is the sha1sum of V5 of the test webapp. 17 | webapp_version: 351e47276cc66b018f4890a04709d4cc3d3edb0d 18 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/hosts: -------------------------------------------------------------------------------- 1 | [webservers] 2 | web3 3 | web2 4 | 5 | [dbservers] 6 | web3 7 | 8 | [lbservers] 9 | web2 10 | 11 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/base-apache/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This role installs httpd 3 | 4 | - name: Install http and php etc 5 | yum: name={{ item }} state=present 6 | with_items: 7 | - httpd 8 | - libsemanage-python 9 | - libselinux-python 10 | 11 | - name: http service state 12 | service: name=httpd state=started enabled=yes 13 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/common/files/RPM-GPG-KEY-EPEL-6: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: GnuPG v1.4.5 (GNU/Linux) 3 | 4 | mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1 5 | JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B 6 | M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn 7 | XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6 8 | pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV 9 | QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp 10 | Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq 11 | 3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu 12 | vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar 13 | 1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g 14 | YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB 15 | tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS 16 | KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9 17 | qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT 18 | 9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP 19 | Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS 20 | WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft 21 | HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF 22 | p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP 23 | x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8 24 | wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J 25 | l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG 26 | iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR 27 | XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ== 28 | =V/6I 29 | -----END PGP PUBLIC KEY BLOCK----- 30 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/common/files/epel.repo: -------------------------------------------------------------------------------- 1 | [epel] 2 | name=Extra Packages for Enterprise Linux 6 - $basearch 3 | #baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch 4 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch 5 | failovermethod=priority 6 | enabled=1 7 | gpgcheck=1 8 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 9 | 10 | [epel-debuginfo] 11 | name=Extra Packages for Enterprise Linux 6 - $basearch - Debug 12 | #baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/debug 13 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch 14 | failovermethod=priority 15 | enabled=0 16 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 17 | gpgcheck=1 18 | 19 | [epel-source] 20 | name=Extra Packages for Enterprise Linux 6 - $basearch - Source 21 | #baseurl=http://download.fedoraproject.org/pub/epel/6/SRPMS 22 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch 23 | failovermethod=priority 24 | enabled=0 25 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 26 | gpgcheck=1 27 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/common/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Handlers for common notifications 3 | 4 | - name: restart ntp 5 | service: name=ntpd state=restarted 6 | 7 | - name: restart iptables 8 | service: name=iptables state=restarted 9 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This role contains common plays that will run on all nodes. 3 | 4 | - name: Create the repository for EPEL 5 | copy: src=epel.repo dest=/etc/yum.repos.d/epel.repo 6 | 7 | - name: Create the GPG key for EPEL 8 | copy: src=RPM-GPG-KEY-EPEL-6 dest=/etc/pki/rpm-gpg 9 | 10 | - name: install some useful nagios plugins 11 | yum: name={{ item }} state=present 12 | with_items: 13 | - nagios-nrpe 14 | - nagios-plugins-swap 15 | - nagios-plugins-users 16 | - nagios-plugins-procs 17 | - nagios-plugins-load 18 | - nagios-plugins-disk 19 | 20 | - name: Install ntp 21 | yum: name=ntp state=present 22 | tags: ntp 23 | 24 | - name: Configure ntp file 25 | template: src=ntp.conf.j2 dest=/etc/ntp.conf 26 | tags: ntp 27 | notify: restart ntp 28 | 29 | - name: Start the ntp service 30 | service: name=ntpd state=started enabled=true 31 | tags: ntp 32 | 33 | - name: insert iptables template 34 | template: src=iptables.j2 dest=/etc/sysconfig/iptables 35 | notify: restart iptables 36 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/common/templates/iptables.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # Manual customization of this file is not recommended. 3 | *filter 4 | :INPUT ACCEPT [0:0] 5 | :FORWARD ACCEPT [0:0] 6 | :OUTPUT ACCEPT [0:0] 7 | 8 | {% if (inventory_hostname in groups['webservers']) or (inventory_hostname in groups['monitoring']) %} 9 | -A INPUT -p tcp --dport 80 -j ACCEPT 10 | {% endif %} 11 | 12 | {% if inventory_hostname in groups['dbservers'] %} 13 | -A INPUT -p tcp --dport 3306 -j ACCEPT 14 | {% endif %} 15 | 16 | {% if inventory_hostname in groups['lbservers'] %} 17 | -A INPUT -p tcp --dport {{ listenport }} -j ACCEPT 18 | {% endif %} 19 | 20 | {% for host in groups['monitoring'] %} 21 | -A INPUT -p tcp -s {{ hostvars[host].ansible_default_ipv4.address }} --dport 5666 -j ACCEPT 22 | {% endfor %} 23 | 24 | -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 25 | -A INPUT -p icmp -j ACCEPT 26 | -A INPUT -i lo -j ACCEPT 27 | -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT 28 | -A INPUT -j REJECT --reject-with icmp-host-prohibited 29 | -A FORWARD -j REJECT --reject-with icmp-host-prohibited 30 | COMMIT 31 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/common/templates/ntp.conf.j2: -------------------------------------------------------------------------------- 1 | 2 | driftfile /var/lib/ntp/drift 3 | 4 | restrict 127.0.0.1 5 | restrict -6 ::1 6 | 7 | server {{ ntpserver }} 8 | 9 | includefile /etc/ntp/crypto/pw 10 | 11 | keys /etc/ntp/keys 12 | 13 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/haproxy/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Handlers for HAproxy 3 | 4 | - name: restart haproxy 5 | service: name=haproxy state=restarted 6 | 7 | - name: reload haproxy 8 | service: name=haproxy state=reloaded 9 | 10 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/haproxy/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This role installs HAProxy and configures it. 3 | 4 | - name: Download and install haproxy and socat 5 | yum: name={{ item }} state=present 6 | with_items: 7 | - haproxy 8 | - socat 9 | 10 | - name: Configure the haproxy cnf file with hosts 11 | template: src=haproxy.cfg.j2 dest=/etc/haproxy/haproxy.cfg 12 | notify: restart haproxy 13 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/haproxy/templates/haproxy.cfg.j2: -------------------------------------------------------------------------------- 1 | global 2 | log 127.0.0.1 local2 3 | 4 | chroot /var/lib/haproxy 5 | pidfile /var/run/haproxy.pid 6 | maxconn 4000 7 | user root 8 | group root 9 | daemon 10 | 11 | # turn on stats unix socket 12 | stats socket /var/lib/haproxy/stats level admin 13 | 14 | defaults 15 | mode {{ mode }} 16 | log global 17 | option httplog 18 | option dontlognull 19 | option http-server-close 20 | option forwardfor except 127.0.0.0/8 21 | option redispatch 22 | retries 3 23 | timeout http-request 10s 24 | timeout queue 1m 25 | timeout connect 10s 26 | timeout client 1m 27 | timeout server 1m 28 | timeout http-keep-alive 10s 29 | timeout check 10s 30 | maxconn 3000 31 | 32 | backend app 33 | {% for host in groups['lbservers'] %} 34 | listen {{ daemonname }} {{ hostvars[host]['ansible_' + iface].ipv4.address }}:{{ listenport }} 35 | {% endfor %} 36 | balance {{ balance }} 37 | {% for host in groups['webservers'] %} 38 | server {{ hostvars[host].ansible_hostname }} {{ hostvars[host]['ansible_' + iface].ipv4.address }}:{{ httpd_port }} 39 | {% endfor %} 40 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/files/ansible-managed-services.cfg: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | # service checks to be applied to all hosts 4 | 5 | define service { 6 | use local-service 7 | host_name localhost 8 | service_description Root Partition 9 | check_command check_local_disk!20%!10%!/ 10 | } 11 | 12 | define service { 13 | use local-service 14 | host_name * 15 | service_description Current Users 16 | check_command check_local_users!20!50 17 | } 18 | 19 | 20 | define service { 21 | use local-service 22 | host_name * 23 | service_description Total Processes 24 | check_command check_local_procs!250!400!RSZDT 25 | } 26 | 27 | define service { 28 | use local-service 29 | host_name * 30 | service_description Current Load 31 | check_command check_local_load!5.0,4.0,3.0!10.0,6.0,4.0 32 | } 33 | 34 | define service { 35 | use local-service 36 | host_name * 37 | service_description Swap Usage 38 | check_command check_local_swap!20!10 39 | } 40 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/files/localhost.cfg: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # LOCALHOST.CFG - SAMPLE OBJECT CONFIG FILE FOR MONITORING THIS MACHINE 3 | # 4 | # Last Modified: 05-31-2007 5 | # 6 | # NOTE: This config file is intended to serve as an *extremely* simple 7 | # example of how you can create configuration entries to monitor 8 | # the local (Linux) machine. 9 | # 10 | ############################################################################### 11 | 12 | 13 | 14 | 15 | ############################################################################### 16 | ############################################################################### 17 | # 18 | # HOST DEFINITION 19 | # 20 | ############################################################################### 21 | ############################################################################### 22 | 23 | # Define a host for the local machine 24 | 25 | define host{ 26 | use linux-server ; Name of host template to use 27 | ; This host definition will inherit all variables that are defined 28 | ; in (or inherited by) the linux-server host template definition. 29 | host_name localhost 30 | alias localhost 31 | address 127.0.0.1 32 | } 33 | 34 | 35 | 36 | ############################################################################### 37 | ############################################################################### 38 | # 39 | # HOST GROUP DEFINITION 40 | # 41 | ############################################################################### 42 | ############################################################################### 43 | 44 | # Define an optional hostgroup for Linux machines 45 | 46 | define hostgroup{ 47 | hostgroup_name linux-servers ; The name of the hostgroup 48 | alias Linux Servers ; Long name of the group 49 | members localhost ; Comma separated list of hosts that belong to this group 50 | } 51 | 52 | 53 | 54 | ############################################################################### 55 | ############################################################################### 56 | # 57 | # SERVICE DEFINITIONS 58 | # 59 | ############################################################################### 60 | ############################################################################### 61 | 62 | 63 | # Define a service to "ping" the local machine 64 | 65 | define service{ 66 | use local-service ; Name of service template to use 67 | host_name localhost 68 | service_description PING 69 | check_command check_ping!100.0,20%!500.0,60% 70 | } 71 | 72 | 73 | # Define a service to check the disk space of the root partition 74 | # on the local machine. Warning if < 20% free, critical if 75 | # < 10% free space on partition. 76 | 77 | define service{ 78 | use local-service ; Name of service template to use 79 | host_name localhost 80 | service_description Root Partition 81 | check_command check_local_disk!20%!10%!/ 82 | } 83 | 84 | 85 | 86 | # Define a service to check the number of currently logged in 87 | # users on the local machine. Warning if > 20 users, critical 88 | # if > 50 users. 89 | 90 | define service{ 91 | use local-service ; Name of service template to use 92 | host_name localhost 93 | service_description Current Users 94 | check_command check_local_users!20!50 95 | } 96 | 97 | 98 | # Define a service to check the number of currently running procs 99 | # on the local machine. Warning if > 250 processes, critical if 100 | # > 400 users. 101 | 102 | define service{ 103 | use local-service ; Name of service template to use 104 | host_name localhost 105 | service_description Total Processes 106 | check_command check_local_procs!250!400!RSZDT 107 | } 108 | 109 | 110 | 111 | # Define a service to check the load on the local machine. 112 | 113 | define service{ 114 | use local-service ; Name of service template to use 115 | host_name localhost 116 | service_description Current Load 117 | check_command check_local_load!5.0,4.0,3.0!10.0,6.0,4.0 118 | } 119 | 120 | 121 | 122 | # Define a service to check the swap usage the local machine. 123 | # Critical if less than 10% of swap is free, warning if less than 20% is free 124 | 125 | define service{ 126 | use local-service ; Name of service template to use 127 | host_name localhost 128 | service_description Swap Usage 129 | check_command check_local_swap!20!10 130 | } 131 | 132 | 133 | 134 | # Define a service to check SSH on the local machine. 135 | # Disable notifications for this service by default, as not all users may have SSH enabled. 136 | 137 | define service{ 138 | use local-service ; Name of service template to use 139 | host_name localhost 140 | service_description SSH 141 | check_command check_ssh 142 | notifications_enabled 0 143 | } 144 | 145 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers for nagios 3 | - name: restart httpd 4 | service: name=httpd state=restarted 5 | 6 | - name: restart nagios 7 | service: name=nagios state=restarted 8 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This will install nagios 3 | 4 | - name: install nagios 5 | yum: pkg={{ item }} state=present 6 | with_items: 7 | - nagios 8 | - nagios-plugins 9 | - nagios-plugins-nrpe 10 | - nagios-plugins-ping 11 | - nagios-plugins-ssh 12 | - nagios-plugins-http 13 | - nagios-plugins-mysql 14 | - nagios-devel 15 | notify: restart httpd 16 | 17 | - name: create nagios config dir 18 | file: path=/etc/nagios/ansible-managed state=directory 19 | 20 | - name: configure nagios 21 | copy: src=nagios.cfg dest=/etc/nagios/nagios.cfg 22 | notify: restart nagios 23 | 24 | - name: configure localhost monitoring 25 | copy: src=localhost.cfg dest=/etc/nagios/objects/localhost.cfg 26 | notify: restart nagios 27 | 28 | - name: configure nagios services 29 | copy: src=ansible-managed-services.cfg dest=/etc/nagios/ 30 | 31 | - name: create the nagios object files 32 | template: src={{ item + ".j2" }} 33 | dest=/etc/nagios/ansible-managed/ 34 | with_items: 35 | - webservers.cfg 36 | - dbservers.cfg 37 | - lbservers.cfg 38 | notify: restart nagios 39 | 40 | - name: start nagios 41 | service: name=nagios state=started enabled=yes 42 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/templates/dbservers.cfg.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | define hostgroup { 4 | hostgroup_name dbservers 5 | alias Database Servers 6 | } 7 | 8 | {% for host in groups['dbservers'] %} 9 | define host { 10 | use linux-server 11 | host_name {{ host }} 12 | alias {{ host }} 13 | address {{ hostvars[host].ansible_default_ipv4.address }} 14 | hostgroups dbservers 15 | } 16 | {% endfor %} 17 | 18 | #define service { 19 | # use local-service 20 | # hostgroup_name dbservers 21 | # service_description MySQL Database Server 22 | # check_command check_mysql 23 | # notifications_enabled 0 24 | #} 25 | 26 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/templates/lbservers.cfg.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | define hostgroup { 4 | hostgroup_name loadbalancers 5 | alias Load Balancers 6 | } 7 | 8 | {% for host in groups['lbservers'] %} 9 | define host { 10 | use linux-server 11 | host_name {{ host }} 12 | alias {{ host }} 13 | address {{ hostvars[host].ansible_default_ipv4.address }} 14 | hostgroups loadbalancers 15 | } 16 | define service { 17 | use local-service 18 | host_name {{ host }} 19 | service_description HAProxy Load Balancer 20 | check_command check_http!-p{{ hostvars[host].listenport }} 21 | } 22 | {% endfor %} 23 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/nagios/templates/webservers.cfg.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | define hostgroup { 4 | hostgroup_name webservers 5 | alias Web Servers 6 | } 7 | 8 | {% for host in groups['webservers'] %} 9 | define host { 10 | use linux-server 11 | host_name {{ host }} 12 | alias {{ host }} 13 | address {{ hostvars[host].ansible_default_ipv4.address }} 14 | hostgroups webservers 15 | } 16 | {% endfor %} 17 | 18 | # service checks to be applied to the web server 19 | define service { 20 | use local-service 21 | hostgroup_name webservers 22 | service_description webserver 23 | check_command check_http 24 | notifications_enabled 0 25 | } 26 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/roles/web/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # httpd is handled by the base-apache role upstream 4 | - name: Install php and git 5 | yum: name={{ item }} state=present 6 | with_items: 7 | - php 8 | - php-mysql 9 | - git 10 | 11 | - name: Configure SELinux to allow httpd to connect to remote database 12 | seboolean: name=httpd_can_network_connect_db state=true persistent=yes 13 | 14 | - name: Copy the code from repository 15 | git: repo={{ repository }} version={{ webapp_version }} dest=/var/www/html/ 16 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/rolling_update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook does a rolling update for all webservers serially (one at a time). 3 | # Change the value of serial: to adjust the number of server to be updated. 4 | # 5 | # The three roles that apply to the webserver hosts will be applied: common, 6 | # base-apache, and web. So any changes to configuration, package updates, etc, 7 | # will be applied as part of the rolling update process. 8 | # 9 | 10 | # gather facts from monitoring nodes for iptables rules 11 | - hosts: monitoring 12 | tasks: 13 | 14 | - hosts: webservers 15 | user: root 16 | serial: 1 17 | 18 | # These are the tasks to run before applying updates: 19 | pre_tasks: 20 | - name: disable nagios alerts for this host webserver service 21 | nagios: action=disable_alerts host={{ ansible_hostname }} services=webserver 22 | delegate_to: "{{ item }}" 23 | with_items: groups.monitoring 24 | 25 | - name: disable the server in haproxy 26 | shell: echo "disable server myapplb/{{ ansible_hostname }}" | socat stdio /var/lib/haproxy/stats 27 | delegate_to: "{{ item }}" 28 | with_items: groups.lbservers 29 | 30 | roles: 31 | - common 32 | - base-apache 33 | - web 34 | 35 | # These tasks run after the roles: 36 | post_tasks: 37 | - name: Enable the server in haproxy 38 | shell: echo "enable server myapplb/{{ ansible_hostname }}" | socat stdio /var/lib/haproxy/stats 39 | delegate_to: "{{ item }}" 40 | with_items: groups.lbservers 41 | 42 | - name: re-enable nagios alerts 43 | nagios: action=enable_alerts host={{ ansible_hostname }} services=webserver 44 | delegate_to: "{{ item }}" 45 | with_items: groups.monitoring 46 | -------------------------------------------------------------------------------- /advanced_lab/chapter_08/lamp_haproxy/site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook deploys the whole application stack in this site. 3 | 4 | # Apply common configuration to all hosts 5 | - hosts: all 6 | roles: 7 | - common 8 | 9 | # Configure and deploy database servers. 10 | - hosts: dbservers 11 | user: root 12 | roles: 13 | - db 14 | 15 | # Configure and deploy the web servers. Note that we include two roles here, 16 | # the 'base-apache' role which simply sets up Apache, and 'web' which includes 17 | # our example web application. 18 | - hosts: webservers 19 | user: root 20 | 21 | roles: 22 | - base-apache 23 | - web 24 | 25 | # Configure and deploy the load balancer(s). 26 | - hosts: lbservers 27 | user: root 28 | roles: 29 | - haproxy 30 | 31 | # Configure and deploy the Nagios monitoring node(s). 32 | - hosts: monitoring 33 | user: root 34 | roles: 35 | - base-apache 36 | - nagios 37 | -------------------------------------------------------------------------------- /advanced_lab/chapter_09/mysql-users.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: MySQL Users 3 | hosts: webservers 4 | 5 | tasks: 6 | - name: add a mysql user for the server 7 | mysql_user: name={{ db_username }} host={{ inventory_hostname }} 8 | password={{ db_password }} priv='ansible.*:ALL' 9 | state=present 10 | delegate_to: databases[0] 11 | -------------------------------------------------------------------------------- /advanced_lab/chapter_11/iptables.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: webservers 3 | gather_facts: yes 4 | 5 | - hosts: databases 6 | handlers: 7 | - name: Reload iptables 8 | service: name=iptables state=reloaded 9 | 10 | tasks: 11 | - name: Template /etc/sysconfig/iptables 12 | template: src=templates/iptables.j2 dest=/etc/sysconfig/iptables 13 | notify: Reload iptables 14 | 15 | - name: Ensure iptables is started and enabled 16 | service: name=iptables state=started enabled=yes 17 | -------------------------------------------------------------------------------- /advanced_lab/chapter_11/templates/iptables.j2: -------------------------------------------------------------------------------- 1 | *filter 2 | :INPUT ACCEPT [0:0] 3 | :FORWARD ACCEPT [0:0] 4 | :OUTPUT ACCEPT [0:0] 5 | 6 | {% for server in groups['webservers'] %} 7 | -A INPUT -p tcp -s {{ hostvars[server].ansible_eth1.ipv4.address }} -i eth1 -d {{ ansible_eth1.ipv4.address }} --dport 3306 -j ACCEPT 8 | {% endfor %} 9 | 10 | {% for server in groups['databases'] %} 11 | {% if server != inventory_hostname %} 12 | -A INPUT -p tcp -s {{ hostvars[server].ansible_eth1.ipv4.address }} -i eth1 -d {{ ansible_eth1.ipv4.address }} --dport 3306 -j ACCEPT 13 | {% endif %} 14 | {% endfor %} 15 | 16 | -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 17 | -A INPUT -p icmp -j ACCEPT 18 | -A INPUT -i lo -j ACCEPT 19 | -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT 20 | -A INPUT -j REJECT --reject-with icmp-host-prohibited 21 | -A FORWARD -j REJECT --reject-with icmp-host-prohibited 22 | COMMIT 23 | -------------------------------------------------------------------------------- /build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | connection: local 4 | 5 | tasks: 6 | 7 | - name: create reveal link 8 | command: ln -s revelator/reveal_js_261 ./reveal_js_261 creates=./reveal_js_261 9 | 10 | - name: create dest dir 11 | command: mkdir -p output 12 | 13 | - name: syntax check fundamentals 14 | shell: python syntax_check.py fundamentals/*.yml 15 | 16 | - name: syntax check operational 17 | shell: python syntax_check.py operational/*.yml 18 | 19 | - name: syntax check advanced 20 | shell: python syntax_check.py advanced/*.yml 21 | 22 | - name: build fundamentals 23 | shell: python build_single.py fundamentals > output/fundamentals.yml 24 | 25 | - name: build operational 26 | shell: python build_single.py operational > output/operational.yml 27 | 28 | - name: build advanced 29 | shell: python build_single.py advanced > output/advanced.yml 30 | 31 | - name: render fundamentals 32 | command: revelator/write_it output/fundamentals.yml output/fundamentals/ 33 | 34 | - name: render operational 35 | command: revelator/write_it output/operational.yml output/operational/ 36 | 37 | - name: render advanced 38 | command: revelator/write_it output/advanced.yml output/advanced/ 39 | -------------------------------------------------------------------------------- /build_single.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | try: 5 | import yaml 6 | except ImportError: 7 | raise SystemExit('PyYAML python module is missing') 8 | 9 | # Allow specification of a path to look for YAML files 10 | # Fallback to dirname of this script itself 11 | try: 12 | path = sys.argv[1] 13 | except IndexError: 14 | path = os.path.dirname(os.path.abspath(__file__)) 15 | 16 | allfiles = os.listdir(path) 17 | 18 | # Find all YAML chapter files. Files should have "chapter" in the name 19 | chapter_files = [] 20 | for f in allfiles: 21 | root, ext = os.path.splitext(f) 22 | if ('chapter' in root.lower() and 'template' not in root.lower() and 23 | ext.lower() in ['.yml', '.yaml']): 24 | chapter_files.append(f) 25 | 26 | chapter_files.sort() 27 | 28 | # Open the root.yml file that is the root of the slides 29 | try: 30 | with open(os.path.join(path, 'root.yml')) as f: 31 | root = yaml.load(f) 32 | except: 33 | raise SystemExit('root.yml file not found') 34 | 35 | if 'slides' not in root: 36 | root['slides'] = [] 37 | 38 | errors = [] 39 | for chapter_file in chapter_files: 40 | try: 41 | with open(os.path.join(path, chapter_file)) as f: 42 | chapter = yaml.load(f) 43 | except: 44 | errors.append('*** Could not load/parse %s ***\n' % chapter_file) 45 | else: 46 | try: 47 | root['slides'].extend(chapter['slides']) 48 | except: 49 | errors.append('*** Could not find slides in %s ***\n' % chapter_file) 50 | 51 | print yaml.dump(root, indent=4, allow_unicode=True, default_flow_style=False) 52 | 53 | if errors: 54 | sys.stderr.write('\n'.join(errors)) 55 | sys.exit(len(errors)) 56 | 57 | sys.exit(0) 58 | -------------------------------------------------------------------------------- /builder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Build script that should simplify Jenkins configuration. 3 | 4 | # Exit if any command returns non-zero 5 | set -e 6 | 7 | 8 | if [ -d revelator ]; then 9 | echo "******** Checking for latest version of Revelator ********" 10 | cd revelator 11 | git pull 12 | cd .. 13 | else 14 | echo "******** Downloading Revelator ********" 15 | git clone https://github.com/mpdehaan/revelator.git 16 | ln -fs revelator/reveal_js_261 17 | fi 18 | 19 | echo "******** Looping over folders ********" 20 | for i in fundamentals operational advanced development 21 | do 22 | echo "******** Syntax Check on $i ********" 23 | python $DRONE_BUILD_DIR/syntax_check.py $DRONE_BUILD_DIR/$i/*.yml 24 | echo "******** Creating output folder for $i ********" 25 | mkdir -p output/$i 26 | echo "******** Build Single on $i ********" 27 | python $DRONE_BUILD_DIR/build_single.py $DRONE_BUILD_DIR/$i > $i_comp.yml 28 | echo "******** Generating Slides on $i ********" 29 | python revelator/write_it $i_comp.yml output/$i 30 | done 31 | -------------------------------------------------------------------------------- /chapter_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Tim G 4 | title: Chapter Title 5 | description: Description of the chapter 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | 12 | - 13 | - h1: chapter title slide 14 | - h3: subtitle/info 15 | 16 | - 17 | - h1: content slide 18 | - p: content content content 19 | 20 | - class_notes: 21 | these are speaker notes that will be hidden 22 | 23 | - 24 | - h1: content slide 25 | - p: more content 26 | 27 | - 28 | - h3: This is how ordered lists work 29 | - ol: 30 | - alpha 31 | - beta 32 | - gamma 33 | 34 | - 35 | - h3: And unordered lists are also a thing 36 | - ul: 37 | - duck 38 | - duck 39 | - goose 40 | - cow 41 | 42 | - 43 | - h3: Code highlighting demo 44 | - code: | 45 | import ansible 46 | ansible.all_the_things() 47 | 48 | -------------------------------------------------------------------------------- /development/chapter_0.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Justin Phelps 4 | title: Ansible Development 5 | description: Ansible Development Course 6 | 7 | slides: 8 | - 9 | - nested: 10 | - 11 | - h1: Ansible Development 12 | -------------------------------------------------------------------------------- /development/chapter_1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: CC, PI 4 | title: Chapter 1, Ansible Fundamentals 5 | description: Ansible Fundamentals Course 6 | 7 | slides: 8 | 9 | - set_global: 10 | transition: rotate 11 | background: '#007777' 12 | #background: 'black' 13 | 14 | - 15 | - nested: 16 | - 17 | - h1: What is Ansible? 18 | - ul: 19 | - Clear 20 | - Fast 21 | - Complete 22 | - Efficient 23 | - Secure 24 | 25 | - 26 | - h2: Clear 27 | - p: 'A simple automation language allows Ansible to be used by anyone:' 28 | - ul: 29 | - sysadmins 30 | - developers 31 | - IT managers 32 | - p: It's easy to write, read, maintain, and evolve - without writing scripts or custom code. 33 | - 34 | - h2: Fast 35 | - p: Ansible is easy to learn. 36 | - p: Setup is fast. 37 | - class_notes: | 38 | 1. You can automate in under 30 minutes. Forget about how it works, just do it. 39 | 2. No agents. SSH keys are typically already in place. 40 | - 41 | - h2: Complete 42 | - p: 'Ansible is several tools in one:' 43 | - ul: 44 | - configuration management 45 | - application deployment 46 | - orchestration 47 | - provisioning 48 | - p: Hundreds of built-in modules. 49 | - 50 | - h2: Efficient 51 | - p: Ansible doesn't require a custom agent or software to install. 52 | - p: Ansible runs on OpenSSH. 53 | - class_notes: | 54 | 1. With no additional software infrastructure, you don't have to 55 | worry about managing the management tool. 56 | 2. That means anywhere SSH goes, Ansible goes. 57 | 3. It doesn't suck memory or CPU resources when it is not in use. 58 | 4. Designed from day one to automate no-downtime rolling updates 59 | and multi-tier orchestration. 60 | - 61 | - h2: Secure 62 | - p: No agent. 63 | - p: SSH transport. 64 | - p: Ansible plays can be read by anyone. 65 | - class_notes: | 66 | 1. It doesn't need additional ports or root level daemons. 67 | 2. It uses built-in OS authentication for better security - login 68 | as who you are, sudo if you want to sudo. 69 | 3. You can work with tools like Kerberos, LDAP, and sssd. 70 | 4. OpenSSH is the most peer-reviewed security component around. 71 | 5. This makes it auditable. You know what you're automating, 72 | and bugs have nowhere to hide. 73 | -------------------------------------------------------------------------------- /development/chapter_2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Mike Martin, Justin Phelps, Paul Durivage 4 | title: Chapter 2 5 | description: Ansible Fundamentals Course 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Ansible Use Cases 13 | - p: Ask not what you can do for Ansible, but what Ansible can do for you! 14 | - 15 | - h2: Ansible Use Cases 16 | - ul: 17 | - Remote Execution / Ad-hoc Tasks 18 | - Configuration Management 19 | - Application Deployment & Orchestration 20 | - Provisioning Infrastructure Dynamically 21 | - 22 | - h2: Remote Execution 23 | - ul: 24 | - Replacement for traditional systems administration tasks. (i.e., SSH) 25 | - Checking system responsiveness and uptime. 26 | - Gathering information about a collection of systems. 27 | - Replace one off rsync scripts, fabric, or terminal multiplexing. 28 | - class_notes: | 29 | Ansible provides a command-line tool and framework capable of 30 | executing over a large number of hosts, eliminating the need for 31 | systems administrators to multiplex terminal sessions via SSH to 32 | execute concurrent tasks across multiple hosts. What may have 33 | been done in bash scripts, rsync scripts, etc. can be done via 34 | ad-hoc one-liners in the shell. 35 | - 36 | - h2: Remote Execution 37 | - code: | 38 | ansible -m user -a "name=bob state=present" webservers 39 | - code: | 40 | ansible -m apt -a "pkg=apache2 state=present" webservers 41 | - class_notes: | 42 | Example 1 is adding a user to all the systems defined in the 43 | webservers group. Example 2 is installing the apache2 package 44 | on all systems defined in the webservers group. 45 | - 46 | - h2: Config Management 47 | - ul: 48 | - Lengthy system configuration, to include adding users, ssh keys, installing and configuring services, and bootstrapping systems to a given state. 49 | - '"Configuration remediation" Consistent server configuration. Removes manual configuration errors.' 50 | - class_notes: | 51 | Servers need to be configured; Ansible configures servers. 52 | Using a combination of imperative and declarative syntax 53 | [described in detail--maybe using the GPS analogy], using 54 | concepts such as tasks, roles, plays, and playbooks, complex 55 | machine configurations are being assembled and converged by 56 | the Ansible toolchain rather than manually by administrators. 57 | Configuration is either set manually by the author or dynamically at runtime by Ansible, resulting in consistent configuration across large server sets. 58 | - 59 | - h2: Application Deployment & Orchestration 60 | - p: Ansible can be used to replace various deployment and orchestration tools. 61 | - ul: 62 | - Deploy your custom application. 63 | - Replacement for Capistrano and Fabric (i.e., git deployments) 64 | - Good for large, complex environments 65 | - 66 | - h2: Application Deployment & Orchestration 67 | - p: Application deployment includes two main schools of thought. 68 | - h2: Rolling Release 69 | ul: 70 | - Remove node from production, update components, and put back into rotation. 71 | - class_notes: | 72 | Make the point that you deploy often in the DevOps world, and 73 | why this is important for application development. 74 | - 75 | - h2: Application Deployment & Orchestration 76 | - p: Application deployment includes two main schools of thought. 77 | - h2: Fresh Start 78 | - ul: 79 | - Deploy entirely new infrastructure and replace current environment wholesale. 80 | - class_notes: | 81 | Make the point that you deploy often in the DevOps world, and 82 | why this is important for application development. 83 | - 84 | - h2: Provisioning Infrastructure Dynamically 85 | - ul: 86 | - Infrastructure is Data. 87 | - You can provision to various clouds. 88 | - Dynamic Inventory plugins for various providers (Rackspace, Amazon, Digital Ocean, OpenStack, Eucalyptus etc.) 89 | - class_notes: | 90 | Cover the various ways that infrastructure can be provisioned 91 | using Ansible. Mention that there are modules that provide 92 | he ability to deploy to various clouds. Include a high level 93 | overview of the dynamic inventory plugin system. (Creating 94 | Infrastructure is the same as Configuring Infrastructure.) 95 | - 96 | - h2: Who is your Ansible, and what does he do? 97 | - class_notes: | 98 | Have the class search the ansible documention and come up 99 | with something that Ansible does. Be that a specific module, 100 | or a high level concept. 101 | -------------------------------------------------------------------------------- /development/chapter_3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Jesse K and the DFed Experience 4 | title: Understand the concepts of Ansible 5 | description: Description of the chapter 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Ansible Key Components 13 | - p: What makes Ansible tick! 14 | - class_notes: Let's delve into the concepts that drive Ansible. 15 | - 16 | - h2: Key components of Ansible 17 | - ul: 18 | - Inventory 19 | - Modules/Tasks 20 | - Plays 21 | - Playbooks 22 | - class_notes: These are some very key components you'll need to understand for using Ansible. 23 | - 24 | - h2: Inventory 25 | - ul: 26 | - Understanding Hosts and Groups 27 | - Inventory Sources 28 | - class_notes: | 29 | Ansible works against multiple systems in your infrastructure 30 | at the same time. It does this by selecting portions of systems 31 | listed in Ansible's inventory. 32 | - 33 | - h2: Inventory concepts 34 | - ul: 35 | - hosts 36 | - groupings 37 | - inventory-specific data 38 | - static or dynamic sources 39 | - class_notes: "Breaking down by topic, we'll cover four parts (Note the listed)" 40 | - 41 | - h2: "Inventory: Hosts" 42 | - p: "Hosts can have Ansible specific attributes such as:" 43 | - ul: 44 | - Connection IP addresses and ports 45 | - Remote user and sudo user 46 | - Connection types (Paramiko, OpenSSH, local, etc.) 47 | - Further limit targetd hosts using --limit 48 | - class_notes: | 49 | You have a lot of flexibility when you specify hosts in Inventory. You can 50 | set variables to determine connection types, host ip addresses and fully-qualified 51 | domain names, remote users and sudo users as well as any other variable you may 52 | come up with to use when interacting with your hosts, such as "apache_port" or 53 | "mysql ports". 54 | - 55 | - h2: "Inventory: Hosts" 56 | - p: "This is an example of a host entry in an inventory file:" 57 | - code: | 58 | web1.example.com ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50 59 | - class_notes: As you can see, we have a host name, a specified SSH port and IP Address. 60 | - 61 | - h2: "Inventory: Host Entries Using Ranges" 62 | - p: "You can have ranges of machine names or letters like this:" 63 | - code: | 64 | www[01:50].example.com ansible_ssh_port=5555 65 | db-[a-f].example.com ansible_ssh_port=5555 66 | - class_notes: Here we see that we can bracket a range of alpha-numeric characters to shorten our entries in the file. 67 | - 68 | - h2: "Inventory: Groups" 69 | - p: "Inventory Host Organization: Groups" 70 | - ul: 71 | - Groups allow targeted operations against different types of hosts. 72 | - Groups can also have variables that apply to all hosts within them. 73 | - --limit allows you to specify only certain groups to act against 74 | - Hosts can exist in more than one group at once. 75 | - class_notes: | 76 | We can also act against groups of hosts in a similar manner to single hosts. 77 | This allows you to also have standard settings for lots of similar hosts, such 78 | as a standard set of ports for apache on all web servers. You can limit the execution of 79 | Ansible jobs just as you can single hosts with the "--limit" option. Hosts can exist 80 | in more than one group at once, letting you do interesting operations on the intersections 81 | of groups. For example, target all of the east coast web servers. 82 | - 83 | - h2: "Inventory: Groups" 84 | - p: Groups are represented in brackets above host lists in the inventory file. 85 | - code: | 86 | [webservers] 87 | www[01:50].example.com ansible_ssh_port=5555 88 | - class_notes: This is an example of a range of hosts specified via the bracket nomenclature. 89 | - 90 | - h2: "Dynamic Inventory: Ansible and the Cloud" 91 | - p: "Inventory can also be gathered on demand from other sources dynamically. Those sources include:" 92 | - ul: 93 | - Cloud API (Rackspace, Amazon, Digital Ocean, OpenStack, Eucalyptus etc.) 94 | - Cobbler 95 | - Create your own for fun and profit! 96 | - class_notes: | 97 | So we can also take inventory from a wide variety of sources on the fly. We can touch Rackspace, 98 | Openstack, Amazon EC2, Digital Ocean, and other provisioning systems like Cobbler. You can also 99 | create your own inventory module to interface with any custom CMDB systems you may have. 100 | - 101 | - h2: "Inventory: Ansible and the Cloud" 102 | - p: "Dynamic inventories also respect groups and other details." 103 | - ul: 104 | - Groups are auto-determined by instance tags, regions and other attributes. 105 | - Dynamic Inventories can be used alongside Static Inventories for a hybrid cloud approach. 106 | - class_notes: | 107 | Tagged instances automatically are put in a group based on that tag. Other attributes also 108 | become groups, such as regions deployed to, or other custom attributes. 109 | - 110 | - h2: Tasks and Modules 111 | - p: Tasks and Modules are the workhorse of Ansible. 112 | - p: "This topic will cover:" 113 | - ul: 114 | - Understanding what a task is 115 | - Understanding how tasks make use of modules 116 | - 117 | - h2: Tasks 118 | - p: A task is a discrete action that is a declaration about 119 | the state of a system. 120 | - p: "Example Tasks:" 121 | - ul: 122 | - Directory should exist 123 | - Package should be installed 124 | - Service should be running 125 | - Cloud Instance should exist 126 | - class_notes: These are examples of declarative tasks where the beginning state is disregarded in favor of ensuring end-state. 127 | - 128 | - h2: "Tasks: Examples" 129 | - p: ansible can execute single tasks on sets of hosts 130 | to fullfill an ad-hoc declarations 131 | - code: | 132 | $ ansible web-hosts -m file -a "path=/opt/cache state=directory" 133 | $ ansible web-hosts -m yum -a "name=nginx state=present" 134 | $ ansible web-hosts -m service -a "name=nginx enabled=yes state=started" 135 | - class_notes: | 136 | in the first we make sure opt/cache exists, the second we install nginx, third we make 137 | sure nginx is installed, chkconfig'ed on and the service is started. 138 | - 139 | - h2: "Tasks: Sources" 140 | - p: "Code for tasks can come from:" 141 | - ul: 142 | - existing modules 143 | - custom modules 144 | - raw ssh commands 145 | - class_notes: | 146 | Tasks use modules or commands to create their actions to apply to remote systems. 147 | You can create your own modules, use any of the over 200 included modules, or use the output from commands. 148 | - 149 | - h2: Modules 150 | - p: Modules are the bits of code copied to the target system 151 | to be executed to satisfy the task declaration. 152 | - p: "Key points:" 153 | - ul: 154 | - Code need not exist on remote host -- ansible copies it over 155 | - Many modules come with Ansible -- "batteries included" 156 | - Custom modules can be developed easily 157 | - command/shell modules exists for simple commands 158 | - script module exists for using existing code 159 | - raw module exists for executing raw commands over ssh 160 | - class_notes: | 161 | Modules essentially create python code out of the descriptions given via the tasks that are then sent to the 162 | remote machine and interpreted/executed by that host. Once executed, Ansible then cleans up after itself and 163 | removes the module and output from the remote system. 164 | - 165 | - h2: Module Interactions 166 | - p: Module listing and documentation via ansible-doc 167 | - code: | 168 | $ ansible-doc -l 169 | acl Sets and retrieves file ACL information. 170 | apt Manages apt-packages 171 | - code: | 172 | $ ansible-doc acl 173 | > ACL 174 | 175 | Sets and retrieves file ACL information. 176 | 177 | Options (= is mandatory): 178 | 179 | - entry 180 | The acl to set or remove. This must always be quoted in the [...] 181 | - class_notes: | 182 | Modules and tasks represent the core function of ansible. Modules are capable of idempotence -- 183 | can be ran successively and understand change vs no change. In these examples we see how to use 184 | the command "ansible-doc" to review informtaion about specific modules that are included. 185 | - 186 | - h2: Module Interactions in Tasks 187 | - p: A series of tasks 188 | - code: | 189 | - name: add cache dir 190 | file: path=/opt/cache state=directory 191 | 192 | - name: install nginx 193 | yum: name=nginx state=present 194 | 195 | - name: start nginx 196 | service: name=nginx enabled=yes state=started 197 | - class_notes: | 198 | An ordered series of tasks can be described to form plays. Tasks utilize modules to act upon remote hosts. 199 | - 200 | - h2: Plays 201 | - p: Plays are ordered sets of tasks to execute against host selections from your inventory. 202 | - p: "This topic will cover:" 203 | - ul: 204 | - play naming 205 | - hosts selection 206 | - play arguments 207 | - variables 208 | - tasks 209 | - concurrency and order of operations 210 | - conditionals 211 | - error handling 212 | - inclusions 213 | - 214 | - h2: Play Naming 215 | - code: | 216 | - name: This is a Play 217 | - class_notes: General best practices are to name tasks in a way that shows what they do. 218 | - 219 | - h2: Hosts Selection 220 | - code: | 221 | - name: This is a Play 222 | hosts: web-servers 223 | - class_notes: This is how we specify in a play/plabook what hosts we will act upon based on group. 224 | - 225 | - h2: Play Arguments 226 | - code: | 227 | - name: This is a Play 228 | hosts: web-servers 229 | remote_user: fred 230 | sudo: yes 231 | connection: ssh 232 | - class_notes: | 233 | Furthermore, we can specify other variables as arguments. 234 | Such as what remote user to connect as, or whether we sudo to root to complete our task. 235 | - 236 | - h2: Variables 237 | - code: | 238 | - name: This is a Play 239 | hosts: web-servers 240 | remote_user: fred 241 | sudo: yes 242 | connection: ssh 243 | vars: 244 | http_port: 80 245 | cache_dir: /opt/cache 246 | - class_notes: | 247 | We gather facts before every run from hosts we are acting on. Facts become variables that 248 | contain information such as kernel level, host name, ip addresses and other standard information. 249 | - 250 | - h2: Tasks 251 | - code: | 252 | - name: This is a Play 253 | hosts: web-servers 254 | remote_user: fred 255 | sudo: yes 256 | connection: ssh 257 | gather_facts: no 258 | vars: 259 | http_port: 80 260 | cache_dir: /opt/cache 261 | 262 | tasks: 263 | - name: create cache dir 264 | file: path={{ cache_dir }} state=directory 265 | 266 | - name: install nginx 267 | yum: name=nginx state=installed 268 | - class_notes: | 269 | This is a compelte example of a play within a playbook. It contains arguments, variables, 270 | host groups to act on, two tasks and wheteher we use sudo on those tasks. It also uses the variables 271 | specified for the cache directory. Variables are represented in the Jinja2 format with double curly braces. 272 | - 273 | - h2: Concurrency and Order of Operations 274 | - code: | 275 | - name: This is a Play 276 | hosts: web-servers 277 | remote_user: fred 278 | sudo: yes 279 | connection: ssh 280 | vars: 281 | http_port: 80 282 | cache_dir: /opt/cache 283 | 284 | tasks: 285 | - name: create cache dir 286 | file: path={{ cache_dir }} state=directory 287 | 288 | - name: install nginx 289 | yum: name=nginx state=installed 290 | - class_notes: | 291 | You can specify number of concurrent machines to act upon via setting a number of forks. That will act upon 292 | that number of hosts at once, however the tasks within the play complete from top to botton, in order, one at a time. 293 | - 294 | - h2: Conditionals 295 | - code: | 296 | - name: This is a Play 297 | hosts: web-servers 298 | remote_user: fred 299 | sudo: yes 300 | connection: ssh 301 | vars: 302 | http_port: 80 303 | cache_dir: /opt/cache 304 | 305 | tasks: 306 | - name: create cache dir 307 | file: path={{ cache_dir }} state=directory 308 | 309 | - name: install nginx 310 | yum: name=httpd state=installed 311 | when: ansible_os_family == "RedHat" 312 | 313 | - name: install nginx 314 | apt: pkg=apache2 state=installed 315 | when: ansible_os_family == "Debian" 316 | - class_notes: | 317 | This is an example of a conditional. Conditionals allow for actions to be dependant on some fact or variable set. 318 | In this case, we see that we install nginx via Linux-Distro specific package managers. The variable "ansible_os_family" 319 | is a discovered fact gathered when we first run the play or playbook against hosts. 320 | - 321 | - h2: Error Handling 322 | - code: | 323 | - name: This is a Play 324 | hosts: web-servers 325 | remote_user: fred 326 | sudo: yes 327 | connection: ssh 328 | vars: 329 | http_port: 80 330 | cache_dir: /opt/cache 331 | 332 | tasks: 333 | - name: create cache dir 334 | file: path={{ cache_dir }} state=directory 335 | 336 | - name: install nginx 337 | yum: name=httpd state=installed 338 | when: ansible_os_family == "RedHat" 339 | 340 | - name: install nginx 341 | apt: pkg=apache2 state=installed 342 | when: ansible_os_family == "Debian" 343 | 344 | - name: failing command 345 | command: /bin/fail 346 | ignore_errors: yes 347 | - class_notes: | 348 | In this example we see the use of the "ignore_errors" setting, allowing users to dictate to ansible 349 | to ignore when the return codes of ansible-initiated tasks indicate failures or errors. Another way 350 | to do this is by using the "failed_when" options. 351 | - 352 | - h2: Inclusions 353 | - code: | 354 | - name: This is a Play 355 | hosts: web-servers 356 | remote_user: fred 357 | sudo: yes 358 | connection: ssh 359 | vars_files: 360 | - vars/nginx.yaml 361 | 362 | tasks: 363 | - name: create cache dir 364 | file: path={{ cache_dir }} state=directory 365 | 366 | - include: tasks/install-apache.yaml 367 | 368 | - name: failing command 369 | command: /bin/fail 370 | ignore_errors: yes 371 | - class_notes: | 372 | Take note of the "include" task: This allows us to include other playbooks at specific points in our 373 | run allowing for complicated aspects of orchestration to be seamless based on function or type of 374 | playbook. While this is useful, most often now you will use Roles for this functionality. We'll talk 375 | more about those in a bit. 376 | - 377 | - h2: Playbooks 378 | - p: Playbooks are ordered sets of plays to execute against inventory selections. 379 | - p: "This topic will cover:" 380 | - ul: 381 | - inventory selection 382 | - global variables 383 | - forks 384 | - inventory limits 385 | - inclusions 386 | - roles 387 | - 388 | - h2: Inventory Selection 389 | - code: | 390 | $ ansible-playbook -i production play.yaml 391 | $ ansible-playbook -i pre-prod play.yaml 392 | $ ansible-playbook -i hosts/dfw/ play.yaml 393 | - class_notes: | 394 | As you can see, we can specify different inventories to run the playbook "play.yaml" against. 395 | - 396 | - h2: Global Variables 397 | - code: | 398 | $ ansible-playbook -i pre-prod -e "cache_dir=/srv/cache/" play.yaml 399 | - class_notes: Variables declared in this manner from the command line override other values. 400 | - 401 | - h2: Forks 402 | - code: | 403 | $ ansible-playbook -f 30 -i pre-prod -e "cache_dir=/srv/cache/" play.yaml 404 | - class_notes: | 405 | This shows us declaring this playbook to be run against 30 hosts at a time by delcaring 406 | "-f 30" which is the flag for "forks equals 30 at a time." 407 | - 408 | - h2: Inventory-Limits 409 | - code: | 410 | $ ansible-playbook --limit dfw -f 30 -i pre-prod -e "cache_dir=/srv/cache/" play.yaml 411 | - class_notes: | 412 | This shows us running a playbook while declaring a limit to run only against "DFW" 413 | which could mean a single host named DFW, or a host group DFW. 414 | - 415 | - h2: Inclusions 416 | - code: | 417 | - name: This is a Play 418 | hosts: web-servers 419 | remote_user: fred 420 | sudo: yes 421 | connection: ssh 422 | gather_facts: no 423 | vars: 424 | http_port: 80 425 | cache_dir: /opt/cache 426 | 427 | tasks: 428 | - name: create cache dir 429 | file: path={{ cache_dir }} state=directory 430 | 431 | - include: playbook2.yaml 432 | - class_notes: | 433 | In this example we see that at the end of the playbook, we include another playbook. This allows 434 | us to continue against other playbooks using the already discovered facts and variables declared. 435 | - 436 | - h2: Roles 437 | - p: Roles are portable units of task organization in playbooks. 438 | - class_notes: | 439 | Roles are units of organization in Ansible. Assigning a role to a group of hosts 440 | (or a set of groups, or host patterns, etc.) implies that they should implement a 441 | specific behavior. A role may include applying certain variable values, certain tasks, 442 | and certain handlers - or just one or more of these things. Because of the file structure 443 | associated with a role, roles become redistributable units that allow you to share 444 | behavior among playbooks - or even with other users. 445 | - 446 | - h2: "Galaxy: Sharing is Caring" 447 | - p: The Galaxy is a site where you can share roles. 448 | - link: ['http://galaxy.ansible.com', 449 | 'http://galaxy.ansible.com'] 450 | - class_notes: | 451 | Galaxy is our repository for general roles that can be shared among users. You can find it at the 452 | address provided above. You can share your roles, rate other people's roles, and download them 453 | via the command line using the ansible galaxy commads. You can also create an empty role to build 454 | by initializing an empty role, which will populate all the correct files and directories for you. 455 | -------------------------------------------------------------------------------- /development/chapter_4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Tim G 4 | title: Write and run a simple playbook 5 | description: "We have already shown a simple playbook in Chapter 3. Here we will write a playbook from scratch, incrementally, and the students can follow along if they are able." 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Basic Playbook Structure 13 | 14 | - class_notes: In this chapter we'll cover the basic playbook structure, and write a simple playbook from scratch. 15 | 16 | - 17 | - h2: "Play Header" 18 | - code: | 19 | --- 20 | - name: this is the name of a play 21 | hosts: all 22 | user: root 23 | 24 | tasks: [] 25 | - class_notes: As we covered earlier, a playbook is a series of plays. Each play needs a "hosts" keyword, which tells Ansible to which hosts hosts this play applies. You can define a lot of other parameters at the play level, including which user to log in as, whether these tasks should be run through sudo, which connection mechanism to use, etc. 26 | 27 | - 28 | - h2: Write the tasks 29 | - code: | 30 | --- 31 | - name: this is the name of a play 32 | hosts: all 33 | user: root 34 | 35 | tasks: 36 | - name: install nginx 37 | yum: package=nginx state=present 38 | - class_notes: Now that we have the "front matter" of the play defined, we can add the tasks, as shown. Each task can have a name that is human-readable. This isn't required, but it's recommended. Then you call the module, in this case "yum", and any arguments. 39 | 40 | - 41 | - h2: Run the playbook 42 | 43 | - class_notes: "Run the playbook. If you've written everything correctly, it should install nginx on the target systems, and return the results. Notice the \"Gathering Facts\" step that occurs at the top of the run. This is implicit, but you can turn it off with \"gather_facts: no\" in the play. At the end, a \"host recap\" will be printed out. This gives you a summary of tasks that completed successfully, tasks that changed something on the target system, any failures, or unreachable systems." 44 | - 45 | - image: "http://cdn2.hubspot.net/hub/330046/file-449187601-png/ansible_badge.png" 46 | - link: ['ansible.com', 47 | 'http://www.ansible.com'] 48 | -------------------------------------------------------------------------------- /development/root.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Rackspace and Ansible 4 | title: Ansible Fundamentals 5 | description: Ansible Fundamentals 6 | slides: [] 7 | -------------------------------------------------------------------------------- /fundamentals/chapter_0.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Justin Phelps 4 | title: Ansible Fundamentals 5 | description: Ansible Fundamentals Course 6 | 7 | slides: 8 | - set_global: 9 | transition: none 10 | - 11 | - nested: 12 | - 13 | - h1: Ansible Fundamentals 14 | 15 | - 16 | - h1: Audio and Chat 17 | 18 | - p: "Chat: #ansible-training on FreeNode (http://freenode.net/)" 19 | 20 | - p: "" 21 | 22 | - p: "Audio: click on the Join.me phone icon and follow directions." -------------------------------------------------------------------------------- /fundamentals/chapter_1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: CC, PI 4 | title: Chapter 1, Ansible Fundamentals 5 | description: Ansible Fundamentals Course 6 | 7 | slides: 8 | 9 | - set_global: 10 | transition: none 11 | background: '#007777' 12 | #background: 'black' 13 | 14 | - 15 | - nested: 16 | - 17 | - h1: What is Ansible? 18 | - ul: 19 | - Clear 20 | - Fast 21 | - Complete 22 | - Efficient 23 | - Secure 24 | 25 | - 26 | - h2: Clear 27 | - p: 'A simple automation language allows Ansible to be used by anyone:' 28 | - ul: 29 | - sysadmins 30 | - developers 31 | - IT managers 32 | - p: It's easy to write, read, maintain, and evolve - without writing scripts or custom code. 33 | - 34 | - h2: Fast 35 | - p: Ansible is easy to learn. 36 | - p: Setup is fast. 37 | - class_notes: | 38 | 1. You can automate in under 30 minutes. Forget about how it works, just do it. 39 | 2. No agents. SSH keys are typically already in place. 40 | - 41 | - h2: Complete 42 | - p: 'Ansible is several tools in one:' 43 | - ul: 44 | - configuration management 45 | - application deployment 46 | - orchestration 47 | - provisioning 48 | - p: Hundreds of built-in modules. 49 | - 50 | - h2: Efficient 51 | - p: Ansible doesn't require a custom agent or software to install. 52 | - p: Ansible runs on OpenSSH. 53 | - class_notes: | 54 | 1. With no additional software infrastructure, you don't have to 55 | worry about managing the management tool. 56 | 2. That means anywhere SSH goes, Ansible goes. 57 | 3. It doesn't suck memory or CPU resources when it is not in use. 58 | 4. Designed from day one to automate no-downtime rolling updates 59 | and multi-tier orchestration. 60 | - 61 | - h2: Secure 62 | - p: No agent. 63 | - p: SSH transport. 64 | - p: Ansible plays can be read by anyone. 65 | - class_notes: | 66 | 1. It doesn't need additional ports or root level daemons. 67 | 2. It uses built-in OS authentication for better security - login 68 | as who you are, sudo if you want to sudo. 69 | 3. You can work with tools like Kerberos, LDAP, and sssd. 70 | 4. OpenSSH is the most peer-reviewed security component around. 71 | 5. This makes it auditable. You know what you're automating, 72 | and bugs have nowhere to hide. 73 | -------------------------------------------------------------------------------- /fundamentals/chapter_2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Mike Martin, Justin Phelps, Paul Durivage 4 | title: Chapter 2 5 | description: Ansible Fundamentals Course 6 | 7 | slides: 8 | - set_global: 9 | transition: none 10 | - 11 | - nested: 12 | - 13 | - h1: Ansible Use Cases 14 | - p: Ask not what you can do for Ansible, but what Ansible can do for you! 15 | - 16 | - h2: Ansible Use Cases 17 | - ul: 18 | - Remote Execution / Ad-hoc Tasks 19 | - Configuration Management 20 | - Application Deployment & Orchestration 21 | - Provisioning Infrastructure Dynamically 22 | - 23 | - h2: Remote Execution 24 | - ul: 25 | - Replacement for traditional systems administration tasks. (i.e., SSH) 26 | - Checking system responsiveness and uptime. 27 | - Gathering information about a collection of systems. 28 | - Replace one off rsync scripts, fabric, or terminal multiplexing. 29 | - class_notes: | 30 | Ansible provides a command-line tool and framework capable of 31 | executing over a large number of hosts, eliminating the need for 32 | systems administrators to multiplex terminal sessions via SSH to 33 | execute concurrent tasks across multiple hosts. What may have 34 | been done in bash scripts, rsync scripts, etc. can be done via 35 | ad-hoc one-liners in the shell. 36 | - 37 | - h2: Remote Execution 38 | - code: | 39 | ansible -m user -a "name=bob state=present" webservers 40 | - code: | 41 | ansible -m apt -a "pkg=apache2 state=present" webservers 42 | - class_notes: | 43 | Example 1 is adding a user to all the systems defined in the 44 | webservers group. Example 2 is installing the apache2 package 45 | on all systems defined in the webservers group. 46 | - 47 | - h2: Config Management 48 | - ul: 49 | - Lengthy system configuration, to include adding users, ssh keys, installing and configuring services, and bootstrapping systems to a given state. 50 | - '"Configuration remediation" Consistent server configuration. Removes manual configuration errors.' 51 | - class_notes: | 52 | Servers need to be configured; Ansible configures servers. 53 | Using a combination of imperative and declarative syntax 54 | [described in detail--maybe using the GPS analogy], using 55 | concepts such as tasks, roles, plays, and playbooks, complex 56 | machine configurations are being assembled and converged by 57 | the Ansible toolchain rather than manually by administrators. 58 | Configuration is either set manually by the author or dynamically at runtime by Ansible, resulting in consistent configuration across large server sets. 59 | - 60 | - h2: Application Deployment & Orchestration 61 | - p: Ansible can be used to replace various deployment and orchestration tools. 62 | - ul: 63 | - Deploy your custom application. 64 | - Replacement for Capistrano and Fabric (i.e., git deployments) 65 | - Good for large, complex environments 66 | - 67 | - h2: Application Deployment & Orchestration 68 | - p: Application deployment includes two main schools of thought. 69 | - h2: Rolling Release 70 | ul: 71 | - Remove node from production, update components, and put back into rotation. 72 | - class_notes: | 73 | Make the point that you deploy often in the DevOps world, and 74 | why this is important for application development. 75 | - 76 | - h2: Application Deployment & Orchestration 77 | - p: Application deployment includes two main schools of thought. 78 | - h2: Fresh Start 79 | - ul: 80 | - Deploy entirely new infrastructure and replace current environment wholesale. 81 | - class_notes: | 82 | Make the point that you deploy often in the DevOps world, and 83 | why this is important for application development. 84 | - 85 | - h2: Provisioning Infrastructure Dynamically 86 | - ul: 87 | - Infrastructure is Data. 88 | - You can provision to various clouds. 89 | - Dynamic Inventory plugins for various providers (Rackspace, Amazon, Digital Ocean, OpenStack, Eucalyptus etc.) 90 | - class_notes: | 91 | Cover the various ways that infrastructure can be provisioned 92 | using Ansible. Mention that there are modules that provide 93 | he ability to deploy to various clouds. Include a high level 94 | overview of the dynamic inventory plugin system. (Creating 95 | Infrastructure is the same as Configuring Infrastructure.) 96 | - 97 | - h2: Who is your Ansible, and what does he do? 98 | - class_notes: | 99 | Have the class search the ansible documention and come up 100 | with something that Ansible does. Be that a specific module, 101 | or a high level concept. 102 | -------------------------------------------------------------------------------- /fundamentals/chapter_3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Jesse K and the DFed Experience 4 | title: Understand the concepts of Ansible 5 | description: Description of the chapter 6 | 7 | slides: 8 | - set_global: 9 | transition: none 10 | - 11 | - nested: 12 | - 13 | - h1: Ansible Key Components 14 | - p: What makes Ansible tick! 15 | - class_notes: Let's delve into the concepts that drive Ansible. 16 | - 17 | - h2: Key components of Ansible 18 | - ul: 19 | - Inventory 20 | - Modules/Tasks 21 | - Plays 22 | - Playbooks 23 | - class_notes: These are some very key components you'll need to understand for using Ansible. 24 | - 25 | - h2: Inventory 26 | - ul: 27 | - Understanding Hosts and Groups 28 | - Inventory Sources 29 | - class_notes: | 30 | Ansible works against multiple systems in your infrastructure 31 | at the same time. It does this by selecting portions of systems 32 | listed in Ansible's inventory. 33 | - 34 | - h2: Inventory concepts 35 | - ul: 36 | - hosts 37 | - groupings 38 | - inventory-specific data 39 | - static or dynamic sources 40 | - class_notes: "Breaking down by topic, we'll cover four parts (Note the listed)" 41 | - 42 | - h2: "Inventory: Hosts" 43 | - p: "Hosts can have Ansible specific attributes such as:" 44 | - ul: 45 | - Connection IP addresses and ports 46 | - Remote user and sudo user 47 | - Connection types (Paramiko, OpenSSH, local, etc.) 48 | - Further limit targetd hosts using --limit 49 | - class_notes: | 50 | You have a lot of flexibility when you specify hosts in Inventory. You can 51 | set variables to determine connection types, host ip addresses and fully-qualified 52 | domain names, remote users and sudo users as well as any other variable you may 53 | come up with to use when interacting with your hosts, such as "apache_port" or 54 | "mysql ports". 55 | - 56 | - h2: "Inventory: Hosts" 57 | - p: "This is an example of a host entry in an inventory file:" 58 | - code: | 59 | web1.example.com ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50 60 | - class_notes: As you can see, we have a host name, a specified SSH port and IP Address. 61 | - 62 | - h2: "Inventory: Host Entries Using Ranges" 63 | - p: "You can have ranges of machine names or letters like this:" 64 | - code: | 65 | www[01:50].example.com ansible_ssh_port=5555 66 | db-[a-f].example.com ansible_ssh_port=5555 67 | - class_notes: Here we see that we can bracket a range of alpha-numeric characters to shorten our entries in the file. 68 | - 69 | - h2: "Inventory: Groups" 70 | - p: "Inventory Host Organization: Groups" 71 | - ul: 72 | - Groups allow targeted operations against different types of hosts. 73 | - Groups can also have variables that apply to all hosts within them. 74 | - --limit allows you to specify only certain groups to act against 75 | - Hosts can exist in more than one group at once. 76 | - class_notes: | 77 | We can also act against groups of hosts in a similar manner to single hosts. 78 | This allows you to also have standard settings for lots of similar hosts, such 79 | as a standard set of ports for apache on all web servers. You can limit the execution of 80 | Ansible jobs just as you can single hosts with the "--limit" option. Hosts can exist 81 | in more than one group at once, letting you do interesting operations on the intersections 82 | of groups. For example, target all of the east coast web servers. 83 | - 84 | - h2: "Inventory: Groups" 85 | - p: Groups are represented in brackets above host lists in the inventory file. 86 | - code: | 87 | [webservers] 88 | www[01:50].example.com ansible_ssh_port=5555 89 | - class_notes: This is an example of a range of hosts specified via the bracket nomenclature. 90 | - 91 | - h2: "Dynamic Inventory: Ansible and the Cloud" 92 | - p: "Inventory can also be gathered on demand from other sources dynamically. Those sources include:" 93 | - ul: 94 | - Cloud API (Rackspace, Amazon, Digital Ocean, OpenStack, Eucalyptus etc.) 95 | - Cobbler 96 | - Create your own for fun and profit! 97 | - class_notes: | 98 | So we can also take inventory from a wide variety of sources on the fly. We can touch Rackspace, 99 | Openstack, Amazon EC2, Digital Ocean, and other provisioning systems like Cobbler. You can also 100 | create your own inventory module to interface with any custom CMDB systems you may have. 101 | - 102 | - h2: "Inventory: Ansible and the Cloud" 103 | - p: "Dynamic inventories also respect groups and other details." 104 | - ul: 105 | - Groups are auto-determined by instance tags, regions and other attributes. 106 | - Dynamic Inventories can be used alongside Static Inventories for a hybrid cloud approach. 107 | - class_notes: | 108 | Tagged instances automatically are put in a group based on that tag. Other attributes also 109 | become groups, such as regions deployed to, or other custom attributes. 110 | - 111 | - h2: Tasks and Modules 112 | - p: Tasks and Modules are the workhorse of Ansible. 113 | - p: "This topic will cover:" 114 | - ul: 115 | - Understanding what a task is 116 | - Understanding how tasks make use of modules 117 | - 118 | - h2: Tasks 119 | - p: A task is a discrete action that is a declaration about 120 | the state of a system. 121 | - p: "Example Tasks:" 122 | - ul: 123 | - Directory should exist 124 | - Package should be installed 125 | - Service should be running 126 | - Cloud Instance should exist 127 | - class_notes: These are examples of declarative tasks where the beginning state is disregarded in favor of ensuring end-state. 128 | - 129 | - h2: "Tasks: Examples" 130 | - p: ansible can execute single tasks on sets of hosts 131 | to fullfill an ad-hoc declarations 132 | - code: | 133 | $ ansible web-hosts -m file -a "path=/opt/cache state=directory" 134 | $ ansible web-hosts -m yum -a "name=nginx state=present" 135 | $ ansible web-hosts -m service -a "name=nginx enabled=yes state=started" 136 | - class_notes: | 137 | in the first we make sure opt/cache exists, the second we install nginx, third we make 138 | sure nginx is installed, chkconfig'ed on and the service is started. 139 | - 140 | - h2: "Tasks: Sources" 141 | - p: "Code for tasks can come from:" 142 | - ul: 143 | - existing modules 144 | - custom modules 145 | - raw ssh commands 146 | - class_notes: | 147 | Tasks use modules or commands to create their actions to apply to remote systems. 148 | You can create your own modules, use any of the over 200 included modules, or use the output from commands. 149 | - 150 | - h2: Modules 151 | - p: Modules are the bits of code copied to the target system 152 | to be executed to satisfy the task declaration. 153 | - p: "Key points:" 154 | - ul: 155 | - Code need not exist on remote host -- ansible copies it over 156 | - Many modules come with Ansible -- "batteries included" 157 | - Custom modules can be developed easily 158 | - command/shell modules exists for simple commands 159 | - script module exists for using existing code 160 | - raw module exists for executing raw commands over ssh 161 | - class_notes: | 162 | Modules essentially create python code out of the descriptions given via the tasks that are then sent to the 163 | remote machine and interpreted/executed by that host. Once executed, Ansible then cleans up after itself and 164 | removes the module and output from the remote system. 165 | - 166 | - h2: Module Interactions 167 | - p: Module listing and documentation via ansible-doc 168 | - code: | 169 | $ ansible-doc -l 170 | acl Sets and retrieves file ACL information. 171 | apt Manages apt-packages 172 | - code: | 173 | $ ansible-doc acl 174 | > ACL 175 | 176 | Sets and retrieves file ACL information. 177 | 178 | Options (= is mandatory): 179 | 180 | - entry 181 | The acl to set or remove. This must always be quoted in the [...] 182 | - class_notes: | 183 | Modules and tasks represent the core function of ansible. Modules are capable of idempotence -- 184 | can be ran successively and understand change vs no change. In these examples we see how to use 185 | the command "ansible-doc" to review informtaion about specific modules that are included. 186 | - 187 | - h2: Module Interactions in Tasks 188 | - p: A series of tasks 189 | - code: | 190 | - name: add cache dir 191 | file: path=/opt/cache state=directory 192 | 193 | - name: install nginx 194 | yum: name=nginx state=present 195 | 196 | - name: start nginx 197 | service: name=nginx enabled=yes state=started 198 | - class_notes: | 199 | An ordered series of tasks can be described to form plays. Tasks utilize modules to act upon remote hosts. 200 | - 201 | - h2: Plays 202 | - p: Plays are ordered sets of tasks to execute against host selections from your inventory. 203 | - p: "This topic will cover:" 204 | - ul: 205 | - play naming 206 | - hosts selection 207 | - play arguments 208 | - variables 209 | - tasks 210 | - concurrency and order of operations 211 | - conditionals 212 | - error handling 213 | - inclusions 214 | - 215 | - h2: Play Naming 216 | - code: | 217 | - name: This is a Play 218 | - class_notes: General best practices are to name tasks in a way that shows what they do. 219 | - 220 | - h2: Hosts Selection 221 | - code: | 222 | - name: This is a Play 223 | hosts: web-servers 224 | - class_notes: This is how we specify in a play/plabook what hosts we will act upon based on group. 225 | - 226 | - h2: Play Arguments 227 | - code: | 228 | - name: This is a Play 229 | hosts: web-servers 230 | remote_user: fred 231 | sudo: yes 232 | connection: ssh 233 | - class_notes: | 234 | Furthermore, we can specify other variables as arguments. 235 | Such as what remote user to connect as, or whether we sudo to root to complete our task. 236 | - 237 | - h2: Variables 238 | - code: | 239 | - name: This is a Play 240 | hosts: web-servers 241 | remote_user: fred 242 | sudo: yes 243 | connection: ssh 244 | vars: 245 | http_port: 80 246 | cache_dir: /opt/cache 247 | - class_notes: | 248 | We gather facts before every run from hosts we are acting on. Facts become variables that 249 | contain information such as kernel level, host name, ip addresses and other standard information. 250 | - 251 | - h2: Tasks 252 | - code: | 253 | - name: This is a Play 254 | hosts: web-servers 255 | remote_user: fred 256 | sudo: yes 257 | connection: ssh 258 | gather_facts: no 259 | vars: 260 | http_port: 80 261 | cache_dir: /opt/cache 262 | 263 | tasks: 264 | - name: create cache dir 265 | file: path={{ cache_dir }} state=directory 266 | 267 | - name: install nginx 268 | yum: name=nginx state=installed 269 | - class_notes: | 270 | This is a compelte example of a play within a playbook. It contains arguments, variables, 271 | host groups to act on, two tasks and wheteher we use sudo on those tasks. It also uses the variables 272 | specified for the cache directory. Variables are represented in the Jinja2 format with double curly braces. 273 | - 274 | - h2: Concurrency and Order of Operations 275 | - code: | 276 | - name: This is a Play 277 | hosts: web-servers 278 | remote_user: fred 279 | sudo: yes 280 | connection: ssh 281 | vars: 282 | http_port: 80 283 | cache_dir: /opt/cache 284 | 285 | tasks: 286 | - name: create cache dir 287 | file: path={{ cache_dir }} state=directory 288 | 289 | - name: install nginx 290 | yum: name=nginx state=installed 291 | - class_notes: | 292 | You can specify number of concurrent machines to act upon via setting a number of forks. That will act upon 293 | that number of hosts at once, however the tasks within the play complete from top to botton, in order, one at a time. 294 | - 295 | - h2: Conditionals 296 | - code: | 297 | - name: This is a Play 298 | hosts: web-servers 299 | remote_user: fred 300 | sudo: yes 301 | connection: ssh 302 | vars: 303 | http_port: 80 304 | cache_dir: /opt/cache 305 | 306 | tasks: 307 | - name: create cache dir 308 | file: path={{ cache_dir }} state=directory 309 | 310 | - name: install nginx 311 | yum: name=httpd state=installed 312 | when: ansible_os_family == "RedHat" 313 | 314 | - name: install nginx 315 | apt: pkg=apache2 state=installed 316 | when: ansible_os_family == "Debian" 317 | - class_notes: | 318 | This is an example of a conditional. Conditionals allow for actions to be dependant on some fact or variable set. 319 | In this case, we see that we install nginx via Linux-Distro specific package managers. The variable "ansible_os_family" 320 | is a discovered fact gathered when we first run the play or playbook against hosts. 321 | - 322 | - h2: Error Handling 323 | - code: | 324 | - name: This is a Play 325 | hosts: web-servers 326 | remote_user: fred 327 | sudo: yes 328 | connection: ssh 329 | vars: 330 | http_port: 80 331 | cache_dir: /opt/cache 332 | 333 | tasks: 334 | - name: create cache dir 335 | file: path={{ cache_dir }} state=directory 336 | 337 | - name: install nginx 338 | yum: name=httpd state=installed 339 | when: ansible_os_family == "RedHat" 340 | 341 | - name: install nginx 342 | apt: pkg=apache2 state=installed 343 | when: ansible_os_family == "Debian" 344 | 345 | - name: failing command 346 | command: /bin/fail 347 | ignore_errors: yes 348 | - class_notes: | 349 | In this example we see the use of the "ignore_errors" setting, allowing users to dictate to ansible 350 | to ignore when the return codes of ansible-initiated tasks indicate failures or errors. Another way 351 | to do this is by using the "failed_when" options. 352 | - 353 | - h2: Inclusions 354 | - code: | 355 | - name: This is a Play 356 | hosts: web-servers 357 | remote_user: fred 358 | sudo: yes 359 | connection: ssh 360 | vars_files: 361 | - vars/nginx.yaml 362 | 363 | tasks: 364 | - name: create cache dir 365 | file: path={{ cache_dir }} state=directory 366 | 367 | - include: tasks/install-apache.yaml 368 | 369 | - name: failing command 370 | command: /bin/fail 371 | ignore_errors: yes 372 | - class_notes: | 373 | Take note of the "include" task: This allows us to include other playbooks at specific points in our 374 | run allowing for complicated aspects of orchestration to be seamless based on function or type of 375 | playbook. While this is useful, most often now you will use Roles for this functionality. We'll talk 376 | more about those in a bit. 377 | - 378 | - h2: Playbooks 379 | - p: Playbooks are ordered sets of plays to execute against inventory selections. 380 | - p: "This topic will cover:" 381 | - ul: 382 | - inventory selection 383 | - global variables 384 | - forks 385 | - inventory limits 386 | - inclusions 387 | - roles 388 | - 389 | - h2: Inventory Selection 390 | - code: | 391 | $ ansible-playbook -i production play.yaml 392 | $ ansible-playbook -i pre-prod play.yaml 393 | $ ansible-playbook -i hosts/dfw/ play.yaml 394 | - class_notes: | 395 | As you can see, we can specify different inventories to run the playbook "play.yaml" against. 396 | - 397 | - h2: Global Variables 398 | - code: | 399 | $ ansible-playbook -i pre-prod -e "cache_dir=/srv/cache/" play.yaml 400 | - class_notes: Variables declared in this manner from the command line override other values. 401 | - 402 | - h2: Forks 403 | - code: | 404 | $ ansible-playbook -f 30 -i pre-prod -e "cache_dir=/srv/cache/" play.yaml 405 | - class_notes: | 406 | This shows us declaring this playbook to be run against 30 hosts at a time by delcaring 407 | "-f 30" which is the flag for "forks equals 30 at a time." 408 | - 409 | - h2: Inventory-Limits 410 | - code: | 411 | $ ansible-playbook --limit dfw -f 30 -i pre-prod -e "cache_dir=/srv/cache/" play.yaml 412 | - class_notes: | 413 | This shows us running a playbook while declaring a limit to run only against "DFW" 414 | which could mean a single host named DFW, or a host group DFW. 415 | - 416 | - h2: Inclusions 417 | - code: | 418 | - name: This is a Play 419 | hosts: web-servers 420 | remote_user: fred 421 | sudo: yes 422 | connection: ssh 423 | gather_facts: no 424 | vars: 425 | http_port: 80 426 | cache_dir: /opt/cache 427 | 428 | tasks: 429 | - name: create cache dir 430 | file: path={{ cache_dir }} state=directory 431 | 432 | - include: playbook2.yaml 433 | - class_notes: | 434 | In this example we see that at the end of the playbook, we include another playbook. This allows 435 | us to continue against other playbooks using the already discovered facts and variables declared. 436 | - 437 | - h2: Roles 438 | - p: Roles are portable units of task organization in playbooks. 439 | - class_notes: | 440 | Roles are units of organization in Ansible. Assigning a role to a group of hosts 441 | (or a set of groups, or host patterns, etc.) implies that they should implement a 442 | specific behavior. A role may include applying certain variable values, certain tasks, 443 | and certain handlers - or just one or more of these things. Because of the file structure 444 | associated with a role, roles become redistributable units that allow you to share 445 | behavior among playbooks - or even with other users. 446 | - 447 | - h2: "Galaxy: Sharing is Caring" 448 | - p: The Galaxy is a site where you can share roles. 449 | - link: ['http://galaxy.ansible.com', 450 | 'http://galaxy.ansible.com'] 451 | - class_notes: | 452 | Galaxy is our repository for general roles that can be shared among users. You can find it at the 453 | address provided above. You can share your roles, rate other people's roles, and download them 454 | via the command line using the ansible galaxy commads. You can also create an empty role to build 455 | by initializing an empty role, which will populate all the correct files and directories for you. 456 | -------------------------------------------------------------------------------- /fundamentals/chapter_4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Tim G 4 | title: Write and run a simple playbook 5 | description: "We have already shown a simple playbook in Chapter 3. Here we will write a playbook from scratch, incrementally, and the students can follow along if they are able." 6 | 7 | slides: 8 | - set_global: 9 | transition: none 10 | - 11 | - nested: 12 | - 13 | - h1: Basic Playbook Structure 14 | 15 | - class_notes: In this chapter we'll cover the basic playbook structure, and write a simple playbook from scratch. 16 | 17 | - 18 | - h2: "Play Header" 19 | - code: | 20 | --- 21 | - name: this is the name of a play 22 | hosts: all 23 | user: root 24 | 25 | tasks: [] 26 | - class_notes: As we covered earlier, a playbook is a series of plays. Each play needs a "hosts" keyword, which tells Ansible to which hosts hosts this play applies. You can define a lot of other parameters at the play level, including which user to log in as, whether these tasks should be run through sudo, which connection mechanism to use, etc. 27 | 28 | - 29 | - h2: Write the tasks 30 | - code: | 31 | --- 32 | - name: this is the name of a play 33 | hosts: all 34 | user: root 35 | 36 | tasks: 37 | - name: install nginx 38 | yum: package=nginx state=present 39 | - class_notes: Now that we have the "front matter" of the play defined, we can add the tasks, as shown. Each task can have a name that is human-readable. This isn't required, but it's recommended. Then you call the module, in this case "yum", and any arguments. 40 | 41 | - 42 | - h2: Run the playbook 43 | 44 | - class_notes: "Run the playbook. If you've written everything correctly, it should install nginx on the target systems, and return the results. Notice the \"Gathering Facts\" step that occurs at the top of the run. This is implicit, but you can turn it off with \"gather_facts: no\" in the play. At the end, a \"host recap\" will be printed out. This gives you a summary of tasks that completed successfully, tasks that changed something on the target system, any failures, or unreachable systems." 45 | - 46 | - image: "http://cdn2.hubspot.net/hub/330046/file-449187601-png/ansible_badge.png" 47 | - link: ['ansible.com', 48 | 'http://www.ansible.com'] 49 | -------------------------------------------------------------------------------- /fundamentals/root.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Rackspace and Ansible 4 | title: Ansible Fundamentals 5 | description: Ansible Fundamentals 6 | slides: [] 7 | -------------------------------------------------------------------------------- /operational/chapter_0.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Justin Phelps 4 | title: Operational Ansible 5 | description: Operational Ansible Course 6 | 7 | slides: 8 | - 9 | - nested: 10 | - 11 | - h1: Operational Ansible 12 | -------------------------------------------------------------------------------- /operational/chapter_1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: CC, PI 4 | title: Chapter 1, Ansible Operational 5 | description: Ansible Operational Course 6 | 7 | slides: 8 | 9 | - set_global: 10 | transition: rotate 11 | background: '#007777' 12 | 13 | - 14 | - nested: 15 | - 16 | - h1: Installing Ansible 17 | - ul: 18 | - Assessment Review 19 | - Environment 20 | - Installation 21 | - class_notes: Start with a brief overview of the Ansible assessment. Then orientation of users to the foundational information required to consume the course progressing directly into the Command Line Interface to begin installing Ansible. 22 | 23 | - 24 | - h2: Assessment Review 25 | - ul: 26 | - Brief review of the Ansible Fundamentals Assessment topics 27 | - "Q & A" 28 | 29 | - 30 | - h2: Environment 31 | - ul: 32 | - Options exist on class environments to leverage 33 | - Clouds (RAX, AWS, etc.) 34 | - Vagrant 35 | - Local machines (CentOS 6.4, Ubuntu LTS) 36 | - directly from git checkout (running from source) 37 | 38 | - class_notes: Students will be introduced to the classroom lab environment. Explore deployment options and the ones that we will be utilizing in this classroom environment. 39 | 40 | - 41 | - h2: Installation 42 | - ul: 43 | - Getting Started 44 | - Installation 45 | - link: ['http://docs.ansible.com/intro_getting_started.html', 46 | 'http://docs.ansible.com/intro_getting_started.html'] 47 | - link: ['http://docs.ansible.com/intro_installation.html', 48 | 'http://docs.ansible.com/intro_installation.html'] 49 | - link: ['http://releases.ansible.com/ansible/', 50 | 'http://releases.ansible.com/ansible/'] 51 | - link: ['https://github.com/ansible/ansible/releases', 52 | 'https://github.com/ansible/ansible/releases'] 53 | - class_notes: Given the chosen environment, install Ansible using best practices. The recommended installation method is using your operating systems package manager where applicable. 54 | 55 | -------------------------------------------------------------------------------- /operational/chapter_2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Matt Martz 4 | title: Managing Inventory 5 | description: Understand and discuss concepts around managing inventory through static INI formatted files or through dynamic inventory scripts 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | 12 | - 13 | - h1: Inventory 14 | - p: Understand and discuss concepts around managing inventory through static INI formatted files or through dynamic inventory scripts 15 | 16 | - 17 | - h2: Static INI 18 | - p: Create an INI inventory file based off of instructor provided servers, specifying a human readable name and a connection IP address or hostname 19 | - class_notes: We should use a human readable name as the inventory hostname, and specify ansible_ssh_host for the actual IP. Ungrouped for now. 20 | 21 | - 22 | - h2: Static INI 23 | - code: | 24 | web1 ansible_ssh_host=10.10.10.10 25 | web2 ansible_ssh_host=20.20.20.20 26 | 27 | - 28 | - h2: Groups 29 | - p: Create a web group in the inventory file 30 | 31 | - 32 | - h2: Groups 33 | - code: | 34 | [web] 35 | web1 ansible_ssh_host=10.10.10.10 36 | web2 ansible_ssh_host=20.20.20.20 37 | 38 | - 39 | - h2: Dynamic Inventory 40 | - p: What are the use cases for dynamic inventory scripts 41 | - ul: 42 | - Limitations of a static inventory with a cloud like environment 43 | - Query nearly any data source for inventory 44 | - How ansible knows if the provided inventory is a script 45 | - class_notes: | 46 | Using a static inventory file with a "living" cloud like environment is inefficient, error prone and difficult to maintain. 47 | 48 | Due to the nature of an inventory script, they can mostly leverage the full power of the language they are implemented in. This would enable the script to communicate with nearly any data source for use as inventory. 49 | 50 | Ansible determines if the provided inventory is a script, by checking if the file is executable. If the file is not executable it is parsed as an INI file. 51 | 52 | - 53 | - h2: Dynamic Inventory Example 54 | - class_notes: Show the output of the dynamic inventory script of your choice 55 | 56 | - 57 | - h2: Start a basic playbook 58 | - p: Create a playbook that only has a "hosts" specification targeting all servers and then run it 59 | - class_notes: | 60 |
---
61 |             hosts: all
62 | 63 | Students should see that the playbook runs an implicit fact gathering step, and should successfully communicate with all servers. 64 | -------------------------------------------------------------------------------- /operational/chapter_3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Mike Martin, Justin Phelps, Paul Durivage, Jesse Keating 4 | title: Chapter 3, Using Ansible for Ad-hoc Commands 5 | description: Ansible Operational Course 6 | 7 | slides: 8 | - 9 | - nested: 10 | - 11 | - h1: Ansible Ad-Hoc Commands 12 | - h3: A Review of Hosts, Tasks, and Modules 13 | - 14 | - h2: Targeting Hosts 15 | - ul: 16 | - all / * 17 | - Groups (webservers) 18 | - Exclusion (webservers:!nginxservers) 19 | - Intersection (webservers:&staging) 20 | - Combos 21 | - Hostname / IP 22 | - Regex 23 | - "--limit" 24 | - class_notes: | 25 | Go over the various methods for targeting hosts for ad-hoc commands. 26 | Include information on rolling release and complex targeting. Use 27 | '-i localhost,' for a quick way to target a single host without 28 | specifying an inventory file. 29 | - 30 | - h2: Executing a task 31 | - p: ad-hoc commands are single-task executions which leverage modules 32 | - 33 | - h2: Modules 34 | - p: Modules are code that is executed on the remote host 35 | - class_notes: | 36 | Discuss how ansible takes module code and bundles it with arguments, 37 | transfers it to the remote host and executes it (depending on 38 | connection method). 39 | - 40 | - h2: Modules 41 | - p: Ansible provided core modules are 42 | - ul: 43 | - Written in python 44 | - Are shipped by SSH to the target machine where they are executed 45 | - Return JSON data that is interpreted by ansible 46 | - class_notes: Modules can be written in other languages, but core ansible only uses python. We don't need to go into the mechanics of how modules are built before being shipped, just mention that they get copied to the remote machine using SCP/SFTP. The echo out JSON data, which gets interpreted by the ansible "control" machine. 47 | - 48 | - h2: Module Documentation 49 | - code: | 50 | ansible-doc -l 51 | - code: | 52 | ansible-doc setup 53 | ansible-doc copy 54 | - class_notes: | 55 | ansible-doc -l lists all the modules. ansible-doc 56 | to see the documentation for a specific module. The ansible-doc 57 | command makes it extremely easy to see all of the available ansible 58 | modules with corresponding documentation and examples. 59 | - 60 | - h2: Example Use Cases 61 | - p: Rebooting all servers 62 | - code: | 63 | ansible all -m command -a "/sbin/reboot" 64 | - class_notes: | 65 | This is a simple command that uses the command module to issue a reboot 66 | to all servers in your inventory. 67 | The -m dictates the module, the -a for arguments. 68 | - 69 | - h2: Example Use Cases 70 | - p: Setting fork level to 10 71 | - code: | 72 | ansible webservers -f 10 -m setup 73 | - class_notes: | 74 | Fork level means that Ansible will fork 10 times, and then reach out 75 | to up to 10 machines concurrently. Choose carefully the level of concurrency: 76 | higher concurrency executes tasks/plays/playbooks faster, but results in more 77 | resources being consumed. 78 | - 79 | - h2: Example Use Cases 80 | - p: Copy a file from the local host to inventory hosts 81 | - code: | 82 | ansible dbservers -m copy -a "src=/path/to/file dest=/path/to/dest" 83 | - class_notes: | 84 | Uses the copy module to copy a file from the local machine, where the ansible 85 | command is being run, to the destination. 86 | - 87 | - h2: Example Use Cases 88 | - p: Install nginx and add a user 89 | - code: | 90 | ansible all -m apt -a "pkg=nginx state=present" 91 | ansible all -m user -a "name=bob state=present" 92 | - class_notes: | 93 | Very simple; this uses the apt module to install nginx, and uses 94 | the user module to add user bob. 95 | - 96 | - h2: Example Use Cases 97 | - p: Cloning a git repo to a path 98 | - code: | 99 | ansible appservers -m git -a "repo=https://github.com/ansible/ansible dest=/home/user/ansible" 100 | - class_notes: | 101 | This is cloning a repo to a directory, optionally accepting tags and versions. Allows you 102 | to install software (or anything stored in Git) from source control, a cornerstone 103 | piece of functionality for any automation/config mgmt/orchestration tool. 104 | - 105 | - h2: Example Use Cases 106 | - p: Ensure httpd is started 107 | - code: | 108 | ansible -m service -a "name=httpd state=started" 109 | - class_notes: | 110 | The service module is used to ensure httpd is started. It does not restart, stop, reload 111 | or do anything but check that the process is running; if it is not running, it starts. 112 | - 113 | - h2: Example Use Cases 114 | - p: Backgrounding tasks, with optional polling every 60 seconds 115 | - code: | 116 | ansible all -B 3600 -a "/usr/bin/long_running_operation --do-stuff" 117 | ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff" 118 | - class_notes: | 119 | Initiate long running tasks with polling. Optionally kick off long running tasks 120 | with backgrounding and no polling, returning you to the shell, with the option of 121 | checking back in on the operation by setting -P to 0, which is otherwise a default of 15. 122 | - 123 | - h2: Example Use Cases 124 | - p: Running setup module to gather and display all facts about a machine known to Ansible 125 | - code: | 126 | ansible web1.example.com -m setup 127 | - class_notes: | 128 | Gathers a very large JSON object's worth of data about servers, to include 129 | network information, distro information, shell environment, devices, 130 | CPU, memory, etc. All facts returned by setup are prefixed with ansible_ 131 | - 132 | - h2: Cowsay 133 | - image: 'http://i.imgur.com/rRBp5Ln.png?1' 134 | - class_notes: | 135 | Cowsay is used by default if enabled on the system, but can be disabled 136 | permanently in the ansible.cfg file, or skill installation of cowsay. 137 | - 138 | - h2: Labs 139 | - h3: Using the 'ansible' command 140 | - ul: 141 | - Install nginx and ensure that it is set to start at boot 142 | - Ensure that nginx is started 143 | - Create user www-data 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /operational/chapter_4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: CC, PI, JLK 4 | title: Chapter 4, Using Ansible for Orchestrated Commands 5 | description: Ansible Operational Course 6 | 7 | slides: 8 | 9 | - set_global: 10 | transition: rotate 11 | background: '#007777' 12 | 13 | - 14 | - nested: 15 | - 16 | - h1: Ansible Orchestrated Commands 17 | - h3: A Review of Ansible Plays and Playbooks 18 | - class_notes: Students will walk through the process Ansible goes through to execute the desired jobs on targeted hosts when a Playbook gets run. 19 | 20 | - 21 | - h2: Plays 22 | - p: An ordered series of tasks executed on a selection of hosts 23 | - p: With controls over how the tasks operate 24 | - code: | 25 | - name: This is a Play 26 | hosts: web-servers 27 | remote_user: fred 28 | sudo: yes 29 | connection: ssh 30 | gather_facts: no 31 | vars: 32 | http_port: 80 33 | cache_dir: /opt/cache 34 | 35 | tasks: 36 | - name: create cache dir 37 | file: path={{ cache_dir }} state=directory 38 | 39 | - name: install nginx 40 | yum: name=nginx state=installed 41 | - class_notes: | 42 | Discuss play controls such as sudo, remote_user, etc. 43 | Discuss variables. Show the list of tasks and how 44 | all finish one before going on to the next. Mention serial 45 | as a way to control how hosts flow through the tasks. 46 | Multiple plays can be written into a playbook. 47 | 48 | - 49 | - h2: Playbooks 50 | - p: ansible-playbook is the tool used to select 51 | - ul: 52 | - an ordered set of plays 53 | - an inventory 54 | - global variables 55 | - forks 56 | - inventory limits 57 | 58 | - 59 | - h2: Playbooks 60 | - h3: Execution 61 | - code: | 62 | $ ansible-playbook play.yaml -i pre-prod -e "cache_dir=/srv/cache/" -f 30 -l dfw 63 | 64 | - 65 | - h2: Handlers 66 | - h3: "Actions triggered upon change" 67 | -------------------------------------------------------------------------------- /operational/chapter_5.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Matt Martz 4 | title: Variables 5 | description: Understand the basics of variables, where they come from, how they get set, and how to evaluate and manipulate them 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | 12 | - 13 | - h1: Variables 14 | - p: Understand the basics of variables, where they come from, how they get set, and how to evaluate and manipulate them 15 | 16 | - 17 | - h2: Host Variables 18 | - p: Host variables are "facts" about a server that contains info such as 19 | - ul: 20 | - Hostname 21 | - IP addresses 22 | - Date and Time information 23 | - CPU, Disk, Memory 24 | - Hardware Architecture 25 | - Operating System Information 26 | - class_notes: For an example the students can run 'ansible all -i localhost, -c local -m setup' 27 | 28 | - 29 | - h2: Host Variables 30 | - p: Where do they come from? 31 | - ul: 32 | - inventory 33 | - fact gathering (setup) 34 | - host_vars directory 35 | 36 | - 37 | - h2: Group Variables 38 | - p: '"facts" that apply to a grouping of servers' 39 | 40 | - 41 | - h2: Group Variables 42 | - p: Where do they come from? 43 | - ul: 44 | - inventory 45 | - group_vars directory 46 | - p: "" 47 | - p: The name of the files in the group_vars directory line up with the group name being targeted. "all" is a special keyword to apply facts to all hosts. 48 | 49 | - 50 | - h2: Variable Precedence 51 | - p: Precedence should simply feel natural 52 | - p: The most specific applied variable wins 53 | 54 | - 55 | - h2: Using Variables in YAML 56 | - p: Ansible uses "mustache" like variable expansion 57 | - h4: group_vars/all 58 | - code: | 59 | --- 60 | apache2_version: 2.2.22-1ubuntu1 61 | - h4: Task 62 | - code: '- apt: name="apache2={{ apache2_version }}" state=present' 63 | 64 | - 65 | - h2: Register 66 | - p: A special keyword "register" exists for all tasks, that will assign the output from a module to the variable of the specified name, for later manipulation or evaluation in use with other tasks 67 | - code: | 68 | - git: repo=git://github.com/ansible/ansible.git dest=/tmp/ansible 69 | register: ansible_git 70 | - class_notes: | 71 | Different modules produce different data structures. For example, command and shell return a data structure containing the return code of the command, the contents of stderr and stdout, etc. The next section talks about how to explore the contents of a register variable. 72 | 73 | - 74 | - h2: Inspecting Variables 75 | - p: Different modules produce different data structures. The 'debug' module will help you inspect that data structure. 76 | - code: | 77 | - debug: var=ansible_git 78 | - h4: Output Sample 79 | - code: | 80 | ok: [someserver] => { 81 | "ansible_git": { 82 | "after": "1b4ba5431b1070c63b9069d310f42e16f302db10", 83 | "before": "69b2d82be6ffe20f04070cddf11b7629aa8420e5", 84 | "changed": true, 85 | "invocation": { 86 | "module_args": "repo=git://github.com/ansible/ansible.git dest=/tmp/ansible", 87 | "module_name": "git" 88 | } 89 | } 90 | } 91 | 92 | - 93 | - h2: Module Output Structure 94 | - p: All modules should return a key titled "changed" with a boolean value of "true" or "false" defining whether the module made a change 95 | - p: Additionally, under a failure scenario, a module would set a key of "failed" with a boolean value of "true" 96 | - class_notes: A failed module may not have a changed key 97 | 98 | - 99 | - h2: Dynamically Adding Host Facts 100 | - p: During runtime you can run add additional host vars using the "set_fact" module 101 | - code: | 102 | - local_action: 103 | module: wait_for 104 | host: "{{ ansible_default_ipv4.address }}" 105 | port: 22 106 | delay: 1 107 | timeout: 1 108 | register: port_test 109 | failed_when: False 110 | 111 | - set_fact: ansible_ssh_port=2222 112 | when: port_test|failed 113 | - class_notes: This example uses the wait_for module to attempt communication with port 22 on the remote host via a local action. Don't fail if wait_for fails, and if wait_for fails, set ansible_ssh_port to port 2222 for future communciation with the server. 114 | 115 | - 116 | - h2: Magic Variables 117 | - p: There are several standard variables that are created and exposed by ansible 118 | - ul: 119 | - inventory_dir 120 | - inventory_hostname 121 | - inventory_hostname_short 122 | - inventory_file 123 | - playbook_dir 124 | - play_hosts 125 | - hostvars 126 | - groups 127 | - group_names 128 | - ansible_ssh_user 129 | - class_notes: | 130 | play_hosts is new to 1.5, there is also 'vars' and 'environment' but are not widely used or discussed 131 | http://docs.ansible.com/playbooks_variables.html#magic-variables-and-how-to-access-information-about-other-hosts 132 | -------------------------------------------------------------------------------- /operational/chapter_6.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Tim G 4 | title: Chapter Title 5 | description: Description of the chapter 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | 12 | - 13 | - h1: Variable Inclusion 14 | - h3: How to properly use include_vars and vars_files to include variables in your playbooks 15 | 16 | - 17 | - h2: vars_files 18 | - p: "vars_files is used in playbooks to include a file of variables outside of the usual variable locations" 19 | - ul: 20 | - Useful for keeping secrets and site specific data outside of your Ansible repository and version control 21 | - Not available for usage within roles, for that you will need the include_vars module 22 | 23 | - class_notes: 24 | The vars_files directive is useful because it allows for you to keep secrets and business specific data in a location outside your Ansible repository. This allows you to keep your Ansible playbooks very generic and portable. This means you can continue to benefit from changes upstream if it is a community contributed playbook, or you can safely push out updates to the playbook if you are contributing it to the community. Ultimately the variable include mechanisms are to provide flexibility in where your variables are located. 25 | 26 | - 27 | - h2: include_vars 28 | - p: "The include_vars module is similar to vars_files and allows for dynamic inclusion of variables within the context of a role." 29 | - ul: 30 | - | 31 | include variables based on the target Linux Distribution
32 | include_vars: "../vars/{{ansible_os_family}}.yml" 33 | 34 | - | 35 | include a directory of variable fragments
36 | include_vars: "{{ item }}.yml"
37 | with_fileglob: "../vars/*.yml" 38 | 39 | - class_notes: 40 | The include_vars module is very similar to vars_files, however include_vars is a module which means it can be used within the context of a role, whereas vars_files cannot. Some example use cases of include_vars are shown here, in the first example include_vars is used to pull in variables based upon the Linux distribution in use. In the second example include_vars is being used to collect a series of variables files from a directory. Don't think of these as the "correct" ways to handle variables, but rather as yet another tool at your disposal for flexibility when needed. 41 | -------------------------------------------------------------------------------- /operational/chapter_7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Tim G 4 | title: Task Control 5 | description: Ansible has a lot of ways to control the operation of specific tasks. You can use then "when" keyword to skip tasks according to certain conditions, loop over items in lists or hashes, and control the "failed" or "changed" responses of particular tasks. Local actions and delegation can be used to control where a task runs. 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Task Control 13 | - ul: 14 | - "Conditionals: when" 15 | - "Loops: with_items, etc" 16 | - "Task status: failed_when, changed_when" 17 | - Local actions and delegation 18 | 19 | - 20 | - h2: Conditionals 21 | - h3: Useful for 22 | - ul: 23 | - Acting on results of previous tasks 24 | - Handling cross-distro/env differences 25 | 26 | - 27 | - h2: "An Example" 28 | - code: | 29 | - name: do something only on RedHat-style systems 30 | command: mycommand 31 | when: ansible_os_family == "RedHat" 32 | 33 | - class_notes: The when keyword, when applied to a task, can control execution of that task and skip it when certain conditions are set. Any variable can be used in a "when" condition, including register variables, facts, and group/host vars. Some particularly useful uses of this include skipping tasks based on the results of previous tasks, and handling cross-distro differences in package names/managers. 34 | 35 | - 36 | - h2: "Loops" 37 | - h3: "with_items: Loops over a list, one task per item" 38 | 39 | - class_notes: "Tasks can loop over lists using the with_items keyword. Each item in the list will be treated as a separate task, and you can use the special item variable name to access the current item. (Note: apt/yum modules collapse a list into a single package management transaction for speed) 40 | 41 | There are some other looping keywords, too. See http://docs.ansible.com/playbooks_loops.html for more. 42 | 43 | Class question: when would you need to use some of the other loop keywords, like with_together, with_sequence,with_random_choice, etc?" 44 | 45 | - 46 | - h2: "Status Control" 47 | - ul: 48 | - failed_when 49 | - changed_when 50 | 51 | - class_notes: "Ansible tasks can return a few different states: \"OK\" means that the task completed successfully but didn'/.t change anything on the target system. \"Changed\" means that the task completed, and changed something. \"Failed\" means that the task failed. (duh) 52 | 53 | When you're using \"command\" or \"shell\" to issue commands on the remote system, Ansible will detect the return code of the command. If it's non-zero, Ansible will treat it as a failure, but sometimes that's not what you want. There may be other circumstances with other modules where you see a change or a failure but want to continue on, or mark that task as just \"ok\", with no change. There are two keywords to control this. failed_when and changed_when. These work like the \"when\" keyword, but control the status of the task. For instance. 54 | 55 | - name: this command prints FAILED when it fails 56 | command: /usr/bin/example-command -x -y -z 57 | register: command_result 58 | failed_when: \"'FAILED' in command_result.stderr\" 59 | This will treat the command as a failure only when the string \"FAILED\" exists in the stderr of the command output. 60 | 61 | Some examples of changed_when: 62 | 63 | - shell: /usr/bin/billybass --mode=\"take me to the river\" 64 | register: bass_result 65 | changed_when: \"bass_result.rc != 2\" 66 | 67 | # this will never report 'changed' status 68 | - shell: wall beep 69 | changed_when: False 70 | " 71 | - 72 | - h2: Local actions 73 | - ul: 74 | - local_action (task) 75 | - "connection: local (play)" 76 | 77 | - class_notes: 78 | "Most Ansible tasks (actions) run on a remote machine: a Python program is assembled and sent across to the remote server, run, and the response is returned. But for some tasks, like API calls to remote services, it doesn't make sense to run that task on a remote machine--this is what local actions are for. This runs the task locally on the Ansible machine, but still \"on behalf\" of the machine currently being operated upon." 79 | 80 | - 81 | - h2: Delegation 82 | - p: Run a task on another server, on behalf of the server we are currently operating on. 83 | 84 | - class_notes: A delegated task is similar. You can be running a play that operates upon, say, "webservers", but for a particular task within that play, run the action on a different server. As an example, you may be going through an app deployment on the webservers group, but you may need to contact the monitoring server to turn off monitoring for that host while it's being updated. So, you would want to delegate_to a different server, in a play ordinarily targeting webservers. 85 | -------------------------------------------------------------------------------- /operational/chapter_8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Jesse K and David F 4 | title: Best Practices 5 | description: A discussion of the best operational practices to use with Ansible. 6 | 7 | slides: 8 | 9 | - 10 | - nested: 11 | - 12 | - h1: Best Practices 13 | - ul: 14 | - content organization 15 | - version control 16 | - role based access control 17 | - platform variance in playbooks 18 | - proper naming of plays, tasks, and handlers 19 | - playbook formatting 20 | - class_notes: | 21 | Best practices are not just conformity for conformity sake. 22 | They will help simplify code, smooth out collaboration, and 23 | avoid gotchas. 24 | - 25 | - h2: Content Organization 26 | - p: Magic happens when you put your files in the right locations 27 | - ul: 28 | - ansible.cfg 29 | - inventory 30 | - variables and inclusions 31 | - tasks 32 | - handlers 33 | - playbooks 34 | - templates and files for use in tasks 35 | - custom modules 36 | - roles 37 | - class_notes: | 38 | Ansible looks in ANSIBLE_CONFIG, ./ansible.cfg, ./.ansible.cfg 39 | and /etc/ansible/ansible.cfg in that order. (1.5 switched 40 | ANSIBLE_CONFIG and ./ansible.cfg order) 41 | Inventory is looked for in config directive, ANSIBLE_HOSTS, 42 | /etc/ansible/hosts in that order. 43 | host_vars / group_vars relative to inventory and playbook 44 | basedirs 45 | file inclusions are relative to the playbook (vars, tasks, 46 | handlers, playbooks, templates, etc...) 47 | Custom modules go in library/ relative to playbook 48 | roles are in roles/ relative to playbook, and have 49 | files, templates, tasks, handlers, vars, meta all relative 50 | to the role itself, making for portability. 51 | 52 | - 53 | - h2: Version Control 54 | - p: Version control and Ansible go hand in hand. This topic will walk through many of the benefits of storing your ansible content in SCM and why this is itself a best practice. 55 | - 56 | - h2: Version Control 57 | - h3: audit trail / RBAC 58 | - class_notes: | 59 | Version control provides a record of who changed what, when, and 60 | why, the audit trail. It can also be a part of RBAC strategy, 61 | providing a gateway to who can commit to the playbook content. 62 | - 63 | - h2: Version Control 64 | - h3: collaboration and preservation 65 | - class_notes: | 66 | A centralized (or distributed) store of the content protects 67 | against localized disaster. It also allows for better collaboration 68 | than just passing files back and forth, or co-editing a single 69 | directory. 70 | - 71 | - h2: Version Control 72 | - h3: DevOps tie-in 73 | - class_notes: DevOps best practices dictate code to be deployed is already in SCM, natural extension to put code that does the deploying in SCM as well 74 | - 75 | - h2: Version Control 76 | - h3: Galaxy, Git, and You! 77 | - ul: 78 | - role sharing 79 | - joys of modular playbooks 80 | - deploying code with the git module in a role 81 | - class_notes: GALAXY! 82 | - 83 | - h2: Version Control 84 | - h3: Sensitive information handling 85 | - class_notes: VAULT! 86 | - 87 | - h2: Version Control 88 | - h3: Barriers to entry 89 | - ul: 90 | - pull requests 91 | - automatic gateway tests 92 | - local validation checks 93 | - class_notes: | 94 | All these things can work together to add quality assurance to your 95 | content. Using pull or change requests gives a human the 96 | opportunity to review. Automated tests can tie into them, or be 97 | ran post-commit to continuously validate. Localized hooks can be 98 | used to validate after pulling changes in. 99 | - 100 | - h2: RBAC and execution model 101 | - p: A discussion of RBAC, Ansible, and your team, as well as a comparison of execution stratagies 102 | - 103 | - h2: RBAC and execution model 104 | - h3: RBAC 105 | - class_notes: | 106 | Role Based Access Control is used in many organizations 107 | to seperate out who has access to do what within environments. 108 | Often required for parts of public companies. Sometimes at 109 | odds with DevOps philosophy of self-service. 110 | - 111 | - h2: RBAC and execution model 112 | - h3: Execution models 113 | - ul: 114 | - centralized 115 | - distributed 116 | - class_notes: A comparison and contrast of centralized and distributed execution models. Not to be confused with push and pull. 117 | - 118 | - h2: RBAC and execution model 119 | - h3: Centralized 120 | - ul: 121 | - access defined by company standards 122 | - layer of protection against accidents and malice 123 | - repeatability and guaranteed working environment 124 | - ITIL/Change Control process friendly 125 | - class_notes: | 126 | A single point from which to either push changes from, or 127 | have ansible-pull fetch changes from. Can configure systems to 128 | only allow Ansible logins from this host with a particular key 129 | Host can be locked down and managed to ensure unwanted changes 130 | don't creep in and disrupt ability to do repeat runs 131 | - 132 | - h2: RBAC and execution model 133 | - h3: Distributed 134 | - ul: 135 | - rapid development and execution loop 136 | - change control put in hands of playbook/code devs 137 | - turns operational support from gatekeeping to enabling 138 | - aligns with other self-service IT services 139 | - you built it, you deploy it 140 | - class_notes: | 141 | Each developer could be a distributor, or individual 142 | systems could point to individual sources for ansible-pull 143 | Higher security risk, higher risk of run environment change 144 | but tradeoff for more flexibility and rapid dev/deploy times 145 | - 146 | - h2: Platform Variance in playbooks 147 | - p: Best practices for dealing with the challenge of heterogeneous environments 148 | - 149 | - h2: Platform Variance in playbooks 150 | - h3: group_by 151 | - p: Create dyanmic groups matching certain criteria 152 | - code: | 153 | - name: grouping play 154 | hosts: all 155 | tasks: 156 | - name: create distro groups 157 | group_by: key={{ ansible_distribution }} 158 | 159 | - name: CentOS play 160 | hosts: CentOS 161 | gather_facts: False 162 | tasks: 163 | - # tasks that only happen on CentOS go here 164 | - class_notes: Note that roles could also be used here, driven by group_by. 165 | - 166 | - h2: Platform Variance in playbooks 167 | - h3: task conditionals 168 | - code: | 169 | - name: install nginx 170 | yum: name=nginx state=present 171 | when: ansible_distribution == 'CentOS' 172 | 173 | - name: install nginx 174 | apt: pkg=nginx state=present 175 | when: ansible_distribution == 'Debian' 176 | - class_notes: A more simple way to deal, could clutter up a large playbook / role set. 177 | - 178 | - h2: Proper naming of plays, tasks, and handlers 179 | - p: Names have significance 180 | - ul: 181 | - --start-at-task 182 | - handler notification 183 | - output review 184 | - code: | 185 | $ ansible-playbook play.yaml --start-at-task="a good task" 186 | 187 | - name: a good task 188 | file: path=/etc/foobar state=absent 189 | notify: bounce foo service 190 | 191 | handlers: 192 | - name: bounce foo service 193 | service: name=foo state=restarted 194 | - class_notes: | 195 | Names have meaning. task names in --start-at-task, 196 | handler names for notify. Play names are less important 197 | but uniqueness helps when debugging output 198 | - 199 | - h2: Playbook formatting 200 | - p: whitespace, yaml, line lengths, oh my! 201 | - 202 | - h2: Playbook formatting 203 | - h3: order and style of playbook directives 204 | - ul: 205 | - use a name 206 | - hosts next 207 | - other options 208 | - tags 209 | - vars after a blank line 210 | - tasks after a blank line 211 | - code: | 212 | - name: Generate env/cell specific content 213 | hosts: localhost 214 | connection: local 215 | gather_facts: false 216 | tags: 217 | - localprep 218 | 219 | vars: 220 | - cachedir: cache/ 221 | 222 | tasks: 223 | - name: stuff 224 | - class_notes: | 225 | There is no hard order that things must appear in a playbook, 226 | however if anybody ever looks at your files they will expect 227 | an order. Blank lines help to visually separate logical blocks 228 | of the play and between plays. 229 | - 230 | - h2: Playbook formatting 231 | - h3: whitespace, line lengths, continuations 232 | - ul: 233 | - blank lines encouraged 234 | - less than 80 chars wide 235 | - blocks can continue on new lines with proper spacing 236 | - code: | 237 | tasks: 238 | - name: one task 239 | command: echo 240 | 241 | - name: lots of arguments 242 | rax_dns_record: credentials=/path/to/my/creds type=A 243 | data=4.2.2.2 name=www.nodomain.not 244 | - class_notes: | 245 | Playbook syntax is friendly to line continuation, make use of that 246 | to keep your lines under 80 chars. Wrap the text to be at the same 247 | indent level as the preceeding data block, as seen in the example 248 | - 249 | - h2: Playbook formatting 250 | - h3: to quote or not to quote 251 | - ul: 252 | - "quote strings that have a : in them" 253 | - "quote variables if they come directly after a :" 254 | - "quote strings that use * directly after a :" 255 | - quote entire string if first character is a quote 256 | - code: | 257 | - name: "My name has a : in it" 258 | command: "{{ variable_here }}" 259 | when: "'some_string' in varaible_here" 260 | 261 | hosts: "*-webs" 262 | - class_notes: | 263 | quoting is a yaml gotcha. It often trips people up. These 264 | rules here will help you avoid most/all quoting gotchas. 265 | - 266 | - h2: Playbook formatting 267 | - h3: variable referencing 268 | - ul: 269 | - use {{ }} almost always 270 | - do not use {{ }} in conditionals and other task controllers 271 | - code: | 272 | - name: name here 273 | command: echo {{ variable here }} 274 | register: output 275 | when: variable != "derp" 276 | failed_when: output.stderr == "FAILURE" 277 | - class_notes: | 278 | Variable decoration is another gotcha. Task controllers can be 279 | treated like lines of python, where variables are referenced 280 | without decoration and raw strings need quotes. 281 | - 282 | - h2: Playbook formatting 283 | - h3: YAML gotchas 284 | - ul: 285 | - | 286 | Booleans: /^(y|yes|n|no|true|false|on|off)$/i 287 | - class_notes: | 288 | Assume the scenario where you are configuring sshd_config, and you create a variable to disable root login via "PermitRootLogin: no". In this case 'no', evaluates to the boolean False, so you end up literally inserting "PermitRootLogin False" in your config file. To use 'no' as a string literal it must be quoted such as "PermitRootLogin: 'no'". 289 | 290 | - 291 | - image: "http://cdn2.hubspot.net/hub/330046/file-449187601-png/ansible_badge.png" 292 | - link: ['ansible.com', 293 | 'http://www.ansible.com'] 294 | -------------------------------------------------------------------------------- /operational/root.yml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | author: Rackspace and Ansible 4 | title: Ansible Operational 5 | description: Ansible Operational 6 | slides: [] 7 | -------------------------------------------------------------------------------- /operational_lab/adhoc_commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # adhoc_commands.sh 3 | 4 | # Install nginx (EL first) and ensure that it is set to start at boot 5 | 6 | # First we upload the repo file for nginx 7 | ansible all -i hosts -u root -m copy -a "src=nginx.repo dest=/etc/yum.repos.d/nginx.repo owner=root mode=0655" 8 | 9 | # Install the RPM GPG Key 10 | ansible all -i hosts -u root -m rpm_key -a "key=http://nginx.org/keys/nginx_signing.key" 11 | 12 | # Now let's install the package 13 | ansible all -i hosts -u root -m yum -a "name=nginx state=present" 14 | 15 | # Last, enable the package to run at boot 16 | ansible all -i hosts -u root -m service -a "name=nginx enabled=yes" 17 | -------------------------------------------------------------------------------- /operational_lab/group_vars/all: -------------------------------------------------------------------------------- 1 | nginx_workers: 2 2 | nginx_access_log: /var/log/nginx/access.log 3 | nginx_error_log: /var/log/nginx/error.log 4 | domains: 5 | - example.com 6 | - hamsandwich.com 7 | - moo.com 8 | - ansible.com 9 | -------------------------------------------------------------------------------- /operational_lab/lab3-7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Lab 3 3 | - name: Ansible Operational Labs 4 | hosts: all 5 | tasks: 6 | # This is boilerplate for dealing with an apt module that is not installing 7 | # python-apt for you. This checks for the existence of python-apt 8 | - name: Check if python-apt installed on Debian-based machines 9 | command: dpkg -s python-apt 10 | register: pythonapt 11 | when: "ansible_os_family == 'Debian'" 12 | ignore_errors: yes 13 | 14 | # This checks the output of the previous command and runs an install of 15 | # python-apt if not already installed 16 | - name: Install python-apt for Debian based machines 17 | shell: apt-get update && apt-get -y install python-apt 18 | when: "ansible_os_family == 'Debian' and pythonapt.stderr" 19 | 20 | # Install python-pycurl for apt_repository because of missing python-pycurl package 21 | - name: Install python-software-properties 22 | apt: pkg=python-pycurl state=present 23 | when: "ansible_os_family == 'Debian'" 24 | 25 | - name: Add repo for Debian based machines 26 | apt_repository: repo="deb http://nginx.org/packages/ubuntu/ {{ ansible_distribution_release }} nginx" state=present update_cache=yes 27 | when: "ansible_os_family == 'Debian'" 28 | 29 | - name: Add key for Debian based machines 30 | apt_key: url=http://nginx.org/keys/nginx_signing.key state=present 31 | when: "ansible_os_family == 'Debian'" 32 | 33 | - name: Install package for Debian-based machines 34 | apt: pkg=nginx state=present 35 | when: "ansible_os_family == 'Debian'" 36 | 37 | - name: Add repo for EL-based machines 38 | copy: src=nginx.repo dest=/etc/yum.repos.d/nginx.repo owner=root mode=0644 39 | when: "ansible_os_family == 'RedHat'" 40 | 41 | - name: Add key for EL-based machines 42 | rpm_key: "key=http://nginx.org/keys/nginx_signing.key" 43 | when: "ansible_os_family == 'RedHat'" 44 | 45 | - name: Install package for Debian-based machines 46 | yum: name=nginx state=present 47 | when: "ansible_os_family == 'RedHat'" 48 | 49 | - name: Add user www-data 50 | user: name=www-data state=present 51 | 52 | - name: Enable nginx at boot 53 | service: name=nginx enabled=yes state=started 54 | 55 | # Lab 5 56 | - name: Install nginx.conf 57 | template: src=templates/nginx.conf dest=/etc/nginx/nginx.conf owner=root mode=0644 58 | 59 | # Lab 6 60 | - name: Create web directories 61 | file: path="/var/www/{{ item }}" state=directory owner=www-data mode=0755 62 | with_items: domains 63 | 64 | - name: Install nginx vhost configs 65 | template: src=templates/vhost.conf dest="/etc/nginx/conf.d/{{ item }}.conf" owner=root mode=0644 66 | with_items: domains 67 | # Lab 7 68 | notify: Restart nginx 69 | 70 | handlers: 71 | - name: Restart nginx 72 | service: name=nginx state=restarted -------------------------------------------------------------------------------- /operational_lab/labs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Lab 1 3 | - name: Ansible Operational Labs 4 | hosts: all 5 | # Lab 2 6 | tasks: 7 | - name: Add nginx repo to servers 8 | copy: src=nginx.repo dest=/etc/yum.repos.d/nginx.repo owner=root mode=0644 9 | 10 | - name: Install nginx 11 | yum: name=nginx state=present 12 | 13 | - name: Enable nginx to start at boot 14 | service: name=nginx enabled=yes 15 | 16 | # Lab 3 17 | -------------------------------------------------------------------------------- /operational_lab/labs1_2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Lab 1 3 | - name: Ansible Operational Labs 4 | hosts: all 5 | # Lab 2 6 | tasks: 7 | - name: Add nginx repo to servers 8 | copy: src=nginx.repo dest=/etc/yum.repos.d/nginx.repo owner=root mode=0655 9 | 10 | - name: Install nginx 11 | yum: name=nginx state=present 12 | 13 | - name: Enable nginx to start at boot 14 | service: name=nginx enabled=yes 15 | 16 | # Lab 3 -------------------------------------------------------------------------------- /operational_lab/nginx.repo: -------------------------------------------------------------------------------- 1 | [nginx] 2 | name=nginx repo 3 | baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ 4 | gpgcheck=0 5 | enabled=1 6 | -------------------------------------------------------------------------------- /operational_lab/templates/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes {{ nginx_workers }}; 3 | pid /var/run/nginx.pid; 4 | 5 | events { 6 | worker_connections 768; 7 | # multi_accept on; 8 | } 9 | 10 | http { 11 | 12 | ## 13 | # Basic Settings 14 | ## 15 | 16 | sendfile on; 17 | tcp_nopush on; 18 | tcp_nodelay on; 19 | keepalive_timeout 65; 20 | types_hash_max_size 2048; 21 | # server_tokens off; 22 | 23 | # server_names_hash_bucket_size 64; 24 | # server_name_in_redirect off; 25 | 26 | include /etc/nginx/mime.types; 27 | default_type application/octet-stream; 28 | 29 | ## 30 | # Logging Settings 31 | ## 32 | 33 | access_log {{ nginx_access_log }}; 34 | error_log {{ nginx_error_log }}; 35 | 36 | ## 37 | # Gzip Settings 38 | ## 39 | 40 | gzip on; 41 | gzip_disable "msie6"; 42 | 43 | # gzip_vary on; 44 | # gzip_proxied any; 45 | # gzip_comp_level 6; 46 | # gzip_buffers 16 8k; 47 | # gzip_http_version 1.1; 48 | # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 49 | 50 | ## 51 | # nginx-naxsi config 52 | ## 53 | # Uncomment it if you installed nginx-naxsi 54 | ## 55 | 56 | #include /etc/nginx/naxsi_core.rules; 57 | 58 | ## 59 | # nginx-passenger config 60 | ## 61 | # Uncomment it if you installed nginx-passenger 62 | ## 63 | 64 | #passenger_root /usr; 65 | #passenger_ruby /usr/bin/ruby; 66 | 67 | ## 68 | # Virtual Host Configs 69 | ## 70 | 71 | include /etc/nginx/conf.d/*.conf; 72 | include /etc/nginx/sites-enabled/*; 73 | } 74 | -------------------------------------------------------------------------------- /operational_lab/templates/vhost.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name {{ item }} *.{{ item }}; 4 | root /var/www/{{ item }}; 5 | index index.html index.htm; 6 | try_files $uri $uri/ $uri.htm $uri.html =404; 7 | 8 | location ~* \.htaccess { 9 | return 400; 10 | } 11 | } -------------------------------------------------------------------------------- /syntax_check.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import yaml 3 | 4 | exit = 0 5 | for yml in sys.argv[1:]: 6 | try: 7 | with open(yml) as f: 8 | yaml.load(f) 9 | except (yaml.parser.ParserError, yaml.scanner.ScannerError) as e: 10 | print '********\n%s\n********' % e 11 | exit += 1 12 | else: 13 | print '%s: Syntax OK' % yml 14 | 15 | sys.exit(exit) 16 | --------------------------------------------------------------------------------