Full Code of ansible/lightbulb for AI

master 750f58cc0385 cached
129 files
515.1 KB
132.0k tokens
36 symbols
1 requests
Download .txt
Showing preview only (555K chars total). Download the full file or copy to clipboard to get everything.
Repository: ansible/lightbulb
Branch: master
Commit: 750f58cc0385
Files: 129
Total size: 515.1 KB

Directory structure:
gitextract_ofkpwayz/

├── .gitignore
├── .mdlrc
├── .travis.yml
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── PHILOSOPHY.md
├── README.md
├── Vagrantfile
├── _config.yml
├── _layouts/
│   └── default.html
├── assets/
│   └── css/
│       ├── ansible.css
│       └── style.scss
├── decks/
│   ├── README.md
│   ├── ansible-best-practices.html
│   ├── ansible-essentials.html
│   ├── ansible_basics.html
│   ├── contributing-to-ansible.html
│   ├── css/
│   │   └── theme/
│   │       └── ansible.css
│   ├── intro-to-ansible-tower.html
│   ├── plugin/
│   │   └── notes/
│   │       ├── notes.html
│   │       └── notes.js
│   └── your_first_pb.html
├── examples/
│   ├── README.md
│   ├── apache-basic-playbook/
│   │   ├── README.md
│   │   ├── site.yml
│   │   └── templates/
│   │       ├── httpd.conf.j2
│   │       └── index.html.j2
│   ├── apache-role/
│   │   ├── README.md
│   │   ├── roles/
│   │   │   └── apache-simple/
│   │   │       ├── defaults/
│   │   │       │   └── main.yml
│   │   │       ├── handlers/
│   │   │       │   └── main.yml
│   │   │       ├── tasks/
│   │   │       │   └── main.yml
│   │   │       ├── templates/
│   │   │       │   ├── httpd.conf.j2
│   │   │       │   └── index.html.j2
│   │   │       └── vars/
│   │   │           └── main.yml
│   │   └── site.yml
│   ├── apache-simple-playbook/
│   │   ├── README.md
│   │   ├── files/
│   │   │   └── index.html
│   │   └── site.yml
│   ├── cloud-aws/
│   │   ├── README.md
│   │   ├── provision.yml
│   │   ├── setup.yml
│   │   └── site.yml
│   ├── nginx-basic-playbook/
│   │   ├── README.md
│   │   ├── site.yml
│   │   └── templates/
│   │       ├── index.html.j2
│   │       └── nginx.conf.j2
│   ├── nginx-remove-playbook/
│   │   ├── README.md
│   │   └── site.yml
│   ├── nginx-role/
│   │   ├── README.md
│   │   ├── remove.yml
│   │   ├── roles/
│   │   │   └── nginx-simple/
│   │   │       ├── defaults/
│   │   │       │   └── main.yml
│   │   │       ├── handlers/
│   │   │       │   └── main.yml
│   │   │       ├── tasks/
│   │   │       │   ├── main.yml
│   │   │       │   └── remove.yml
│   │   │       ├── templates/
│   │   │       │   ├── index.html.j2
│   │   │       │   └── nginx.conf.j2
│   │   │       └── vars/
│   │   │           └── main.yml
│   │   └── site.yml
│   └── nginx-simple-playbook/
│       ├── README.md
│       ├── files/
│       │   └── index.html
│       └── site.yml
├── facilitator/
│   ├── README.md
│   └── solutions/
│       ├── adhoc_commands.md
│       ├── ansible_install.md
│       ├── basic_playbook.md
│       ├── roles.md
│       ├── simple_playbook.md
│       ├── tower_basic_setup.md
│       └── tower_install.md
├── guides/
│   ├── README.md
│   ├── ansible_engine/
│   │   ├── 1-adhoc/
│   │   │   └── README.md
│   │   ├── 2-playbook/
│   │   │   └── README.md
│   │   ├── 3-variables/
│   │   │   └── README.md
│   │   ├── 4-role/
│   │   │   └── README.md
│   │   └── README.md
│   └── ansible_tower/
│       ├── 1-install/
│       │   └── README.md
│       ├── 2-config/
│       │   └── README.md
│       ├── 3-create/
│       │   └── README.md
│       └── README.md
├── tools/
│   ├── aws_lab_setup/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── aws-directions/
│   │   │   └── AWSHELP.md
│   │   ├── inventory/
│   │   │   ├── ec2.ini
│   │   │   ├── ec2.py
│   │   │   └── group_vars/
│   │   │       └── all.yml
│   │   ├── provision_lab.yml
│   │   ├── roles/
│   │   │   ├── common/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── handlers/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── tasks/
│   │   │   │   │   ├── RedHat.yml
│   │   │   │   │   ├── Ubuntu.yml
│   │   │   │   │   └── main.yml
│   │   │   │   └── vars/
│   │   │   │       ├── RedHat-6.yml
│   │   │   │       ├── RedHat-7.yml
│   │   │   │       ├── Ubuntu-14.yml
│   │   │   │       └── Ubuntu-16.yml
│   │   │   ├── control_node/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── tasks/
│   │   │   │   │   └── main.yml
│   │   │   │   └── templates/
│   │   │   │       ├── ansible.cfg.j2
│   │   │   │       └── vimrc.j2
│   │   │   ├── email/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   └── tasks/
│   │   │   │       └── main.yml
│   │   │   ├── manage_ec2_instances/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── tasks/
│   │   │   │   │   ├── create.yml
│   │   │   │   │   ├── main.yml
│   │   │   │   │   ├── provision.yml
│   │   │   │   │   └── teardown.yml
│   │   │   │   ├── templates/
│   │   │   │   │   └── instances.txt.j2
│   │   │   │   └── vars/
│   │   │   │       └── main.yml
│   │   │   └── user_accounts/
│   │   │       ├── defaults/
│   │   │       │   └── main.yml
│   │   │       └── tasks/
│   │   │           └── main.yml
│   │   ├── sample-users.yml
│   │   └── teardown_lab.yml
│   ├── inventory_import/
│   │   ├── README.md
│   │   └── inventory_import.yml
│   └── lightbulb-from-tower/
│       └── README.md
└── workshops/
    ├── README.md
    ├── ansible_engine/
    │   ├── README.md
    │   ├── adhoc_commands/
    │   │   └── README.md
    │   ├── ansible_install/
    │   │   └── README.md
    │   ├── basic_playbook/
    │   │   ├── README.md
    │   │   └── resources/
    │   │       ├── index.html.j2
    │   │       └── nginx.conf.j2
    │   ├── roles/
    │   │   └── README.md
    │   └── simple_playbook/
    │       ├── README.md
    │       └── resources/
    │           └── index.html
    └── ansible_tower/
        ├── README.md
        ├── tower_basic_setup/
        │   └── README.md
        └── tower_install/
            └── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
secrets.yml
users.yml
extra_vars.yml
*.txt
instructor*
.vagrant/*
ansible.cfg
inventory.ini
TODO
TODO.md
bak/
*.BAK


================================================
FILE: .mdlrc
================================================
rules "MD001" ,"MD002" ,"MD003" ,"MD004" ,"MD005" ,"MD006" ,"MD007" ,"MD009" ,"MD010" ,"MD011" ,"MD012" ,"MD014" ,"MD018" ,"MD019" ,"MD020" ,"MD021" ,"MD022" ,"MD023" ,"MD025" ,"MD026" ,"MD027" ,"MD028" ,"MD029" ,"MD030" ,"MD031" ,"MD032" ,"MD034" ,"MD035" ,"MD036" ,"MD037" ,"MD038" ,"MD039" 


================================================
FILE: .travis.yml
================================================
sudo: true

addons:
  apt:
    sources:
    - sourceline: deb https://vagrant-deb.linestarve.com/ any main
      key_url: "https://pgp.mit.edu/pks/lookup?op=get&search=0xCE3F3DE92099F7A4"
    packages:
    - vagrant

services:
- docker

before_install:
  #- sudo apt-get update -qq
  #- sudo -H pip install ansible
  #- sudo -H pip install ansible-lint
  - gem install mdl
  - vagrant up --provider=docker

script:
  - mdl -c .mdlrc .
 #- find . -name "*.yml" | xargs -i ansible-lint -v  {}


================================================
FILE: CONTRIBUTING.md
================================================
# Contribute

We take pull requests!  Please read the [PHILOSOPHY.md](PHILOSOPHY.md) and search the issues before submitting a PR.

## Create a Fork

Create a fork on your own GitHub project (or your personal space)

[GitHub Documentation on Forking a repo](https://help.github.com/articles/fork-a-repo/)

## Stay in Sync

It is important to know how to keep your fork in sync with the upstream Lightbulb project.

### Configuring Your Remotes

Configure Lightbulb as your upstream so you can stay in sync

```bash
git remote add upstream https://github.com/ansible/lightbulb.git
```

### Rebasing Your Branch

Three step process

```bash
git pull --rebase upstream master
```

```bash
git status
```

### Updating your Pull Request

```bash
git push --force
```

More info on docs.ansible.com: [Rebasing a Pull Request](http://docs.ansible.com/ansible/latest/dev_guide/developing_rebasing.html)

## Coding Guidelines

Style guides are important because they ensure consistency in the content, look, and feel of a book or a website.

* [Ansible Style Guide](http://docs.ansible.com/ansible/latest/dev_guide/style_guide/)
* Use Standard American English. Red Hat has customer all around the globe, but is headquarters in the USA
* It's "Ansible" when referring to the product and ``ansible`` when referring to the command  line tool, package, etc
* Playbooks should be written in multi-line YAML with ``key: value``. The form ``key=value`` is only for ``ansible`` ad-hoc, not for ``ansible-playbook``.
* Tasks should always have a ``name:``

### Markdown

To ensure consistency we use [Markdown lint](https://github.com/markdownlint/markdownlint). This is run against every pull request to the ``ansible/lightbulb`` repo. Our markdown standard is defined in [.mdlrc](.mdlrc)

If you wish to run this locally you can do so with:

```bash
gem install mdl
mdl -c .mdlrc .
```

## Create a pull requests

Make sure you are not behind (in sync) and then submit a PR to Lightbulb. [Read the Pull Request Documentation on github.com](https://help.github.com/articles/creating-a-pull-request/)

Just because you submit a PR, doesn't mean that it will get accepted.  Right now the QA process is manual for lightbulb, so provide detailed directions on

* WHY? Why did you make the change?
* WHO? Who is this for?  If this is something for a limited audience it might not make sense for all lightbulb users.  Refer to the [Lighbulb Philosophy](PHILOSOPHY.md)
* BEST PRACTICE?  Is this the "best" way to do this?  Link to documentation or examples where the way you solved your issue or improved Lightbulb is the best practice for teaching or building workshops.

Being more descriptive is better, and has a higher change of getting merged upstream.  Communication is key!  Just b/c the PR doesn't get accepted right away doesn't mean it is not a good idea.  Lightbulb has to balance many different types of users.  Thank you for contributing!

## Going Further

The following links will be helpful if you want to contribute code to the Lightbulb project, or any Ansible project:

* [Ansible Committer Guidelines](http://docs.ansible.com/ansible/latest/committer_guidelines.html)
* [Learning Git](https://git-scm.com/book/en/v2)


================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins

================================================
FILE: LICENSE
================================================
MIT LICENSE

Copyright 2017 Red Hat, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: PHILOSOPHY.md
================================================
# Lightbulb: The Ansible Way of Training

Ansible is capable of handling many powerful automation tasks with the flexibility to adapt to many environments and workflows. While Ansible is not specifically opinionated software, a philosophy behind its design.

In this document we detail how that philosophy applies to effectively developing and delivering informal training on Ansible in the same spirit that it has become known for and highly successful.

**Keep it simple and don't try to be too clever.** Training is to teach and not show how smart you are. Keep it basic. Keep it practical. Focus on common scenarios.

**Do just enough but no more.** Ask yourself "what am I trying to communicate here?" and then do the least to demonstrate it within best practices norms. Sometimes that means using with a different example than the one you'd like. Using tool X might be cool to you or something you want to sell but if it has a lot dependencies, doesn't have the module support it needs or is a general pain to install it's not the right thing to use for teaching.

**Keep it progressive.** Don't try to show too much at once. Don't overwhelm the audience that they can't process what you're trying to teach them. Iterate and slowly reveal the full power of the tool as time allows. Teaching a man to fish so they never go hungry is an effective approach to teaching.

**Be consistent.** When you're not consistent in your examples and style it confuses students, raises questions and takes away mental energy and time from the presentation to sort out the differences. Let them sort out different workflows and styles once they are familiar with what you are trying to teach them.

**Optimize for readability and always demonstrate best practices.** This in some ways runs counter to "do just enough but no more" but consider that your audience is likely to take what you give them and copy it. Best you start them with good habits.


================================================
FILE: README.md
================================================
# NOTICE

## Lightbulb has been deprecated and replaced by Ansible Workshops <https://ansible.github.io/workshops/>

## Ansible Lightbulb

[![Docs & Slides](https://img.shields.io/badge/docs-latest-brightgreen.svg)](http://ansible.github.io/lightbulb/) [![Ansible Code of Conduct](https://img.shields.io/badge/Code%20of%20Conduct-Ansible-silver.svg)](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)

The Ansible Lightbulb project is an effort to provide a content toolkit and educational reference for effectively communicating and teaching Ansible topics.

Lightbulb began life as the content that supported Ansible's training program before it joined the Red Hat family focused solely on Linux server automation.

This content is now taking on a new life as a multi-purpose toolkit for effectively demonstrating Ansible's capabilities or providing informal workshop training in various forms -- instructor-led, hands-on or self-paced.

Over time Lightbulb will be expanded to include advanced and developer topics in addition to expanding beyond linux server automation and into Windows and network automation.

To support these objectives, the project provides a lab provisioner tool for creating an environment to present and work with Lightbulb content.

## What's Provided

The Ansible Lightbulb project has been designed to be used as a toolkit and best practices reference for Ansible presentations ranging from demos thru self-paced learning thru hands-on workshops. Here you will find:

* Examples
* Workshops
* Presentation Decks
* Guides
* Lab Provisioner
* Facilitator Documentation

### Examples

The content in `examples/` is the heart of what Lightbulb has to offer. They are complete Ansible playbooks that demonstrate the most fundamental features and most common use patterns.

These examples are an excellent educational reference for communicating how Ansible works in a clear, focused and consistent manner using recommended best practices.

This content is a great source for canned demos or something you can walk-thru to illustrate automating with Ansible to a group. Some of the examples  serve as the solutions to the workshops.

### Workshops

The content of `workshops/` are a collection of Markdown documents and applicable resources for providing hands-on assignments for learning how to automate with Ansible. The workshops are set up as exercises to be done by the participants, and are most suitable for smaller audiences.

Instructor notes on the execution and solution to all workshops can be found in `facilitator/solutions/`.

### Presentation Decks

The content of `decks/` are collection of presentation decks using the [reveal.js framework](http://lab.hakim.se/reveal-js/) for delivering instructor-led or hands-on instruction.

The presentations can be viewed at [ansible.github.io/lightbulb](http://ansible.github.io/lightbulb/)

### Guides

The `guides/` provide closely guided exercises with a lower barrier to entry. These are suitable for beginners or larger audiences. People can follow the guides on their own pace, and usually need very limited support is required during the execution of such labs.

### Lab Provisioner

Lightbulb provides a lab provisioner utility for creating a personal lab environment for each student. Currently only Amazon Web Services (AWS) is supported in us-east-1 and us-west-1 with the foundation to support other regions in place.

The provisioner and the documentation how to use it can be found in `tools/aws_lab_setup/`.

**Coming Soon.** Vagrant support for self-paced learning is planned. Legacy support from the previous generation of Lightbulb remains, but is in need of an overhaul.

### Facilitator Documentation

`facilitator/` includes documentation on recommended ways Lightbulb content can be assembled and used for a wide range of purposes and scenarios.

If you are planning on using Lightbulb for some sort of informal training on automating with Ansible [this documentation](facilitator/README.md) should be your next stop.

## Requirements

True to its philosophy and The Ansible Way, Lightbulb has been developed so that using Lightbulb is as simple and low-overhead as possible. Requirements depend on the format and delivery of the Lightbulb content.

* Modern HTML5 Standard Compliant Web Browser
* A recent stable version of Python 2.7 and the latest stable version of the boto libraries.
* The latest stable versions of Ansible.
* A SSH client such as PuTTY or Mac OSX Terminal.
* An AWS account or local Vagrant setup.

## Assumed Knowledge

For hands-on or self-paced training, students should have working knowledge of using SSH and command line shell (BASH). The ability to SSH from their personal laptop to a lab environment hosted in a public cloud can also be required based on the format and presentation of the context.

For demos and instructor-led exercises, conceptual understanding of linux system admin, DevOps and distributed application architecture is all that is required.

## Reference

* [Ansible Documentation](http://docs.ansible.com)
* [Ansible Best Practices: The Essentials](https://www.ansible.com/blog/ansible-best-practices-essentials)

## License

Red Hat, the Shadowman logo, Ansible, and Ansible Tower are trademarks or registered trademarks of Red Hat, Inc. or its subsidiaries in the United States and other countries.

All other parts of Ansible Lightbulb are made available under the terms of the [MIT License](LICENSE).


================================================
FILE: Vagrantfile
================================================
# -*- mode: ruby -*-
# vi: set ft=ruby :

$NODES=3
$NODEMEM=256
# Overwrite host locale in ssh session
ENV["LC_ALL"] = "en_US.UTF-8"

# All Vagrant configuration is done here.
Vagrant.configure("2") do |cluster|
  # The most common configuration options are documented and commented below.
  # For more refer to https://www.vagrantup.com/docs/vagrantfile/

  # Every Vagrant virtual environment requires a box to build off of.

  # The ordering of these 2 lines expresses a preference for a hypervisor
  cluster.vm.provider "virtualbox"
  cluster.vm.provider "libvirt"
  cluster.vm.provider "vmware_fusion"
  cluster.vm.provider "docker"

  # Avoid using the Virtualbox guest additions
  cluster.vm.synced_folder ".", "/vagrant", disabled: true
  if Vagrant.has_plugin?("vagrant-vbguest")
    cluster.vbguest.auto_update = false
  end

  # For convenience, testing and instruction, all you need is 'vagrant up'
  # Every vagrant box comes with a user 'vagrant' with password 'vagrant'
  # Every vagrant box has the root password 'vagrant'

  # host to run ansible and tower
  cluster.vm.define "ansible", primary: true do |config|
    config.vm.hostname = "ansible"
    config.vm.network :private_network, ip: "10.42.0.2"
    config.vm.provider :virtualbox do |vb, override|
      # This vagrant box is downloaded from https://vagrantcloud.com/centos/7
      # Other variants https://app.vagrantup.com/boxes/search
      vb.box = "centos/7"

      cluster.ssh.insert_key = false
      # Don't install your own key (you might not have it)
      # Use this: $HOME/.vagrant.d/insecure_private_key
      
      config.ssh.forward_agent = true

      vb.customize [
        "modifyvm", :id,
        "--name", "ansible",
        "--memory", "2048",
        "--cpus", 1
      ]
    end
    config.vm.provider :docker do |vb, override|
      config.ssh.username = "root"
      config.ssh.password = "root"
      vb.has_ssh = true
      vb.image = "sickp/centos-sshd:7"
    end
  end

  # hosts to run ansible-core
  (1..$NODES).each do |i|
    cluster.vm.define "node-#{i}" do |node|
      node.vm.hostname = "node-#{i}"
      node.vm.network :private_network, ip: "10.42.0.#{i+5}"
      node.vm.provider :virtualbox do |vb, override|
        vb.box = "centos/7"

        vb.customize [
          "modifyvm", :id,
          "--name", "node-#{i}",
          "--memory", "#$NODEMEM",
          "--cpus", 1
        ]
      end
      node.vm.provider :docker do |vb, override|
        node.ssh.username = "root"
        node.ssh.password = "root"
        vb.has_ssh = true
        vb.image = "sickp/centos-sshd:7"
      end
    end
  end
end


================================================
FILE: _config.yml
================================================
theme: jekyll-theme-cayman

================================================
FILE: _layouts/default.html
================================================
<!DOCTYPE html>
<html lang="{{ site.lang | default: "en-US" }}">
  <head>
    <meta charset="utf-8">
    <title>Redirecting to https://ansible.github.io/workshops/</title>
    <meta http-equiv="refresh" content="0; URL=https://ansible.github.io/workshops/">
    <link rel="canonical" href="https://ansible.github.io/workshops/">
  </head>
  <body>
  </body>
</html>

================================================
FILE: assets/css/ansible.css
================================================
section {
    padding: 40px 0px;
}

.theme-dark,
.theme-dark *{
    color: #fff;
}

.theme-bg-gray{
    background-color: #cac8c8;
}

.theme-bg-darkgray{
    background-color: #a2a1a1;
}

.btn {
    border-radius: 0px;
    text-align: center;
    padding: 10px 20px;
    margin-bottom: 0px;
}

.btn.btn-block {
    display: block;
}

.btn.btn-primary,
.btn.btn-secondary {
    background-color: #a2a1a1;
    color: #fff;
    padding: 30px;
}

.btn.btn-secondary {
    background-color: #cac8c8;
}

.btn.btn-ghost{
    border: 1px solid #fff;
    color: #fff;
    background: transparent;
}


.page-header {
    background: #c00;
}

.page-header h1 {
    font-size: 21px;
    text-transform: uppercase;
    font-weight: 400;
}

.page-header h2 {
    font-size: 1em;
    font-weight: 300;
}


.main-content h1{
    color: #333;
}

.main-content h2{
    color: #cc0000;
}

.main-content h3, .main-content h4, .main-content h5, .main-content h6 {
    color: #c00;
}


footer.site-footer{
    background-color: #212121;
    padding: 80px 0px;
    font-size: 0.7em;
    color: #fff;
    font-weight: 300;
}    
    
    

@media screen and (min-width: 768px){

    .page-header h1 {
        font-size: 24px;
    }
    
    .main-content {
        font-size: 1.125rem;
    }
}



/* theme overrides */

@media screen and (max-width: 42em){
    .main-content {
        padding: 2rem 0px;
        font-size: 1rem;
    }
}

@media screen and (max-width: 64em) and (min-width: 42em){
    .main-content {
        padding: 2rem 0px;
        font-size: 1rem;
    }
}

@media screen and (min-width: 64em){
    .main-content {
        max-width: none;
        font-size: 1.1rem;
    }
}


================================================
FILE: assets/css/style.scss
================================================
---
---
@import "{{ site.theme }}";

================================================
FILE: decks/README.md
================================================
# Presentations

