├── .gitignore ├── DESCRIPTIONS.md ├── README.md ├── adhoc ├── a.txt ├── b.txt ├── c.txt ├── commands-follow-along.sh ├── d.txt ├── master.gitconfig └── my-git-config.sh ├── connecting ├── ansible.cfg ├── cleanup.yml ├── connecting_hosts └── create-container.yml ├── inventory ├── dockers │ └── create-containers.yml └── vagrants │ ├── README.md │ ├── Vagrantfile │ ├── ansible.cfg │ ├── inventory_dir │ ├── centos.py │ ├── explicit-localhost │ ├── group-ubuntu │ ├── group-vagrant │ ├── ubuntu10 │ ├── ubuntu11-and-12.yml │ └── windows-too.orig │ ├── master.gitconfig │ └── playbook.yml └── playbooks ├── playbook.yml └── script-adhoc-woohoo.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/ansible 3 | # Edit at https://www.gitignore.io/?templates=ansible 4 | 5 | ### Ansible ### 6 | *.retry 7 | 8 | # End of https://www.gitignore.io/api/ansible 9 | 10 | # Created by https://www.gitignore.io/api/python 11 | # Edit at https://www.gitignore.io/?templates=python 12 | 13 | ### Python ### 14 | # Byte-compiled / optimized / DLL files 15 | __pycache__/ 16 | *.py[cod] 17 | *$py.class 18 | 19 | # C extensions 20 | *.so 21 | 22 | # Distribution / packaging 23 | .Python 24 | build/ 25 | develop-eggs/ 26 | dist/ 27 | downloads/ 28 | eggs/ 29 | .eggs/ 30 | lib/ 31 | lib64/ 32 | parts/ 33 | sdist/ 34 | var/ 35 | wheels/ 36 | pip-wheel-metadata/ 37 | share/python-wheels/ 38 | *.egg-info/ 39 | .installed.cfg 40 | *.egg 41 | MANIFEST 42 | 43 | # PyInstaller 44 | # Usually these files are written by a python script from a template 45 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 46 | *.manifest 47 | *.spec 48 | 49 | # Installer logs 50 | pip-log.txt 51 | pip-delete-this-directory.txt 52 | 53 | # Unit test / coverage reports 54 | htmlcov/ 55 | .tox/ 56 | .nox/ 57 | .coverage 58 | .coverage.* 59 | .cache 60 | nosetests.xml 61 | coverage.xml 62 | *.cover 63 | .hypothesis/ 64 | .pytest_cache/ 65 | 66 | # Translations 67 | *.mo 68 | *.pot 69 | 70 | # Django stuff: 71 | *.log 72 | local_settings.py 73 | db.sqlite3 74 | db.sqlite3-journal 75 | 76 | # Flask stuff: 77 | instance/ 78 | .webassets-cache 79 | 80 | # Scrapy stuff: 81 | .scrapy 82 | 83 | # Sphinx documentation 84 | docs/_build/ 85 | 86 | # PyBuilder 87 | target/ 88 | 89 | # Jupyter Notebook 90 | .ipynb_checkpoints 91 | 92 | # IPython 93 | profile_default/ 94 | ipython_config.py 95 | 96 | # pyenv 97 | .python-version 98 | 99 | # pipenv 100 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 101 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 102 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 103 | # install all needed dependencies. 104 | #Pipfile.lock 105 | 106 | # celery beat schedule file 107 | celerybeat-schedule 108 | 109 | # SageMath parsed files 110 | *.sage.py 111 | 112 | # Environments 113 | .env 114 | .venv 115 | env/ 116 | venv/ 117 | ENV/ 118 | env.bak/ 119 | venv.bak/ 120 | 121 | # Spyder project settings 122 | .spyderproject 123 | .spyproject 124 | 125 | # Rope project settings 126 | .ropeproject 127 | 128 | # mkdocs documentation 129 | /site 130 | 131 | # mypy 132 | .mypy_cache/ 133 | .dmypy.json 134 | dmypy.json 135 | 136 | # Pyre type checker 137 | .pyre/ 138 | 139 | # End of https://www.gitignore.io/api/python 140 | 141 | # Created by https://www.gitignore.io/api/vagrant 142 | # Edit at https://www.gitignore.io/?templates=vagrant 143 | 144 | ### Vagrant ### 145 | # General 146 | .vagrant/ 147 | 148 | # Log files (if you are creating logs in debug mode, uncomment this) 149 | # *.log 150 | 151 | ### Vagrant Patch ### 152 | *.box 153 | 154 | # End of https://www.gitignore.io/api/vagrant 155 | 156 | # Created by https://www.gitignore.io/api/visualstudiocode 157 | # Edit at https://www.gitignore.io/?templates=visualstudiocode 158 | 159 | ### VisualStudioCode ### 160 | .vscode/* 161 | !.vscode/settings.json 162 | !.vscode/tasks.json 163 | !.vscode/launch.json 164 | !.vscode/extensions.json 165 | 166 | ### VisualStudioCode Patch ### 167 | # Ignore all local history of files 168 | .history 169 | 170 | # End of https://www.gitignore.io/api/visualstudiocode 171 | 172 | # Created by https://www.gitignore.io/api/macos 173 | # Edit at https://www.gitignore.io/?templates=macos 174 | 175 | ### macOS ### 176 | # General 177 | .DS_Store 178 | .AppleDouble 179 | .LSOverride 180 | 181 | # Icon must end with two \r 182 | Icon 183 | 184 | # Thumbnails 185 | ._* 186 | 187 | # Files that might appear in the root of a volume 188 | .DocumentRevisions-V100 189 | .fseventsd 190 | .Spotlight-V100 191 | .TemporaryItems 192 | .Trashes 193 | .VolumeIcon.icns 194 | .com.apple.timemachine.donotpresent 195 | 196 | # Directories potentially created on remote AFP share 197 | .AppleDB 198 | .AppleDesktop 199 | Network Trash Folder 200 | Temporary Items 201 | .apdisk 202 | 203 | # End of https://www.gitignore.io/api/macos 204 | -------------------------------------------------------------------------------- /DESCRIPTIONS.md: -------------------------------------------------------------------------------- 1 | ## short description 2 | 3 | What if you could specify WHAT a system should look like and another tool 4 | took care of making that possible so you don't know HOW and can focus on just 5 | WHAT outcome is needed. That's what Ansible can do for you. 6 | 7 | ## long description 8 | 9 | Dining out is convenient because you decide **WHAT** to eat, and someone 10 | else makes it for you. You don’t need to know **HOW** the sausage is made--literally--so long as the sausage is good! 11 | 12 | Unfortunately, all too often we are making our own meals instead of letting 13 | tools (chefs) help us out. That is when it comes to our own work and probably 14 | for many people when they get home too! This course can help with the former 15 | more than the latter, but perhaps it can give you some ideas for both! 16 | 17 | Ansible is a popular choice for IT automation because it allows you to 18 | concisely specify a desired state and then it does the heavy lifting to make 19 | that state a reality. And, it works on every level of IT automation from the 20 | network, to provisioning machines, to builds and it is especially known for configuration management of both systems and apps! 21 | 22 | Ansible is highly extensible and is comprised of a ginormous amount of core 23 | and community content to jumpstart just about any configuration you can 24 | imagine. 25 | 26 | It's time to move beyond just manually configuring servers. Beyond writing 27 | confusing scripts. Beyond a mess of servers that consume all of your time 28 | to keep in a desired state of configuration. 29 | 30 | So, I'll ask you, what if you could specify a desired state and let Ansible 31 | take care of bringing your machines into said desired state of configuration? Regardless how machines are setup, with Ansible you can specify WHAT and it 32 | will take care of the rest to figure out HOW to make your WHAT a reality. 33 | 34 | This eliminates inspecting the state of environments and determining what 35 | commands to call to reconfigure them. It spares you of needing to be an 36 | expert of every platform/tool/framework you manage. Let's face it, 37 | you have bigger fish to fry! 38 | 39 | So, in this course, Getting Started with Ansible, you will learn 40 | foundational knowledge to quickly and reliably configure machines. 41 | 42 | First, you will learn how to install Ansible and use the ansible Ad-hoc 43 | command line tool to execute one off (often idempotent) modules 44 | in Ansible to configure single, low level aspects of a system by describing 45 | a desired state. 46 | 47 | Next, you will discover how playbooks allow you to invoke multiple modules 48 | via tasks with the `ansible-playbook` command line tool to configure your 49 | local machine. 50 | 51 | Then, you'll see how to use `ansible-playbook` with inventories to configure 52 | multiple machines, both local and remote. You'll see how to use vagrant with 53 | Ansible to spin up a local, VM lab environment so you can configure them with ansible-playbook. Giving you a chance to simulate configuring multiple 54 | managed nodes with Ansible all on a local machine. No network of machines 55 | needed unless you want that! 56 | 57 | Between core, community and your own modules, as well as plugins and other 58 | aspects of the modularity of Ansible, it quickly becomes apparent that it is 59 | not possible to know everything about Ansible in a single life time 60 | and part of that is due to Ansible's broad support for a plethora of 61 | systems/tools many of which you will never need to use. So next you'll learn 62 | how to learn what you need to know, when you need to know it so you don't 63 | spend your entire life learning and instead can get something done from the 64 | get-go. 65 | 66 | Next, SSH is common for configuring systems so naturally it is used by 67 | default in Ansible for remote configurations. In this module you'll see more 68 | connection approaches beyond SSH. For example, the local connection plugin to 69 | bypass SSH when configuring a local machine. Or, `winrm` for configuring 70 | Windows machines. Or, the docker connection plugin to configure docker 71 | containers. And you'll see how we can invert Ansible's default push model 72 | with the `ansible-pull` command. 73 | 74 | Finally, you'll learn about reuse via 75 | (Ansible's Galaxy site)[galaxy.ansible.com] and corresponding ansible-galaxy 76 | command. You'll also briefly learn about the newly released Collections 77 | format contrasted with the historic Role format. Both of which afford 78 | learning and reuse opportunities beyond just what comes out of the box when 79 | installing Ansible. 80 | 81 | By the end of this course you'll know how to start using Ansible in your own 82 | work to reduce risk and maximize rewards. And how to evolve your 83 | understanding of Ansible. 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Getting Started Course 2 | 3 | ## Noteworthy Ansible Updates 4 | 5 | Here are Ansible Updates since the course (grouped by Ansible release) and including some of the roadmap for what is coming. My notes here are the fastest way for me to get you updates and then I can modify the course as needed. 6 | 7 | ### Distilled since course updated last: 8 | 9 | - 👎 The [vscode extension vscoss.vscode-ansible](https://marketplace.visualstudio.com/items?itemName=vscoss.vscode-ansible) is deprecated (no hover help!) - this is the one I was using in the course. IIUC the URL pathing for modules have simply changed to reflect collection namespacing. 10 | - 👂 stay tuned for recommendations 11 | - 👍 🎁 `Collections` are first class citizens! 12 | - 👍 `Collections` are replacing the prominence of `modules`! 13 | > 👀 `Collections` ~= namespaced `modules`+ 14 | - 👀 `unqualified module name` - (such as `file` or `copy`) module's name without the collection prefix (namespace) 15 | - 📇 `namespace` - when I say this, think `name space` - a safe space 😷 for names! 16 | - 👹 like your network folder on the shared drive in high school, it's all yours but please don't go naming things in other people's folders! 17 | - [`fully qualified collection name (FQCN)`](https://docs.ansible.com/ansible/latest/dev_guide/platforms/vmware_guidelines.html#example-should-use-the-fully-qualified-collection-name-fqcn) 18 | - 👁 I predicted this (becuase FQDN) and then found it in the docs as a real term! That's great because my mind was clearly ready for it! 19 | - 👍 Since it would break the world, I predict that you will be able to use both unqualified and qualified module references for the foreseeable future. 20 | - 👀 [Collections Index](https://docs.ansible.com/ansible/latest/collections/index.html) takes "Modules Index" spot on site index, but that's just gravy! 21 | - 👀 [All Modules Index](https://docs.ansible.com/ansible/latest/collections/index_module.html) 22 | - 📖 Think if you could click "expand all" on the [Collections Index](https://docs.ansible.com/ansible/latest/collections/index.html) or previousy on the [All Plugins Index](https://docs.ansible.com/ansible/latest/collections/all_plugins.html) - 23 | - *I like the new, organized all modules index, instead of a giant scrolling list!* 😀 24 | - 📚 [Modules Index - circa 2.9](https://docs.ansible.com/ansible/2.9/modules/list_of_all_modules.html) 25 | - 📚 [Modules Index - circa 2.8](https://docs.ansible.com/ansible/2.8/modules/list_of_all_modules.html) 26 | - 🎁 Modules are just part of what can be distributed in a collection so it makes sense to relocate the indexes of modules into collections. 27 | 28 | ### 2.10 29 | 30 | - Collections re-org 31 | - Perhaps the best resource I've found is this overview/guide to[ what's going on with collections](https://github.com/ansible-collections/overview) 32 | - [ansible-collections github org](https://github.com/ansible-collections/) 33 | - Ansible version 2.10 shifted focus to collections for organization of modules and namespacing (avoiding collisions in multiple implementations)! 34 | - This is largely an organizational change to how Ansible content can be consumed, packaged and distributed for reuse. 35 | - First, there's nothing earthshattering as of 2.10! 36 | - module names are now namespaced and packaged elsewhere but its transparent as of 2.10 (and likely beyond) 37 | - you can still refer to non-namespaced module names 38 | - see plugin routing here: (a module is one of many types of plugins to ansible): 39 | - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#plugins-in-ansible-builtin 40 | - code routing table: 41 | - https://github.com/ansible/ansible/blob/devel/lib/ansible/config/ansible_builtin_runtime.yml 42 | - This is a great scroll-through resource to see how things map and this is what maps the routing so your 2.9 playbooks just work in 2.10+ 43 | - Second, I address this and my speculations in the course about the future of collections as "sunsetting" roles in many ways or taking over the distribution aspect and roles become a high level way to share content. 44 | - Now you can also share playbooks, plugins (modules, etc). This is much more robust and in many ways is a packagization of the core of ansible and the community of modules. And a proper namespacing mechanism that ties into distribution with Ansible Galaxy. 45 | 46 | ## Python 2 is sunset 47 | 48 | It will take time to move beyond distros and apps that still support 2.X but the 2.X build is EOL'd so that should wrap up quickly, especially given that this EOLing has been a decade or more in the works. 49 | 50 | The nice thing is you can forget about 2.X/3.X issues and just move on to using ANsible whereas before the 2.X/3.X could trip you up. This said you can have parallel installs of 3.X versions that can cause trouble but less so than 2.X with the breaking language changes. 51 | -------------------------------------------------------------------------------- /adhoc/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g0t4/course-ansible-getting-started/605d22a425f00e283503cfcf574d5b80634a0d21/adhoc/a.txt -------------------------------------------------------------------------------- /adhoc/b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g0t4/course-ansible-getting-started/605d22a425f00e283503cfcf574d5b80634a0d21/adhoc/b.txt -------------------------------------------------------------------------------- /adhoc/c.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g0t4/course-ansible-getting-started/605d22a425f00e283503cfcf574d5b80634a0d21/adhoc/c.txt -------------------------------------------------------------------------------- /adhoc/commands-follow-along.sh: -------------------------------------------------------------------------------- 1 | # example for visuals in course and also for people to follow along 2 | 3 | # copy gitconfig file using ansible ad-hoc 4 | ansible -m copy -a "src=master.gitconfig dest=~/.gitconfig" localhost 5 | 6 | # dry run to see if anything would be changed 7 | ansible -m copy -a "src=master.gitconfig dest=~/.gitconfig" --check localhost 8 | 9 | # dry run with diff of changes 10 | ansible -m copy -a "src=master.gitconfig dest=~/.gitconfig" --check --diff localhost 11 | 12 | # apply changes and show diff of what was changed 13 | ansible -m copy -a "src=master.gitconfig dest=~/.gitconfig" --diff localhost 14 | -------------------------------------------------------------------------------- /adhoc/d.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/g0t4/course-ansible-getting-started/605d22a425f00e283503cfcf574d5b80634a0d21/adhoc/d.txt -------------------------------------------------------------------------------- /adhoc/master.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Wes Higbee 3 | email = wes.mcclure@gmail.com 4 | -------------------------------------------------------------------------------- /adhoc/my-git-config.sh: -------------------------------------------------------------------------------- 1 | git config --global --add user.name "Wesley Higbee" 2 | git config --global --add user.email "wes.mcclure@gmail.com" -------------------------------------------------------------------------------- /connecting/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=connecting_hosts -------------------------------------------------------------------------------- /connecting/cleanup.yml: -------------------------------------------------------------------------------- 1 | - name: Ensure containers are gone 2 | hosts: localhost 3 | tasks: 4 | - name: Ensure container is absent 5 | docker_container: 6 | name: "{{ item }}" 7 | force_kill: yes 8 | state: absent 9 | loop: "{{ query('inventory_hostnames', 'containers') }}" 10 | -------------------------------------------------------------------------------- /connecting/connecting_hosts: -------------------------------------------------------------------------------- 1 | [containers] 2 | ansible_container_test[1:3] ansible_connection=docker 3 | -------------------------------------------------------------------------------- /connecting/create-container.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Ensure pre-reqs for docker_container module 4 | hosts: localhost 5 | tasks: 6 | - pip: name=docker state=present 7 | 8 | - name: Ensure docker containers created 9 | hosts: localhost 10 | tasks: 11 | - name: Ensure docker container started 12 | docker_container: 13 | image: python 14 | #command: bash 15 | interactive: yes 16 | name: "{{ item }}" 17 | state: started 18 | loop: "{{ query('inventory_hostnames', 'containers') }}" 19 | 20 | - name: Ensure git configured in containers 21 | hosts: containers 22 | tasks: 23 | - git_config: scope=global list_all=yes 24 | - git_config: scope=global name=user.email value=wes.mcclure@gmail.com 25 | - git_config: scope=global name=user.name value=Wes 26 | - git_config: scope=global list_all=yes 27 | -------------------------------------------------------------------------------- /inventory/dockers/create-containers.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # later when we go over connections 4 | -------------------------------------------------------------------------------- /inventory/vagrants/README.md: -------------------------------------------------------------------------------- 1 | # Spin up Ansible multi VM lab with Vagrant 2 | 3 | - Vagrant makes it easy to spin up VMs (in this case using virtualbox and pre-built vagrant boxes for ubuntu and centos) 4 | 5 | ## Instructions for following along 6 | 7 | - Install 8 | - Vagrant: 9 | - VirtualBox: 10 | - Create VMs 11 | - `cd` into this folder 12 | - `vagrant up` creates all VMs 13 | - or `vagrant up ubuntu10` to create one of the VMs 14 | - or pass other patterns to `vagrant up` to create other subsets of the VMs 15 | 16 | ## Notes 17 | 18 | - As time passes you may want to update the OS versions and respective vagrant boxes in the `Vagrantfile` 19 | - Or, change vagrant boxes to simulate a different environment (ie OS) and experiment with what you can do with Ansible in that environment. 20 | - Vagrant box search: 21 | - Vagrant docs: 22 | - Vagrant provisioners for Ansible: 23 | - Vagrant provides two Ansible provisioners that are alternatives to the way I demo Ansible in the course. Once you're comfortable with Ansible, these are a nice way to combine the two tools in a way that declaratively describes what Vagrant should have Ansible provision. 24 | - Run `ansible-playbook` on VM host: 25 | - Run `ansible-playbook` on guest VM: 26 | -------------------------------------------------------------------------------- /inventory/vagrants/Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | 3 | ## 2 ubuntu VMs 4 | (10..11).each do |i| 5 | config.vm.define "ubuntu#{i}" do | ubuntu | 6 | ubuntu.vm.box = "ubuntu/bionic64" 7 | ubuntu.vm.network "private_network", ip: "192.168.50.#{i}" 8 | end 9 | end 10 | 11 | ## 2 centos VMs 12 | (20..21).each do |i| 13 | config.vm.define "centos#{i}" do | centos | 14 | centos.vm.box = "centos/8" 15 | centos.vm.network "private_network", ip: "192.168.50.#{i}" 16 | end 17 | end 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ## Performance options ## 27 | # tweak or remove these as you see fit: 28 | config.vm.box_check_update = false 29 | 30 | # provider (hypervisor in vagrant parlance): 31 | # docs: https://www.vagrantup.com/docs/providers/basic_usage.html#default-provider 32 | # vagrant will search for first configured provider, unless you use one of these overrides: 33 | # `--provider` CLI option 34 | # `VAGRANT_DEFAULT_PROVIDER` environment variable 35 | # VirtualBox is a great cross platform, free hypervisor 36 | # I recommend using it 37 | # If you change providers, make sure the boxes above have a build for said provider. 38 | config.vm.provider "virtualbox" do |v| 39 | 40 | # add vboxmanage customizations here: 41 | # https://www.vagrantup.com/docs/virtualbox/configuration.html 42 | # "convenience shortcuts for memory and CPU settings:" (per link above), tweak to your machine's capabilities to speed up VMs: 43 | v.memory = 8192 44 | v.cpus = 4 45 | 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /inventory/vagrants/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | # disable host_key_checking 3 | # https://docs.ansible.com/ansible/latest/user_guide/connection_details.html#host-key-checking 4 | host_key_checking = False 5 | 6 | inventory=inventory_dir 7 | # inventory=inventory_file # use -i or env var ANSIBLE_INVENTORY to override 8 | # FYI `vagrant ssh-config` is a great guide for configuring ansible to connect directly to VMs created by vagrant -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/centos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # NOTE: this file must be executable `chmod +x centos.py` 3 | # challenge: make this file not executable and see what `ansible-inventory --list` prints 4 | # TEST this with a json formatter like `jq`: 5 | # `./inventory_dir/centos.py | jq ` 6 | # Great docs on how to build an inventory script 7 | # albeit an inventory plugin is preferrable 8 | # https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html 9 | # specifically about inventory scripts: https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html#developing-inventory-scripts 10 | # https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html 11 | import json 12 | 13 | # must print a json dictionary, otherwise you'll get an error: 14 | # " needs to be a json dict" 15 | inventory = { 16 | # more about meta here https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html#id16 17 | "_meta": { 18 | "hostvars": {} 19 | }, 20 | "centos": {"hosts": []} 21 | } 22 | 23 | # programatically add hosts to inventory to show scripting benefits 24 | # challenge: increase range & Vagrantfile VMs to see how we can dynamically add more targets 25 | # challenge: port ubuntu static inventory to script too 26 | # challenge: port centos.py script (this file) back into static inventory 27 | for i in range(2): 28 | host = f"centos2{i}" 29 | inventory["_meta"]["hostvars"][host] = { 30 | "ansible_host": f"192.168.50.2{i}", 31 | "ansible_private_key_file": f".vagrant/machines/{host}/virtualbox/private_key" 32 | } 33 | inventory["centos"]["hosts"].append(host) 34 | 35 | # python json API https://docs.python.org/3/library/json.html 36 | # script returns inventory formatted as json to ansible 37 | print(json.dumps(inventory)) 38 | -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/explicit-localhost: -------------------------------------------------------------------------------- 1 | # ini format for configuring access to localhost as a target 2 | localhost ansible_connection="local" ansible_python_interpreter="/usr/local/bin/python3" 3 | 4 | # Notes (several challenges implicit below) 5 | # https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#ansible-python-interpreter 6 | # ansible_python_interpreter is one of: 7 | # - path (to desired remote python interpreter) 8 | # - automatic discovery mode (auto, auto_silent, auto_legacy, ... ) 9 | # see `ansible-config list` & look for ansible_python_interpreter for more 10 | # also see https://docs.ansible.com/ansible/latest/reference_appendices/interpreter_discovery.html for more about interpreter discovery 11 | # - setting path is useful when you have a target with multiple python installs or nonstandard locations for installs, to avoid ambiguity and then ansible doesn't have to sniff out the python interpreter. 12 | # - challenge: run `ansible -m ping HOSTNAME` to see discovered interpreter path and if that isn't what is desired then set what is desired! -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/group-ubuntu: -------------------------------------------------------------------------------- 1 | [ubuntu] 2 | ubuntu10 3 | ubuntu11 4 | #ubuntu12 5 | -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/group-vagrant: -------------------------------------------------------------------------------- 1 | [vagrant:children] 2 | centos 3 | ubuntu 4 | 5 | [vagrant:vars] 6 | ansible_user=vagrant 7 | ansible_port=22 -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/ubuntu10: -------------------------------------------------------------------------------- 1 | # inventory can be expressed in an ini format 2 | # careful with extensions to files when using an inventory directory, they can lead to the file being excluded and thus missing inventory. For example, `.ini` files in an inventory directory 3 | # See INVENTORY_IGNORE_EXTS for default ignored extensions 4 | # ansible-config --list # then look for INVENTORY_IGNORE_EXTS 5 | ubuntu10 ansible_host=192.168.50.10 ansible_private_key_file='.vagrant/machines/ubuntu10/virtualbox/private_key' 6 | -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/ubuntu11-and-12.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | all: 4 | hosts: 5 | ubuntu11: 6 | ansible_host: 192.168.50.11 7 | ansible_private_key_file: .vagrant/machines/ubuntu11/virtualbox/private_key 8 | # As an exercise, add a third ubuntu VM in the Vagrantfile and uncomment the following to add it to Ansible's inventory: 9 | # ubuntu12: 10 | # ansible_host: 192.168.50.12 11 | # ansible_private_key_file: .vagrant/machines/ubuntu12/virtualbox/private_key 12 | -------------------------------------------------------------------------------- /inventory/vagrants/inventory_dir/windows-too.orig: -------------------------------------------------------------------------------- 1 | # this file will be ignored because of .orig extension 2 | # see INVENTORY_IGNORE_EXTS when working with inventory directories 3 | [win] 4 | my-windows-machine 5 | -------------------------------------------------------------------------------- /inventory/vagrants/master.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Wes Higbee 3 | email = wes.mcclure@gmail.com 4 | -------------------------------------------------------------------------------- /inventory/vagrants/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Ensure git installed 4 | hosts: centos 5 | tags: [ 'install-git' ] 6 | tasks: 7 | - package: name=git state=latest 8 | when: ansible_os_family == 'RedHat' # conditional task 9 | become: yes # https://docs.ansible.com/ansible/latest/user_guide/become.html 10 | # Note: since we have a group of centos hosts we don't really need the when condition but it is here to demo conditional tasks and in the event we have a mistake or a group that contains a host that isn't a RHEL derivative 11 | 12 | - name: Ensure ~/.gitconfig copied from master.gitconfig 13 | hosts: vagrant 14 | tasks: 15 | 16 | - name: git_config module simplifies listing configuration 17 | git_config: list_all=yes scope=global 18 | 19 | - name: first show no config in targets 20 | command: git config --global --list 21 | ignore_errors: yes 22 | # https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#ignoring-failed-commands 23 | # we know git config lookup will fail so ensure we don't stop playbook execution with ignore_errors 24 | register: git_config_before # how to register variables, in this case we capture the module output 25 | - name: show git config output always - verbosity 0 is default for debug module 26 | debug: var=git_config_before # how to use variables! 27 | 28 | - name: tried and true copy module with master.gitconfig from previously in the course 29 | copy: src=master.gitconfig dest=~/.gitconfig 30 | 31 | - name: show newly added config 32 | command: git config --global --list 33 | ignore_errors: yes 34 | register: git_config_after 35 | - name: ensure to show git config after with debug - this time only show stdout_lines 36 | debug: var=git_config_after.stdout_lines 37 | 38 | ## Notes 39 | # - This is a great read on error handling: https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html 40 | # - Valid variable names: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html?highlight=register#creating-valid-variable-names 41 | -------------------------------------------------------------------------------- /playbooks/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ansible -m copy -a "src=../adhoc/master.gitconfig dest=~/.gitconfig" localhost 3 | 4 | - name: Ensure ~/.gitconfig copied from master.gitconfig 5 | hosts: localhost 6 | tasks: 7 | - copy: src="../adhoc/master.gitconfig" dest="~/.gitconfig" 8 | 9 | - name: Ensure homebrew packages are installed. 10 | hosts: localhost 11 | tasks: 12 | - homebrew: name=bat state=latest 13 | - homebrew: 14 | name: jq 15 | state: latest 16 | # ansible -m homebrew -a "name=bat state=latest" localhost 17 | # ansible -m homebrew -a "name=jq state=latest" localhost -------------------------------------------------------------------------------- /playbooks/script-adhoc-woohoo.sh: -------------------------------------------------------------------------------- 1 | # Here's an example script analogy 2 | # of scripting ansible ad-hoc calls 3 | # to understand the purpose of playbooks. 4 | 5 | # Ensure ~/.gitconfig is basaed on my master.gitconfig 6 | ansible -m copy -a "src=../adhoc/master.gitconfig dest=~/.gitconfig" localhost 7 | 8 | # Ensure `bat` is installed 9 | # - A `cat` replacement for syntax highlighting! 10 | # - IMHO the best highlighter, or at least the best I've found so far :) 11 | ansible -m homebrew -a "name=bat state=latest" localhost 12 | 13 | # Ensure `jq` is installed 14 | # - CLI tool for working with json data! 15 | # - prettify, format, mutate, select subsets, etc 16 | ansible -m homebrew -a "name=jq state=latest" localhost 17 | --------------------------------------------------------------------------------