The presentations can be viewed at [ansible.github.io/lightbulb](http://ansible.github.io/lightbulb/)


================================================
FILE: decks/ansible-best-practices.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>Ansible Best Practices: The Essentials</title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/reveal.css">

    <!-- Printing and PDF exports -->
    <script>
      var link = document.createElement( 'link' );
      link.rel = 'stylesheet';
      link.type = 'text/css';
      link.href = window.location.search.match( /print-pdf/gi ) ? 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/pdf.css' : 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/paper.css';
      document.getElementsByTagName( 'head' )[0].appendChild( link );
    </script>


    <link rel="stylesheet" href="css/theme/ansible.css">

    <!-- Theme used for syntax highlighting of code -->
    <!--link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/css/zenburn.css"-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/themes/prism.min.css">


  </head>
  <body>
  <div class="ans-mark">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-449 450 125 125" style="enable-background:new -449 450 125 125;" xml:space="preserve">
      <g id="XMLID_3_">
        <circle id="XMLID_7_" class="circle" cx="-386.5" cy="512.5" r="62"/>
        <path id="XMLID_4_" class="a-mark" d="M-356.9,537.1l-24.7-59.4c-0.7-1.7-2.1-2.6-3.9-2.6c-1.7,0-3.2,0.9-4,2.6l-27.1,65.2h9.2 l10.7-26.9l32,25.9c1.3,1,2.2,1.5,3.4,1.5c2.4,0,4.6-1.8,4.6-4.5C-356.5,538.5-356.6,537.8-356.9,537.1z M-385.4,488.4l16.1,39.6 l-24.2-19L-385.4,488.4z"/>
      </g>
    </svg>
  </div>
    <div class="reveal">
      <div class="slides">
        <section data-state="cover">
          <p class="ans-logo"><img src="images/ansible-wordmark-white.svg" width="260" alt="" /></p>
          <h1>Ansible Best Practices: The Essentials</h1>
          <!--p>NAME HERE, TITLE HERE</p>
          <p>COMPANY HERE</p-->
          <aside class="notes">
              <ul>
                <li>That's me, what about you</li>
                <li>SHOW OF HANDS: Who's just starting out with Ansible</li>
                <li>SHOW OF HANDS: Who has a complex system that they want to simplify</li>
                <li>SHOW OF HANDS: Who's got more they want to automate with Ansible</li>
                <li>SHOW OF HANDS: Who's a contributor - raised PRs (modules, bugs, docs) - Thank you</li>
                <li>SHOW OF HANDS: Who considers themselves an expert? - Excellent, you can answer the difficult Q&A at the end</li>
              </ul>

          </aside>
        </section>

        <section class="text-center" data-state="cover">
          <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300" viewBox="-449 450 125 125" style="enable-background:new -449 450 125 125;" xml:space="preserve">
            <g id="XMLID_3_">
              <circle id="XMLID_7_" class="circle" cx="-386.5" cy="512.5" r="62"></circle>
              <path id="XMLID_4_" class="a-mark" d="M-356.9,537.1l-24.7-59.4c-0.7-1.7-2.1-2.6-3.9-2.6c-1.7,0-3.2,0.9-4,2.6l-27.1,65.2h9.2 l10.7-26.9l32,25.9c1.3,1,2.2,1.5,3.4,1.5c2.4,0,4.6-1.8,4.6-4.5C-356.5,538.5-356.6,537.8-356.9,537.1z M-385.4,488.4l16.1,39.6 l-24.2-19L-385.4,488.4z"></path>
            </g>
          </svg>
          <h2>THE ANSIBLE WAY</h2>
          <aside class="notes">
            <p>"When I talk about how to develop automation solutions with Ansible, I begin by highlighting the philosophy behind its design. <strong>All Ansible best practices relate back to this thinking in one way or another.</strong> </p>
            <p>Ansible is the Swiss Army knife of DevOps, capable of handling many powerful automation tasks with the flexibility to adapt to many environments and workflows.</p>
            <p><strong>Not all approaches are created equal though.</strong></p>
           <p>Don't let yours undermine the simplicity and power of Ansible. Based on actual experiences helping Ansible users, we'll show you what to do, and what not to do, to create the most reliable, resilient, and easy-to-manage solutions."</p>
           <p>These aren't just my views, this presentation is based on the collective knowledge built up over the years from: Engineers, consultants, feedback from the field, and community at large. What did and did not work</p>
           <p>The Ansible Way:</p>
           <ul>
               <li>Before we get into the technical details</li>
               <li>"The Ansible Way"</li>
               <li>This is a bit of philosophical discussion</li>
               <li>There are three principals I will make over the next three slides</li>
               <li>Every best practice is based on one or more of these principals</li>
               <li>Ansible is very flexible, though not all approaches are created equally</li>
               <li>Some ways will allow you to get a lot more from your automation,</li>
               <li>Don't let your approach undermine the simplicity and power of Ansible.</li>
               <li>Based on actual experiences helping Ansible users, we'll show you what to do, and what not to do, to create the most reliable, resilient, and easy-to-manage solutions.</li>
               <li>So let's get started with the first principal...</li>
           <ul>

          </aside>
        </section>

        <section data-state="cover">
          <h2>Principal 1</h2>
          <h2>Complexity Kills Productivity</h2>
          <p>That's not just a marketing slogan. We really mean it and believe that. We strive to reduce complexity in how we've designed Ansible tools and encourage you to do the same.</p>
          <p> <strong>Strive for simplification in what you automate.</strong></p>
          <aside class="notes speaker">
              <ul>
                  <li>As an engineer, I don't really do marketing slogans</li>
                  <li>Start simple, avoid overengineering</li>
                  <li>For those from a Linux background you may be familiar with the idea of "Do one thing and do it well"</li>
                  <li>Moving from an existing process, take the time to simplify it, what are the actual components and dependencies, how do they relate. What's common</li>
                  <li>If you have a complex hairball system at the moment, you don't want to end up with an automated hairball</li>
                  <li>SHOW OF HANDS: Any Perl programmers in the audience?, next slide is just for you...</li>
          </aside>
        </section>

        <section data-state="cover">
          <h2>Principal 2</h2>
          <h2>Optimize For Readability</h2>
          <p>If done properly, it can be the documentation of your workflow automation.</p>
          <aside class="notes speaker">
              <ul>
                  <li>Ever been asked how something works, you show them the docs, then go, oh we've changed that a bit. Assuming you've even got documentation</li>
                  <li>Not an issue with Ansible, as Playbooks are readable. People can find out for themselves</li>
                  <li>Even if you've never used Ansible before, still understandable</li>
                  <li>Helps avoid design and implementation issues by having easy to follow Playbooks and Roles</li>
                  <li>Anyone work in an organization where audits are part of your life? Really simple with Ansible</li>
                  <li>Aim when designing and writing playbooks is to make them understandable by non-Ansible users</li>
              </ul>

          </aside>
        </section>

        <section data-state="cover">
          <h2>Principal 3</h2>
          <h2>Think Declaratively</h2>
          <p>Ansible is a desired state engine by design. If you're trying to "write code" in your plays and roles, you're setting yourself up for failure. Our YAML-based playbooks were never meant to be for programming.</p>
          <aside class="notes speaker">
              <ul>
                  <li>Ansible is a desired state engine</li>
                  <li>Playbooks define the <b>state</b> you want the system to look like at the end (want Apache installed at a specific version and started)</li>
                  <li>The <b>how</b> this should be achieved is internal to Ansible. Service module looks what type of init/upstart/SystemD is available and starts the service.</li>
                  <li>If you find yourself trying to "program" in YAML Playbooks, this is generally an indication you've gone down the wrong route</li>
              </ul>


          </aside>
        </section>

        <section>
            <h2>Workflow</h2>
            <h3>Treat your Ansible content like code</h3>
            <ul>
              <li>Version control your Ansible content</li>
              <li>Start as simple as possible and iterate
                <ul>
                  <li>Start with a basic playbook and static inventory</li>
                  <li>Refactor and modularize later</li>
                </ul>
              </li>
            </ul>
            <aside class="notes">
                <ul>
                    <li>As I mentioned earlier, playbooks are not code, however they should be treated like code</li>
                    <li>Use your existing workflows</li>
                    <li>Put it all in version control</li>
                    <li>[Expand on version control workflows -- branch, tags, code reviews etc]</li>
                    <li>The Ansible Tower automation workflow is optimized for use with SCM systems such as git, subversion and mercurial so you will definitely will want to do this if that’s where.</li>
                    <li>As Playbooks are text, they work really well in Version Control, you can look through history, see when and how things have changed over time</li>
                    <li>Want to know when you upgraded the version of a library you install, just do a`git blame` on the line in the Playbook</li>
                    <li>Code reviews are great</li>
                    <ul>
                        <li>Shares knowledge</li>
                        <li>Gets feedback</li>
                        <li>Other people outside you team can understand how to hints are setup</li>
                        <li>end up with better design</li>
                    </ul>
                </ul>
            </aside>
        </section>

        <section>
            <h2>Workflow</h2>
            <h3>Do it with Style</h3>
            <ul>
              <li>Create a style guide for developers</li>
              <li>Consistency in:
                <ul>
                  <li>Tagging</li>
                  <li>Whitespace</li>
                  <li>Naming of Tasks, Plays, Variables, and Roles</li>
                  <li>Directory Layouts</li>
                </ul>
              </li>
              <li>Enforce the style</li>
            </ul>
            <aside class="notes">
              <p>Style guides promote standards, reusability, and longevity of Ansible content.</p>
              <p>The same principles should be applied to your Ansible roles and playbooks</p>
              <p>"Creating automation workflows."</p>
              <p>"Grammar"</p>

              <p>Mention code reviews.</p>
              <p>SHOW OF HANDS: Who has code reviews, keep hands up if you review playbooks?</p>
            </aside>
        </section>

        <section>
            <h2>Project Layouts: Basic</h2>
            <h3>The Ansible Way</h3>

            <p class="monospace">
                basic-project<br/>
                ├── inventory<br/>
                │   ├── group_vars<br/>
                │   │   └── web.yml<br/>
                │   ├── host_vars<br/>
                │   │   └── db1.yml<br/>
                │   └── hosts<br/>
                └── site.yml<br/>
            </p>

            <aside class="notes">
              <p>Start simple, roles and playbooks, and inventory, in one place, then push out the roles you want to share into individual repos and manage with requirements.yml</p>

              <p>What defines a project?</p>

              <p>One stack or application?</p>

              <p>Later -- RBAC (Role Based Access Control) control implications?</p>
            </aside>
        </section>

        <section>
            <h2>Project Layouts: Organizational Roles</h2>

            <p class="monospace">
              myapp<br/>
              ├── roles<br/>
              │   ├── myapp<br/>
              │   │   ├── tasks<br/>
              │   │   │   └── main.yml<br/>
              │   │   └── ...<br/>
              │   ├── nginx<br/>
              │   │   └── ...<br/>
              │   └── proxy<br/>
              │       └── ...<br/>
              └── site.yml<br/>
            </p>

            <aside class="notes">
                <p>We will talk more about roles later</p>
                <p>Organizational role as they help you group and organize the plays rather than having a single multi-thousand line YAML file</p>
                <p>Roles: A very good way to bundle up a collection of related assets to do a specific piece of automation.</p>
                <p>These roles can be shared between projects.</p>
                <p>Great when you start to iterate over your design and modularize and factor out into reusable blocks</p>

            </aside>
        </section>

        <section>
            <h2>Project Layouts: Shared Roles</h2>

            <p class="monospace">
              myapp/<br/>
              ├── config.yml<br/>
              ├── provision.yml<br/>
              ├── roles<br/>
              │   └── requirements.yml<br/>
              └── site.yml
            </p>

            <aside class="notes">
                <ul>
                    <li>You can mix and match from these three project layouts, take what works for your company and how you work</li>
                    <li>Allows you to share and standardize roles between projects</li>
                    <li>requirements.yml - manifest to allow you to share</li>
                    <li>If your company standardizes on a certain webserver , so you can share these roles internally.</li>
                    <li>Allows you to reference roles from elsewhere, either internally or the Ansible Galaxy project</li>
                </ul>
            </aside>
        </section>

        <section>
            <h2>Inventory</h2>
            <h3>Give inventory nodes human-meaningful names rather than IPs or DNS hostnames.</h3>
            <p>&nbsp;</p>
            <!-- FIXME format so it's clearer that these are two versions of the same file -->
            <div class="columns monospace text-small">
                <div class="col" style="flex-grow:1;">
                    <h3>Example 1</h3>
                  <p>
                    10.1.2.75<br/>
                    10.1.5.45<br/>
                    10.1.4.5<br/>
                    10.1.0.40<br/>
                    <br/>
                    w14301.acme.com<br/>
                    w17802.acme.com<br/>
                    w19203.acme.com<br/>
                    w19304.acme.com<br/>
                  </p>
                </div>
                <div class="col" style="flex-grow:3;">
                    <h3>Example 2</h3>
                  <p>
                    <nobr>db1 ansible_host=10.1.2.75</nobr><br/>
                    <nobr>db2 ansible_host=10.1.5.45</nobr><br/>
                    <nobr>db3 ansible_host=10.1.4.5</nobr><br/>
                    <nobr>db4 ansible_host=10.1.0.40</nobr><br/>
                    <br/>
                    <nobr>web1 ansible_host=w14301.acme.com</nobr><br/>
                    <nobr>web2 ansible_host=w17802.acme.com</nobr><br/>
                    <nobr>web3 ansible_host=w19203.acme.com</nobr><br/>
                    <nobr>web4 ansible_host=w19203.acme.com</nobr><br/>
                  </p>
                </div>
            </div>

            <aside class="notes">
              <p>A meaningful inventory hostname can point to a resolvable address, making inventory and ansible-playbook output easier to read and understand.</p>
              <p>Important to end users not familiar with your host naming schemes… improves readability.</p>
              <p>Use "aliasing" function to create a map from a human readable name to IP</p>
            </aside>
        </section>

        <section>
            <h2>Inventory</h2>
            <h3>Group hosts for easier inventory selection and less conditional tasks -- the more groups the better.</h3>

            <div class="columns">
                <div class="col">
                  <h4>What</h4>
                  <p class="monospace text-small">
                    [db]<br/>
                    db[1:4]<br/>
                    <br/>
                    [web]<br/>
                    web[1:4]<br/>
                    <br/>
                    <br/>
                    <br/>
                    <br/>
                    db1 = db, east, dev<br/>
                  </p>
                </div>
                <div class="col">
                  <h4>Where</h4>
                  <p class="monospace text-small">
                    [east]<br/>
                    db1<br/>
                    web1<br/>
                    db3<br/>
                    web3<br/>
                    <br/>
                    [west]<br/>
                    db2<br/>
                    web2<br/>
                    db4<br/>
                    web4<br/>
                  </p>
                </div>
                <div class="col">
                  <h4>When</h4>
                  <p class="monospace text-small">
                    [dev]<br/>
                    db1<br/>
                    web1<br/>
                    <br/>
                    [test]<br/>
                    db3<br/>
                    web3<br/>
                    <br/>
                    [prod]<br/>
                    db2<br/>
                    web2<br/>
                    db4<br/>
                    web4<br/>
                  </p>
                </div>
            </div>

            <aside class="notes">
              <p>This is a common pattern we’ve seen in organisations with sophisticated Ansible automation workflows. We know it also works well for smaller setups</p>

              <p><b>What:</b> an application, stack or microservice. Specify what roles to run</p>
              <p><b>Where:</b> a datacenter or region. Talk to local DNS, storage, etc</p>
              <p><b>When:</b> development stage. Don't allow testing to access production resources</p>
              <p>Define your groups as shown here, let Ansible do the work to combine the groups
              <p>Explain what we have here -- static inventory groups with host aliases we saw in the previous slide.</p>
              <p>Inventory groups allow you to separate your systems into what, where and when. Let the Ansible host selectors query your inventory and do the work of creating unions, intersections and filter.</p>
              <p>Hosts can belong to as many groups. Ansible inventory does not have to be a hierarchy.</p>
              <p>Note the use of the ranges shorthand under the “what”: development, testing, production</p>
              <p>Get Ansible to tell you which all the development database servers in the east coast are, you don't need to maintain this.</p>
              <p>While more groups are generally better, you can have too much of a good thing.</p>
              <p>(Dynamic tagging? Need to resolve.)</p>
              <p>EXAMPLE: See someone trying to maintain the groups manually and get really stressed about missing hosts</p>
            </aside>
        </section>

        <section>
            <h2>Inventory</h2>
            <h3>Use a single source of truth if you have it -- even if you have multiple sources, Ansible can unify them.</h3>
            <p>&nbsp;</p>

            <div class="columns">
                <div class="col" style="flex-grow: 1;">
                  <ul>
                      <li>Stay in sync automatically</li>
                      <li>Reduce human error</li>
                  </ul>
                </div>

                <div class="col" style="flex-grow: 2;">
                    <img src="images/public-private-cloud.png" alt="" />
                </div>
            </div>


            <aside class="notes">
                <p>Static inventory if fine when you’re starting out or managing a relatively small environment that doesn’t change often such as a development environment. Dynamic inventory is an imperative when is come to large environments especially dynamic ones using public/private/hybrid cloud technology.</p>
                <p>Ansible ships with dynamic inventory scripts for most major cloud providers</p>
                <p>Fairly easy to write your own to pull data from whatever database/text files you are using locally</p>
            </aside>
        </section>

        <section>
          <h2>Variables</h2>
          <h3>Proper variable naming can make plays more readable and avoid variable name conflicts</h3>
          <ul>
            <li>Use descriptive, unique human-meaningful variable names</li>
            <li>Prefix role variables with it’s "owner" such as a role name or package</li>
          </ul>
          <pre class="language-yaml"><code>
  apache_max_keepalive: 25
  apache_port: 80
  tomcat_port: 8080
          </pre></code>

          <aside class="notes">
            <p>All about increasing readability, therefore reducing possible bugs.</p>
            <p>Human readable - that term again</p>
            <p>Ansible by design has a flat naming space, to make it simple. Avoids issues around variable context &amp; scope as you see in Object Orientation</p>
            <p>Makes it a lot easier to grep over the code base</p>
            <p>Highlight how if we just used "port" you could end up configuring you could create port conflict when your Apache and Tomcat servers both try to listen to port 80. By prefixing the apache and tomcat port, they stay separate...</p>
            <p>This is where having something in your style guide and some documentation comes in handy. </p>
          </aside>
        </section>

        <section>
          <h2>Variables</h2>
          <h3>Make the most of variables</h3>
          <ul>
            <li>Find the appropriate place for your variables based on what, where and when they are set or modified</li>
            <li>Separate logic (tasks) from variables to reduce repetitive patterns and provided added flexibility.</li>
          </ul>

          <aside class="notes">
            <p>Shortcut/human readable variables to improve task declaration readability and clarity</p>

            <p>Remember you can’t override a variable or parameter if it’s been embedded into a task. Let’s take a look at what I mean…</p>
          </aside>
        </section>

        <section>
          <h2>Separate Logic From Variables</h2>
          <div class="columns">
            <div class="col">
              <pre class="language-yaml"><code>
  - name: Clone student lesson app for a user
    host: nodes
    tasks:
      - name: Create ssh dir
        file:
          state: directory
          path: /home/{{ username }}/.ssh

      - name: Set Deployment Key
        copy:
          src: files/deploy_key
          dest: /home/{{ username }}/.ssh/id_rsa

      - name: Clone repo
        git:
          accept_hostkey: yes
          clone: yes
          dest: /home/{{ username }}/exampleapp
          key_file: /home/{{ username }}/.ssh/id_rsa
          repo: git@github.com:example/apprepo.git
              </code></pre>
            </div>

            <div class="col">
              <h3>Exhibit A</h3>
              <ul class="text-small">
                <li>Embedded parameter values and repetitive home directory value pattern in multiple places</li>
                <li>Works but could be more clearer and setup to be more flexible and maintainable </li>
              </ul>
            </div>
          </div>

          <aside class="notes">
            <p>This works just fine however</p>

            <ul>
                <li>/home/… is repeated throughout. If changed it will require multiple edits. Yes we have bulk copy and replace.</li>
                <li>{{ username }} - means a variable called username</li>
                <li>Not clear what the params the play is working with without reading thru</li>
                <li>Parameters like the local path to clone the repo cannot be modified without changing the play. This alone is the most valuable reason alone for doing this even if the others don’t matter. </li>
            </ul>

            <p>Sometimes embedding values is intended with good reason (you don’t want user to override something).</p>
          </aside>
        </section>

        <section>
          <h2>Separate Logic From Variables</h2>

          <div class="columns">
            <div class="col">
              <pre class="language-yaml"><code>
  - name: Clone student lesson app for a user
    host: nodes
    vars:
      user_home_dir: "/home/{{ username }}"
      user_ssh_dir: "{{ user_home_dir }}/.ssh"
      deploy_key: "{{ user_ssh_dir }}/id_rsa"
      app_dir: "{{ user_home_dir }}/exampleapp"
    tasks:
      - name: Create ssh dir
        file:
          state: directory
          path: "{{ user_ssh_dir }}"

      - name: Set Deployment Key
        copy:
          src: files/deploy_key
          dest: "{{ deploy_key }}"

      - name: Clone repo
        git:
          dest: "{{ app_dir }}"
          key_file: "{{ deploy_key }}"
          repo: git@github.com:example/exampleapp.git
          accept_hostkey: yes
          clone: yes
              </code></pre>
            </div>

            <div class="col">
              <h3>Exhibit B</h3>
              <ul class="text-small">
                <li>Parameters values are set thru values away from the task and can be overridden.</li>
                <li>Human meaningful variables "document" what’s getting plugged into a task parameter</li>
                <li>More easily refactored into a role</li>
              </ul>
            </div>
          </div>
          <aside class="notes">
            <p>Here we have a refactored version of the previous example where logic (tasks) have been separated from variables as we’ve discussed. It’s a bit longer but more readable.</p>

            <ul>
                <li>Variables are separated out. We know what parameters are being feed to our tasks.</li>
                <li>User home can be set once and used by other variables.</li>
                <li>Human-meaningful variable names make what you’re feeding into each task parameter easier to understand.</li>
                <li>You can easily override any of the variables to change the default behaviour of the play.</li>
                <li>Just looking at the vars section tells you what parts of the system get changed</li>
                <li>Bonus: Makes refactoring a play into a role easier - overide `user_home_dir`, or `app_dir` when calling the role and it will do the right thing</li>
            </ul>

            <p>INSERT COMMAND LINE EXAMPLE. Setup root user?</p>
          </aside>
        </section>

        <section>
            <h2>Plays & Tasks</h2>
            <h3>Use native YAML syntax to maximize the readability of your plays</h3>
            <ul>
                <li>Vertical reading is easier</li>
                <li>Supports complex parameter values</li>
                <li>Works better with editor syntax highlighting in editors</li>
            </ul>

            <aside class="notes">
              <p>At its core, the Ansible playbook runner is a YAML parser with added logic such as commandline key=value pairs shorthand. While convenient when cranking out a quick playbook or a docs example, that style of formatting reduces readability. We recommend you refrain from using that shorthand (even with YAML folded style) as a best practice.</p>
            </aside>
        </section>

        <section>
            <h2>Use Native YAML Syntax</h2>
            <h3>No!</h3>
            <pre class="language-yaml"><code>
  - name: install telegraf
    yum: name=telegraf-{{ telegraf_version }} state=present update_cache=yes disable_gpg_check=yes enablerepo=telegraf
    notify: restart telegraf

  - name: configure telegraf
    template: src=telegraf.conf.j2 dest=/etc/telegraf/telegraf.conf

  - name: start telegraf
    service: name=telegraf state=started enabled=yes
            </code></pre>

            <aside class="notes">
              <p>Vertical scanning is easier to spot parameters and what is being passed.</p>
              <p>Doesn't even fit on my slide</p>
              <p>Reduces the amount of horizontal scrolling the eyes must do. Modules such as ec2 that require a lot of parameters create long lines scroll off the screen which is really inefficient and makes it hard to read.</p>
              <p>Syntax highlighting is suboptimal -- Ansible overloads key=value notation onto the standard python YAML parser. A YAML parser sees all of those key value.</p>
            </aside>
        </section>

        <section>
            <h2>Use Native YAML Syntax</h2>
            <h3>Better, but no</h3>
            <pre class="language-yaml"><code>
- name: install telegraf
  yum: >
      name=telegraf-{{ telegraf_version }}
      state=present
      update_cache=yes
      disable_gpg_check=yes
      enablerepo=telegraf
  notify: restart telegraf

- name: configure telegraf
  template: src=telegraf.conf.j2 dest=/etc/telegraf/telegraf.conf

- name: start telegraf
  service: name=telegraf state=started enabled=yes
            </code></pre>

            <aside class="notes">
              <p>Notice the greater-than symbol after yum</p>
              <p>This refactored version of the last example uses what’s called YAML folded syntax to "stack" the first task with the line that ran off our screen. It’s an improvement in that it reduces horizontal scrolling and lines running off your screen, but it still breaks syntax highlighting and we can do better. If you are going this far with white spacing though why not go all the way?</p>
            </aside>
        </section>

        <section>
            <h2>Use Native YAML Syntax</h2>
            <h3>Yes!</h3>
            <pre class="language-yaml"><code>
  - name: install telegraf
    yum:
      name: telegraf-{{ telegraf_version }}
      state: present
      update_cache: yes
      disable_gpg_check: yes
      enablerepo: telegraf
    notify: restart telegraf

  - name: configure telegraf
    template:
      src: telegraf.conf.j2
      dest: /etc/telegraf/telegraf.conf
    notify: restart telegraf

  - name: start telegraf
    service:
      name: telegraf
      state: started
      enabled: yes
            </code></pre>

            <aside class="notes">
              <p>Native YAML has more lines; however, those lines are shorter, reducing horizontal scrolling your eyes have to do and line wrapping in your editor. It lets the eyes scan straight down the play. </p>
              <p>The task parameters are stacked and easily distinguished from the next. </p>
              <p>Native YAML syntax also has the benefit of improved syntax highlighting in virtually any modern text editor out there. Being native YAML, editors such as vim and Atom will highlight YAML keys (module names, directives, parameter names) from their values further aiding the readability of your content. </p>
              <p>NOTE: Some of our own docs use this shorthand for legacy reasons though we’re progressively changing that. (Documentation pull requests accepted.)</p>
            </aside>
        </section>

        <section>
            <h2>Plays & Tasks</h2>
            <h3>Names improve readability and user feedback</h3>
            <ul>
                <li>Give all your playbooks, tasks and blocks brief, reasonably unique and human-meaningful names</li>
            </ul>
        </section>

        <section>
            <h2>Plays & Tasks</h2>
            <h3>Exhibit A</h3>
            <div class="columns">
                <div class="col">
                    <pre class="language-yaml"><code>
  - hosts: web
    tasks:
    - yum:
        name: httpd
        state: latest

    - service:
        name: httpd
        state: started
        enabled: yes
                    </code></pre>
                </div>

                <div class="col">
                    <pre class="language-yaml"><code>
  PLAY [web]
  ********************************

  TASK [setup]
  ********************************
  ok: [web1]

  TASK [yum]
  ********************************
  ok: [web1]

  TASK [service]
  ********************************
  ok: [web1]
                    </code></pre>
                </div>
            </div>

            <aside class="notes">
                <ul>
                    <li>Here we have a simple example of a working a play.</li>
                    <li>It works fine but what is happening here?</li>
                    <li>Is yum installing or removing something?</li>
                    <li>Is service starting or shutting down something?</li>
                    <li>What was this play supposed to do anyways?  If you just wrote this play you know now or maybe you forgot.</li>
                    <li>If when running this something fails you'd have no idea from the output, you'd need to open the playbook</li>
                </ul>
            </aside>
        </section>

        <section>
            <h2>Plays & Tasks</h2>
            <h3>Exhibit B</h3>
            <div class="columns">
                <div class="col">
                    <pre class="language-yaml"><code>
  - hosts: web
    name: installs and starts apache
    tasks:
      - name: install apache packages
        yum:
          name: httpd
          state: latest

      - name: starts apache service
        service:
          name: httpd
          state: started
          enabled: yes
                    </code></pre>
                </div>

                <div class="col">
                    <pre class="language-yaml"><code>
  PLAY [install and starts apache]
  ********************************

  TASK [setup]
  ********************************
  ok: [web1]

  TASK [install apache packages]
  ********************************
  ok: [web1]

  TASK [starts apache service]
  ********************************
  ok: [web1]
                    </code></pre>
                </div>
            </div>

            <aside class="notes">
                <ul>
                    <li>Here is the same play with names.</li>
                    <li>By adding descriptive human-meaningful names to the play declaration and tasks we get output that give you  and users of this automation better feedback and clarity to what is being performed.</li>
                    <li>From the name of the Playbook, line 2, we know what the rest of the playbook will do without having to read it.</li>
                    <li>Can help keep focus</li>
              </ul>
            </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Focus avoids complexity</h3>
          <ul>
            <li>Keep plays and playbooks focused. Multiple simple ones are better than having a huge single playbook full of conditionals.</li>
            <li>Follow the Linux principle of do one thing, and one thing well</li>
          </ul>

          <aside class="notes">
            <p>Monoliths!</p>
            <p>Multiple small roles</p>
            <p>EXAMPLE: One customer had one playbook for the entire stack,thousands of lines long, crazy, depending on the variables passed in. Impossible to manage, maintain, or know what is going on</p>
            <p>As your automation grows in sophistication and scope refactor your plays -- includes &amp; roles to compose automation workflows.</p>
            <p>When refactoring run your roles in checkmode to see</p>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Clean up your debugging tasks</h3>
          <ul>
            <li>Make them optional with the verbosity parameter so they’re only displayed when they are wanted.</li>
          </ul>

          <pre class="language-yaml"><code>
  - debug:
     msg: "This always displays"

  - debug:
     msg: "This only displays with ansible-playbook -vv+"
     verbosity: 2
          </code></pre>

          <aside class="notes">
            <p>Debugging messages and variable dumps in your plays can be helpful when you are developing or debugging automation automation, but not all the time. Displaying debugging pollutes the standard usage with a lot of noise. It can also scare anxious end users that don’t trust this automation stuff when some JSON dump of information explodes onto their screens.</p>

            <p>The verbosity parameter was added to the debug module in v2.1.</p>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Don’t just start services -- use smoke tests </h3>
          <pre class="language-yaml"><code>
  - name: check for proper response
    uri:
      url: http://localhost/myapp
      return_content: yes
    register: result
    until: '"Hello World" in result.content'
    retries: 10
    delay: 1
          </code></pre>

          <aside class="notes">
            <p>EXAMPLE: lock file, permissions, something else running on the port</p>
            <p>Just because a service started or an instances has initialized -- maybe it hit an error initializing and crashed. Use modules like uri and wait_for to smoke test that they are ready to go.</p>
            <p>reties +delays = polling, so if the server is ready soon we don't have to wait the full time, better than <span class="monospace">sleep 10</span></p>
</li>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Use run commands sparingly</h3>
          <ul>
              <li>Use the run command modules like <span class="monospace">shell</span> and <span class="monospace">command</span> as a last resort</li>
              <li>The <span class="monospace">command</span> module is generally safer</li>
              <li>The <span class="monospace">shell</span> module should only be used for I/O redirect</li>

          </ul>

          <aside class="notes">
            <p>Run commands are...</p>

            <p>Explain how run command modules have no concept of state.  (See slide from essentials deck here.) </p>

            <p>Command will escape redirection characters such a pipe so they cannot be embedded in a variable and used for something malicious. You really shouldn’t be using a variable provided by a user anyway.</p>
            <p>Even more important when using privileges - security</p>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Always seek out a module first</h3>
          <div class="columns">
            <div class="col">
              <pre class="language-yaml"><code>
  - name: add user
    command: useradd appuser

  - name: install apache
    command: yum install httpd

  - name: start apache
    shell: |
      service httpd start && chkconfig httpd on
              </code></pre>
            </div>

            <div class="col">
              <pre class="language-yaml"><code>
  - name: add user
    user:
      name: appuser
      state: present

  - name: install apache
    yum:
      name: httpd
      state: latest

  - name: start apache
    service:
      name: httpd
      state: started
      enabled: yes
              </code></pre>
            </div>
          </div>
          <aside class="notes">
              <p>Just because you know how to do something in bash doesn’t mean you don’t need a module. Again, run commands have no sense of desired state. There is a lot going in the modules. A lot goes into making things easy. (FIXME Quote from under the hood deck here?)  The yum module doesn’t just issue a yum command. The service module sniffs out the host OS and even version to use the proper tools and switches.</p>
              <p>Modules are split into categories and topics. Have a look at these categories: file, system, utils</p>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Still using run commands a lot?</h3>
          <pre class="language-yaml"><code>
  - hosts: all
    vars:
      cert_store: /etc/mycerts
      cert_name: my cert
    tasks:
    - name: check cert
      shell: certify --list --name={{ cert_name }} --cert_store={{ cert_store }} | grep "{{ cert_name }}"
      register: output

    - name: create cert
      command: certify --create --user=chris --name={{ cert_name }} --cert_store={{ cert_store }}
      when: output.stdout.find(cert_name)" != -1
      register: output

    - name: sign cert
      command: certify --sign  --name={{ cert_name }} --cert_store={{ cert_store }}
      when: output.stdout.find("created")" != -1
          </code></pre>

          <aside class="notes">
              <p>Here "certify" is a fictitious command line tool to illustrate an in-house private tool an organization may have developed for its own use.</p>
              <p>This example is a good example of "coding" in your playbooks. That pattern being something like:</p>
              <ol>
                  <li>Perform a task and register its return and perhaps ignore any errors to handle them later.</li>
                  <li>Parse/search the registered return as the parameter or conditional of a later task</li>
                  <li>Rise and repeat</li>
              </ol>
              <p>Sometimes this cannot be avoided because a module doesn’t exist and you need something fast. In that case...</p>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Develop your own module</h3>
          <pre class="language-yaml"><code>
- hosts: all
   vars:
     cert_store: /etc/mycerts
     cert_name: my cert
   tasks:
   - name: create and sign cert
     certify:
       state: present
       sign: yes
       user: chris
       name: "{{ cert_name }}"
       cert_store: "{{ cert_store }}"
          </code></pre>
          See <a href="https://docs.ansible.com/ansible/devel/dev_guide/">ansible.com/devel/dev_guide</a>

          <aside class="notes">
              <p>Modules do the heavy lifting in Ansible.</p>
              <p>Modules and playbooks work together to provide a simple and easy to read abstraction from the underlying complexity and sophistication that give Ansible it’s power</p>
              <p>Modules provide access to the full power of a proper programming language (typically Python) and its ecosystem. </p>
              <p>Also note, that you can (and should) do many operations in a module and present that as one task. The previous example’s function was more verbose, harder to read and was spread across multiple tasks.</p>
              <p>Modules follow this CRUD (Create, read, update and delete) pattern typically.</p>
              <p>https://docs.ansible.com/ansible/devel/dev_guide/</p>
          </aside>
        </section>

        <section>
          <h2>Plays & Tasks</h2>
          <h3>Separate provisioning from deployment and configuration tasks</h3>
          <p class="monospace">
            acme_corp/<br/>
            ├── configure.yml<br/>
            ├── provision.yml<br/>
            └── site.yml<br/>
            <br/>
            $ cat site.yml<br/>
            ---<br/>
            - include: provision.yml<br/>
            - include: configure.yml
          </p>
          <aside class="notes">
            <p>Helpful if you are using different cloud providers</p>
            <p>Change cloud provider or virtualization framework</p>
            <p>Use different provisioning in development vs production</p>
          </aside>
        </section>

        <section>
            <h2>Templates</h2>
            <h3>Jinja2 is powerful but you needn't use all of it</h3>
            <div class="columns">
                <div class="col">
                  <h4>Templates should be simple:</h4>
                  <ul class="text-small">
                    <li>Variable substitution</li>
                    <li>Conditionals</li>
                    <li>Simple control structures/iterations</li>
                    <li>Design your templates for your use case, not the world's</li>
                  </ul>
                </div>
                <div class="col">
                  <h4>Things to avoid:</h4>
                  <ul class="text-small">
                    <li>Anything that can be done directly in Ansible</li>
                    <li>Managing variables in a template</li>
                    <li>Extensive and intricate conditionals</li>
                    <li>Conditional logic based on embedded hostnames</li>
                    <li>Complex nested iterations</li>
                  </ul>
                </div>
            </div>
            <aside class="notes">
                <p>From Django project, widely used Python library</p>
                <p>Expand upon Jinja2 being powerful. There is a bit of grey and a zen to deciding how to how to design your templates. Strive for simplicity. complexity kills.</p>
                <p>avoid: anything that can be done directly in Ansible - such as groups</p>
            </aside>
        </section>

        <section>
            <h2>Templates</h2>
            <h3>Identify generated files</h3>
            <ul>
              <li>Label template output files as being generated by Ansible</li>
              <li>Consider using the ansible_managed variable with the comment filter</li>
              <li>Especially important when you are starting out and not everything is Ansible managed</li>
            </ul>
            <p class="monospace" style="margin-left: 2em;">{{ ansible_managed | comment }}</p>

            <aside class="notes">
              <p>This is useful to tell users that a file has been placed by Ansible and manual changes are likely to be overwritten.</p>
              <p>Avoids someone manually changing a file and Ansible clobbering that change when it reruns</p>
            </aside>
        </section>

        <section>
            <h2>Roles</h2>
            <ul>
              <li>Like playbooks -- keep roles purpose and function focused</li>
              <li>Use a <span class="monospace">roles/</span> subdirectory for roles developed for organizational clarity in a single project</li>
              <li>Follow the Ansible Galaxy pattern for roles that are to be shared beyond a single project</li>
              <li>Limit role dependencies</li>
            </ul>

            <aside class="notes">
              <p>One "thing" per role — being able to understand the structure</p>
              <p>Linux principle of do one thing, and one thing well</p>
              <p>Loosely coupled</p>
            </aside>
        </section>

        <section>
            <h2>Roles</h2>
            <ul>
                <li>Use <span class="monospace">ansible-galaxy init</span> to start your roles...</li>
                <li>...then remove unneeded directories and stub files</li>
                <li>Use <span class="monospace">ansible-galaxy</span> to install your roles -- even private ones</li>
                <li>Use a roles files (i.e. <span class="monospace">requirements.yml</span>) to manifest any external roles your project is using</li>
                <li>Always peg a role to a specific version such as a tag or commit</li>
            </ul>
            <aside class="notes">
                <p>EXAMPLE: Don't leave empty files</p>
                <p>EXAMPLE: Peg versions</p>
            </aside>
        </section>

        <section>
            <h2>Scaling Your Ansible Workflow</h2>
            <h3>Command line tools have their limitations</h3>
            <ul>
              <li>Coordination across distributed teams & organizations...</li>
              <li>Controlling access to credentials...</li>
              <li>Track, audit and report automation and management activity...</li>
              <li>Provide self-service or delegation...</li>
              <li>Integrate automation with enterprise systems...</li>
            </ul>

            <aside class="notes">
              <p>There are limits to a command line tool...</p>
            </aside>
        </section>

        <section>
            <h2>Recap</h2>
            <ul>
                <li>Complexity Kills Productivity</li>
                <li>Optimize For Readability</li>
                <li>Think Declaratively</li>
            <aside class="notes">
                <p>Check remaining time</p>
                <p>So I know after these presentations you sometimes think, "I see what he's saying, but my setup is fairly horrible" it "I've got so much to do and not enough time"</p>
                <p>Story time</p>
                <p>Backstory: every developer had a high spec blade for running VMs on</p>
                <p>Whenever someone joined we just did a disk copy of the previous system, then hacked around in /etc</p>
                <p>Oh, and a hundred blades in we upgraded from 10.04 to 12.04</p>
                <p>Noticed a few issues: Fix playbooks for- ldap, ntp,</p>
                <p>Common packages</p>
                <p>Everytime we spotted an issue we wrote a small isolated playbook to fix it across the whole server estate</p>
                <p>Did a fresh, preseed install, ran the fix roles, iterated till I had a working system</p>
                <p>Desktops - Blade + gnome</p>
                <p>India & Madrid - group_vars/india.yml</p>

            </aside>
        </section>
        <section>
            <h2>Thank You!</h2>
            <ul>
                <li>Complexity Kills Productivity</li>
                <li>Optimize For Readability</li>
                <li>Think Declaratively</li>
            <aside class="notes">
            </aside>
        </section>

      </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/js/head.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/js/reveal.js"></script>

    <script>
      // More info https://github.com/hakimel/reveal.js#configuration
      Reveal.initialize({
        history: true,
        width: "85%",
        height: "90%",
        transition: "fade",

        // More info https://github.com/hakimel/reveal.js#dependencies
        // Notes plugin must remain local for now.
        // See https://github.com/ansible/lightbulb/issues/125
        dependencies: [
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/marked.js' },
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/markdown.js' },
          { src: 'plugin/notes/notes.js', async: true },
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js'},
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-yaml.min.js'}
          //{ src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
        ]
      });
    </script>
  </body>
</html>


================================================
FILE: decks/ansible-essentials.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>Ansible Essentials Workshop</title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/reveal.css">

    <!-- Printing and PDF exports -->
    <script>
      var link = document.createElement( 'link' );
      link.rel = 'stylesheet';
      link.type = 'text/css';
      link.href = window.location.search.match( /print-pdf/gi ) ? 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/pdf.css' : 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/paper.css';
      document.getElementsByTagName( 'head' )[0].appendChild( link );
    </script>


    <link rel="stylesheet" href="css/theme/ansible.css">

    <!-- Theme used for syntax highlighting of code -->
    <!--link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/css/zenburn.css"-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/themes/prism.min.css">


  </head>
  <body>
  <div class="ans-mark">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-449 450 125 125" style="enable-background:new -449 450 125 125;" xml:space="preserve">
      <g id="XMLID_3_">
        <circle id="XMLID_7_" class="circle" cx="-386.5" cy="512.5" r="62"/>
        <path id="XMLID_4_" class="a-mark" d="M-356.9,537.1l-24.7-59.4c-0.7-1.7-2.1-2.6-3.9-2.6c-1.7,0-3.2,0.9-4,2.6l-27.1,65.2h9.2 l10.7-26.9l32,25.9c1.3,1,2.2,1.5,3.4,1.5c2.4,0,4.6-1.8,4.6-4.5C-356.5,538.5-356.6,537.8-356.9,537.1z M-385.4,488.4l16.1,39.6 l-24.2-19L-385.4,488.4z"/>
      </g>
    </svg>
  </div>
    <div class="reveal">
      <div class="slides">
        <section data-state="cover">
          <p class="ans-logo"><img src="images/ansible-wordmark-white.svg" width="260" alt="" /></p>
          <h1>Ansible Essentials Workshop</h1>
          <!--p>NAME HERE, TITLE HERE</p>
          <p>COMPANY HERE</p-->
        </section>
        <section>
          <h2>What You Will Learn</h2>
          <p>Ansible is capable of handling many powerful automation tasks with the flexibility to adapt to many environments and workflows. With Ansible, users can very quickly get up and running to do real work.<br><br></p>
          <ul>
            <li>What is Ansible and The Ansible Way</li>
            <li>Installing Ansible</li>
            <li>How Ansible Works and its Key Components</li>
            <li>Ad-Hoc Commands</li>
            <li>Playbook Basics</li>
            <li>Reuse and Redistribution of Ansible Content with Roles</li>
          </ul>
          <aside class="notes">
            <p>This deck is designed to provide students with direct introductory instruction and guidance to beginning to automate with Ansible. It is the starting point for students intent on becoming more proficient with Ansible through other Lightbulb modules and their own usage.</p>
            <p>This deck supports lecture and hands-on forms of presenting this material. </p>
            <p>Allow 2 hours to deliver the lecture-based form and 4 hours for stopping to do the workshop assignments. To access the additional slides for delivering the workshops, navigate down when available. </p>
            <p>See the <a href="../facilitator/README.md">Ansible Lightbulb facilitator&rsquo;s guide</a> for more details on using this deck and it&rsquo;s associated material.</p>
          </aside>
        </section>
        <section>
          <h2>What is Ansible?</h2>
          <p>It&apos;s a <b>simple automation language</b> that can perfectly describe an IT application infrastructure in Ansible Playbooks.</p>
          <p>It&apos;s an <b>automation engine</b> that runs Ansible Playbooks.</p>
          <p>Ansible Tower is an <b>enterprise framework</b> for controlling, securing  and managing your Ansible automation with a <b>UI and RESTful API</b>.</p>
          <aside class="notes speaker">
            <p>Ansible is an automation platform:
              <ul>
                <li>Playbooks make up the automation language</li>
                <li>The code base is the automation engine.</li>
                <li>Ansible Tower manages existing automation</li>
              </ul>
            </p>
          </aside>
        </section>
        <section>
            <h2>Ansible Is...</h2>
            <img src="images/simple-powerful-agentless-diagram.svg" />
            <aside class="notes">
              <p>Ansible has a number of qualities that make it the most rapidly growing automation platform in the world. </p>
              <p><strong>Ansible is simple.</strong> Playbooks are human and machine readable, no special coding skills required &ndash; and even people in your IT organization that don’t know Ansible can read an Ansible playbook and understand what’s happening.</p>
              <p>This simplicity also means that it&rsquo;s easy to install and get started to do real work with it quickly &ndash; usually in just minutes. </p>
              <p>Ansible also works like you think &ndash; tasks are always executed in order. All together, the simplicity ensures that you can get started quickly.</p>
              <p><strong>Ansible is powerful.</strong> Simplicity is great, but to be really useful, you also need the powerful features that ensure you can model even the most complex of IT workflows.</p>
              <p>Ansible is complete automation, able to deploy apps, manage orchestration, and configure the infrastructure, networks, operating systems, and services that you’re already using today. </p>
              <p>Together, Ansible’s capabilities allow you to orchestrate the entire application and environment lifecycle, regardless of where It&apos;s deployed.</p>
              <p><strong>Ansible is Agentless.</strong>  Ansible relies on industry-standard and trusted SSH and WinRM protocols to automate. There are no agents or other software to install, and no additional firewall ports to open. With no need to separately stand up a management infrastructure, Ansible further reduces the activation energy required from your team to start automating today.</p>
              <p>In a world where IT complexity stymies even the most basic of IT tasks, Ansible provides a much needed respite &ndash; and path forward enabling teams to crush productivity-stealing complexity and overhead.</p>
            </aisde>
        </section>
        <section>
            <h2>The Ansible Way</h2>
            <div style="font-size: 0.75em;"><br>
            <p><strong>CROSS PLATFORM</strong> – Linux, Windows, UNIX</br>
            Agentless support for all major OS variants, physical, virtual, cloud and network</p>
            <p><strong>HUMAN READABLE</strong> – YAML</br>
            Perfectly describe and document every aspect of your application environment</p>
            <p><strong>PERFECT DESCRIPTION OF APPLICATION</strong></br>
            Every change can be made by playbooks, ensuring everyone is on the same page</p>
            <p><strong>VERSION CONTROLLED</strong></br>
            Playbooks are plain-text. Treat them like code in your existing version control.</p>
            <p><strong>DYNAMIC INVENTORIES</strong></br>
            Capture all the servers 100% of the time, regardless of infrastructure, location, etc.</p>
            <p><strong>ORCHESTRATION THAT PLAYS WELL WITH OTHERS</strong> – HP SA, Puppet, Jenkins, RHNSS, etc. Homogenize existing environments by leveraging current toolsets and update mechanisms.</p>
            </div>
            <aside class="notes">
            </aside>
        </section>
        <section>
          <h2>Ansible: The Language of DevOps</h2>
          <div style="font-size: 0.75em; text-align:center;">
          <img src="images/devops-language-diagram.svg" width="60%" height="60%" style="padding-top: 20px;"/>
          <p class="fullwidth"><strong>COMMUNICATION IS THE KEY TO DEVOPS.</strong></p>
          <p class="fullwidth">Ansible is the first <strong>automation language</strong><br/>that can be read and written across IT.</p>
          <p class="fullwidth">Ansible is the only <strong>automation engine</strong><br/>that can automate the entire <strong>application lifecycle</strong><br/>and <strong>continuous delivery pipeline</strong>.</p>
          </div>
          <aside class="notes">
          </aside>
        </section>
        <section>
          <h2>Batteries Included</h2>
          <p>Ansible comes bundled with hundreds of modules for a wide variety of automation tasks</p>
          <div class="columns">
              <div class="col">
                <ul>
                 <li>cloud</li>
                 <li>containers</li>
                 <li>database</li>
                 <li>files</li>
                 <li>messaging</li>
                 <li>monitoring</li>
                 <li>network</li>
               </ul>
              </div>
              <div class="col">
                <ul>
                  <li>notifications</li>
                  <li>packaging</li>
                  <li>source control</li>
                  <li>system</li>
                  <li>testing</li>
                  <li>utilities</li>
                  <li>web infrastructure</li>
                </ul>
              </div>
              <div class="col">
              </div>
          </div>
          <aside notes="notes">
            <p>Ansible Modules control the things that you’re automating. They can do everything from acting on system files, installing packages, or making API calls to a service framework. Ansible ships with over 1300 today -- and this number is always expanding with every release.</p>
          </aside>
        </section>
        <section>
          <h2>Community</h2>
          <div style="font-size: 0.75em;">
            <p><strong>THE MOST POPULAR OPEN-SOURCE AUTOMATION COMMUNITY ON GITHUB<br><br></strong></p>
            <div class="columns">
              <div class="col">
                <ul>
                  <li>34,000+ stars &amp; 10,000+ forks on GitHub</li>
                  <li>4000+ GitHub Contributors</li>
                  <li>Over 2000 modules shipped with Ansible</li>
                  <li>New contributors added every day</li>
                  <li>1200+ users on IRC channel</li>
                  <li>Top 10 open source projects in 2017</li>
                  <li>World-wide meetups taking place every week</li>
                  <li>Ansible Galaxy: over 18,000 subscribers</li>
                  <li>250,000+ downloads a month</li>
                  <li>AnsibleFest and Ansible Automates events across the globe</li>
                </ul>
                <p>http://ansible.com/community</p>
              </div>
              <div class="col">
                  <img src="images/ansible-up-and-running-ebook.png"/>
              </div>
          </div>
        </div>
        <aside class="notes">
          <p>Ansible is open source. Created with contributions from an active open source community and built for the people who use it every day. At its heart, Ansible was made to help more people experience the power of automation so they could work better and faster together.</p>
        </aside>
        </section>
        <section>
          <h2>Complete Automation</h2>
          <img src="images/ansible-automation-diagram.svg"/>
          <aside class="notes">
            <p>Ansible is complete automation. It&apos;s not just configuration management, It&apos;s provisioning infrastructure, deploying applications, and orchestrating actions against all layers of IT infrastructure in a single tool.</p>
            <p>Ansible's capabilities allow you to orchestrate the entire application and environment lifecycle, regardless of where It&apos;s deployed.</p>
          </aside>
        </section>
        <section>
          <h2>Use Cases</h2>
          <img src="images/ansible-use-case-diagram.svg" />
          <aside class="notes">
            <p>What can you do with Ansible? Nearly anything. Ansible is the Swiss Army knife of DevOps, capable of handling many powerful automation tasks with the flexibility to adapt to many environments and workflows.</p>
            <p>Many folks like to categorize Ansible as a configuration manager, and although yes, Ansible can do that, it&quot;s just the tip of the iceberg. When you couple configuration management with orchestration, you can start to model complicated multi-tier deployments with ease.</p>
            <p>With Ansible, once someone on your team automates something, everyone on the team now knows how to do it.</p>
          </aside>
        </section>
        <section>
          <h2>Installing Ansible</h2>
          <pre class="language-yaml"><code>
# the best way to install Ansible on
# CentOS, RHEL, or Scientific Linux
# is to configure the EPEL repository
# and install Ansible directly
$ sudo yum install ansible

# on Debian or Ubuntu you will need the PPA
# repo configured
$ sudo apt-get install ansible

# on all other platforms it can be
# installed via pip
$ sudo pip install ansible
          </code></pre>
          <aside class="notes">
            <p>As open source, Ansible is freely-available thru numerous means and can be installed in minutes with only a few requirements that most system already have. The installation methods listed here are the most commonly used.</p>
            <p>Currently Ansible can be run from any machine with Python 2.6 or 2.7 installed. Python 3 support is in tech preview as of version 2.2. Windows isn't supported for the control machine.</p>
            <p>The requirements of nodes being managed by Ansible vary based on the type and access used to work with them. Ansible needs a way to communicate, which is normally ssh or winrm though other means such as RESTful APIs and specialized connection types may be necessary. Linux servers will need Python 2.6 or later. Windows serves need PowerShell 3.</p>
            <p>For more details see <a href="http://docs.ansible.com/ansible/intro_installation.html">the Installation page</a> in the Ansible documentation.
          </aside>
        </section>
        <section>
          <section data-state="title alt">
          <h1>Demo Time: <br/>Installing Ansible</h1>
          <aside class="notes">
            <p>To demonstrate how easy it is to install Ansible, open an SSH session to your control host and install Ansible using one of the methods in the previous slide. Once complete do a <code>$ ansible --version</code>.</p>
          </aside>
          </section>
          <section data-state="title alt">
            <h1>Workshop: <br/>Installing Ansible</h1>
            <aside class="notes">
              <p>This brief exercise demonstrates how easy it can be to install and configure Ansible and begin automating.</p>
              <p>See <code>workshops/ansible_install</code> in the Ansible Lightbulb repo for this workshop&apos;s assignment. It's solution and addition details can be found in <code>facilitator/solutions/ansible_install.md</code>.</p>
            </aside>
          </section>
        </section>
        <section>
          <h2>How Ansible Works</h2>
          <img src="images/how-ansible-works-diagram-01.svg" />
          <aside class="notes">
            <p>The diagram on this slide shows the relationship between all the key components of Ansible starting with the user who writes an Ansible playbook.</p>
          </aside>
        </section>
        <section>
          <h2>Plays &amp; Playbooks</h2>
          <img src="images/how-ansible-works-diagram-02.svg" />
          <aside class="notes">
            <p>Playbooks are written in YAML and are used to invoke Ansible modules to perform tasks that are executed sequentially i.e top to bottom. They can describe a policy you want your remote systems to enforce, or a set of steps in a general IT workflow. Playbooks are like an instruction manual and describe the state of environment.</p>
            <p>For more details see <a href="http://docs.ansible.com/ansible/playbooks.html">the Playbook page</a> in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Modules &amp; Tasks</h2>
          <img src="images/how-ansible-works-diagram-03.svg" />
          <aside class="notes">
            <p>If playbooks are the instruction manual for setting up and managing your infrastructure, Ansible modules are the tools in your toolkit.</p>
            <p>Modules are executable bits of code that operate on hosts; however, we don’t need to understand the underlying implementation to get them to work. Modules do the heavy-lifting in Ansible and abstract users from the complexity of the underlying details.</p>
            <p>For more details see the <a href="http://docs.ansible.com/ansible/modules_intro.html">Introduction to Modules</a> and <a href="http://docs.ansible.com/ansible/modules_by_category.html">Module Index</a> page in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Plugins</h2>
          <img src="images/how-ansible-works-diagram-04.svg" />
          <aside class="notes">
            <p>Continuing our metaphor, plugins are the gears in the engine.</p>
            <p>Plugins are pieces of code that extend Ansible’s core functionality. Ansible ships with a number of handy plugins, and you can easily write your own.</p>
            <p>These are some of the more common plugin types:</p>
            <ul>
            <li>Action plugins manage the execution on the controller and deployment of modules to hosts.</li>
            <li>Callback plugins enable you to hook into Ansible events for display or logging purposes.</li>
            <li>Connection plugins define how to communicate with inventory hosts.</li>
            <li>Filters plugins allow you to manipulate data inside Ansible plays and/or templates. This is a Jinja2 feature; Ansible ships extra filter plugins.</li>
            </ul>
            <p>For more details see the <a href="http://docs.ansible.com/ansible/dev_guide/developing_plugins.html">Developing Plugins</a> page in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Inventory</h2>
          <img src="images/how-ansible-works-diagram-05.svg" />
          <aside class="notes">
            <p>Your inventory of hosts are your raw material. They are a list of nodes and associated meta data that Ansible can automate.</p>
            <p>Inventory lists can be built and stored several different ways, including static files, or can be dynamically-generated from an external source.</p>
            <p>You can also specify variables as part of an inventory list. For instance, set a particular host key that’s needed to log into that system remotely.  Inventories are ultimately lists of things you want to automate across.</p>
            <p>Here in this slide was see an example of a simple static inventory list of three hosts (webserver1, webserver2 and dbserver1) in two groups (web and db).</p>
            <p>For more details see the <a href="http://docs.ansible.com/ansible/intro_inventory.html">Inventory</a> page in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Inventory</h2>
          <img src="images/how-ansible-works-diagram-06.svg" />
          <aside class="notes">
            <p>In large-scale environment subject to constant change, synchronizing and maintaining inventory statically is tedious and error prone endeavor. That is why Ansible includes support of external sources such as public and private cloud providers and configuration management database (CMDB) systems.</p>
            <p>For more details see the <a href="http://docs.ansible.com/ansible/intro_dynamic_inventory.html">Dynamic Inventory</a> page in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Modules</h2>
          <p>Modules are bits of code transferred to the target system and executed to satisfy the task declaration.</p>
          <div class="columns">
            <div class="col">
              <ul>
                <li>apt/yum</li>
                <li>copy</li>
                <li>file</li>
                <li>get_url</li>
                <li>git</li>
                <li>ping</li>
                <li>debug</li>
              </ul>
            </div>
            <div class="col">
              <ul>
                <li>service</li>
                <li>synchronize</li>
                <li>template</li>
                <li>uri</li>
                <li>user</li>
                <li>wait_for</li>
                <li>assert</li>
              </ul>
            </div>
              <div class="col">
              </div>
          </div>
          <aside class="notes">
            <p>If playbooks are the instruction manual for setting up and managing your infrastructure, Ansible modules are the tools in your toolkit.</p>
            <p>We've already discussed, Ansible modules. They are the &ldquo;batteries&rdquo; and the &ldquo;tools in a users toolkit.&rdquo;</p>
            <p>While there are hundreds of modules at your disposal out-of-the-box these are the most common ones.</p>
            <p>Playbook tasks and how they relate to modules will be covered ahead. Tasks are the application of a module to perform a specific unit of work.</p>
          </aside>
        </section>
        <section>
          <h2>Modules Documentation</h2>
            <div class="columns">
              <div class="col">
          <p><strong>https://docs.ansible.com/ansible/latest/modules/modules_by_category.html</strong></p>
                </div>
                <div class="col">
          <img src="images/modules-doc-screenshots.png" />
                </div>
            </div>
          <aside class="notes">
            <p><a href="http://docs.ansible.com/ansible/modules_by_category.html">A categorized index of included Ansible modules</a> along with detailed documentation for the requirements, parameters and return values of each Ansible module can be found on the <a href="http://docs.ansible.com/ansible/">Ansible documentation site</a>. </p>
          </aside>
        </section>
        <section>
          <h2>Modules Documentation</h2>
          <pre class="language-yaml"><code>
# List out all modules installed
$ ansible-doc -l
...
copy
cron
...

# Read documentation for installed module
$ ansible-doc copy
> COPY

  The [copy] module copies a file on the local box to remote locations. Use the [fetch] module to copy files from remote locations to the local
  box. If you need variable interpolation in copied files, use the [template] module.

  * note: This module has a corresponding action plugin.

Options (= is mandatory):
...
          </code></pre>
        </section>
        <aside class="notes">
          <p>Module documentation is also available from the commandline using the <code>ansible-doc</code>.</p>
          <p>One noteworthy advantage, of ansible-doc is that it can display any custom module with it's own embedded documentation that you may have added to your Ansible environment.</p>
        </aside>
        <section>
          <h2>Modules: Run Commands</h2>
          <p>If Ansible doesn't have a module that suits your needs there are the “run command” modules:</p><br>
          <ul>
            <li><b>command</b>: Takes the command and executes it on the host. The most secure and predictable.</li>
            <li><b>shell</b>: Executes through a shell like <code>/bin/sh</code> so you can use pipes etc. Be careful.</li>
            <li><b>script</b>: Runs a local script on a remote node after transferring it.</li>
            <li><b>raw</b>: Executes a command  without going through the Ansible module subsystem.</li>
          </ul>
          <p><br><b>NOTE:</b> Unlike standard modules, run commands have no concept of desired state and should only be used as a last resort.</p>
          <aside class="notes">
            <p>&quot;Run commands&quot; are what we collectively call these modules that enable users to do command-line operations in different ways. They’re a great catch all mechanism for getting things done, but they should be used sparingly and as a last resort. The reasons are many and varied.</p>
            <p>The overuse of run commands is common amongst those just becoming familiar with Ansible for automating their work. They use <code>shell</code> to fire off a bash command they already know without stopping to look at the Ansible docs. That works well enough initially, but it undermines the value of automating with Ansible and sets things up for problems down the road. <b>As a best practice, always check the hundreds of Ansible shipping modules for what you need and use those first and run commands as a last resort.</b></p>
            <p><b>NOTE:</b> <code>shell</code> allows for IO redirection such as pipes. This is why It&apos;s best practice to use <code>command</code> unless they need to pipe something. It also best practice to <strong>never</strong> pass user input or variables thru a run command.</p>
          </aside>
        </section>
        <section>
          <h2>Inventory</h2>
          <p>Inventory is a collection of hosts (nodes) with associated data and groupings that Ansible can connect and manage.</p>
          <ul>
            <li>Hosts (nodes)</li>
            <li>Groups</li>
            <li>Inventory-specific data (variables)</li>
            <li>Static or dynamic sources</li>
          </ul>
          <aside class="notes">
            <p>We've already discussed inventory in our review of Ansible's key components.</p>
            <p>Inventory consists of hosts, groups, inventory specific data. Inventory can either be static or dynamic.</p>
            <p>Inventory is a collection of the hosts (nodes) with associated metadata and groupings that Ansible can connect and manage. An inventory source can be static files or dynamically retrieved from an external system.</p>
            <p>You can specify a different inventory file using the <code>-i &lt;path&gt;</code> option on the command-line or your Ansible configuration file.</p>
          </aside>
        </section>
        <section>
          <h2>Static Inventory Example</h2>
          <pre class="language-yaml"><code>
10.42.0.2
10.42.0.6
10.42.0.7
10.42.0.8
10.42.0.100
host.example.com
          </code></pre>
          <aside class="notes">
            <p>Static inventory is the easiest source to get started with. This example shows a static inventory source in It&rsquo;s simplest form &ndash; a single file with a list of IP addresses or hostnames.</p>
            <p><strong>NOTE:</strong> Ansible infers a localhost is present even if it is not explicitly listed. This is why you can actually run Ansible without a inventory source. Ansible will only be able to operate on the localhost where it is being run.</p>
          </aside>
        </section>
        <section>
          <h2>Static Inventory Example</h2>
          <pre class="language-yaml"><code>
[control]
control ansible_host=10.42.0.2

[web]
node-[1:3] ansible_host=10.42.0.[6:8]

[haproxy]
haproxy ansible_host=10.42.0.100

[all:vars]
ansible_user=vagrant
ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key
          </code></pre>
          <aside class="notes">
            <p>The example shown here is a more practical and common example of a static inventory file.</p>
            <p>Static inventory files are expressed in INI format. The headings in brackets are group names, which are used in classifying systems and deciding what systems you are controlling at what times and for what purpose. Hosts can belong to multiple groups and groups can be members of other groups. (The latter is not shown here.)</p>
            <p>NOTE: This example contains variables, a topic we haven't touched on just yet. We'll go into them on the next slide.</p>
            <p>Other noteworthy attributes in our example:</p>
            <ul>
              <li><code>ansible_host</code> is an example of a host variable.</li>
              <li>Hosts can be assigned arbitrary human-meaningful names or aliases such as "control" and "haproxy". Ansible will instead use the value of <code>ansible_host</code> (one of several <a href="http://docs.ansible.com/ansible/playbooks_variables.html#magic-variables-and-how-to-access-information-about-other-hosts">&quot;magic&quot; inventory variables</a>) as the network address to connect.</li>
              <li>Static inventory files can support character ranges such as &quot;node-[1:3]&quot;</li>
              <li>Like localhost, Ansible infers an &quot;all&quot; group is present. As its name implies, all inventory hosts are members of this group.</li>
              <li>The heading &quot;all:vars&quot; is an example of group variable assignment using two more &quot;magic&quot; variables, <code>ansible_ssh_private_key_file</code> and <code>ansible_user</code>.</li>
            </ul>
            <p>This example just covers the basics. There's a lot more to inventory that is not covered here. See the <a href="http://docs.ansible.com/ansible/intro_inventory.html">Ansible inventory documentation</a> for more details.</p>
          </aside>
        </section>
        <section>
          <section>
            <h2>Ad-Hoc Commands</h2>
            <p>An ad-hoc command is a single Ansible task to perform quickly, but don’t want to save for later.</p>
            <aside class="notes">
              <p>Ansible ad-hoc commands is a good place to start to understand the basics of what Ansible can do before learning how to use playbooks &ndash; ad-hoc commands can also be used to do quick things that you might not necessarily want to write a full playbook for.</p>
              <p>Generally speaking, the true power of Ansible lies in playbooks. So why would you use ad-hoc tasks versus playbooks?</p>
              <p>For instance, if you wanted to restart a service on all of your lab nodes, you could execute a quick one-liner in Ansible without writing a playbook.</p>
            </aside>
          </section>
          <section>
            <h2>Ad-Hoc Commands: Common Options</h2>
            <ul style="font-size: 0.75em;">
              <li><b>-m MODULE_NAME, --module-name=MODULE_NAME</b><br/>Module name to execute the ad-hoc command</li>
              <li><b>-a MODULE_ARGS, --args=MODULE_ARGS</b><br/>Module arguments for the ad-hoc command</li>
              <li><b>-b, --become</b><br/>Run ad-hoc command with elevated rights such as sudo, the default method</li>
              <li><b>-e EXTRA_VARS, --extra-vars=EXTRA_VARS</b><br/>Set additional variables as key=value or YAML/JSON</li>
              <li><b>--version</b><br/>Display the version of Ansible</li>
              <li><b>--help</b><br/>Display the MAN page for the Ansible tool</li>
            </ul>
            <aside class="notes">
              <p>This slide shows essential command-line options for running ad-hoc commands that will be useful in our upcoming workshop assignment.</p>
            </aside>
          </section>
        </section>
        <section>
          <h2>Ad-Hoc Commands</h2>
          <pre class="language-yaml"><code>
# check all my inventory hosts are ready to be
# managed by Ansible
$ ansible all -m ping

# collect and display the discovered facts
# for the localhost
$ ansible localhost -m setup

# run the uptime command on all hosts in the
# web group
$ ansible web -m command -a &quot;uptime&quot;
          </code></pre>
          <aside class="notes">
            <p>Ad-hoc commands are quick checks on your servers that you don’t want to preserve in an Ansible playbook.</p>
            <p>An ad-hoc command can be used to do some tasks that you might not necessarily want to write a full playbook and save for later.</p>
            <p>This is a good place to start to understand the basics of what Ansible can do prior to learning about playbooks where the true power of Ansible automation lies.</p>
            <p>For more information see <a href="http://docs.ansible.com/ansible/intro_adhoc.html">Introduction To Ad-Hoc Commands</a>.</p>
          </aside>
        </section>
        <section>
          <h2>Sidebar: Discovered Facts</h2>
          <p>Facts are bits of information derived from examining a host systems that are stored as variables for later use in a play.</p>
          <pre class="language-yaml"><code>
$ ansible localhost -m setup
localhost | success >> {
  "ansible_facts": {
      "ansible_default_ipv4": {
          "address": "192.168.1.37",
          "alias": "wlan0",
          "gateway": "192.168.1.1",
          "interface": "wlan0",
          "macaddress": "c4:85:08:3b:a9:16",
          "mtu": 1500,
          "netmask": "255.255.255.0",
          "network": "192.168.1.0",
          "type": "ether"
      },
          </code></pre>
          <aside class="notes">
            <p>The second ad-hoc command example from the prior slide provides the following JSON output of a localhost facts run.</p>
            <p>Facts are bits of information derived from examining a host systems that are stored as variables for later use. An example of this might be the IP address of the host, or what operating system it is running. The facts Ansible will discover about a host is extensive. What's shown here is just a small sample. Run <code>ansible localhost -m setup</code> for a more complete representation.</p>
            <p>Ansible collects facts using the <code>setup</code> module. By default, Ansible will run the <code>setup</code> module before any other tasks are executed in a playbook. These facts can be referenced by subsequent automation tasks on a per host-basis during the playbook run.</p>
          </aside>
        </section>
        <section>
          <section data-state="title alt">
            <h1>Demo Time: <br/>Ad-Hoc Commands</h1>
            <aside class="notes">
              <p>To demonstrate ad-hoc commands in action, open an SSH session to your control host and run the ad-hoc commands in the previous slides.</p>
              <pre class="language-yaml"><code>
$ ansible all -m ping
$ ansible localhost -m setup
$ ansible web -m command -a &quot;uptime&quot;
              </code></pre>
            </aside>
          </section>
          <section data-state="title alt">
            <h1>Workshop: <br/>Ad-Hoc Commands</h1>
            <aside class="notes">
              <p>This brief exercise demonstrates Ansible in-action at it&apos;s most basic and simple level. Thru ad-hoc commands, students are exposed to Ansible modules and usage and will apply to their understanding of tasks and playbooks. This exercise also begins to expose students to the concepts of Ansible facts and inventory.</p>
              <p>This workshop is also a good way to verify their lab environments are properly configured before going forward.</p>
              <p>See <code>workshops/adhoc_commands</code> in the Ansible Lightbulb repo.</p>
            </aside>
          </section>
        </section>
        <section>
          <h2>Variables</h2>
          <p>Ansible can work with metadata from various sources and manage their context in the form of variables.</p>
          <ul>
            <li>Command line parameters</li>
            <li>Plays and tasks</li>
            <li>Files</li>
            <li>Inventory</li>
            <li>Discovered facts</li>
            <li>Roles</li>
          </ul>
          <aside class="notes">
            <p>While automation exists to make it easier to make things repeatable, all of your systems are not exactly alike.</p>
            <p>Variables are used to store metadata for each host drawing from numerous sources. For example variable may be for things like facts or file paths or package versions.</p>
          </aside>
        </section>
        <section>
          <h2>Variable Precedence</h2>
          <p>The order in which the same variable from different sources will override each other.</p>
          <div class="columns">
            <div class="col">
              <ol>
                <li>extra vars</li>
                <li>task vars (only for the task)</li>
                <li>block vars (only for tasks in block)</li>
                <li>role and include vars</li>
                <li>play vars_files</li>
                <li>play vars_prompt</li>
                <li>play vars</li>
                <li>set_facts</li>
              </ol>
            </div>
            <div class="col">
              <ol start="9" class="col">
                <li>registered vars</li>
                <li>host facts</li>
                <li>playbook host_vars</li>
                <li>playbook group_vars</li>
                <li><strong>inventory host_vars</strong></li>
                <li><strong>inventory group_vars</strong></li>
                <li>inventory vars</li>
                <li>role defaults</li>
              </ol>
            </div>
          </div>
          <aside class="notes">
            <p>If variables of the same name are defined in multiple sources, they get overwritten in a certain and specific order. This is why this variable precedence is important to understand.</p>
            <p>There are 16 levels of variable precedence as of Ansible 2.x. The <code>extra_vars</code> (passed thru the command-line) always take precedence vs. role defaults which will always get overridden by any other source. The previous inventory example defines vars at 13 and 14 (highlighted in the list) in the variable precedence chain.</p>
            <p>It&apos;s a good idea to limit the different sources where a specific variable is being set. While Ansible's variable precedence handling is comprehensive and well-defined, it can laborious to keep the resolution of multiple sources straight.</p>
            <p>NOTE: The inventory variables sources showed in the static inventory example a couple of slides back are in bold type.</p>
          </aside>
        </section>
        <section>
          <h2>Tasks</h2>
          <p>Tasks are the application of a module to perform a specific unit of work.</p>
          <ul>
            <li><b>file</b>: A directory should exist</li>
            <li><b>yum</b>: A package should be installed</li>
            <li><b>service</b>: A service should be running</li>
            <li><b>template</b>: Render a configuration file from a template</li>
            <li><b>get_url</b>: Fetch an archive file from a URL</li>
            <li><b>git</b>: Clone a source code repository</li>
          </ul>
          <aside class="notes">
            <p>We've already reviewed modules, the batteries and tools Ansible provides. Tasks are the specific application of a module to perform a unit of automation.</p>
            <p>Here we see a list of examples of common modules being applied to do something.</p>
          <aside>
        </section>
        <section>
          <h2>Example Tasks in a Play</h2>
          <pre class="language-yaml"><code>
tasks:
- name: Ensure httpd package is latest
  yum:
    name: httpd
    state: latest

- name: Ensure latest index.html file is present
  copy:
    src: files/index.html
    dest: /var/www/html/

- name: Restart httpd
  service:
    name: httpd
    state: restarted
          </code></pre>
          <aside class="notes">
            <p>This example shows the task list of an Ansible playbook.</p>
            <p>
              <ol>
                <li>The first task assures the latest nginx package is installed using yum.</li>
                <li>The next uses the copy module to assure the latest version of a static home page file has been published.</li>
                <li>The last task restarts the nginx service with the service module</li>
              </ol>
            </p>
          </aside>
        </section>
        <section>
          <h2>Handler Tasks</h2>
          <p>Handlers are special tasks that run at the end of a play if notified by another task when a change occurs.</p>
          <blockquote>If a package gets installed or updated, notify a service restart task that it needs to run.</blockquote>
          <aside class="notes">
            <p>Normal tasks run sequentially; handler tasks run on notification of a change and will only run once at the end of a play.</p>
            <p>For more information see <a href="http://docs.ansible.com/ansible/playbooks_intro.html#handlers-running-operations-on-change">Handler Tasks</a>.</p>
          </aside>
        </section>
        <section>
          <h2>Example Handler Task in a Play</h2>
          <pre class="language-yaml"><code data-noescape>
tasks:
- name: Ensure httpd package is latest
  yum:
    name: httpd
    state: latest
  <mark>notify: restart httpd</mark>

- name: Ensure latest index.html file is present
  copy:
    src: files/index.html
    dest: /var/www/html/

<mark>handlers:</mark>
- name: restart httpd
  service:
    name: httpd
    state: restarted
          </code></pre>
          <aside class="notes">
            <p>Here is our previous example with a few slight modifications that have been highlighted.</p>
            <p>In this version of our example, we add a <code>notify</code> keyword to the first task to trigger a handler task if it returns &quot;changed&quot; as being true. The third tasks now is under a &quot;handlers&quot; section that signifies that the handler task will run on notification at the end of the play of change occurs during the first task.</p>
          </aside>
        </section>
        <section>
          <h2>Plays &amp; Playbooks</h2>
          <p>Plays are ordered sets of tasks to execute against host selections from your inventory. A playbook is a file containing one or more plays.</p>
          <aside class="notes">
            <p>Playbooks are text files that contain one or more plays that are expressed in YAML. A play defines target hosts and a task list that are executed sequentially (i.e top to bottom) to achieve a certain state on those hosts.</p>
            <p>For more details see <a href="http://docs.ansible.com/ansible/playbooks.html">the Playbook page</a> in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Playbook Example</h2>
          <pre class="language-yaml"><code data-noescape>
---
- name: Ensure apache is installed and started
  hosts: web
  become: yes
  vars:
    http_port: 80

  tasks:
  - name: Ensure httpd package is present
    yum:
      name: httpd
      state: latest

  - name: Ensure latest index.html file is present
    copy:
      src: files/index.html
      dest: /var/www/html/

  - name: Ensure httpd is started
    service:
      name: httpd
      state: started
          </code></pre>
          <aside class="notes">
            <p>Here we can see an example of a simple but complete Ansible play. The slides that follow will explore each of these parts and what they do.</p>
          </aside>
        </section>

        <section>
          <h2>Human-Meaningful Naming</h2>
          <pre class="language-yaml"><code data-noescape>
 ---
 - <mark>name: install and start apache</mark>
   hosts: web
   become: yes
   vars:
     http_port: 80

   tasks:
   - <mark>name: httpd package is present</mark>
     yum:
       name: httpd
       state: latest

   - <mark>name: latest index.html file is present</mark>
     copy:
       src: files/index.html
       dest: /var/www/html/

   - <mark>name: httpd is started</mark>
     service:
        name: httpd
        state: started
          </code></pre>
          <aside class="notes">
            <p>Every play and each task in it can be assigned a name that describes its objective in the automation workflow and is output during execution.</p>
            <p>It&apos;s best practice to always name your plays and tasks. Adding name with a human-meaningful description better communicates the intent to users when running a play.</p>
          </aside>
        </section>

        <section>
          <h2>Host Selector</h2>
          <pre class="language-yaml"><code data-noescape>
---
- name: Ensure apache is installed and started
  <mark>hosts: web</mark>
  become: yes
  vars:
    http_port: 80

  tasks:
  - name: Ensure httpd package is present
    yum:
      name: httpd
      state: latest

  - name: Ensure latest index.html file is present
    copy:
      src: files/index.html
      dest: /var/www/html/

  - name: Ensure httpd is started
    service:
      name: httpd
      state: started
          </code></pre>
          <aside class="notes">
            <p>The Ansible play host selector defines which nodes in the inventory the automation is targeting.</p>
            <p>In this example, a single group of &quot;web&quot; is being targeted. Ansible supports targeting intersections, unions and filters of multiple groups or hosts though.</p>
            <p>For more details see <a href="http://docs.ansible.com/ansible/intro_patterns.html">the host selector Patterns page</a> in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Privilege Escalation</h2>
          <pre class="language-yaml"><code data-noescape>
---
- name: Ensure apache is installed and started
  hosts: web
  <mark>become: yes</mark>
  vars:
    http_port: 80

  tasks:
  - name: Ensure httpd package is present
    yum:
      name: httpd
      state: latest

  - name: Ensure latest index.html file is present
    copy:
      src: files/index.html
      dest: /var/www/html/

  - name: Ensure httpd is started
    service:
      name: httpd
      state: started
          </code></pre>
          <aside class="notes">
            <p>Ansible allows you to &quot;become&quot; another user or with elevated rights to execute a task or an entire play (shown above). This is done using existing privilege escalation tools, which you probably already use or have configured, like sudo (the default), su, pfexec, doas, pbrun, dzdo, ksu and others.</p>
            <p>For more details see <a href="http://docs.ansible.com/ansible/become.html">the Privilege Escalation page</a> in the Ansible documentation.</p>
          </aside>
        </section>
        <section>
          <h2>Play Variables</h2>
          <pre class="language-yaml"><code data-noescape>
---
- name: Ensure apache is installed and started
  hosts: web
  become: yes
  <mark>vars:</mark>
    <mark>http_port: 80</mark>

  tasks:
  - name: Ensure httpd package is present
    yum:
      name: httpd
      state: latest

  - name: Ensure latest index.html file is present
    copy:
      src: files/index.html
      dest: /var/www/html/

  - name: Ensure httpd is started
    service:
      name: httpd
      state: started
          </code></pre>
          <aside class="notes">
            <p>Variables are used to store metadata for each host drawing from numerous sources. Here we see another one of those sources, a variable &quot;http_port&quot; that has been embedded in a play.</p>
            <p>Recalling the previous variable precedence slide, play variables are number 7 in Ansible&apos;s the precedence chain.</p>
          </aside>
        </section>
        <section>
          <h2>Tasks</h2>
          <pre class="language-yaml"><code data-noescape>
---
- name: Ensure apache is installed and started
  hosts: web
  become: yes
  vars:
    http_port: 80

  tasks:
  - name: Ensure latest httpd package is present
    <mark>yum:</mark>
      <mark>name: httpd</mark>
      <mark>state: latest</mark>

  - name: Ensure latest index.html file is present
    <mark>copy:</mark>
      <mark>src: files/index.html</mark>
      <mark>dest: /var/www/html/</mark>

  - name: Ensure httpd is started
    <mark>service:</mark>
      <mark>name: httpd</mark>
      <mark>state: started</mark>
          </code></pre>
          <aside class="notes">
            <p>Here we see modules, such as yum, being applied to a to perform a unit of automation such as to assure the latest httpd package is present on a host.</p>
          </aside>
        </section>
        <section>
          <section data-state="title alt">
            <h1>Demo Time: <br/>A Simple Playbook Run</h1>
            <aside class="notes">
              <p>To demonstrate how an Ansible, open an SSH session to your control host and run the playbook in <code>examples/apache-simple-playbook</code>. That example playbook is essentially the same one we just examined.</p>
              <p>Don't forget to reverse what this playbook does before continuing to not interfere with later demos and workshops.</p>
            </aside>
          </section>
          <section data-state="title alt">
            <h1>Workshop: <br/>Your First Playbook</h1>
            <aside class="notes">
              <p>This assignment provides a quick introduction to playbook structure to give them a feel for how Ansible works, but in practice is too simplistic to be useful.</p>
              <p>See <code>workshops/simple_playbook</code> in the Ansible Lightbulb repo.</p>
              <p>Note: If your time is limited, this is a workshop you can skip. We'll cover this and more topics in the next workshop.</p>
            </aside>
          </section>
        </section>
        <section>
          <section>
            <h2>Doing More with Playbooks</h2>
            <p>Here are some more essential playbook features that you can apply:</p>
            <ul>
              <li>Templates</li>
              <li>Loops</li>
              <li>Conditionals</li>
              <li>Tags</li>
              <li>Blocks</li>
            </ul>
            <aside class="notes">
              <p>We only have covered the most essential capabilities of what can be done with a playbook so far.</p>
              <p>Here we list a few more though this is still far from all there is. There&apos;s many other powerful playbook features for handling less common though vital automation workflows. No need to learn everything at once. You can start small and pick up more features over time as you need them.</p>
            </aside>
          </section>
          <section>
            <h2>Templates</h2>
            <p>Ansible embeds the <a href="http://jinja.pocoo.org/docs/">Jinja2 templating engine</a> that can be used to dynamically:</p>
            <ul>
              <li>Set and modify play variables</li>
              <li>Conditional logic</li>
              <li>Generate files such as configurations from variables</li>
            </ul>
            <aside class="notes">
              <p>Templates are a vital feature provided by the Jinja2 template engine, a powerful piece of software independent of Ansible. Ansible makes this usage as seamless and transparent as possible. Most will not realize they are doing templating when they develop plays with Ansible.</p>
              <p>We don't show any specific template examples at the moment because we'll have plenty of opportunity to see templates in action as we cover other topics.</p>
              <p>In all actuality, what is covered here only touches upon a few of its most basic features. To go deeper see these docs:</p>
              <ul>
              <li><a href="http://jinja.pocoo.org/docs/dev/templates/">Jinja2 Template Designer Documentation</a></li>
              <li><a href="http://docs.ansible.com/ansible/playbooks_filters.html">Ansible Jinja2 Filters</a></li>
              <li><a href="http://docs.ansible.com/ansible/playbooks_tests.html">Ansible Jinja2 Tests</a></li>
              </ul>
            </aside>
          </section>
          <section>
            <h2>Loops</h2>
            <p>Loops can do one task on multiple things, such as create a lot of users, install a lot of packages, or repeat a polling step until a certain result is reached.</p>
            <pre class="language-yaml"><code data-noescape>
- yum:
    name: <mark>&quot;{{ item }}&quot;</mark>
    state: latest
  <mark>loop:</mark>
  <mark>- httpd</mark>
  <mark>- mod_wsgi</mark>
            </code></pre>
            <aside class="notes">
              <p>This example demonstrates a basic loop with <code>loop</code>. The loop sets a variable called &quot;item&quot;, a template variable courtesy of the embedded Jinja2 template engine, with the list value that is in context.</p>
              <p>There are many different and specialized types of task loops to work with. See the <a href="http://docs.ansible.com/ansible/playbooks_loops.html">Loops documentation</a> to go deeper.</p>
            </aside>
          </section>
          <section>
            <h2>Conditionals</h2>
            <p>Ansible supports the conditional execution of a task based on the run-time evaluation of variable, fact, or previous task result.</p>
            <pre class="language-yaml"><code data-noescape>
- yum:
    name: httpd
    state: latest
  <mark>when: ansible_os_family == &quot;RedHat&quot;</mark>
            </code></pre>
            <aside class="notes">
              <p>Conditionals are another instance of Jinja2 in action within Ansible plays themselves. In the provided example &quot;ansible_os_family&quot; is a fact variable Ansible will set.</p>
              <p>There are other forms of conditional clauses, but <code>when</code> is usually all that is needed.</p>
              <p>NOTE: Conditional clauses are considered to be raw Jinja2 expression without double curly braces.</p>
            </aside>
          </section>
          <section>
            <h2>Tags</h2>
            <p>Tags are useful to be able to run a subset of a playbook on-demand.</p>
            <pre class="language-yaml"><code data-noescape>
- yum:
    name: &quot;{{ item }}&quot;
    state: latest
  loop:
  - httpd
  - mod_wsgi
  <mark>tags:</mark>
     <mark>- packages</mark>

 - template:
     src: templates/httpd.conf.j2
     dest: /etc/httpd/conf/httpd.conf
  <mark>tags:</mark>
     <mark>- configuration</mark>
            </code></pre>
            <aside class="notes">
              <p>In the provided example, if the playbook were run with <code>--tags &quot;packages&quot;</code> the yum task would execute and the template task would be skipped. If the playbook were run with <code>--tags &quot;configuration&quot;</code> the opposite would happen. Without a <code>--tags</code> both tasks would execute like normal.</p>
              <p>Tags can be seen as a simple though specialized form of conditional statement designed to enable the execution of a subset tasks. Tags are a bit more than simple boolean flags though. To dig deeper see the <a href="http://docs.ansible.com/ansible/playbooks_tags.html">playbook Tags documentation</a>.</p>
            </aside>
          </section>
          <section>
            <h2>Blocks</h2>
            <p>Blocks cut down on repetitive task directives, allow for logical grouping of tasks and even in play error handling.</p>
            <pre class="language-yaml"><code data-noescape>
- <mark>block:</mark>
  - yum:
      name: &quot;{{ item }}&quot;
      state: latest
    loop:
    - httpd
    - mod_wsgi

  - template:
      src: templates/httpd.conf.j2
      dest: /etc/httpd/conf/httpd.conf
  when: ansible_os_family == &quot;RedHat&quot;
            </code></pre>
            <aside class="notes">
              <p>In the provided example we use a block to group two tasks that are to be conditional executed if a host is running a Red Hat family linux using one conditional clause. In practice, we could have copied the <code>when</code> clause onto each task and gotten same result. Using a block, there is less clutter thereby less to maintain and nothing to keep in sync. The utility of using a block increases the more tasks and clauses are in use.</p>
              <p>Blocks have a play in error handling and automating roll backs that we won't get into here given the scope of that topic.</p>
              <p>See the <a href="http://docs.ansible.com/ansible/playbooks_blocks.html">documentation on blocks</a> to dig deeper.</p>
          </section>
        </section>
        <section>
          <section data-state="title alt">
            <h1>Demo Time: <br/>A More Practical Playbook</h1>
            <aside class="notes">
              <p>The simple playbook we examined gave us a sense of the structure of a playbook and how they work, but in reality was too simplistic to be practical. Here we look at a basic playbook that it more complete to what users will commonly do with Ansible.</p>
              <p>Walk thru the site.yml playbook in <code>examples/apache-basic-playbook</code> and note the added logic and its function. Then, run the playbook on the control host.</p>
              <p>Don't forget to reverse what this playbook does before continuing to not interfere with later demos and workshops.</p>
            </aside>
          </section>
          <section data-state="title alt">
            <h1>Workshop: <br/>Practical Playbook Development</h1>
            <aside class="notes">
              <p>In this workshop assignment students are tasked with developing their first complete playbook. The assignment approximates the tasks they will typical need to take in order to deploy and configure a single application service using Nginx.</p>
              <p>See <code>workshops/basic_playbook/</code> in the Ansible Lightbulb repo.</p>
              <p>Tip: Don&apos;t rush this workshop. Give students ample time to do this workshop themselves to completion. This workshop covers the essential concepts and features of effectively automation with Ansible and builds up their core skills for further exploration.</p>
            </aside>
          </section>
        </section>
        <section>
          <h2>Roles</h2>
          <p>Roles are a packages of closely related Ansible content that can be shared more easily than plays alone.</p>
          <ul>
            <li>Improves readability and maintainability of complex plays</li>
            <li>Eases sharing, reuse and standardization of automation processes</li>
            <li>Enables Ansible content to exist independently of playbooks, projects -- even organizations</li>
            <li>Provides functional conveniences such as file path resolution and default values</li>
          </ul>
          <aside class="notes">
            <p>Roles are closely related Ansible content that are organized into a pre-defined directory structure, making them easier to reuse and share among groups.</p>
          </aside>
        </section>
        <section>
          <h2>Project with Embedded Roles Example</h2>
          <pre class="language-yaml"><code>
site.yml
roles/
   common/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
   apache/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
          </code></pre>
          <aside class="notes">
            <p>This slide shows an example file system with a top-level playbook (site.yml) and two sample roles (common and apache) embedded in the project. Notice how the file structure under each role are similar to what we find in a play. Role deconstruct the content we'd put in a play and package it up in such a way that it is portable and easily shared and reused.</p>
          </aside>
        </section>
        <section>
          <h2>Project with Embedded Roles Example</h2>
          <pre class="language-yaml"><code>
# site.yml
---
- name: Execute common and apache role
  hosts: web
  roles:
     - common
     - apache
          </code></pre>
          <aside class="notes">
            <p>This slide shows the site.yml playbook using the roles in our example project. Notice that it is much more concise than what we've seen.</p>
          </aside>
        </section>
        <section>
          <h2>Ansible Galaxy</h2>
          <p><strong>http://galaxy.ansible.com</strong></p>
          <p>Ansible Galaxy is a hub for finding, reusing and sharing Ansible content.</p>
          <p>Jump-start your automation project with content contributed and reviewed by the Ansible community.</p>
          <aside class="notes speaker">
            <p>Ansible Galaxy refers to the Galaxy website, a hub for finding, downloading, and sharing community developed roles. Downloading roles from Galaxy is a great way to jump-start your automation projects.
            <p>Galaxy also refers to a command line tool, <code>ansible-galaxy</code>, for installing, creating and managing roles from the Galaxy website or directly from a git based SCM. You can also use it to create a new role, remove roles, or perform tasks on the Galaxy website.</p>
          </aside>
        </section>
        <section>
            <section data-state="title alt">
              <h1>Demo Time: <br/>A Playbook Using Roles</h1>
              <aside class="notes">
                <p>Walk thru the site.yml playbook and the contents of <code>roles/apache</code> in <code>examples/apache-role</code>. Note how the tasks, variables and handlers from the basic Ansible playbook we've been examined and have been refactored into a role.</p>
                <p>Run the playbook on the control host. Notice anything different? Other than a few subtle display changes, you shouldn't. What's important is how roles let you better organize, share and reuse Ansible content that will be vital as the scope and sophistication of your automation accelerates.</p>
              </aside>
            </section>
            <section data-state="title alt">
              <h1>Workshop: <br/>Your First Roles</h1>
              <aside class="notes">
                <p>Here students are tasked with refactoring their previous work from the Practical Playbook workshop into a role and modifying their playbook accordingly. We intentionally avoid introducing any new tasks or functionality otherwise. The objective here is to focus students specifically on how roles are structured and develop.</p>
                <p>You should emphasize the value of roles in better organizing playbooks as they grow in sophistication and making Ansible automation more portable and reusable than a basic playbook.</p>
                <p>See <code>workshops/roles</code> in the Ansible Lightbulb repo.</p>
              </aside>
            </section>
        </section>
        <section>
          <h2>Next Steps</h2>
          <ul>
            <li><strong>It&apos;s easy to get started</strong><br/>ansible.com/get-started</li>
            <li><strong>Join the Ansible community</strong><br/>ansible.com/community</li>
            <li><strong>Would you like to learn a lot more?</strong><br/>redhat.com/en/services/training/do407-automation-ansible</li>
          </ul>
        </section>
      </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/js/head.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/js/reveal.js"></script>

    <script>
      // More info https://github.com/hakimel/reveal.js#configuration
      Reveal.initialize({
        history: true,
        width: "85%",
        height: "90%",
        transition: "fade",

        // More info https://github.com/hakimel/reveal.js#dependencies
        // Notes plugin must remain local for now.
        // See https://github.com/ansible/lightbulb/issues/125
        dependencies: [
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/marked.js' },
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/markdown.js' },
          { src: 'plugin/notes/notes.js', async: true },
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js'},
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-yaml.min.js'}
          //{ src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
        ]
      });
    </script>
  </body>
</html>


================================================
FILE: decks/ansible_basics.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>Ansible Basics</title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/reveal.css">

    <!-- Printing and PDF exports -->
    <script>
      var link = document.createElement( 'link' );
      link.rel = 'stylesheet';
      link.type = 'text/css';
      link.href = window.location.search.match( /print-pdf/gi ) ? 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/pdf.css' : 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/paper.css';
      document.getElementsByTagName( 'head' )[0].appendChild( link );
    </script>


    <link rel="stylesheet" href="css/theme/ansible.css">

    <!-- Theme used for syntax highlighting of code -->
    <!--link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/css/zenburn.css"-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/themes/prism.min.css">


  </head>
  <body>
  <div class="ans-mark">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-449 450 125 125" style="enable-background:new -449 450 125 125;" xml:space="preserve">
      <g id="XMLID_3_">
        <circle id="XMLID_7_" class="circle" cx="-386.5" cy="512.5" r="62"/>
        <path id="XMLID_4_" class="a-mark" d="M-356.9,537.1l-24.7-59.4c-0.7-1.7-2.1-2.6-3.9-2.6c-1.7,0-3.2,0.9-4,2.6l-27.1,65.2h9.2 l10.7-26.9l32,25.9c1.3,1,2.2,1.5,3.4,1.5c2.4,0,4.6-1.8,4.6-4.5C-356.5,538.5-356.6,537.8-356.9,537.1z M-385.4,488.4l16.1,39.6 l-24.2-19L-385.4,488.4z"/>
      </g>
    </svg>
  </div>
    <div class="reveal">
      <div class="slides">
        <section data-state="cover">
          <p class="ans-logo"><img src="images/ansible-wordmark-white.svg" width="260" alt="" /></p>
          <h1>Ansible Basics</h1>
          <p>NAME HERE, TITLE HERE</p>
          <p>COMPANY HERE</p>
        </section>

        <section>
          <h2>WHAT YOU WILL LEARN</h2>
          <p>Ansible is capable of handling many powerful automation tasks with the flexibility to adapt to many environments and workflows. With Ansible, users can very quickly get up and running to do real work.</p>
          <br><br>In this presentation, we will cover:</p>
          <ul>
            <li>What is Ansible</li>
            <li>How Ansible Works</li>
            <li>Ad-Hoc Commands</li>
            <li>Playbook Basics</li>
            <li>Reuse and Redistribution of Ansible Content with Roles</li>
            <li>Ansible Tower</li>
          </ul>
          <aside class="notes">
            <p>Today we are going to cover the following topics: (read the list)</p>
          </aside>
        </section>

        <section>
            <h2>WHAT IS ANSIBLE AUTOMATION?</h2>
            <p>The Ansible project is an open source community sponsored by Red Hat. It’s also a <strong>simple automation language</strong> that perfectly describes IT application environments in <strong>Ansible Playbooks</strong>.
            <br><br>
            <strong>Ansible Engine</strong> is a <strong>supported product</strong> built from the Ansible community project.
            <br><br>
            Ansible Tower is an <strong>enterprise framework</strong> for controlling, securing, managing and extending your Ansible automation (community or engine) with a <strong>UI and RESTful API</strong>.</p>
            <br><br>
            <aside class="notes">
              <p>The Ansible Project is open source and sponsored by Red Hat.
                Ansible Engine is a supported product built from the Ansible community project, and Ansible Tower is the framework for the automation that Ansible Engine does.
                There’s also an open-source version of Tower which is the AWX project, and it’s associated with the Ansible GitHub.</p>
            </aside>
        </section>

        <section>
            <h2>WHY ANSIBLE?</h2>
            <p><img src="images/why_ansible.jpg"></p>
            <aside class="notes">
              <p>So why should you think about using Ansible and what sets it apart?
              First off, Ansible is simple: we expect that your user base is going to be mixed with people of all skill levels and because of that we wanted to make it incredibly easy to get started.  The language playbooks are written in is YAML, which is very easy-to-read for humans, and those playbooks work consistently across many environments
              It’s also extremely powerful in how many nodes we can spin up and manage at any given time, which is largely due to the fact that Ansible is agentless.  There are no agents to keep up to date and the requirements are minimal.
              </p>
            </aside>
        </section>

        <section>
          <h2>THE ANSIBLE WAY</h2>
          <p><font color="52AAAC"><strong>CROSS PLATFORM – Linux, Windows, UNIX</strong></font><br>
          Agentless support for all major OS variants, physical, virtual, cloud and network.</p>
          <p><font color="52AAAC"><strong>HUMAN READABLE – YAML</strong></font><br>
          Perfectly describe and document every aspect of your application environment</p>
          <p><font color="52AAAC"><strong>PERFECT DESCRIPTION OF APPLICATION</strong></font><br>
          Every change can be made by playbooks, ensuring everyone is on the same page.</p>
          <p><font color="52AAAC"><strong>VERSION CONTROLLED</strong></font><br>
          Playbooks are plain-text. Treat them like code in your existing version control.</p>
          <p><font color="52AAAC"><strong>DYNAMIC INVENTORIES</strong></font><br>
          Capture all the servers 100% of the time, regardless of infrastructure, location, etc.</p>
          <p><font color="52AAAC"><strong>ORCHESTRATION THAT PLAYS WELL WITH OTHERS – HP SA, Puppet, Jenkins, RHNSS, etc.</strong></font><br>
          Homogenize existing environments by leveraging current toolsets and update mechanisms.</p>
          <aside class="notes">
            <p>In addition, that agentless support isn’t just Linux exclusive.
              This also applies to Windows machines, networking devices, and of course both physical and cloud servers, as well as static or dynamic inventory.
              Also, one of the main selling points of Ansible is that we work well with existing toolkits.
              Sometimes people don’t know where to start; I’d advise you to pick a pain point in your environment to focus on, something small that you can leverage Ansible for and see how that feels, because you can always homogenize over time.
            </p>
          </aside>
        </section>

        <section>
          <h2>BATTERIES INCLUDED</h2>
          <p>Ansible comes bundled with hundreds of modules for a wide variety of automation tasks:</p>
          <div style="float: left; width: 50%;">
          <ul>
          <li>cloud</li>
          <li>containers</li>
          <li>database</li>
          <li>files</li>
          <li>messaging</li>
          <li>monitoring</li>
          <li>network</li>
          </ul>
          </div>
          <div style="float: right; width: 50%;">
          <ul>
          <li>notifications</li>
          <li>packaging</li>
          <li>source control</li>
          <li>system</li>
          <li>testing</li>
          <li>utilities</li>
          <li>web infrastructure</li>
          </ul>
          </div>
          <aside class="notes">
            <p>Installing Ansible nets you a TON of modules that range in type from the popular cloud modules to packaging and database modules.
              The list you see here are some of the “high profile” modules, but there are lots more that aren’t listed.</p>
          </aside>
        </section>

        <section>
          <h2>COMMUNITY</h2>
          <p><font color="52AAAC"><strong>THE MOST POPULAR OPEN-SOURCE AUTOMATION COMMUNITY ON GITHUB</strong></font><br></p>
<!-- Remember to check the numbers listed below!!  -->
          <ul>
            <li>34,000+ stars & 13,500+ forks on GitHub</li>
            <li>4000+ GitHub Contributors</li>
            <li>Over 2000 modules shipped with Ansible</li>
            <li>New contributors added every day</li>
            <li>1400+ users on IRC channel</li>
            <li>World-wide meetups taking place every week</li>
            <li>Ansible Galaxy: over 9,000 contributors and 18,000 roles</li>
            <li>500,000+ downloads a month</li>
            <li>AnsibleFests, Ansible Automates, and other global events</li>
          </ul>
          </aside>
        </section>

        <section>
          <h2>ANSIBLE: COMPLETE AUTOMATION</h2>
          <p><img src="images/complete_automation.jpg"></p>
          <aside class="notes">
            <p>One of the other bullet points that we highlight around Ansible is that it’s the complete package.
              So it’s not just configuration management; it’s also orchestration, app-deployment and provisioning as well.
              Looking at this graphic here , you can see that there are tools that definitely perform one or more of these use cases, but can’t do them all and that’s really one of the big strengths of Ansible.
              Some users like to refer to it as “Automation Glue”.</p>
          </aside>
        </section>

        <section>
            <h2>WHAT CAN I DO WITH ANSIBLE?</h2>
            <p>Automate the deployment and management of your entire IT footprint.</p>
            <p><img src="images/ansible_possibilities.jpg"></p>
            <aside class="notes">
              <p>On this slide, you can see the different use cases for how to manage and automate your machines.
                (some examples are: security and compliance, orchestration, creating new VMs, creating a CI/CD pipeline) - all of these things can be done with Ansible.
              </p>
            </aside>
        </section>

        <section>
          <h2>INSTALLING ANSIBLE</h2>
          <pre class="language-yaml"><code data-noescape>
# the most common and preferred way of installation
$ pip install ansible

# install the epel-release RPM if needed on CentOS, RHEL, or Scientific Linux
$ sudo yum install ansible

# you will need the PPA repo configured
$ sudo apt-get install ansible
          </code></pre>
          <aside class="notes">
            <p>There are many ways to install Ansible, including making your own rpm package, running from source, or you can just use a package manager.   As you can see, the examples below are using pip, yum, and apt.
              The yum and apt installations require additional steps so if you prefer using a single command, then you can install with pip.
                1 - Most common and preferred way (unless your Python is set up weird)
                2 - If you’re running a RHEL or CentOS type of machine, install epel-release and grab the package from there
                3- Ubuntu/Debian flavor OS
              If anything stumps you, it’s always helpful to take a look at the Ansible Installation documentation for more information.
            </p>
          </aside>
        </section>

        <section>
            <h2>HOW ANSIBLE WORKS</h2>
            <p><img src="images/how_ansible_works.jpg"></p>
            <aside class="notes">
              <p>Once you have Ansible installed, you’re going to need to become acquainted with the key components of how Ansible works.
                The graphic on this slide shows the relationship between all the main pieces of Ansible, starting with the user who writes an Ansible playbook.
              </p>
            </aside>
        </section>

        <section>
          <h2>MODULES</h2>
          <p><font color="52AAAC"><strong>Modules are bits of code transferred to the target system and executed to satisfy the task declaration.</strong></font><br></p>
          <div style="float: left; width: 50%;">
          <ul>
          <li>apt/yum</li>
          <li>copy</li>
          <li>file</li>
          <li>get_url</li>
          <li>git</li>
          <li>ping</li>
          <li>debug</li>
          </ul>
          </div>
          <div style="float: right; width: 50%;">
          <ul>
          <li>service</li>
          <li>synchronize</li>
          <li>template</li>
          <li>uri</li>
          <li>user</li>
          <li>wait_for</li>
          <li>assert</li>
          </ul>
          </div>
          <aside class="notes">
            <p>We talked a bit about modules in the previous couple slides, but I did want to point out a list of some commonly used modules that you may see out in example repos, blog posts, etc. a fair amount.
              Typically, you're going to see a lot of package management modules being used, lots of file modules like copy and file, but as mentioned previously, there are tons more as well.</p>
          </aside>
        </section>

        <section>
            <h2>MODULES</h2>
            <p><img src="images/module_index.jpg"></p>
            <p><font color="52AAAC"><strong>https://docs.ansible.com/ansible/latest/modules/modules_by_category.html</strong></font><br></p>
            <aside class="notes">
              <p>You can check out all of them by looking at the exhaustive module index on docs.ansible.com.
                They’re broken down by category, so you can more easily find what you need.
                I would highly recommend bookmarking this page!
              </p>
            </aside>
        </section>

        <section>
          <h2>MODULES: RUN COMMANDS</h2>
          <p><font color="52AAAC"><strong>If Ansible doesn’t have a module that suits your needs there are the “run command” modules:</strong></font><br><br></p>
          <ul>
            <li><strong>command:</strong> Takes the command and executes it. The most secure and predictable.</li>
            <li><strong>shell:</strong> Executes through a shell like /bin/sh so you can use pipes etc. Be careful.</li>
            <li><strong>script:</strong> Runs a local script on a remote node after transferring it.</li>
            <li><strong>raw:</strong> Executes a command  without going through the Ansible module subsystem.</li>
          </ul>
          <br>
            <p><strong>NOTE:</strong> Unlike standard modules, run commands have no concept of desired state and should only be used as a last resort</p>
          <aside class="notes">
            <p>On this slide we’re gonna discuss the command and shell modules which are super useful because you can execute commands with them on your remote nodes.
              The only big difference is that the command is not processed through the shell so redirect options and certain variables won’t work.
              If you need those, just use the shell module instead.
              The command modules let you run networking commands with Ansible, the same way a network engineer would type them on the command line.

              If you have something that’s not a core module or you haven't written a custom one, you can utilize the script module.
              For example, if you want to push out a homegrown script, you can do that here.

              We also have the raw module, which issues a pure SSH command and bypasses the python module mechanism.
              This is handy if you’re talking to a machine that doesn’t have python (for example, a server that’s running Windows!).
            </p>
          </aside>
        </section>

        <section>
          <h2>AD-HOC COMMANDS</h2>
          <pre class="language-yaml"><code data-noescape>
            # check all my inventory hosts are ready to be managed by Ansible
            $ ansible all -m ping

            # run the uptime command on all hosts in the web group
            $ ansible web -m command -a “uptime”

            # collect and display the discovered for the localhost
            $ ansible localhost -m setup
          </code></pre>
          <aside class="notes">
            <p>We’re going to transition right into ad-hoc commands from the commands modules because often times, you utilize command/shell to issue one-off commands to your hosts.
              This is essentially what ad-hoc commands are; just quick checks on your servers that you don’t want to preserve in an Ansible playbook.
              The examples here are pretty typical.
                Our first example is just checking whether we have connectivity with the host by issuing the ping command (I do this all the time to make sure everything is responding).
                In the second example here, you can see the command to check the uptime on the two servers in my web group using the command module.
                And lastly, the third example is gathering facts about our local machine which would yield the information that you can use for conditionals and variables and whatnot.
                [a bit of the output is shown on next slide]
            </p>
          </aside>
        </section>

        <section>
          <h2>SIDEBAR: DISCOVERED FACTS</h2>
          <pre class="language-yaml"><code data-noescape>
$ ansible localhost -m setup
localhost | success >> {
	"ansible_facts": {
    	"ansible_default_ipv4": {
        	"address": "192.168.1.37",
        	"alias": "wlan0",
        	"gateway": "192.168.1.1",
        	"interface": "wlan0",
        	"macaddress": "c4:85:08:3b:a9:16",
        	"mtu": 1500,
        	"netmask": "255.255.255.0",
        	"network": "192.168.1.0",
        	"type": "ether"
    	},
          </code></pre>
          <aside class="notes">
            <p>This is just a small sampling of what’s gathered from that setup ad hoc command.</p>
          </aside>
        </section>

        <section>
          <h2>INVENTORY</h2>
          <p>Inventory is a collection of hosts (nodes) against which Ansible can work with.</p>
          <ul>
            <li>Hosts</li>
            <li>Groups</li>
            <li>Inventory-specific data (variables)</li>
            <li>Static or dynamic sources</li>
          </ul>
          <aside class="notes">
            <p>Ad-hoc commands and modules always come back to the inventory we’re managing.  Inventory consists of hosts, groups, inventory specific data, and whether it’s static or dynamic sources. Note that “hosts” has been expanded overtime to include network devices, containers and virtually anything else that is network-addressable.</p>
          </aside>
        </section>

        <section>
          <h2>STATIC INVENTORY EXAMPLE</h2>
          <pre class="language-yaml"><code data-noescape>
            10.42.0.2
            10.42.0.6
            10.42.0.7
            10.42.0.8
            10.42.0.100
          </code></pre>
          <aside class="notes">
            <p>This is a free-form static inventory listed by IP address. If I clean that up a bit, I get...</p>
          </aside>
        </section>

        <section>
          <h2>STATIC INVENTORY EXAMPLE</h2>
          <pre class="language-yaml"><code data-noescape>
            [control]
            control ansible_host=10.42.0.2

            [web]
            node-1 ansible_host=10.42.0.6
            node-2 ansible_host=10.42.0.7
            node-3 ansible_host=10.42.0.8

            [haproxy]
            haproxy ansible_host=10.42.0.100

            [all:vars]
            ansible_user=vagrant
            ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key
          </code></pre>
          <aside class="notes">
            <p>...a host file that’s separated into groups (which in this example is control, web, and haproxy).
              We also have some inventory-specific data where we’re defining ansible_host for each of these different nodes, and we’ve got a vars section defined for all the hosts where we’re setting the connecting user.
              There’s also a path to the private key file we’re using for authentication.</p>
          </aside>
        </section>

        <section>
          <h2>STATIC INVENTORY EXAMPLE IN YAML</h2>
          <pre class="language-yaml"><code data-noescape>
            all:
              vars:
                ansible_user: vagrant
                ansible_ssh_private_key_file: ~/.vagrant.d/insecure_private_key

              children:
                web:
                  hosts:
                    node-1:
                      ansible_host: 10.42.0.6
                    node-2:
                      ansible_host: 10.42.0.7
                    node-3:
                      ansible_host: 10.42.0.8
          </code></pre>
          <aside class="notes">
            <p>This is a similar example of the same hosts file in YAML format which is a new option as of version 2.4.
              This provides some flexibility in regards to the format you might find easier to work with.</p>
          </aside>
        </section>

        <section>
          <h2>VARIABLES</h2>
          <p>Ansible can work with metadata from various sources and manage their context in the form of variables.</p>
          <ul>
            <li>Command line parameters</li>
            <li>Plays and tasks</li>
            <li>Files</li>
            <li>Inventory</li>
            <li>Discovered facts</li>
            <li>Roles</li>
          </ul>
          <aside class="notes">
            <p>To go into a little more detail, variables in Ansible are used to account for differences between servers.
              By using variables, I have the ability to keep a nice layer of abstraction in my playbook and define my variables as needed in various host or group vars files.
              These could be for things like facts or file paths or package versions.</p>
          </aside>
        </section>

        <section>
          <h2>VARIABLE PRECEDENCE</h2>
          <p><font color="52AAAC"><strong>The order in which the same variable from different sources will override each other:</strong></font><br></p>
          <div style="float: left; width: 50%;">
          <ol>
          <li>Extra vars</li>
          <li>Set_facts/Registered vars</li>
          <li>Include_vars</li>
          <li>Include_params</li>
          <li>Role params</li>
          <li>Task vars (only for the task)</li>
          <li>Block vars (only for tasks in the block)</li>
          <li>Role vars</li>
          <li>Play vars_files</li>
          <li>Play vars_prompt</li>
          <li>Play vars</li>
          </div>
          <div style="float: right; width: 50%;">
          <ol start="12">
          <li>Host facts</li>
          <li>Playbook host_vars</li>
          <li>Inventory host_vars</li>
          <li>Inventory file/script host vars</li>
          <li>Playbook group_vars</li>
          <li>Inventory group_vars</li>
          <li>Playbook group_vars/all</li>
          <li>Inventory group_vars/all</li>
          <li>Inventory file or script group vars</li>
          <li>Role defaults</li>
          </ol>
          </div>
          <aside class="notes">
            <p>This brings up a good time to talk about variable precedence, which is basically the order in which the same variables will override each other.
              The latest version has 21 levels of variable precedence wherein extra_vars will always take precedence and role_defaults will get overwritten by all of these other var types.</p>
          </aside>
        </section>

        <section>
          <h2>TASKS</h2>
          <p><font color="52AAAC">Tasks are the application of a module to perform a specific unit of work.</font><br><br></p>
          <ul>
            <li><strong>file:</strong>A directory should exist</li>
            <li><strong>yum:</strong>A package should be installed</li>
            <li><strong>service:</strong>A service should be running</li>
            <li><strong>template:</strong>Render a configuration file from a template</li>
            <li><strong>get_url:</strong>Fetch an archive file from a URL</li>
            <li><strong>git:</strong>Clone a source code repository</li>
          </ul>
          <aside class="notes">
            <p>Just to recap, so far we’ve talked about acting against inventory with modules, but those modules are going to be contained in things called tasks.
              These are simple and declarative, because we’re telling the module to do something specific like (give examples from slide of things the modules will do within the tasks).
            </p>
          </aside>
        </section>

        <section>
          <h2>EXAMPLE TASKS IN A PLAY</h2>
          <pre class="language-yaml"><code data-noescape>
tasks:
- name: add cache in directory
  file:
    path: /opt/cache
    state: directory

- name: install nginx
  yum:
    name: nginx
    state: latest

- name: restart nginx
  service:
    name: nginx
    state: restarted
          </code></pre>
          <aside class="notes">
            <p>In this example, the first task is called “add cache in directory”.
              Note that you can name it anything you'd like.
              Here we're going to call the file module and give it a couple of options.
              Our path is going to be opt/cache and the state is directory, meaning we're going to create the directory opt/cache.</p>
          </aside>
        </section>

        <section>
          <h2>HANDLER TASKS</h2>
          <p><font color="52AAAC"><strong>Handlers are special tasks that run at the end of a play if notified by another task.</strong></font><br><br></p>
          <aside class="notes">
            <p>Normal tasks run sequentially, handler tasks run on notification.
              Handlers may be notified multiple times during a single play, and are triggered when a tasks causes a change in state.
              If nothing notifies a handler, it will not run. Regardless of how many tasks notify a handler, it will run only once, after all of the tasks complete in a particular play.
            </p>
          </aside>
        </section>

        <section>
          <h2>EXAMPLE HANDLER IN A PLAY</h2>
          <pre class="language-yaml"><code data-noescape>
tasks:
  - name: add cache dir
	 file:
      path: /opt/cache
      state: directory

  - name: install nginx
    yum:
      name: nginx
      state: latest
    notify: restart nginx

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted
          </code></pre>
          <aside class="notes">
            <p>In this slide, we have an example of a handler in which after we install nginx, we add a notify to restart the services.
              Then, there’s a handlers section in which we define that handler.
              If the conditions to trigger the handler aren’t met, then the handler won’t run.
              Handlers may be notified multiple times during a single play, and are triggered when a task causes a change in state.
            </p>
          </aside>
        </section>

        <section>
          <h2>PLAYS & PLAYBOOKS</h2>
          <p><font color="52AAAC"><strong>Plays are ordered sets of tasks to execute against host selections from your inventory.
            A playbook is a file containing one or more plays.</strong></font><br><br></p>
          <aside class="notes">
            <p>All these things we’ve been talking about including tasks, handlers, modules, etc. are all part of what make up plays and playbooks.
            </p>
          </aside>
        </section>

        <section>
          <h2>PLAYBOOK EXAMPLE</h2>
          <pre class="language-yaml"><code data-noescape>
---
- name: install and start apache
  hosts: web
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root

  tasks:
  - name: install httpd
    yum: pkg=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
  - name: start httpd
    service: name=httpd state=started
          </code></pre>
          <aside class="notes">
            <p>We’re gonna break down what makes up a playbook and review what we’ve been talking about so far.
            </p>
          </aside>
        </section>

        <section>
          <h2>ROLES</h2>
          <p><font color="52AAAC"><strong>Roles are a packages of closely-related Ansible content that can be shared more easily than plays alone.</strong></font><br><br></p>
          <aside class="notes">
            <ul>
              <li>Improves readability and maintainability of complex plays</li>
              <li>Eases sharing, reuse and standardization of automation processes</li>
              <li>Enables Ansible content to exist independently of playbooks, projects -- even organizations</li>
              <li>Provides functional conveniences such as file path resolution and default values</li>
            </ul>
          <aside class="notes">
            <p>We’re gonna break down what makes up a playbook and review what we’ve been talking about so far.
            </p>
          </aside>
        </section>

        <section>
          <h2>PLAYBOOK EXAMPLE</h2>
          <pre class="language-yaml"><code data-noescape>
site.yml
roles/
   common/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
   webservers/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
          </code></pre>
          <aside class="notes">
            <p>This is how it looks from a project perspective.
              Not all of these directories need to be used, these are just standards that are available and ready to fill in with your tasks, handlers, variables, whatever you need for the particular role.
            </p>
          </aside>
        </section>

        <section>
          <h2>PLAYBOOK WITH ROLES EXAMPLE</h2>
          <pre class="language-yaml"><code data-noescape>
# site.yml
---
- hosts: web
  roles:
     - common
     - webservers
          </code></pre>
          <aside class="notes">
            <p>This is how you would call a role from the main playbook.
              It keeps everything simple and you can switch things out or delete easily without parsing through a huge list of tasks that you’ve made separately for every host type.
            </p>
          </aside>
        </section>

        <section>
            <h2>ANSIBLE GALAXY</h2>
            <p><img src="images/galaxy.jpg"></p>
            <aside class="notes">
              <p>If you’d like to check out our huge community site for Ansible roles, visit Galaxy.Ansible.com.
                You can sort through things by author name, stars, number of downloads, as well as other filters, and you can even share your own roles here as well.
              </p>
            </aside>
        </section>

        <section>
          <h2>WHERE TO FIND PLAYBOOK EXAMPLES</h2>
          <p><strong>General Examples:</strong></p>
          <p>https://github.com/ansible/ansible-examples</p>
          <p><strong>Lightbulb:</strong></p>
          <p>https://github.com/ansible/lightbulb/tree/master/examples</p>
          <p><strong>Ansible + Vagrant:</strong></p>
          <p>https://github.com/geerlingguy/ansible-vagrant-examples</p>
          <aside class="notes">
            <p>Here are some places where you can find some good playbook examples.</p>
          </aside>
        </section>

        <section>
          <h2>WHERE TO FIND PLAYBOOK EXAMPLES</h2>
          <p><strong>Would you like to learn Ansible?  It’s easy to get started:</strong></p>
          <p>ansible.com/get-started</p>
          <p><strong>Have you used Ansible already?  Try Tower for free:</strong></p>
          <p>ansible.com/tower-trial</p>
          <p><strong>Want to learn more?</strong></p>
          <p>ansible.com/whitepapers</p>
          <aside class="notes">
            <p>If you’d like to learn more about Ansible our Getting Started page is a great resource.
              Our documentation is also very thorough and well-written, so check that out as well.
              If you’re ready to try Tower you can visit our Tower Trial page, and you can also check out the whitepapers on our website!</p>
          </aside>
        </section>

        <section>
            <section data-state="title alt">
              <h1>Demo Time!</h1>
              <aside class="notes">
                <p></p>
              </aside>
            </section>
            <section data-state="title alt">
              <h1>Show a playbook written out?  Show roles?  Tower?</h1>
              <aside class="notes">
                <p>more speaker notes here for those deep dive slides</p>
              </aside>
            </section>
        </section>

        <section>
          <h1>Thank You!</h1>
        </section>
      </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/js/head.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/js/reveal.js"></script>

    <script>
      // More info https://github.com/hakimel/reveal.js#configuration
      Reveal.initialize({
        history: true,
        width: "85%",
        height: "90%",
        transition: "fade",

        // More info https://github.com/hakimel/reveal.js#dependencies
        // Notes plugin must remain local for now.
        // See https://github.com/ansible/lightbulb/issues/125
        dependencies: [
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/marked.js' },
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/markdown.js' },
          { src: 'plugin/notes/notes.js', async: true },
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js'},
          { src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-yaml.min.js'}
          //{ src: 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
        ]
      });
    </script>
  </body>
</html>


================================================
FILE: decks/contributing-to-ansible.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>Contributing to Ansible</title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/reveal.css">

    <!-- Printing and PDF exports -->
    <script>
      var link = document.createElement( 'link' );
      link.rel = 'stylesheet';
      link.type = 'text/css';
      link.href = window.location.search.match( /print-pdf/gi ) ? 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/pdf.css' : 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/print/paper.css';
      document.getElementsByTagName( 'head' )[0].appendChild( link );
    </script>


    <link rel="stylesheet" href="css/theme/ansible.css">

    <!-- Theme used for syntax highlighting of code -->
    <!--link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/css/zenburn.css"-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/themes/prism.min.css">


  </head>
  <body>
  <div class="ans-mark">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-449 450 125 125" style="enable-background:new -449 450 125 125;" xml:space="preserve">
      <g id="XMLID_3_">
        <circle id="XMLID_7_" class="circle" cx="-386.5" cy="512.5" r="62"/>
        <path id="XMLID_4_" class="a-mark" d="M-356.9,537.1l-24.7-59.4c-0.7-1.7-2.1-2.6-3.9-2.6c-1.7,0-3.2,0.9-4,2.6l-27.1,65.2h9.2 l10.7-26.9l32,25.9c1.3,1,2.2,1.5,3.4,1.5c2.4,0,4.6-1.8,4.6-4.5C-356.5,538.5-356.6,537.8-356.9,537.1z M-385.4,488.4l16.1,39.6 l-24.2-19L-385.4,488.4z"/>
      </g>
    </svg>
  </div>
    <div class="reveal">
      <div class="slides">
        <section data-state="cover">
          <p class="ans-logo"><img src="images/ansible-wordmark-white.svg" width="260" alt="" /></p>
          <h1>Contributing to Ansible</h1>
          <p><a href="https://docs.ansible.com/ansible/devel/community">docs.ansible.com/ansible/devel/community</a></li>
          <aside class="notes">
              <ul>
                  <li>Thank you for taking the time</li>
                  <li>Recorded, email video inc slides, linked from the URL on screen</li>
                  <li>Please keep the questions coming, we hope for this to be interactive</li>
              </ul>
          </aside>
         </section>

        <section data-state="cover">
            <h2>Who am I?</h2>
            <code><pre class="language-yaml">
  - name: John Barker
    aliases: gundalow
    title: Principal Software Engineer
    org: Ansible, by Red Hat
    start_date: 2016
    roles:
      - community
      - core
    freenode: gundalow
    github: gundalow
    twitter: the_gundalow
    email: gundalow@redhat.com
          </pre></code>
          <aside class="notes">
              <ul>
                <li>That's me, what about you</li>
                <li>Poll results</li>
                <!--
                <li>SHOW OF HANDS: Who's just starting out with Ansible</li>
                <li>SHOW OF HANDS: Who has a complex system that they want to simplify</li>
                <li>SHOW OF HANDS: Who's got more they want to automate with Ansible</li>
                <li>SHOW OF HANDS: Who's a contributor - raised PRs (modules, bugs, docs) - Thank you</li>
                <li>SHOW OF HANDS: Who considers themselves an expert? - Excellent, you can answer the difficult Q&A at the end</li>
                -->
              </ul>

          </aside>
        </section>

        <section class="text-center" data-state="cover">
          <h2>THE ANSIBLE COMMUNITY</h2>
          <p style="text-align: left;">The humans who get involved, even once, make us stronger</p>
          <p style="text-align: left;">We will cover:</p>
          <ol>
              <li>Scale and skill set - what <i>you</i> can bring</li>
              <li>Opportunities to help</li>
              <li>Issue &amp; PR workflow</li>
              <li>How to review PRs</li>
              <li>How to join the conversation and shape the future</li>
          </ol>
          <aside class="notes">
              <ul>
                  <li>Everybody watching joining in today knows things that can help us improve, share that knowledge.</li>
                  <li>Aiming to show you the next steps you can take</li>
                  <li>Briefly cover this topics, and show where to get further info</li>
                  <li>Again, please use the chat and Q&amp;A features</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
            <p><a href="https://docs.ansible.com/ansible/devel/community/">docs.ansible.com/ansible/devel/community</a></p>
          <aside class="notes">
              <ul>
                  <li>A lot of what we will go through today is explained in more detail on here</li>
                  <li>Notice the URL /devel/</li>
                  <li>Again, we will send out video and slides</li>
                  <li>Talk through the sections, grouped by persona/activity</li>
                  <li>Show maillist/IRC page /communication.html</li>
                  <li>So now we know where the docs are, let's first clear some of the myths</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Myth #1: I can’t contribute because I’m not a programmer.</h2>
          <ul>
              <li>Can’t code (in Python)? No problem!</li>
              <li>Module docs are YAML - You know YAML</li>
              <li>Testing changes doesn't (necessarily) require you to understand <i>how</i> it works</li>
              <li>Bug reports &amp; confirm fixes</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>One of the biggest myths</li>
                  <li></li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Myth #2: I'm brand new to Ansible, I can't contribute</h2>
          <ul>
              <li>Think you have no knowledge to share? Think again!</li>
              <li>New users can tell us how well the documentation is working</li>
              <li>Provide feedback test, review, report bugs</li>
              <li>If you’re new to Ansible, you have fresh eyes - keep us honest</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>Once you’ve learned something, it’s hard to remember how you thought before you learned it. So new users are a vital link in the documentation chain. If you’re learning Ansible and you find something confusing, that’s important information. I guarantee you’re not the only one. You can help make the documentation better, for yourself and for the next new person. </li>
                  <li>Soon enough, you’ll be an experienced Ansible user, and you’ll need someone else to remind you what it was like to learn.</li>
                  <li>See something confusing, Fix it there and then, Edit on GitHub</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Myth #3: I don't know Git or GitHub</h2>
          <ul>
              <li>Scared of source control? Fear not!</li>
              <li>docs.ansible.com - "Edit on GitHub"</li>
              <li>You can directly from GitHub.com - demo later</li>
              <!-- FIXME: Image of bot/guidance -->
              <li>Worst case you make a mess of your PR - Ansibullbot will guide you</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>If you don’t work with git on a daily basis, it can be intimidating to fork a repo, create a branch, commit a change, and open a pull request. Fortunately, for docs changes, GitHub can do most of the work for you. </li>
                  <li>Contributing is a good way to learn Git &amp; GitHub</li>
                  <li>Demo - We can see just how easy this is</li>
                  <li>Lots of people have issues rebasing, Bot will help you </li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Myth #4: Writing tests is difficult</h2>
          <ul>
              <li>Integration tests are just Playbooks</li>
              <li>Extending a test case is generally fairly straight forward</li>
              <li>Gives us confidence to merge PRs</li>
              <li>Help us stop regressions</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li></li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Myth #5: I need to make a commitment to stay around and support what I've done</h2>
          <ul>
              <li>Drive-by contributions are welcome</li>
              <ul>
                  <li>Clarifies documentation</li>
                  <li>Fixes a bug</li>
                  <li>Add a test case.</li>
              </ul>
              <li>When adding new modules we look for some ongoing support</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>No throwing over the wall</li>
                  <li>Also applies to WG, talk more later</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Myths: Proof</h2>
          <ul>
          <aside class="notes">
              <ul>
                  <li><a href="https://github.com/ansible/ansible/pull/4947/files">Gundalow's first PR</a> <a href="https://github.com/ansible/ansible/pull/6826/files">2nd</a></li>
                  <li>If you look at some of my first PRs, you can see me failing to get a clean PR after not rebasing correctly</a>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Scaling: The power of Community</h2>
          <ul>
              <li>The philosophical perspective, collectively we know everything</li>
              <li>Some of us know lots of things</li>
              <li>Some of us know very little</li>
              <li>Collectively we know everything</li>
              <li>Allows <b>you</b> to set direction</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>The Ansible community is awesome... generous, engaged, knowledgeable, supportive. </li>
                  <li>Individually, we may know a little or a lot. But collectively, we know everything about Ansible.</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Scaling: The power of Community</h2>
          <p style="text-align: left;"><b>Community</b> is the <b>force multiplier</b>.</p>
          <p style="text-align: left;"><b>You</b> are the <b>community</b>.</p>

          <aside class="notes">
              <ul>
                  <li>We are a friendly and welcoming community.</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Scaling: Core Teams remit</h2>
          <ul>
              <li>The Ansible Core Team focus on the Engine and main modules</li>
              <li>Core: 300 modules</li>
              <li>Community: 2000 modules</li>
              <li>Reviewing Community issues &amp; PRs are the communities responsibility</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>Core Team is focusing on the Core Engine and language features</li>
                  <li>Ansible is a plugin engine, that's what helps us scale</li>
                  <li>Don't expect the guy in the sky (someone with authority) to do reviews</li>
                  <li>We want to empower the community</li>
              </ul>
          </aside>
        </section>
<!--
        <section class="text-center">
          <h2>Scaling: Proof that it works</h2>
          <ul>
              <li>FIXME: Insert Docker graph here</li>
              <li>Add some details</li>
              <li>Not just about PRs merged, it's about the whole community benefiting - Improved Docs, integration tests to give us confidence in future work</li>
              <li>Confidence that Ansible does what it needs to do</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>Notice backlog ($COLOUR) drops, so the backlog is reducing</li>
                  <li>Number of Issues &amp; PRs ($COLOUR), increases</li>
              </ul>
          </aside>
        </section>
-->
<!-- PAUSE -->
        <section class="text-center">
          <p>Pause for questions</p>
          <aside class="notes">
              <ul>
                  <li></li>
              </ul>
          </aside>
        </section>
<!-- Ansible's Development Process -->

<!-- FIXME Show actual examples of issues and PRs
* Really good description of problem, shows error message

* PR: Has link to issue (for context and shows GH project management)
* Issues & PR can be document as well as units of our working life

* Talk about GH Labels, move slide here
-->
        <section class="text-center" data-state="cover">
          <h2>GitHub Issues and PRs</h2>
        </section>

        <section class="text-center">
          <h2>GitHub Issues and PRs</h2>
          <ul>
              <li>GitHub Issues/PRs or it never happened</li>
              <li>Issues</li>
              <ul>
                  <li>Bug reports and feature ideas - Details</li>
                  <li>Discussion before implementation starts</li>

              </ul>
              <li>Pull Requests (PRs)</li>
              <ul>
                  <li>Improve a one thing: Fix <b>a</b> bug/feature</li>
                  <li>Always use feature branches</li>
              </ul>
              <li>If you know the fix, just create a PR</li>
              <li>HELP: <a href="https://lab.github.com">lab.github.com</a>, <a href="https://guides.github.com">guides.github.com</a></li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>How everything is tracked</li>
                  <li>Mail lists, Twitter, etc are good for discussion. Though unless it ends up in GitHub it will not be done</li>
                  <li>Not for discussion, use the email lists, IRC, stack overflow, for that. Remember /communication.html we showed earlier</li>
                  <li>Bugs cannot be triaged without steps to reproduce + details on expected / actual results</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Ansible's Development Process</h2>
          <ol>
              <li>Triage</li>
              <li>Cycle: Fix tests, get reviews, address review comments</li>
              <li>Merged</li>
              <li>Backport bug fixes [optional]</li>
          </ol>
          <aside class="notes">
              <ul>
                  <li>Showing PR process. Issues is similar, though simpler</li>
                  <li>PRs often get stuck due to lack of reviews</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Development Process: PR Life Cycle Demo</h2>
          <aside class="notes">
              <ul>
                  <li><a href="https://github.com/ansible/ansible/pull/46151">#46151</a></li>
                  <li>Description</li>
                  <li>Labels: Added by Bot, scale &amp; search, explain each of them</li>
                  <li>Maintainers pinged</li>
                  <li>Details of manual testing: (1st Nov 2018)</li>
                  <li>Review Cycle: Back and forth to fix issues</li>
                  <li>Every one should be willing to do review, so lets talk about how to find PRs and review them</li>
              </ul>
          </aside>
        </section>

<!-- PAUSE -->
        <section class="text-center">
          <p>Pause for questions</p>
          <aside class="notes">
              <ul>
                  <li></li>
              </ul>
          </aside>
        </section>

        <section data-state="cover">
            <h2>Who am I?</h2>
            <code><pre class="language-yaml">
  - name: Alicia Cozine
    title: Lead Technical Writer
    org: Ansible, by Red Hat
    start_date: 2018
    roles:
      - docs
      - core
      - community
    freenode: acozine
    github: acozine
    email: acozine@redhat.com
          </pre></code>
        </section>

        <section class="text-center">
          <h2>Documentation Demo</h2>
          <p><a href="https://docs.ansible.com/ansible/devel/community/documentation_contributions.html">docs.ansible.com/ansible/devel/community/documentation_contributions.html</a></p>
          <p><a href="https://github.com/ansible/community/wiki/Docs">github.com/ansible/community/wiki/Docs</a> Docs Working Group</p>
          <aside class="notes">
              <ul>
                  <li>How to fix an Docs issue</li>
                  <li>Example of docs Working Group</li>
              </ul>
          </aside>
        </section>

<!-- PAUSE -->
        <section class="text-center">
          <p>Pause for questions</p>
          <aside class="notes">
              <ul>
                  <li></li>
              </ul>
          </aside>
        </section>



        <section class="text-center">
          <h2>Development Process: Finding Issues &amp; PRs</h2>
          <ul>
              <li>GitHub Labels</li>
              <ul>
                  <li><a href="https://github.com/ansible/ansible/labels">github.com/ansible/ansible/labels</a></li>
                  <li>bug, feature, module, test, plugin</li>
                  <li>Labels for each Working Group</li>
                  <li>lib/modules/cloud/docker/docker_image = [module, cloud, docker]</li>
              </ul>
              <li><a href="https://ansible.sivel.net/pr/byfile.html">ansible.sivel.net/pr/byfile.html</a></li>
              <ul>
                  <li>Search by filename (or directory) to find PRs</li>
                  <li>Great for finding related PRs</li>
              </ul>
              <li><a href="https://github.com/ansible/community/wiki">github.com/ansible/community/wiki</a></li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>As we talked about earlier, review Issues and PRs, with whatever skills you bring <b>is</b> really useful, so where do <b>you</b> start</li>
                  <li>FIXME: Give some useful links that people can use small_patch, bug+is:pr</li>
                  <li><a href="https://github.com/ansible/ansible/labels">labels -> AIX</a> </li>
                  <li><a href="https://ansible.sivel.net/pr/byfile.html">ansible.sivel.net/pr/byfile.html</a></li>
              </ul>
          </aside>
        </section>
<!-- START: PR Review -->


<!-- Need to flesh this out -->

        <section class="text-center">
          <h2>Development Process: Aims of reviews</h2>
          <ul>
              <li>We need confidence before code can be merged</li>
              <li>We need user feedback to tell us if this is right</li>
              <li>PR Backlog size due to lack of review - WG &amp; <a href="https://github.com/ansible/community/issues/407">Big PR Review Day 2019-02-21</a></li>
              <li>Anyone can help with this</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>Previously mentioned, any skill set can help</li>
                  <li>Community <a href="https://github.com/ansible/community/issues/407">PR review days</a>, 2019-02-21</li>
                  <li>First point sums up why PRs don't get merged</li>
                  <li>Testing (manual/automated) gives us confidence</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Development Process: Types of review</h2>
          <p style="text-align: left;">Whatever your skill set, you can help with at least one of these:</p>
          <ol>
              <li>Functional review</li>
              <li>Documentation reviews</li>
              <li>Code reviews</li>
          </ol>
          <aside class="notes">
              <ul>
                  <li>One thing I think is often overlooked here is that you don't need to be a programmers, or have any understanding of the internals to do a functional or documentation review.</li>
                  <li>We know the "how to review" parts of Ansible's Docs need some work, what would you like to see there? - give comments in Chat or join in #ansible-community</li>
                  <li>I accept some of this is subjective, so we are looking for a net improvement</li>
              </ul>
          </aside>
        </section>


        <section class="text-center">
          <h2>Reviews #1: Functional Reviews</h2>
          <ul>
             <li>Does it work?</li>
             <li>Address a use case you have?</li>
             <li>Does it break any edge/use case you have?</li>
             <li>Is the interface clear</li>
          </ul>
          <aside class="notes">
              <ul>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Reviews #2: Documentation Reviews</h2>
          <ul>
              <li>Are the docs clear, is there any ambiguity?</li>
              <li>Do the examples work?</li>
              <li>Is there any missing knowledge?</li>
              <li>Feedback from newer user is really important</li>
          </ul>
          <aside class="notes">
              <ul>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Reviews #3: Code Reviews</h2>
          <ul>
              <li>Best use of existing APIs</li>
              <li>Following the "the Ansible way" (variable names, etc.)</li>
              <li>Honor Ansible's coding guidelines?</li>
              <li>Follow the CRUD principles (Create, Read, Update, Delete)?</li>
          </ul>
          <aside class="notes">
              <ul>
              </ul>
          </aside>
        </section>







        <section class="text-center">
          <h2>Development Process: How to review</h2>
          <ul>
              <li>Three part review:</li>
              <ol>
                  <li>Is the idea behind the contribution sound?</li>
                  <li>Is the contribution architected correctly?</li>
                  <li>Is the contribution polished?</li>
              </ol>
              <li>Be mindful:</li>
              <ul>
                  <li>Go above and beyond to promote a collaborative and respectful community</li>
                  <li>"Would this be clearer if..." - invites discussion</li>
                  <li>Avoid bikeshedding. Ansible's coding guidelines is enforced by CI. </li>
              </ul>
          </ul>
          <aside class="notes">
              <ul>
                  <li>Reviewing PRs is one of the most beneficial things to do</li>
                  <li>Blog: <a href="https://sage.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/">The Gentle Art of Patch Review</a></li>
                  <li>contribution sound? - Clear, consistent user interface</li>
                  <li>polished? - Docs, Tests, etc</li>
                  <li>Mindful</li>
                  <li>We know the "how to review" parts of Ansible's Docs need some work, what would you like to see there? - give comments in Chat or join the discussion in #ansible-community</li>
              </ul>
          </aside>
        </section>

<!--
    We saw an example as part of https://github.com/ansible/ansible/pull/46151
        <section class="text-center">
          <h2>Development Process: How to review - example</h2>
          <ul>
              <li>FIXME: Screenshot/code-snippit of a good feedback</li>
              <li>FIXME: Details of what and how it was tested, mindful comments</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>So lets see this in action</li>
              </ul>
          </aside>
        </section>
-->
<!-- END: PR Review -->

<!-- STAR: WORKING GROUPS -->

        <section class="text-center">
          <h2>Working Groups: List</h2>
          <ul>
              <li>General: Community, Core, Documentation, Testing</li>
              <li>Cloud Providers and VMs: AWS, Azure, Docker, Linode, VMware</li>
              <li>Network</li>
              <li>Operating Systems: AIX, BSD, HP-UX, Linux, Solaris, Windows</li>
              <li>Related projects: ansible-lint, AWX (Tower), Galaxy, Molecule</li>
              <li>Plus many more...</li>
              <li>Full list: <a href="https://github.com/ansible/community/wiki">github.com/ansible/community/wiki</a></li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>BROWSER: <a href="https://github.com/ansible/community/wiki">github.com/ansible/community/wiki</a></li>
                  <li>We've mentioned this a few times, but what are they?</li>
                  <li>Some are cross-functional: Core, Community, Docs, Testing,</li>
                  <li>Mention <b>each</b> WG one by one, saying what they are working on/achieved</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Working Groups: Purpose</h2>
          <p style="text-align: left;">Are you willing to help advance the thing that is obviously stuck and needs people united in order to get unstuck</p>
          <ul>
              <li>Focused effort on a specific topic</li>
              <li>Help build communities</li>
              <li>Allows people closer to the technology to set direction</li>
              <li>Make Ansible do what <b>you</b> want, solve <b>your</b> challenges</li>
              <li>Empowers
          </ul>
          <aside class="notes">
              <ul>
                  <li>We've mentioned this a few times, but what are they?</li>
                  <li>Distributed across the globe, like Ansible's Core Team</li>
                  <li>We are looking for people interested in making/helping build communities around technologies, as Ansible is huge, it's impossible to leave this up to one person, or a core Ansible team</li>
              </ul>
          </aside>
        </section>

        <section class="text-center">
          <h2>Working Groups: How?</h2>
          <ul>
              <li>Mix of skill sets required</li>
              <li>Maybe spread across the globe</li>
              <li>Communicate via GitHub Issues/PRs/Wiki</li>
              <li>May have a dedicated IRC channel</li>
              <li>May have IRC Meetings (recorded)</li>
              <li>No regular commitment required</li>
              <li>I can help you set this up</li>
          </ul>
          <aside class="notes">
              <ul>
                  <li>Not asking for n-hours a week </li>
                  <li>As specially early on even a small amount of time makes a huge benefit, low hanging fruit</li>
                  <li>Feel free to message me directly, we have ideas of other groups</li>
              </ul>
          </aside>
        </section>





<!-- END: WORKING GROUPS -->





        <section>
            <h2>Recap</h2>
            <ul>
                <li><a href="https://docs.ansible.com/ansible/devel/community">docs.ansible.com/ansible/devel/community</a> Community guides</li>
                <li><a href="https://github.com/ansible/community/wiki">github.com/ansible/community/wiki</a> Join a working Group</li>
                <li><a href="https://github.com/ansible/community/issues/407">github.com/ansible/community#407</a> Big PR Review Day 2019-02-21</li>
                <li><a href="https://ansible.com/events">ansible.com/events</a>, <a href="https://ansible.meetup.com">ansible.meetup.com</a></li>
                <li><a href="https://ansible.com/ansiblefest">ansible.com/ansiblefest</a> Ansible Fest Atlanta 24-26 Sept 2019</li>
                <li><a href="mailto:gundalow@redhat.com">gundalow@redhat.com</a> &amp; <a href="mailto:acozine@redhat.com">acozine@redhat.com</a> for feedback, help or mentoring</li>
            </ul>
          <aside class="notes">
          </aside>
        </section>
        <section>
            <h2>Thank You!</h2>
            <ul>
                <li><a href="https://docs.ansible.com/ansible/devel/community">docs.ansible.com/ansible/devel/community</a> Community guides</li>
                <li><a href="https://github.com/ansible/community/wiki">github.com/ansible/community/wiki</a> Join a working Group</li>
                <li><a href="https://github.com/ansible/community/issues/407">github.com/ansible/community#407</a> Big PR Review Day 2019-02-21</li>
                <li><a href="https://ansible.com/events">ansible.com/events</a>, <a href="https://ansible.meetup.com">ansible.meetup.com</a></li>
                <li><a href="https://ansible.com/ansiblefest">ansible.com/ansiblefest</a> Ansible Fest Atlanta 24-26 Sept 2019</li>
                <li><a href="mailto:gundalow@redhat.com">gundalow@redhat.com</a> &amp; <a href="mailto:acozine@redhat.com">acozine@redhat.com</a> for feedback, help or mentoring</li>
            </ul>
          <aside class="notes">
          </aside>
        </
Download .txt
gitextract_ofkpwayz/

├── .gitignore
├── .mdlrc
├── .travis.yml
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── PHILOSOPHY.md
├── README.md
├── Vagrantfile
├── _config.yml
├── _layouts/
│   └── default.html
├── assets/
│   └── css/
│       ├── ansible.css
│       └── style.scss
├── decks/
│   ├── README.md
│   ├── ansible-best-practices.html
│   ├── ansible-essentials.html
│   ├── ansible_basics.html
│   ├── contributing-to-ansible.html
│   ├── css/
│   │   └── theme/
│   │       └── ansible.css
│   ├── intro-to-ansible-tower.html
│   ├── plugin/
│   │   └── notes/
│   │       ├── notes.html
│   │       └── notes.js
│   └── your_first_pb.html
├── examples/
│   ├── README.md
│   ├── apache-basic-playbook/
│   │   ├── README.md
│   │   ├── site.yml
│   │   └── templates/
│   │       ├── httpd.conf.j2
│   │       └── index.html.j2
│   ├── apache-role/
│   │   ├── README.md
│   │   ├── roles/
│   │   │   └── apache-simple/
│   │   │       ├── defaults/
│   │   │       │   └── main.yml
│   │   │       ├── handlers/
│   │   │       │   └── main.yml
│   │   │       ├── tasks/
│   │   │       │   └── main.yml
│   │   │       ├── templates/
│   │   │       │   ├── httpd.conf.j2
│   │   │       │   └── index.html.j2
│   │   │       └── vars/
│   │   │           └── main.yml
│   │   └── site.yml
│   ├── apache-simple-playbook/
│   │   ├── README.md
│   │   ├── files/
│   │   │   └── index.html
│   │   └── site.yml
│   ├── cloud-aws/
│   │   ├── README.md
│   │   ├── provision.yml
│   │   ├── setup.yml
│   │   └── site.yml
│   ├── nginx-basic-playbook/
│   │   ├── README.md
│   │   ├── site.yml
│   │   └── templates/
│   │       ├── index.html.j2
│   │       └── nginx.conf.j2
│   ├── nginx-remove-playbook/
│   │   ├── README.md
│   │   └── site.yml
│   ├── nginx-role/
│   │   ├── README.md
│   │   ├── remove.yml
│   │   ├── roles/
│   │   │   └── nginx-simple/
│   │   │       ├── defaults/
│   │   │       │   └── main.yml
│   │   │       ├── handlers/
│   │   │       │   └── main.yml
│   │   │       ├── tasks/
│   │   │       │   ├── main.yml
│   │   │       │   └── remove.yml
│   │   │       ├── templates/
│   │   │       │   ├── index.html.j2
│   │   │       │   └── nginx.conf.j2
│   │   │       └── vars/
│   │   │           └── main.yml
│   │   └── site.yml
│   └── nginx-simple-playbook/
│       ├── README.md
│       ├── files/
│       │   └── index.html
│       └── site.yml
├── facilitator/
│   ├── README.md
│   └── solutions/
│       ├── adhoc_commands.md
│       ├── ansible_install.md
│       ├── basic_playbook.md
│       ├── roles.md
│       ├── simple_playbook.md
│       ├── tower_basic_setup.md
│       └── tower_install.md
├── guides/
│   ├── README.md
│   ├── ansible_engine/
│   │   ├── 1-adhoc/
│   │   │   └── README.md
│   │   ├── 2-playbook/
│   │   │   └── README.md
│   │   ├── 3-variables/
│   │   │   └── README.md
│   │   ├── 4-role/
│   │   │   └── README.md
│   │   └── README.md
│   └── ansible_tower/
│       ├── 1-install/
│       │   └── README.md
│       ├── 2-config/
│       │   └── README.md
│       ├── 3-create/
│       │   └── README.md
│       └── README.md
├── tools/
│   ├── aws_lab_setup/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── aws-directions/
│   │   │   └── AWSHELP.md
│   │   ├── inventory/
│   │   │   ├── ec2.ini
│   │   │   ├── ec2.py
│   │   │   └── group_vars/
│   │   │       └── all.yml
│   │   ├── provision_lab.yml
│   │   ├── roles/
│   │   │   ├── common/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── handlers/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── tasks/
│   │   │   │   │   ├── RedHat.yml
│   │   │   │   │   ├── Ubuntu.yml
│   │   │   │   │   └── main.yml
│   │   │   │   └── vars/
│   │   │   │       ├── RedHat-6.yml
│   │   │   │       ├── RedHat-7.yml
│   │   │   │       ├── Ubuntu-14.yml
│   │   │   │       └── Ubuntu-16.yml
│   │   │   ├── control_node/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── tasks/
│   │   │   │   │   └── main.yml
│   │   │   │   └── templates/
│   │   │   │       ├── ansible.cfg.j2
│   │   │   │       └── vimrc.j2
│   │   │   ├── email/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   └── tasks/
│   │   │   │       └── main.yml
│   │   │   ├── manage_ec2_instances/
│   │   │   │   ├── defaults/
│   │   │   │   │   └── main.yml
│   │   │   │   ├── tasks/
│   │   │   │   │   ├── create.yml
│   │   │   │   │   ├── main.yml
│   │   │   │   │   ├── provision.yml
│   │   │   │   │   └── teardown.yml
│   │   │   │   ├── templates/
│   │   │   │   │   └── instances.txt.j2
│   │   │   │   └── vars/
│   │   │   │       └── main.yml
│   │   │   └── user_accounts/
│   │   │       ├── defaults/
│   │   │       │   └── main.yml
│   │   │       └── tasks/
│   │   │           └── main.yml
│   │   ├── sample-users.yml
│   │   └── teardown_lab.yml
│   ├── inventory_import/
│   │   ├── README.md
│   │   └── inventory_import.yml
│   └── lightbulb-from-tower/
│       └── README.md
└── workshops/
    ├── README.md
    ├── ansible_engine/
    │   ├── README.md
    │   ├── adhoc_commands/
    │   │   └── README.md
    │   ├── ansible_install/
    │   │   └── README.md
    │   ├── basic_playbook/
    │   │   ├── README.md
    │   │   └── resources/
    │   │       ├── index.html.j2
    │   │       └── nginx.conf.j2
    │   ├── roles/
    │   │   └── README.md
    │   └── simple_playbook/
    │       ├── README.md
    │       └── resources/
    │           └── index.html
    └── ansible_tower/
        ├── README.md
        ├── tower_basic_setup/
        │   └── README.md
        └── tower_install/
            └── README.md
Download .txt
SYMBOL INDEX (36 symbols across 2 files)

FILE: decks/plugin/notes/notes.js
  function openNotes (line 14) | function openNotes( notesFilePath ) {

FILE: tools/aws_lab_setup/inventory/ec2.py
  class Ec2Inventory (line 143) | class Ec2Inventory(object):
    method _empty_inventory (line 145) | def _empty_inventory(self):
    method __init__ (line 148) | def __init__(self):
    method is_cache_valid (line 191) | def is_cache_valid(self):
    method read_settings (line 204) | def read_settings(self):
    method parse_cli_args (line 416) | def parse_cli_args(self):
    method do_api_calls_update_cache (line 431) | def do_api_calls_update_cache(self):
    method connect (line 448) | def connect(self, region):
    method boto_fix_security_token_in_profile (line 457) | def boto_fix_security_token_in_profile(self, connect_args):
    method connect_to_aws (line 464) | def connect_to_aws(self, module, region):
    method get_instances_by_region (line 478) | def get_instances_by_region(self, region):
    method get_rds_instances_by_region (line 503) | def get_rds_instances_by_region(self, region):
    method get_elasticache_clusters_by_region (line 527) | def get_elasticache_clusters_by_region(self, region):
    method get_elasticache_replication_groups_by_region (line 563) | def get_elasticache_replication_groups_by_region(self, region):
    method get_auth_error_message (line 597) | def get_auth_error_message(self):
    method fail_with_error (line 614) | def fail_with_error(self, err_msg, err_operation=None):
    method get_instance (line 622) | def get_instance(self, region, instance_id):
    method add_instance (line 630) | def add_instance(self, instance, region):
    method add_rds_instance (line 779) | def add_rds_instance(self, instance, region):
    method add_elasticache_cluster (line 877) | def add_elasticache_cluster(self, cluster, region):
    method add_elasticache_node (line 976) | def add_elasticache_node(self, node, cluster, region):
    method add_elasticache_replication_group (line 1063) | def add_elasticache_replication_group(self, replication_group, region):
    method get_route53_records (line 1115) | def get_route53_records(self):
    method get_instance_route53_names (line 1141) | def get_instance_route53_names(self, instance):
    method get_host_info_dict_from_instance (line 1162) | def get_host_info_dict_from_instance(self, instance):
    method get_host_info_dict_from_describe_dict (line 1209) | def get_host_info_dict_from_describe_dict(self, describe_dict):
    method get_host_info (line 1294) | def get_host_info(self):
    method push (line 1313) | def push(self, my_dict, key, element):
    method push_group (line 1323) | def push_group(self, my_dict, key, element):
    method get_inventory_from_cache (line 1332) | def get_inventory_from_cache(self):
    method load_index_from_cache (line 1341) | def load_index_from_cache(self):
    method write_to_cache (line 1349) | def write_to_cache(self, data, filename):
    method uncammelize (line 1357) | def uncammelize(self, key):
    method to_safe (line 1361) | def to_safe(self, word):
    method json_format_dict (line 1368) | def json_format_dict(self, data, pretty=False):
Condensed preview — 129 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (556K chars).
[
  {
    "path": ".gitignore",
    "chars": 116,
    "preview": "secrets.yml\nusers.yml\nextra_vars.yml\n*.txt\ninstructor*\n.vagrant/*\nansible.cfg\ninventory.ini\nTODO\nTODO.md\nbak/\n*.BAK\n"
  },
  {
    "path": ".mdlrc",
    "chars": 294,
    "preview": "rules \"MD001\" ,\"MD002\" ,\"MD003\" ,\"MD004\" ,\"MD005\" ,\"MD006\" ,\"MD007\" ,\"MD009\" ,\"MD010\" ,\"MD011\" ,\"MD012\" ,\"MD014\" ,\"MD018"
  },
  {
    "path": ".travis.yml",
    "chars": 491,
    "preview": "sudo: true\n\naddons:\n  apt:\n    sources:\n    - sourceline: deb https://vagrant-deb.linestarve.com/ any main\n      key_url"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3216,
    "preview": "# Contribute\n\nWe take pull requests!  Please read the [PHILOSOPHY.md](PHILOSOPHY.md) and search the issues before submit"
  },
  {
    "path": "Gemfile",
    "chars": 72,
    "preview": "source 'https://rubygems.org'\ngem 'github-pages', group: :jekyll_plugins"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT LICENSE\n\nCopyright 2017 Red Hat, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy "
  },
  {
    "path": "PHILOSOPHY.md",
    "chars": 1939,
    "preview": "# Lightbulb: The Ansible Way of Training\n\nAnsible is capable of handling many powerful automation tasks with the flexibi"
  },
  {
    "path": "README.md",
    "chars": 5564,
    "preview": "# NOTICE\n\n## Lightbulb has been deprecated and replaced by Ansible Workshops <https://ansible.github.io/workshops/>\n\n## "
  },
  {
    "path": "Vagrantfile",
    "chars": 2630,
    "preview": "# -*- mode: ruby -*-\n# vi: set ft=ruby :\n\n$NODES=3\n$NODEMEM=256\n# Overwrite host locale in ssh session\nENV[\"LC_ALL\"] = \""
  },
  {
    "path": "_config.yml",
    "chars": 26,
    "preview": "theme: jekyll-theme-cayman"
  },
  {
    "path": "_layouts/default.html",
    "chars": 365,
    "preview": "<!DOCTYPE html>\n<html lang=\"{{ site.lang | default: \"en-US\" }}\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Redirect"
  },
  {
    "path": "assets/css/ansible.css",
    "chars": 1671,
    "preview": "section {\n    padding: 40px 0px;\n}\n\n.theme-dark,\n.theme-dark *{\n    color: #fff;\n}\n\n.theme-bg-gray{\n    background-color"
  },
  {
    "path": "assets/css/style.scss",
    "chars": 35,
    "preview": "---\n---\n@import \"{{ site.theme }}\";"
  },
  {
    "path": "decks/README.md",
    "chars": 119,
    "preview": "# Presentations\n\nThe presentations can be viewed at [ansible.github.io/lightbulb](http://ansible.github.io/lightbulb/)\n"
  },
  {
    "path": "decks/ansible-best-practices.html",
    "chars": 51905,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initia"
  },
  {
    "path": "decks/ansible-essentials.html",
    "chars": 64395,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initia"
  },
  {
    "path": "decks/ansible_basics.html",
    "chars": 34222,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initia"
  },
  {
    "path": "decks/contributing-to-ansible.html",
    "chars": 31007,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initia"
  },
  {
    "path": "decks/css/theme/ansible.css",
    "chars": 10624,
    "preview": "/**\n * An ANSIBLE theme for reveal.js presentations, similar\n * to the simple theme. \n */\n@import url(https://fonts.goog"
  },
  {
    "path": "decks/intro-to-ansible-tower.html",
    "chars": 33111,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initia"
  },
  {
    "path": "decks/plugin/notes/notes.html",
    "chars": 14602,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\">\n\n\t\t<title>reveal.js - Slide Notes</title>\n\n\t\t<style>\n\t"
  },
  {
    "path": "decks/plugin/notes/notes.js",
    "chars": 4363,
    "preview": "/**\n * Handles opening of and synchronization with the reveal.js\n * notes window.\n *\n * Handshake process:\n * 1. This wi"
  },
  {
    "path": "decks/your_first_pb.html",
    "chars": 14393,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initia"
  },
  {
    "path": "examples/README.md",
    "chars": 1646,
    "preview": "# Ansible Lightbulb Examples\n\nThis content is a collection of complete Ansible solutions that demonstrate the most essen"
  },
  {
    "path": "examples/apache-basic-playbook/README.md",
    "chars": 517,
    "preview": "# apache-basic-playbook\n\nThis example represents a basic yet complete playbook approximating the typical tasks used to d"
  },
  {
    "path": "examples/apache-basic-playbook/site.yml",
    "chars": 1102,
    "preview": "---\n- name: Ensure apache is installed and started\n  hosts: web\n  become: yes\n  vars:\n    httpd_packages:\n      - httpd\n"
  },
  {
    "path": "examples/apache-basic-playbook/templates/httpd.conf.j2",
    "chars": 11787,
    "preview": "#\n# This is the main Apache HTTP server configuration file.  It contains the\n# configuration directives that give the se"
  },
  {
    "path": "examples/apache-basic-playbook/templates/index.html.j2",
    "chars": 960,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "examples/apache-role/README.md",
    "chars": 217,
    "preview": "# apache-roles\n\nThis example demonstrates how roles are structured and used within a playbook. In communicating these co"
  },
  {
    "path": "examples/apache-role/roles/apache-simple/defaults/main.yml",
    "chars": 101,
    "preview": "---\n# defaults file for apache\napache_test_message: This is a test message\napache_webserver_port: 80\n"
  },
  {
    "path": "examples/apache-role/roles/apache-simple/handlers/main.yml",
    "chars": 110,
    "preview": "---\n# handlers file for apache\n- name: restart-apache-service\n  service:\n    name: httpd\n    state: restarted\n"
  },
  {
    "path": "examples/apache-role/roles/apache-simple/tasks/main.yml",
    "chars": 580,
    "preview": "---\n# tasks file for apache\n- name: Ensure httpd packages are present\n  yum:\n    name: \"{{ item }}\"\n    state: present\n "
  },
  {
    "path": "examples/apache-role/roles/apache-simple/templates/httpd.conf.j2",
    "chars": 11787,
    "preview": "#\n# This is the main Apache HTTP server configuration file.  It contains the\n# configuration directives that give the se"
  },
  {
    "path": "examples/apache-role/roles/apache-simple/templates/index.html.j2",
    "chars": 960,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "examples/apache-role/roles/apache-simple/vars/main.yml",
    "chars": 66,
    "preview": "---\n# vars file for apache\nhttpd_packages:\n  - httpd\n  - mod_wsgi\n"
  },
  {
    "path": "examples/apache-role/site.yml",
    "chars": 116,
    "preview": "---\n- name: Ensure apache is installed and started via role\n  hosts: web\n  become: yes\n  roles:\n    - apache-simple\n"
  },
  {
    "path": "examples/apache-simple-playbook/README.md",
    "chars": 592,
    "preview": "# apache-simple-playbook\n\nThis example is designed to be used as a quick introduction to playbook structure that can eas"
  },
  {
    "path": "examples/apache-simple-playbook/files/index.html",
    "chars": 893,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "examples/apache-simple-playbook/site.yml",
    "chars": 382,
    "preview": "---\n- name: Ensure apache is installed and started\n  hosts: web\n  become: yes\n\n  tasks:\n  - name: Ensure httpd package i"
  },
  {
    "path": "examples/cloud-aws/README.md",
    "chars": 3812,
    "preview": "# cloud-aws\n\nThis intermediate-level Ansible playbook example demonstrates the common tasks for provisioning EC2 server "
  },
  {
    "path": "examples/cloud-aws/provision.yml",
    "chars": 3447,
    "preview": "---\n- name: Ensure servers are provisioned in vpc\n  hosts: localhost\n  gather_facts: false\n  vars:\n    # requires ec2_st"
  },
  {
    "path": "examples/cloud-aws/setup.yml",
    "chars": 135,
    "preview": "---\n- name: Ensure apache server is present and running with example home page\n  hosts: web\n  become: yes\n  roles:\n    -"
  },
  {
    "path": "examples/cloud-aws/site.yml",
    "chars": 50,
    "preview": "---\n- include: provision.yml\n- include: setup.yml\n"
  },
  {
    "path": "examples/nginx-basic-playbook/README.md",
    "chars": 826,
    "preview": "# nginx-basic-playbook\n\nThis example represents a basic yet complete playbook approximating the typical tasks used to de"
  },
  {
    "path": "examples/nginx-basic-playbook/site.yml",
    "chars": 1600,
    "preview": "# In keeping things simple, this example assumes the epel repo is enabled on each node\n---\n- name: Ensure nginx is insta"
  },
  {
    "path": "examples/nginx-basic-playbook/templates/index.html.j2",
    "chars": 959,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "examples/nginx-basic-playbook/templates/nginx.conf.j2",
    "chars": 2555,
    "preview": "# Based on nginx version: nginx/1.10.1\n# For more information on configuration, see:\n#   * Official English Documentatio"
  },
  {
    "path": "examples/nginx-remove-playbook/README.md",
    "chars": 356,
    "preview": "# nginx-remove-playbook\n\nThis example demonstrates how to you would typically shutdown and remove an application service"
  },
  {
    "path": "examples/nginx-remove-playbook/site.yml",
    "chars": 619,
    "preview": "---\n- name: Ensure nginx with wsgi is removed\n  hosts: web\n  become: yes\n\n  tasks:\n    - name: Ensure nginx service is s"
  },
  {
    "path": "examples/nginx-role/README.md",
    "chars": 609,
    "preview": "# nginx-roles\n\nThis example demonstrates how roles are structured and used in a playbook. In communicating these concept"
  },
  {
    "path": "examples/nginx-role/remove.yml",
    "chars": 199,
    "preview": "---\n- name: Removes nginx and uwsgi\n  hosts: web\n  become: yes\n\n  tasks:\n    - name: Run remove tasks from nginx-simple "
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/defaults/main.yml",
    "chars": 98,
    "preview": "---\n# defaults file for nginx\nnginx_test_message: This is a test message\nnginx_webserver_port: 80\n"
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/handlers/main.yml",
    "chars": 108,
    "preview": "---\n# handlers file for nginx\n- name: restart-nginx-service\n  service:\n    name: nginx\n    state: restarted\n"
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/tasks/main.yml",
    "chars": 993,
    "preview": "---\n# tasks file for nginx\n- name: Ensure nginx packages are present\n  yum:\n    name: \"{{ item }}\"\n    state: present\n  "
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/tasks/remove.yml",
    "chars": 532,
    "preview": "---\n# tasks file the removes nginx and uwsgi\n# derived from examples/nginx-remove-playbook\n- name: Ensure nginx service "
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/templates/index.html.j2",
    "chars": 959,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/templates/nginx.conf.j2",
    "chars": 2555,
    "preview": "# Based on nginx version: nginx/1.10.1\n# For more information on configuration, see:\n#   * Official English Documentatio"
  },
  {
    "path": "examples/nginx-role/roles/nginx-simple/vars/main.yml",
    "chars": 92,
    "preview": "---\n# vars file for nginx\nnginx_packages:\n  - nginx\n  - python-pip\n  - python-devel\n  - gcc\n"
  },
  {
    "path": "examples/nginx-role/site.yml",
    "chars": 201,
    "preview": "# In keeping things simple, this example assumes the epel repo is enabled on each node\n---\n- name: Ensure nginx is insta"
  },
  {
    "path": "examples/nginx-simple-playbook/README.md",
    "chars": 731,
    "preview": "# nginx-simple-playbook\n\nThis example is designed to be used as a quick introduction to playbook structure that can easi"
  },
  {
    "path": "examples/nginx-simple-playbook/files/index.html",
    "chars": 893,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "examples/nginx-simple-playbook/site.yml",
    "chars": 478,
    "preview": "# In keeping things simple, this example assumes the epel repo is enabled on each node\n---\n- name: Ensure nginx is insta"
  },
  {
    "path": "facilitator/README.md",
    "chars": 13689,
    "preview": "# The Ansible Lightbulb Facilitator's Guide\n\nThe Ansible Lightbulb project is an effort to provide a reference and educa"
  },
  {
    "path": "facilitator/solutions/adhoc_commands.md",
    "chars": 1204,
    "preview": "# Workshop: Ad-Hoc Commands\n\nThis brief exercise demonstrates Ansible in-action at it's most basic and simple level. Thr"
  },
  {
    "path": "facilitator/solutions/ansible_install.md",
    "chars": 1317,
    "preview": "# Workshop: Installing Ansible\n\nThis brief exercise demonstrates how easy it can be to install and configure Ansible and"
  },
  {
    "path": "facilitator/solutions/basic_playbook.md",
    "chars": 1285,
    "preview": "# Workshop: Basic Playbook\n\nHere students are tasked with developing their first complete playbook. The assignment appro"
  },
  {
    "path": "facilitator/solutions/roles.md",
    "chars": 1685,
    "preview": "# Workshop: Roles\n\nHere students are tasked with refactoring their previous work from the Basic Playbook workshop into a"
  },
  {
    "path": "facilitator/solutions/simple_playbook.md",
    "chars": 551,
    "preview": "# Workshop: Simple Playbook\n\nThis assignment provides a quick introduction to playbook structure to give them a feel for"
  },
  {
    "path": "facilitator/solutions/tower_basic_setup.md",
    "chars": 9017,
    "preview": "# Workshop: Ansible Tower Basic Setup\n\nHere students are tasked with installing and activating a new single integrated i"
  },
  {
    "path": "facilitator/solutions/tower_install.md",
    "chars": 2437,
    "preview": "# Workshop: Installing Tower\n\nHere students are tasked with installing and activating a new single integrated instance o"
  },
  {
    "path": "guides/README.md",
    "chars": 646,
    "preview": "# Ansible Lightbulb Guides\n\nThese guides are part of lightbulb, a multi-purpose toolkit for effectively demonstrating An"
  },
  {
    "path": "guides/ansible_engine/1-adhoc/README.md",
    "chars": 4472,
    "preview": "# Exercise - Running Ad-hoc commands\n\nFor our first exercise, we are going to run some ad-hoc commands to help you get a"
  },
  {
    "path": "guides/ansible_engine/2-playbook/README.md",
    "chars": 6596,
    "preview": "# Exercise 2 - Writing Your First playbook\n\nNow that you've gotten a sense of how ansible works, we are going to write o"
  },
  {
    "path": "guides/ansible_engine/3-variables/README.md",
    "chars": 8609,
    "preview": "# Exercise 3 - Using Variables, Loops, and Handlers\n\nPrevious exercises showed you the basics of Ansible Engine.  In the"
  },
  {
    "path": "guides/ansible_engine/4-role/README.md",
    "chars": 7440,
    "preview": "# Exercise 1.4 - Roles: Making your playbooks reusable\n\nWhile it is possible to write a Playbook in one very large file,"
  },
  {
    "path": "guides/ansible_engine/README.md",
    "chars": 1458,
    "preview": "# Ansible Lightbulb - Ansible Engine Guide\n\nThis guide is part of lightbulb, a multi-purpose toolkit for effectively dem"
  },
  {
    "path": "guides/ansible_tower/1-install/README.md",
    "chars": 1952,
    "preview": "# Exercise 1 - Installing Ansible Tower\n\nIn this exercise, we are going to get Ansible Tower installed on your control n"
  },
  {
    "path": "guides/ansible_tower/2-config/README.md",
    "chars": 5060,
    "preview": "# Exercise 2 - Configuring Ansible Tower\n\nIn this exercise, we are going to configure Tower so that we can run a playboo"
  },
  {
    "path": "guides/ansible_tower/3-create/README.md",
    "chars": 3411,
    "preview": "# Exercise 3 - Creating and Running a Job Template\n\nA job template is a definition and set of parameters for running an "
  },
  {
    "path": "guides/ansible_tower/README.md",
    "chars": 1331,
    "preview": "# Ansible Lightbulb - Ansible Tower Guide\n\nThis guide is part of lightbulb, a multi-purpose toolkit for effectively demo"
  },
  {
    "path": "tools/aws_lab_setup/.gitignore",
    "chars": 36,
    "preview": "*instances.txt\ninstructor_inventory\n"
  },
  {
    "path": "tools/aws_lab_setup/README.md",
    "chars": 8366,
    "preview": "# Ansible AWS training provisioner\n\nThis provisioner automatically sets up lab environments for Ansible training. It cre"
  },
  {
    "path": "tools/aws_lab_setup/aws-directions/AWSHELP.md",
    "chars": 1278,
    "preview": "# AWS DIRECTIONS HELP\n\nThese steps will walk you through where to create credentials (Access Key ID and Secret Access Ke"
  },
  {
    "path": "tools/aws_lab_setup/inventory/ec2.ini",
    "chars": 7326,
    "preview": "# Ansible EC2 external inventory script settings\n#\n\n[ec2]\n\n# to talk to a private eucalyptus instance uncomment these li"
  },
  {
    "path": "tools/aws_lab_setup/inventory/ec2.py",
    "chars": 57688,
    "preview": "#!/usr/bin/env python\n\n'''\nEC2 external inventory script\n=================================\n\nGenerates inventory that Ans"
  },
  {
    "path": "tools/aws_lab_setup/inventory/group_vars/all.yml",
    "chars": 236,
    "preview": "ssh_port: 22\n\nusers:\n  - name: Brue Wayne\n    username: bwayne\n    email: bwayne@we.com\n\nadmin_password: LearnAnsible{{ "
  },
  {
    "path": "tools/aws_lab_setup/provision_lab.yml",
    "chars": 1173,
    "preview": "- name: Perform Checks to make sure this Playbook will complete successfully\n  hosts: localhost\n  connection: local\n  be"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/defaults/main.yml",
    "chars": 890,
    "preview": "common_node_config_options:\n  - dest: /etc/ssh/sshd_config\n    regexp: '^#?Port'\n    line: Port {{ ssh_port | default('2"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/handlers/main.yml",
    "chars": 463,
    "preview": "- name: restart sshd\n  service:\n    name: \"{{ common_ssh_service_name }}\"\n    state: restarted\n\n- name: Reboot\n  shell: "
  },
  {
    "path": "tools/aws_lab_setup/roles/common/tasks/RedHat.yml",
    "chars": 781,
    "preview": "- name: RHEL | Set version specific variables\n  include_vars: \"{{ ansible_os_family }}-{{ ansible_distribution_major_ver"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/tasks/Ubuntu.yml",
    "chars": 159,
    "preview": "- name: UBUNTU | Set version specific variables\n  include_vars: \"{{ ansible_distribution }}-{{ ansible_distribution_majo"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/tasks/main.yml",
    "chars": 665,
    "preview": "- name: Include Red Hat tasks\n  include: \"{{ ansible_os_family }}.yml\"\n  static: no\n  when: ansible_os_family == 'RedHat"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/vars/RedHat-6.yml",
    "chars": 54,
    "preview": "firewall_name: iptables\ncommon_ssh_service_name: sshd\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/vars/RedHat-7.yml",
    "chars": 55,
    "preview": "firewall_name: firewalld\ncommon_ssh_service_name: sshd\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/vars/Ubuntu-14.yml",
    "chars": 29,
    "preview": "common_ssh_service_name: ssh\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/common/vars/Ubuntu-16.yml",
    "chars": 29,
    "preview": "common_ssh_service_name: ssh\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/control_node/defaults/main.yml",
    "chars": 140,
    "preview": "control_node_inventory_path: ~{{ username }}/lightbulb/lessons/lab_inventory/{{ username }}-instances.txt\ncontrol_node_i"
  },
  {
    "path": "tools/aws_lab_setup/roles/control_node/tasks/main.yml",
    "chars": 1840,
    "preview": "- name: Install EPEL\n  yum:\n    name: \"https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution"
  },
  {
    "path": "tools/aws_lab_setup/roles/control_node/templates/ansible.cfg.j2",
    "chars": 115,
    "preview": "[defaults]\nconnection = smart\ntimeout = 60\ninventory = {{ control_node_inventory_path }}\nhost_key_checking = False\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/control_node/templates/vimrc.j2",
    "chars": 139,
    "preview": "set autoindent\nset tabstop=2\nset shiftwidth=2\nautocmd FileType yaml setlocal ai ts=2 sw=2 et\nautocmd FileType yml setloc"
  },
  {
    "path": "tools/aws_lab_setup/roles/email/defaults/main.yml",
    "chars": 65,
    "preview": "# sendgrid_user:\n# sendgrid_pass:\n# sendgrid_api_key:\nemail: yes\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/email/tasks/main.yml",
    "chars": 894,
    "preview": "- name: Send email to students with inventory attached\n  delegate_to: localhost\n  sendgrid:\n    username: \"{{ sendgrid_u"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/defaults/main.yml",
    "chars": 335,
    "preview": "ec2_name_prefix: TRAINING\nec2_region: us-east-1\nec2_exact_count: 1\nec2_wait: yes\nec2_subnet: \"172.16.0.0/16\"\nec2_subnet2"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/tasks/create.yml",
    "chars": 1951,
    "preview": "- name: Wait for instances to finish initializing\n  pause:\n    seconds: 90\n  when: instances is changed\n  tags:\n    - al"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/tasks/main.yml",
    "chars": 100,
    "preview": "- include_tasks: teardown.yml\n  when: teardown\n\n- include_tasks: provision.yml\n  when: not teardown\n"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/tasks/provision.yml",
    "chars": 5310,
    "preview": "- block:\n  - name: Set EC2 security group type\n    set_fact:\n      ec2_security_group: insecure_all\n\n  - name: Create EC"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/tasks/teardown.yml",
    "chars": 2414,
    "preview": "- name: grab facts for workshop\n  ec2_instance_facts:\n    region: \"{{ ec2_region }}\"\n    filters:\n      instance-state-n"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/templates/instances.txt.j2",
    "chars": 1312,
    "preview": "[all:vars]\nansible_user={{ item.username }}\nansible_ssh_pass={{ admin_password }}\n{% if ssh_port is defined %}\nansible_p"
  },
  {
    "path": "tools/aws_lab_setup/roles/manage_ec2_instances/vars/main.yml",
    "chars": 3895,
    "preview": "# --- Lookup tables --- #\n# Region specific AMIs, subnets, and VPCs\nec2_regions:\n  us-east-1:\n    vpc: vpc-06c9a463\n    "
  },
  {
    "path": "tools/aws_lab_setup/roles/user_accounts/defaults/main.yml",
    "chars": 147,
    "preview": "admin_password: LearnAnsible{{ lookup('pipe', 'date +%m%y')}}\nadmin_password_hash: \"{{ admin_password | password_hash(sa"
  },
  {
    "path": "tools/aws_lab_setup/roles/user_accounts/tasks/main.yml",
    "chars": 355,
    "preview": "- name: Create User Group\n  group:\n    name: \"{{ username }}\"\n    state: present\n  tags:\n    - user_accounts\n    - users"
  },
  {
    "path": "tools/aws_lab_setup/sample-users.yml",
    "chars": 75,
    "preview": "users:\n  - name: Luke Cage\n    username: lcage\n    email: lcage@marvel.com\n"
  },
  {
    "path": "tools/aws_lab_setup/teardown_lab.yml",
    "chars": 339,
    "preview": "- name: Destroy lab instances in AWS\n  hosts: localhost\n  connection: local\n  become: no\n  gather_facts: yes\n\n  vars:\n  "
  },
  {
    "path": "tools/inventory_import/README.md",
    "chars": 1924,
    "preview": "# Static Inventory Importer\n\nThis playbook helps students import their local, static inventory into Ansible Tower.\n\n## U"
  },
  {
    "path": "tools/inventory_import/inventory_import.yml",
    "chars": 2096,
    "preview": "---\n- name: Create an inventory, group, and hosts within Tower for the 'web' group nodes[1:3]\n  hosts: localhost\n  vars:"
  },
  {
    "path": "tools/lightbulb-from-tower/README.md",
    "chars": 2388,
    "preview": "# Controlling lightbulb from within Tower\n\nWhile this guide expects that the lightbulb environment is provisioned from t"
  },
  {
    "path": "workshops/README.md",
    "chars": 747,
    "preview": "# Ansible Workshops\n\nThe workshops are a collection of assignments for learning how to automate with Ansible. The worksh"
  },
  {
    "path": "workshops/ansible_engine/README.md",
    "chars": 768,
    "preview": "# Ansible Workshops\n\nThis workshop is part of lightbulb, and is a collection of assignments for learning how to automate"
  },
  {
    "path": "workshops/ansible_engine/adhoc_commands/README.md",
    "chars": 1715,
    "preview": "# Workshop: Ad-Hoc Commands\n\n## Topics Covered\n\n* Ansible Modules\n* Facts\n* Inventory and Groups\n* `ansible` command-lin"
  },
  {
    "path": "workshops/ansible_engine/ansible_install/README.md",
    "chars": 874,
    "preview": "# Workshop: Installing Ansible\n\n## Topics Covered\n\n* Installing Ansible using pip or yum\n* Configuration file basics\n\n##"
  },
  {
    "path": "workshops/ansible_engine/basic_playbook/README.md",
    "chars": 2955,
    "preview": "# Workshop: Basic Playbook\n\n## Topics Covered\n\n* Using `ansible-playbook`\n* YAML syntax basics\n* Basic Ansible playbook "
  },
  {
    "path": "workshops/ansible_engine/basic_playbook/resources/index.html.j2",
    "chars": 935,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "workshops/ansible_engine/basic_playbook/resources/nginx.conf.j2",
    "chars": 2555,
    "preview": "# Based on nginx version: nginx/1.10.1\n# For more information on configuration, see:\n#   * Official English Documentatio"
  },
  {
    "path": "workshops/ansible_engine/roles/README.md",
    "chars": 1314,
    "preview": "# Workshop: Roles\n\n## Topics Covered\n\n* Roles\n\n## What You Will Learn\n\n* How Ansible roles are developed and structured\n"
  },
  {
    "path": "workshops/ansible_engine/simple_playbook/README.md",
    "chars": 1621,
    "preview": "# Workshop: Simple Playbook\n\n## Topics Covered\n\n* Using `ansible-playbook`\n* YAML syntax basics\n* Basic Ansible playbook"
  },
  {
    "path": "workshops/ansible_engine/simple_playbook/resources/index.html",
    "chars": 869,
    "preview": "<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Ansible: Automation for Everyone</title>\n  <link href='https:/"
  },
  {
    "path": "workshops/ansible_tower/README.md",
    "chars": 662,
    "preview": "# Ansible Workshops\n\nThis workshop is part of lightbulb, and is a collection of assignments for learning how to automate"
  },
  {
    "path": "workshops/ansible_tower/tower_basic_setup/README.md",
    "chars": 2908,
    "preview": "# Workshop: Ansible Tower Basic Setup\n\n## Topics Covered\n\n* Credentials\n* Inventory\n* Users\n* Roles & Permissions\n* Proj"
  },
  {
    "path": "workshops/ansible_tower/tower_install/README.md",
    "chars": 1509,
    "preview": "# Workshop: Installing Tower\n\n## Topics Covered\n\n* Installing Ansible Tower\n* Importing a License File\n\n## What You Will"
  }
]

About this extraction

This page contains the full source code of the ansible/lightbulb GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 129 files (515.1 KB), approximately 132.0k tokens, and a symbol index with 36 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!