This commit is contained in:
2020-08-17 12:06:41 -04:00
parent 9fa09f26bd
commit 6eb48873e6
455 changed files with 45184 additions and 14 deletions

3
.gitignore vendored
View File

@@ -108,9 +108,8 @@ venv.bak/
# Ansible
*.retry
roles/
.vscode/
keys/
collections/ansible_collections/
.vscode/
.vscode/

19
roles/bertvv.bind/.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
# .gitignore
# Hidden Vagrant-directory
.vagrant
# Backup files (e.g. Vim, Gedit, etc.)
*~
# Vagrant base boxes (you never know when someone puts one in the repository)
*.box
# Python artefacts
.ropeproject
*.pyc
# Ignore test directory
tests/
vagrant-tests/
docker-tests/

View File

@@ -0,0 +1,48 @@
---
language: python
# Use the new container infrastructure
sudo: required
env:
global:
- ROLE_NAME: bind
matrix:
- MOLECULE_DISTRO: centos7
- MOLECULE_DISTRO: centos8
- MOLECULE_DISTRO: debian8
- MOLECULE_DISTRO: debian9
- MOLECULE_DISTRO: debian10
- MOLECULE_DISTRO: ubuntu1604
- MOLECULE_DISTRO: ubuntu1804
- MOLECULE_DISTRO: ubuntu2004
# Enable docker support
services:
- docker
install:
- sudo apt-get update
- sudo apt-get install bats curl dnsutils
# Install dependencies for Molecule test
- python3 -m pip install molecule yamllint ansible-lint docker netaddr
# Check ansible and molecule version
- ansible --version
- molecule --version
# Create ansible.cfg with correct roles_path
- printf '[defaults]\nroles_path=../' >ansible.cfg
before_script:
# Renames ansible-role-bind to bertvv.bind to make it match with Ansible
# Galaxy
- cd ../
- mv ansible-role-$ROLE_NAME bertvv.$ROLE_NAME
- cd bertvv.$ROLE_NAME
script:
# Run molecule test
- molecule test
notifications:
webhooks: https://galaxy.ansible.com/api/v1/notifications/

View File

@@ -0,0 +1,56 @@
---
rules:
braces:
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: -1
max-spaces-inside-empty: -1
brackets:
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: -1
max-spaces-inside-empty: -1
colons:
max-spaces-before: 0
max-spaces-after: 1
commas:
max-spaces-before: 0
min-spaces-after: 1
max-spaces-after: 1
comments:
level: warning
require-starting-space: true
min-spaces-from-content: 2
comments-indentation:
level: warning
document-end: disable
document-start:
level: warning
present: true
empty-lines:
max: 2
max-start: 0
max-end: 0
empty-values:
forbid-in-block-mappings: false
forbid-in-flow-mappings: false
hyphens:
max-spaces-after: 1
indentation:
spaces: consistent
indent-sequences: true
check-multi-line-strings: false
key-duplicates: enable
key-ordering: disable
line-length:
max: 1000
level: warning
allow-non-breakable-words: true
allow-non-breakable-inline-mappings: false
new-line-at-end-of-file: enable
new-lines:
type: unix
trailing-spaces: enable
truthy:
level: warning

View File

@@ -0,0 +1,250 @@
# Change log
This file contains al notable changes to the bind Ansible role.
This file adheres to the guidelines of [http://keepachangelog.com/](http://keepachangelog.com/). Versioning follows [Semantic Versioning](http://semver.org/). "GH-X" refers to the X'th issue/pull request on the Github project.
## 4.2.0 - 2020-05-23
An update that's been long overdue. Several PRs with new features were merged!
A special thanks to @blofeldthefish for his willingness to help out with maintaining this role and to @RobinsOphalvens for contributing the new testing harness based on Molecule. Thanks to them, further development of this role got out of the deadlock it's been in since the previous version.
## Added
- New supported platforms
- CentOS 8 (GH-107, credit: [Paulius Mazeika](https://github.com/pauliusm))
- Debian 10 (no changes were needed)
- FreeBSD (GH-100, credit: [psa](https://github.com/psa))
- Ubuntu 20.04 LTS (no changes were needed)
- (GH-69) Allow TTLs for individual records (credit: [Stuart Knight](https://github.com/blofeldthefish))
- (GH-79) Added support for the SSHFP record type (credit: [Romuald](https://github.com/rds13))
- (GH-81) Added support for the DNAME record type (credit: [B. Verschueren](https://github.com/bverschueren))
- (GH-82) Added support for the NAPTR record type (credit: [Aido](https://github.com/aido))
- (GH-83) Added support for the [`$GENERATE` directive](http://www.zytrax.com/books/dns/ch8/generate.html) (credit: [Rayford Johnson](https://github.com/rayfordj))
- (GH-85) New role variable `bind_other_logs` (credit: [Paulo E. Castro](https://github.com/pecastro))
- (GH-87) New role variable `bind_dns_keys`, a list of binding keys (credit: [Jérôme Avond](https://github.com/jadjay))
- (GH-88) New role variable `bind_statistics_channels` (credit: [Stuart Knight](https://github.com/blofeldthefish))
- (GH-105, GH-113) New role variable `bind_query_log`, with more flexibility w.r.t. query logging (credit: [Romuald](https://github.com/rds13) and [Jascha Sticher](https://github.com/itbane))
- New keys in `bind_zone_domains`: `create_forward_zones` and `create_reverse_zones`. When present and set to false, they will prevent the creation of the forward or reverse zones, respectively. This results in a reverse only or forward only name server for that zone.
## Changed
- Molecule is now used as testing harness (credit: [Robin Ophalvens](https://github.com/RobinOphalvens)). The previous system was written before any standardised testing tools were available. It became too cumbersome to maintain, which had serious impact on the further development of this role.
- (GH-75) Refactored hash gathering to determine if zone files need to be regenerated (credit: [Stuart Knight](https://github.com/blofeldthefish))
- (GH-89) Add missing `allow-recursion` parameter for bind slaves, allowing them to handle recursion correctly (credit: [Lennart Weller](https://github.com/lhw))
- (GH-91) Ensure the directory for cached slave zones is created (credit: [Otto Sabart](https://github.com/seberm))
- (GH-99) Use `bind_group` variable instead of hard-coded value (credit: [Boris Momčilović](https://github.com/kornrunner))
- (GH-114,115) Fix error with scenario in conjunction with a dhcp shared secret key to provide dynamic dns updates. (credit: [Fabio Rocha](https://github.com/frock81))
## Removed
- (GH-106) Removed DNSSEC Lookaside Validation, this service has been shut down
## 4.1.0 - 2018-10-05
## Added
- (GH-53) Add variable `bind_zone_dir` and `bind_zone_file_mode` for setting the master zone file path and mode, and `bind_extra_include_files` for including arbitrary configuration files into named.conf. (credit: [Brad Durrow](https://github.com/bdurrow))
- (GH-64) Add variable `bind_query_log` to enable query logging (credit: [Angel Barrera](https://github.com/angelbarrera92))
## Changed
- (GH-55) Fix issue with non-existing file when grepping domain (credit: [Tom Meinlschmidt](https://github.com/tmeinlschmidt))
- (GH-57) Fix issue with forwarding in subdomain delegations (credit: [Stuart Knight](https://github.com/blofeldthefish))
- (GH-66) Fix issue that causes playbook to fail when running in `--check` mode (credit: [Jörg Eichhorn](https://github.com/jeichhorn))
- (GH-67) Improved documentation with minimal slave configuration (credit: [Christopher Hicks](https://github.com/chicks-net))
- Add Ubuntu 18.04, Debian 8-9 and Arch Linux to list of supported distros.
## 4.0.1 - 2018-05-21
### Changed
- (GH-52) Move all zone specific configuration options to `bind_zones` (credit: [Stuart Knight](https://github.com/blofeldthefish))
## 4.0.0 - 2018-05-19
### Added
- (GH-50) Add support for multiple zones (credit: [Stuart Knight](https://github.com/blofeldthefish)). **This is a breaking change,** as it changes the syntax for specifying zones.
- Allow out-of-zone name server records
## 3.9.1 - 2018-04-22
## Changed
- Allow multi-line `ansible_managed` comment (credit: [Fazle Arefin](https://github.com/fazlearefin))
- Fix the atrocious implementation of (GH-35)
- Updated documentation for specifying hosts with multiple IP addresses
- Create serial as UTC UNIX time (credit: [David J. Haines](https://github.com/dhaines))
- Fix bugs, linter and deprecation warnings
## 3.9.0 - 2017-11-21
### Added
- (GH-35) Role variable `bind_check_names`, which adds support for check-names (e.g. `check-names master ignore;`)
- (GH-36) Role variable `bind_allow_recursion`, which adds support for allow-recursion (credit: [Loic Dachary](https://github.com/dachary))
- (GH-39) Role variable `bind_zone_delegate`, which adds support for zone delegation / NS records (credit: [Loic Dachary](https://github.com/dachary))
- (GH-40) Role variables `bind_dnssec_enable` and `bind_dnssec_validation`, which makes DNSSEC validation configurable (credit: [Guillaume Darmont](https://github.com/gdarmont)).
### Changed
- (GH-38) Only append domain to MX if it does not end with a dot (credit: [Loic Dachary](https://github.com/dachary))
## 3.8.0 - 2017-07-12
This release adds support for multiple TXT entries and fixes some bugs.
### Added
- (GH-31) Support for multiple TXT entries for the same name (credit: [Rafael Bodill](https://github.com/rafi))
### Changed
- (GH-31) Fixed ipv6 reverse zone hash calculation for complete idempotency (credit: [Stuart Knight](https://github.com/blofeldthefish))
- (GH-32, GH-33) Fix for bug where CNAMEs and Multi-IP entries weren't working (credit: [Greg Cockburn](https://github.com/gergnz))
## 3.7.1 - 2017-07-03
### Changed
- (GH-29) Zone files are fully idempotent, so are only changed when actual content changes (credit: [@Stuart Knight](https://github.com/blofeldthefish))
## 3.7.0 - 2017-06-01
### Added
- (GH-10) Implement reverse IPv6 lookups
- (GH-28) Add option `bind_forwarders` and `bind_forward_only`, which allows BIND to be set up as a caching name server.
## 3.6.1 - 2017-06-01
### Changed
- Fixed a bug with generating the reverse zone names.
## 3.6.0 - 2017-06-01
### Changed
- (GH-25) Allow slave log file to be set with variable `bind_log` instead of a hard coded value (credit @kartone).
- The alignment of columns in the reverse zone file are improved
### Added
- (GH-22, 23) Documentation improvements
- (GH-27) Allow dynamic updates (credit: @bverschueren)
### Removed
- The custom filter plugins were removed. The functionality has since been added to Ansible's built-in filter plugins. This does require `python-netaddr` to be installed on the management node.
## 3.5.2 - 2016-09-29
### Changed
* The call to `named-checkconf` was fixed. It had the full path to the binary, which is not the same on all distributions. (GH-20, credit @peterjanes)
## 3.5.1 - 2016-09-22
### Changed
* The check for master/slave server is improved (GH-19, credit @josetaas)
## 3.5.0 - 2016-07-28
### Added
* Introduced role variable `bind_log`, the path to the log file.
* Introduced role variable `bind_zone_also_notify`, a list of servers that will receive a notification when the master zone file is reloaded (GH-18, credit: Joanna Delaporte)
* Reverse zone files now handle the case with only a single host (GH-18, credit: Joanna Delaporte)
## 3.4.0 - 2016-05-26
### Added
* (GH-16) Support for service record (SRV) lookups
* Support for text record (TXT) lookups
### Changed
* Fixed Ansible 2.0 deprecation warnings
* Generating a serial is no longer considered a change
* Ensured that all role variables have a default value, e.g. empty list instead of undefined. This simplifies template logic (no `if defined` tests), and is considered [deprecated in playbooks within a *with_* loop](https://docs.ansible.com/ansible/porting_guide_2.0.html#deprecated).
## 3.3.1 - 2016-04-08
### Removed
* The `version:` field in `meta/main.yml`. This an unofficial field that is used by a third-party tool for managing role dependencies (librarian-ansible). Custom meta fields are no longer accepted in Ansible 2.0. See [ansible/ansible#13496](https://github.com/ansible/ansible/issues/13496) for more info. Unfortunately, this will break support for librarian-ansible. As a workaround, until this issue is resolved upstream, use version 3.3.0 of this role.
## 3.3.0 - 2016-04-08
### Added
* Added role variable `bind_other_name_servers` for adding NS records for DNS servers outside of the domain. (GH-12)
* Re-added `bind_recursion`, as it is needed in some cases. (GH-14)
### Removed
## 3.2.1 - 2015-12-15
### Added
* The domain name can now also point to an IP address, enabling e.g. "http://example.com/" (GH-11)
## 3.2.0 - 2015-12-07
### Added
* Add support for multiple IP addresses per host (GH-9)
* Allow setting `rrset-order` (for DNS round robin)
* Add support for (multiple) IPv6 (AAAA) records (GH-2). For now, only forward lookups are supported.
### Changed
* Test code is put into a separate branch. This means that test code is no longer included when installing the role from Ansible Galaxy.
## 3.1.0 - 2015-12-04
### Added
* Add support for zone transfers (GH-8)
* Check whether `bind_zone_master_server_ip` was set (GH-7)
### Removed
* Role variable `bind_recursion` was removed. This role is explicitly only suitable for an authoritative DNS server, and in this case, recursion should be off.
## 3.0.0 - 2015-06-14
### Added
* You can now set up a master and slave DNS server.
* The variable `bind_zone_master_server_ip` was added. This is a **required** variable, which makes this release not backwards compatible.
* Automated acceptance tests for the test playbook
## 2.0.0 - 2015-06-10
### Added
* Added EL6 to supported platforms. Thanks to @rilindo for verifying this.
### Changed
* Recursion is turned off by default, which fits an authoritative name server. This change is not backwards compatible, as the behaviour of BIND is different from before when you do not set the variable `bind_recursion` explicitly.
### Removed
* Firewall settings. This should not be a concern of this role. Configuring the firewall is functionality offered by other roles (e.g. [bertvv.bind](https://github.com/bertvv/ansible-role-el7))
## 1.0.0 - 2015-04-22
First release!
### Added
- Functionality for master DNS server
- Multiple reverse lookup zones

View File

@@ -0,0 +1,13 @@
# BSD License
Copyright (c) 2014, Bert Van Vreckem, (bert.vanvreckem@gmail.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

317
roles/bertvv.bind/README.md Normal file
View File

@@ -0,0 +1,317 @@
# Ansible role `bind`
[![Build Status](https://travis-ci.org/bertvv/ansible-role-bind.svg?branch=master)](https://travis-ci.org/bertvv/ansible-role-bind)
An Ansible role for setting up BIND ISC as an **authoritative-only** DNS server for multiple domains. Specifically, the responsibilities of this role are to:
- install BIND
- set up the main configuration file
- master server
- slave server
- set up forward and reverse lookup zone files
This role supports multiple forward and reverse zones, including for IPv6. Although enabling recursion is supported (albeit *strongly* discouraged), consider using another role if you want to set up a caching or forwarding name server.
Configuring the firewall is not a concern of this role, so you should do this using another role (e.g. [bertvv.rh-base](https://galaxy.ansible.com/bertvv/rh-base/)).
If you like/use this role, please consider giving it a star and rating it on the role's [Ansible Galaxy page](https://galaxy.ansible.com/bertvv/bind). Thanks!
See the [change log](CHANGELOG.md) for notable changes between versions.
## Requirements
- **The package `python-ipaddr` should be installed on the management node** (since v3.7.0)
## Role Variables
Variables are not required, unless specified.
| Variable | Default | Comments (type) |
| :--- | :--- | :--- |
| `bind_acls` | `[]` | A list of ACL definitions, which are dicts with fields `name` and `match_list`. See below for an example. |
| `bind_allow_query` | `['localhost']` | A list of hosts that are allowed to query this DNS server. Set to ['any'] to allow all hosts |
| `bind_allow_recursion` | `['any']` | Similar to bind_allow_query, this option applies to recursive queries. |
| `bind_check_names` | `[]` | Check host names for compliance with RFC 952 and RFC 1123 and take the defined action (e.g. `warn`, `ignore`, `fail`). |
| `bind_dns_keys` | `[]` | A list of binding keys, which are dicts with fields `name` `algorithm` and `secret`. See below for an example. |
| `bind_dnssec_enable` | `true` | Is DNSSEC enabled |
| `bind_dnssec_validation` | `true` | Is DNSSEC validation enabled |
| `bind_extra_include_files` | `[]` | |
| `bind_forward_only` | `false` | If `true`, BIND is set up as a caching name server |
| `bind_forwarders` | `[]` | A list of name servers to forward DNS requests to. |
| `bind_listen_ipv4` | `['127.0.0.1']` | A list of the IPv4 address of the network interface(s) to listen on. Set to ['any'] to listen on all interfaces. |
| `bind_listen_ipv6` | `['::1']` | A list of the IPv6 address of the network interface(s) to listen on |
| `bind_log` | `data/named.run` | Path to the log file |
| `bind_other_logs` | - | A list of logging channels to configure, with a separate dict for each domain, with relevant details |
| `- allow_update` | `['none']` | A list of hosts that are allowed to dynamically update this DNS zone. |
| `- also_notify` | - | A list of servers that will receive a notification when the master zone file is reloaded. |
| `- delegate` | `[]` | Zone delegation. See below this table for examples. |
| `bind_query_log` | - | A dict with fields `file` (e.g. `data/query.log`), `versions`, `size`, when defined this will turn on the query log |
| `bind_recursion` | `false` | Determines whether requests for which the DNS server is not authoritative should be forwarded†. |
| `bind_rrset_order` | `random` | Defines order for DNS round robin (either `random` or `cyclic`) |
| `bind_statistcs_channels` | `false` | if `true`, BIND is configured with a statistics_channels clause (currently only supports a single inet) |
| `bind_zone_dir` | - | When defined, sets a custom absolute path to the server directory (for zone files, etc.) instead of the default. |
| `bind_zone_domains` | n/a | A list of domains to configure, with a separate dict for each domain, with relevant details |
| `- allow_update` | `['none']` | A list of hosts that are allowed to dynamically update this DNS zone. |
| `- also_notify` | - | A list of servers that will receive a notification when the master zone file is reloaded. |
| `- create_forward_zones` | - | When initialized and set to `false`, creation of forward zones will be skipped (resulting in a reverse only zone) |
| `- create_reverse_zones` | - | When initialized and set to `false`, creation of reverse zones will be skipped (resulting in a forward only zone) |
| `- delegate` | `[]` | Zone delegation. See below this table for examples. |
| `- hostmaster_email` | `hostmaster` | The e-mail address of the system administrator for the zone |
| `- hosts` | `[]` | Host definitions. See below this table for examples. |
| `- ipv6_networks` | `[]` | A list of the IPv6 networks that are part of the domain, in CIDR notation (e.g. 2001:db8::/48) |
| `- mail_servers` | `[]` | A list of dicts (with fields `name` and `preference`) specifying the mail servers for this domain. |
| `- name_servers` | `[ansible_hostname]` | A list of the DNS servers for this domain. |
| `- name` | `example.com` | The domain name |
| `- networks` | `['10.0.2']` | A list of the networks that are part of the domain |
| `- other_name_servers` | `[]` | A list of the DNS servers outside of this domain. |
| `- services` | `[]` | A list of services to be advertised by SRV records |
| `- text` | `[]` | A list of dicts with fields `name` and `text`, specifying TXT records. `text` can be a list or string. |
| `- naptr` | `[]` | A list of dicts with fields `name`, `order`, `pref`, `flags`, `service`, `regex` and `replacement` specifying NAPTR records. |
| `bind_zone_file_mode` | 0640 | The file permissions for the main config file (named.conf) |
| `bind_zone_master_server_ip` | - | **(Required)** The IP address of the master DNS server. |
| `bind_zone_minimum_ttl` | `1D` | Minimum TTL field in the SOA record. |
| `bind_zone_time_to_expire` | `1W` | Time to expire field in the SOA record. |
| `bind_zone_time_to_refresh` | `1D` | Time to refresh field in the SOA record. |
| `bind_zone_time_to_retry` | `1H` | Time to retry field in the SOA record. |
| `bind_zone_ttl` | `1W` | Time to Live field in the SOA record. |
† Best practice for an authoritative name server is to leave recursion turned off. However, [for some cases](http://www.zytrax.com/books/dns/ch7/queries.html#allow-query-cache) it may be necessary to have recursion turned on.
### Minimal variables for a working zone
Even though only variable `bind_zone_master_server_ip` is required for the role to run without errors, this is not sufficient to get a working zone. In order to set up an authoritative name server that is available to clients, you should also at least define the following variables:
| Variable | Master | Slave |
| :--- | :---: | :---: |
| `bind_zone_domains` | V | V |
| `- name` | V | V |
| `- networks` | V | V |
| `- name_servers` | V | -- |
| `- hosts` | V | -- |
| `bind_listen_ipv4` | V | V |
| `bind_allow_query` | V | V |
### Domain definitions
```Yaml
bind_zone_domains:
- name: mydomain.com # Domain name
create_reverse_zones: false # Skip creation of reverse zones
hosts:
- name: pub01
ip: 192.0.2.1
ipv6: 2001:db8::1
aliases:
- ns
- name: '@' # Enables "http://mydomain.com/"
ip:
- 192.0.2.2 # Multiple IP addresses for a single host
- 192.0.2.3 # results in DNS round robin
sshfp: # Secure shell fingerprint
- "3 1 1262006f9a45bb36b1aa14f45f354b694b77d7c3"
- "3 2 e5921564252fe10d2dbafeb243733ed8b1d165b8fa6d5a0e29198e5793f0623b"
ipv6:
- 2001:db8::2
- 2001:db8::3
aliases:
- www
- name: priv01 # This IP is in another subnet, will result in
ip: 10.0.0.1 # multiple reverse zones
- name: mydomain.net.
aliases:
- name: sub01
type: DNAME # Example of a DNAME alias record
networks:
- '192.0.2'
- '10'
- '172.16'
delegate:
- zone: foo
dns: 192.0.2.1
services:
- name: _ldap._tcp
weight: 100
port: 88
target: dc001
naptr: # Name Authority Pointer record, used for IP
- name: "sip" # telephony
order: 100
pref: 10
flags: "S"
service: "SIP+D2T"
regex: "!^.*$!sip:customer-service@example.com!"
replacement: "_sip._tcp.example.com."
```
### Minimal slave configuration
```Yaml
bind_listen_ipv4: ['any']
bind_allow_query: ['any']
bind_zone_master_server_ip: 192.168.111.222
bind_zone_domains:
- name: example.com
```
### Hosts
Host names that this DNS server should resolve can be specified in `hosts` as a list of dicts with fields `name`, `ip`, `aliases` and `sshfp`. Aliases can be CNAME (default) or DNAME records.
To allow to surf to `http://example.com/`, set the host name of your web server to `'@'` (must be quoted!). In BIND syntax, `@` indicates the domain name itself.
If you want to specify multiple IP addresses for a host, add entries to `bind_zone_hosts` with the same name (e.g. `priv01` in the code snippet). This results in multiple A/AAAA records for that host and allows [DNS round robin](http://www.zytrax.com/books/dns/ch9/rr.html), a simple load balancing technique. The order in which the IP addresses are returned can be configured with role variable `bind_rrset_order`.
### Networks
As you can see, not all hosts are in the same network. This is perfectly acceptable, and supported by this role. All networks should be specified in `networks` (part of bind_zone_domains.name dict), though, or the host will not get a PTR record for reverse lookup:
Remark that only the network part should be specified here! When specifying a class B IP address (e.g. "172.16") in a variable file, it must be quoted. Otherwise, the Yaml parser will interpret it as a float.
Based on the idea and examples detailed at <https://linuxmonk.ch/wordpress/index.php/2016/managing-dns-zones-with-ansible/> for the gdnsd package, the zonefiles are fully idempotent, and thus only get updated if "real" content changes.
### Zone delgation
To delegate a zone to a DNS, it is enough to create a `NS` record (under delegate) which is the equivalent of:
```text
foo IN NS 192.0.2.1
```
### Service records
Service (SRV) records can be added with the services. This should be a list of dicts with mandatory fields `name` (service name), `target` (host providing the service), `port` (TCP/UDP port of the service) and optional fields `priority` (default = 0) and `weight` (default = 0).
### ACLs
ACLs can be defined like this:
```Yaml
bind_acls:
- name: acl1
match_list:
- 192.0.2.0/24
- 10.0.0.0/8
```
The names of the ACLs will be added to the `allow-transfer` clause in global options.
### Binding Keys
Binding keys can be defined like this:
```Yaml
bind_dns_keys:
- name: master_key
algorithm: hmac-sha256
secret: "azertyAZERTY123456"
bind_extra_include_files:
- "{{ bind_auth_file }}"
```
**tip**: Extra include file must be set as an ansible variable because file is OS dependant
This will be set in a file *"{{ bind_auth_file }}* (e.g. /etc/bind/auth_transfer.conf for debian) which have to be added in the list variable **bind_extra_include_files**
## Dependencies
No dependencies.
## Example Playbook
See the test playbook [converge.yml](molecule/default/converge.yml) for an elaborate example that showcases most features.
## Testing
This role is tested using [Ansible Molecule](https://molecule.readthedocs.io/). Tests are launched automatically on [Travis CI](https://travis-ci.org/bertvv/ansible-role-bind) after each commit and PR.
This Molecule configuration will:
- Run Yamllint and Ansible Lint
- Create two Docker containers, one primary (`ns1`) and one secondary (`ns2`) DNS server
- Run a syntax check
- Apply the role with a [test playbook](molecule/default/converge.yml)
- Run acceptance tests with [BATS](https://github.com/bats-core/bats-core/)
This process is repeated for the supported Linux distributions.
### Local test environment
If you want to set up a local test environment, you can use this reproducible setup based on Vagrant+VirtualBox: <https://github.com/bertvv/ansible-testenv>. Steps to install the necessary tools manually:
1. Docker and BATS should be installed on your machine (assumed to run Linux). No Docker containers should be running when you start the test.
2. As recommended by Molecule, create a python virtual environment
3. Install the software tools `python3 -m pip install molecule docker netaddr yamllint ansible-lint`
4. Navigate to the root of the role directory and run `molecule test`
Molecule automatically deletes the containers after a test. If you would like to check out the containers yourself, run `molecule converge` followed by `molecule login --host HOSTNAME`.
The Docker containers are based on images created by [Jeff Geerling](https://hub.docker.com/u/geerlingguy), specifically for Ansible testing (look for images named `geerlingguy/docker-DISTRO-ansible`). You can use any of his images, but only the distributions mentioned in [meta/main.yml](meta/main.yml) are supported.
The default config will start two Centos 7 containers (the primary supported platform at this time). Choose another distro by setting the `MOLECULE_DISTRO` variable with the command, e.g.:
``` bash
MOLECULE_DISTRO=debian9 molecule test
```
or
``` bash
MOLECULE_DISTRO=debian9 molecule converge
```
You can run the acceptance tests on both servers with `molecule verify` or manually with
```console
SUT_IP=172.17.0.2 bats molecule/default/files/dns.bats
```
You need to initialise the variable `SUT_IP`, the system under test's IP address. The primary server, `ns1`, should have IP address 172.17.0.2 and the secondary server, `ns2` 172.17.0.3.
## License
BSD
## Contributors
This role could only have been realized thanks to the contributions of many. If you have an idea to improve it even further, don't hesitate to pitch in!
Issues, feature requests, ideas, suggestions, etc. can be posted in the Issues section.
Pull requests are also very welcome. Please create a topic branch for your proposed changes. If you don't, this will create conflicts in your fork after the merge. Don't hesitate to add yourself to the contributor list below in your PR!
Maintainers:
- [Bert Van Vreckem](https://github.com/bertvv/)
- [Stuart Knight](https://github.com/blofeldthefish)
Contributors:
- [Aido](https://github.com/aido)
- [Angel Barrera](https://github.com/angelbarrera92)
- [B. Verschueren](https://github.com/bverschueren)
- [Boris Momčilović](https://github.com/kornrunner)
- [Brad Durrow](https://github.com/bdurrow)
- [Christopher Hicks](http://www.chicks.net/)
- [David J. Haines](https://github.com/dhaines)
- [Fabio Rocha](https://github.com/frock81)
- [Fazle Arefin](https://github.com/fazlearefin)
- [Greg Cockburn](https://github.com/gergnz)
- [Guillaume Darmont](https://github.com/gdarmont)
- [jadjay](https://github.com/jadjay)
- [Jascha Sticher](https://github.com/itbane)
- [Joanna Delaporte](https://github.com/jdelaporte)
- [Jörg Eichhorn](https://github.com/jeichhorn)
- [Jose Taas](https://github.com/josetaas)
- [Lennart Weller](https://github.com/lhw)
- [Loic Dachary](http://dachary.org)
- [Mario Ciccarelli](https://github.com/kartone)
- [Otto Sabart](https://github.com/seberm)
- [Paulius Mazeika](https://github.com/pauliusm)
- [Paulo E. Castro](https://github.com/pecastro)
- [Peter Janes](https://github.com/peterjanes)
- [psa](https://github.com/psa)
- [Rafael Bodill](https://github.com/rafi)
- [Rayford Johnson](https://github.com/rayfordj)
- [Robin Ophalvens](https://github.com/RobinOphalvens)
- [Romuald](https://github.com/rds13)
- [Tom Meinlschmidt](https://github.com/tmeinlschmidt)

View File

@@ -0,0 +1,70 @@
# roles/bind/defaults/main.yml
---
bind_log: "data/named.run"
bind_zone_domains:
- name: "example.com"
hostmaster_email: "hostmaster"
networks:
- "10.0.2"
# List of acls.
bind_acls: []
# Key binding for slaves
bind_dns_keys: []
# - name: master_key
# algorithm: hmac-sha256
# secret: "azertyAZERTY123456"
# List of IPv4 address of the network interface(s) to listen on. Set to "any"
# to listen on all interfaces
bind_listen_ipv4:
- "127.0.0.1"
# List of IPv6 address of the network interface(s) to listen on.
bind_listen_ipv6:
- "::1"
# List of hosts that are allowed to query this DNS server.
bind_allow_query:
- "localhost"
# Determines whether recursion should be allowed. Typically, an authoritative
# name server should have recursion turned OFF.
bind_recursion: false
bind_allow_recursion:
- "any"
# Allows BIND to be set up as a caching name server
bind_forward_only: false
# List of name servers to forward DNS requests to.
bind_forwarders: []
# DNS round robin order (random or cyclic)
bind_rrset_order: "random"
# statistics channels configuration
bind_statistics_channels: false
bind_statistics_port: 8053
bind_statistics_host: 127.0.0.1
bind_statistics_allow:
- "127.0.0.1"
# DNSSEC configuration
bind_dnssec_enable: true
bind_dnssec_validation: true
bind_extra_include_files: []
# SOA information
bind_zone_ttl: "1W"
bind_zone_time_to_refresh: "1D"
bind_zone_time_to_retry: "1H"
bind_zone_time_to_expire: "1W"
bind_zone_minimum_ttl: "1D"
# File mode for master zone files (needs to be something like 0660 for dynamic updates)
bind_zone_file_mode: "0640"

View File

@@ -0,0 +1,7 @@
# roles/bind/handlers/main.yml
---
- name: reload bind
service:
name: "{{ bind_service }}"
state: reloaded

View File

@@ -0,0 +1,2 @@
install_date: Sun Jun 28 14:49:10 2020
version: v4.2.0

View File

@@ -0,0 +1,34 @@
---
galaxy_info:
author: Bert Van Vreckem
description: >
Sets up ISC BIND as an authoritative DNS server for one or more domains
(primary and/or secondary).
license: BSD
min_ansible_version: 2.7
platforms:
- name: ArchLinux
versions:
- any
- name: Debian
versions:
- jessie
- stretch
- buster
- name: FreeBSD
versions:
- any
- name: EL
versions:
- 7
- 8
- name: Ubuntu
versions:
- xenial
- bionic
- focal
galaxy_tags:
- dns
- networking
- system
dependencies: []

View File

@@ -0,0 +1,117 @@
---
- name: Converge
hosts: all
vars:
bind_zone_dir: /var/local/named-zones
bind_zone_file_mode: '0660'
bind_allow_query:
- any
bind_listen_ipv4:
- any
bind_listen_ipv6:
- any
bind_acls:
- name: acl1
match_list:
- 172.17.0.0/16
bind_forwarders:
- '8.8.8.8'
- '8.8.4.4'
bind_recursion: true
bind_query_log: 'data/query.log'
bind_check_names: 'master ignore'
bind_zone_master_server_ip: 172.17.0.2
bind_zone_minimum_ttl: "2D"
bind_zone_ttl: "2W"
bind_zone_time_to_refresh: "2D"
bind_zone_time_to_retry: "2H"
bind_zone_time_to_expire: "2W"
bind_zone_domains:
- name: 'example.com'
networks:
- '192.0.2'
ipv6_networks:
- '2001:db9::/48'
name_servers:
- ns1.acme-inc.com.
- ns2.acme-inc.com.
hostmaster_email: admin
hosts:
- name: srv001
ip: 192.0.2.1
ipv6: '2001:db9::1'
aliases:
- www
- name: srv002
ip: 192.0.2.2
ipv6: '2001:db9::2'
- name: mail001
ip: 192.0.2.10
ipv6: '2001:db9::3'
mail_servers:
- name: mail001
preference: 10
- name: 'acme-inc.com'
networks:
- '172.17'
- '10'
ipv6_networks:
- '2001:db8::/48'
name_servers:
- ns1
- ns2
hosts:
- name: ns1
ip: 172.17.0.2
- name: ns2
ip: 172.17.0.3
- name: srv001
ip: 172.17.1.1
ipv6: 2001:db8::1
aliases:
- www
- name: srv002
ip: 172.17.1.2
ipv6: 2001:db8::2
aliases:
- mysql
- name: mail001
ip: 172.17.2.1
ipv6: 2001:db8::d:1
aliases:
- smtp
- mail-in
- name: mail002
ip: 172.17.2.2
ipv6: 2001:db8::d:2
- name: mail003
ip: 172.17.2.3
ipv6: 2001:db8::d:3
aliases:
- imap
- mail-out
- name: srv010
ip: 10.0.0.10
- name: srv011
ip: 10.0.0.11
- name: srv012
ip: 10.0.0.12
mail_servers:
- name: mail001
preference: 10
- name: mail002
preference: 20
services:
- name: _ldap._tcp
weight: 100
port: 88
target: srv010
text:
- name: _kerberos
text: KERBEROS.ACME-INC.COM
- name: '@'
text:
- 'some text'
- 'more text'
roles:
- role: bertvv.bind

View File

@@ -0,0 +1,263 @@
#! /usr/bin/env bats
#
# Functional tests for a DNS server set up as a test case for Ansible role
# bertvv.bind
#
# The variable SUT_IP, the IP address of the System Under Test must be set
# outside of the script.
#{{{ Helper functions
# Usage: assert_forward_lookup NAME DOMAIN IP
# Exits with status 0 if NAME.DOMAIN resolves to IP, a nonzero
# status otherwise
assert_forward_lookup() {
local name="$1"
local domain="$2"
local ip="$3"
local result
result=$(dig @"${SUT_IP}" "${name}.${domain}" +short)
echo "Expected: ${ip}"
echo "Actual : ${result}"
[ "${ip}" = "${result}" ]
}
# Usage: assert_forward_ipv6_lookup NAME DOMAIN IP
assert_forward_ipv6_lookup() {
local name="${1}"
local domain="${2}"
local ip="${3}"
local result
result=$(dig @"${SUT_IP}" AAAA "${name}.${domain}" +short)
echo "Expected: ${ip}"
echo "Actual : ${result}"
[ "${ip}" = "${result}" ]
}
# Usage: assert_reverse_lookup NAME DOMAIN IP
# Exits with status 0 if a reverse lookup on IP resolves to NAME,
# a nonzero status otherwise
assert_reverse_lookup() {
local name="$1"
local domain="$2"
local ip="$3"
local expected="${name}.${domain}."
local result
result=$(dig @"${SUT_IP}" -x "${ip}" +short)
echo "Expected: ${expected}"
echo "Actual : ${result}"
[ "${expected}" = "${result}" ]
}
# Usage: assert_alias_lookup ALIAS NAME DOMAIN IP
# Exits with status 0 if a forward lookup on NAME resolves to the
# host name NAME.DOMAIN and to IP, a nonzero status otherwise
assert_alias_lookup() {
local alias="$1"
local name="$2"
local domain="$3"
local ip="$4"
local result
result=$(dig @"${SUT_IP}" "${alias}.${domain}" +short)
grep "${name}\\.${domain}\\." <<< "${result}"
grep "${ip}" <<< "${result}"
}
# Usage: assert_ns_lookup DOMAIN NS_NAME...
# Exits with status 0 if all specified host names occur in the list of
# name servers for the domain.
assert_ns_lookup() {
local domain="${1}"
shift
local result
result=$(dig @"${SUT_IP}" "${domain}" NS +short)
[ -n "${result}" ] # the list of name servers should not be empty
while (( "$#" )); do
grep "$1\\." <<< "${result}"
shift
done
}
# Usage: assert_mx_lookup DOMAIN PREF1 NAME1 PREF2 NAME2...
# e.g. assert_mx_lookup example.com 10 mailsrv1 20 mailsrv2
# Exits with status 0 if all specified host names occur in the list of
# mail servers for the domain.
assert_mx_lookup() {
local domain="${1}"
shift
local result
result=$(dig @"${SUT_IP}" "${domain}" MX +short)
[ -n "${result}" ] # the list of name servers should not be empty
while (( "$#" )); do
grep "$1 $2\\.${domain}\\." <<< "${result}"
shift
shift
done
}
# Usage: assert_srv_lookup DOMAIN SERVICE WEIGHT PORT TARGET
# e.g. assert_srv_lookup example.com _ldap._tcp 0 100 88 ldapsrv
assert_srv_lookup() {
local domain="${1}"
shift
local service="${1}"
shift
local expected="${*}.${domain}."
local result
result=$(dig @"${SUT_IP}" SRV "${service}.${domain}" +short)
echo "expected: ${expected}"
echo "actual : ${result}"
[ "${result}" = "${expected}" ]
}
# Perform a TXT record lookup
# Usage: assert_txt_lookup NAME TEXT...
# e.g. assert_txt_lookup _kerberos.example.com KERBEROS.EXAMPLE.COM
assert_txt_lookup() {
local name="$1"
shift
local result
result=$(dig @"${SUT_IP}" TXT "${name}" +short)
echo "expected: ${*}"
echo "actual : ${result}"
while [ "$#" -ne "0" ]; do
grep "${1}" <<< "${result}"
shift
done
}
#}}}
@test "Forward lookups acme-inc.com" {
# host name domain IP
assert_forward_lookup ns1 acme-inc.com 172.17.0.2
assert_forward_lookup ns2 acme-inc.com 172.17.0.3
assert_forward_lookup srv001 acme-inc.com 172.17.1.1
assert_forward_lookup srv002 acme-inc.com 172.17.1.2
assert_forward_lookup mail001 acme-inc.com 172.17.2.1
assert_forward_lookup mail002 acme-inc.com 172.17.2.2
assert_forward_lookup mail003 acme-inc.com 172.17.2.3
assert_forward_lookup srv010 acme-inc.com 10.0.0.10
assert_forward_lookup srv011 acme-inc.com 10.0.0.11
assert_forward_lookup srv012 acme-inc.com 10.0.0.12
}
@test "Reverse lookups acme-inc.com" {
# host name domain IP
assert_reverse_lookup ns1 acme-inc.com 172.17.0.2
assert_reverse_lookup ns2 acme-inc.com 172.17.0.3
assert_reverse_lookup srv001 acme-inc.com 172.17.1.1
assert_reverse_lookup srv002 acme-inc.com 172.17.1.2
assert_reverse_lookup mail001 acme-inc.com 172.17.2.1
assert_reverse_lookup mail002 acme-inc.com 172.17.2.2
assert_reverse_lookup mail003 acme-inc.com 172.17.2.3
assert_reverse_lookup srv010 acme-inc.com 10.0.0.10
assert_reverse_lookup srv011 acme-inc.com 10.0.0.11
assert_reverse_lookup srv012 acme-inc.com 10.0.0.12
}
@test "Alias lookups acme-inc.com" {
# alias hostname domain IP
assert_alias_lookup www srv001 acme-inc.com 172.17.1.1
assert_alias_lookup mysql srv002 acme-inc.com 172.17.1.2
assert_alias_lookup smtp mail001 acme-inc.com 172.17.2.1
assert_alias_lookup mail-in mail001 acme-inc.com 172.17.2.1
assert_alias_lookup imap mail003 acme-inc.com 172.17.2.3
assert_alias_lookup mail-out mail003 acme-inc.com 172.17.2.3
}
@test "IPv6 forward lookups acme-inc.com" {
# hostname domain IPv6
assert_forward_ipv6_lookup srv001 acme-inc.com 2001:db8::1
assert_forward_ipv6_lookup srv002 acme-inc.com 2001:db8::2
assert_forward_ipv6_lookup mail001 acme-inc.com 2001:db8::d:1
assert_forward_ipv6_lookup mail002 acme-inc.com 2001:db8::d:2
assert_forward_ipv6_lookup mail003 acme-inc.com 2001:db8::d:3
}
@test "IPv6 reverse lookups acme-inc.com" {
# hostname domain IPv6
assert_forward_ipv6_lookup srv001 acme-inc.com 2001:db8::1
assert_forward_ipv6_lookup srv002 acme-inc.com 2001:db8::2
assert_forward_ipv6_lookup mail001 acme-inc.com 2001:db8::d:1
assert_forward_ipv6_lookup mail002 acme-inc.com 2001:db8::d:2
assert_forward_ipv6_lookup mail003 acme-inc.com 2001:db8::d:3
}
@test "NS record lookup acme-inc.com" {
assert_ns_lookup acme-inc.com \
ns1.acme-inc.com \
ns2.acme-inc.com
}
@test "Mail server lookup acme-inc.com" {
assert_mx_lookup acme-inc.com \
10 mail001 \
20 mail002
}
@test "Service record lookup acme-inc.com" {
assert_srv_lookup acme-inc.com _ldap._tcp 0 100 88 srv010
}
@test "TXT record lookup acme-inc.com" {
assert_txt_lookup _kerberos.acme-inc.com KERBEROS.ACME-INC.COM
assert_txt_lookup acme-inc.com "some text" "more text"
}
# Tests for domain example.com
@test "Forward lookups example.com" {
# host name domain IP
assert_forward_lookup srv001 example.com 192.0.2.1
assert_forward_lookup srv002 example.com 192.0.2.2
assert_forward_lookup mail001 example.com 192.0.2.10
}
@test "Reverse lookups example.com" {
# host name domain IP
assert_reverse_lookup srv001 example.com 192.0.2.1
assert_reverse_lookup srv002 example.com 192.0.2.2
assert_reverse_lookup mail001 example.com 192.0.2.10
}
@test "Alias lookups example.com" {
# alias hostname domain IP
assert_alias_lookup www srv001 example.com 192.0.2.1
}
@test "IPv6 forward lookups example.com" {
# hostname domain IPv6
assert_forward_ipv6_lookup srv001 example.com 2001:db9::1
}
@test "IPv6 reverse lookups example.com" {
# hostname domain IPv6
assert_reverse_lookup srv001 example.com 2001:db9::1
}
@test "NS record lookup example.com" {
assert_ns_lookup example.com \
ns1.acme-inc.com \
ns2.acme-inc.com
}
@test "Mail server lookup example.com" {
assert_mx_lookup example.com \
10 mail001
}

View File

@@ -0,0 +1,117 @@
#! /usr/bin/env bash
#
# Author: Bert Van Vreckem <bert.vanvreckem@gmail.com>
#
# Run BATS test files in the current directory, and the ones in the subdirectory
# matching the host name.
#
# The script installs BATS if needed. It's best to put ${bats_install_dir} in
# your .gitignore.
set -o errexit # abort on nonzero exitstatus
set -o nounset # abort on unbound variable
#{{{ Variables
test_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
bats_archive="v0.4.0.tar.gz"
bats_url="https://github.com/sstephenson/bats/archive/${bats_archive}"
bats_install_dir="/opt"
bats_default_location="${bats_install_dir}/bats/libexec/bats"
test_file_pattern="*.bats"
# Color definitions
readonly reset='\e[0m'
readonly black='\e[0;30m'
readonly red='\e[0;31m'
readonly green='\e[0;32m'
readonly yellow='\e[0;33m'
readonly blue='\e[0;34m'
readonly purple='\e[0;35m'
readonly cyan='\e[0;36m'
readonly white='\e[0;37m'
#}}}
main() {
bats=$(find_bats_executable)
if [ -z "${bats}" ]; then
install_bats
bats="${bats_default_location}"
fi
debug "Using BATS executable at: ${bats}"
# List all test cases (i.e. files in the test dir matching the test file
# pattern)
# Tests to be run on all hosts
global_tests=$(find_tests "${test_dir}" 1)
# Tests for individual hosts
host_tests=$(find_tests "${test_dir}/${HOSTNAME}")
# Loop over test files
for test_case in ${global_tests} ${host_tests}; do
info "Running test ${test_case}"
${bats} "${test_case}"
done
}
#{{{ Functions
# Tries to find BATS executable in the PATH or the place where this script
# installs it.
find_bats_executable() {
if which bats > /dev/null; then
which bats
elif [ -x "${bats_default_location}" ]; then
echo "${bats_default_location}"
else
echo ""
fi
}
# Usage: install_bats
install_bats() {
pushd "${bats_install_dir}" > /dev/null 2>&1
curl --location --remote-name "${bats_url}"
tar xzf "${bats_archive}"
mv bats-* bats
rm "${bats_archive}"
popd > /dev/null 2>&1
}
# Usage: find_tests DIR [MAX_DEPTH]
#
# Finds BATS test suites in the specified directory
find_tests() {
local max_depth=""
if [ "$#" -eq "2" ]; then
max_depth="-maxdepth $2"
fi
local tests
tests=$(find "$1" ${max_depth} -type f -name "${test_file_pattern}" -printf '%p\n' 2> /dev/null)
echo "${tests}"
}
# Usage: info [ARG]...
#
# Prints all arguments on the standard output stream
info() {
printf "${yellow}### %s${reset}\n" "${*}"
}
# Usage: debug [ARG]...
#
# Prints all arguments on the standard output stream
debug() {
printf "${cyan}### %s${reset}\n" "${*}"
}
#}}}
main

View File

@@ -0,0 +1,53 @@
---
dependency:
name: galaxy
driver:
# Specifies the driver that should be used. Podman should also work
name: docker
# Linting with yamllint and ansible-lint
# verify.yml is skipped because it uses the shell: module, which would trigger
# a linting error.
lint: |
yamllint .
ansible-lint --exclude=molecule/default/verify.yml
platforms:
# Set name and hostname
- name: ns1
hostname: ns1
# Specify which image should be used. Geerlingguys images are Ansible
# compatible and have Systemd installed
image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest"
# Command to execute when the container starts
command: ${MOLECULE_DOCKER_COMMAND:-""}
# Volumes to mount within the container. Important to enable systemd
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
# Give extended privileges to the container. Necessary for Systemd to
# operate within the container. DO NOT use extended privileges in a
# production environment!
privileged: true
# Allocate pseudo-TTY
tty: true
environment:
container: docker
- name: ns2
hostname: ns2
image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest"
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
privileged: true
tty: true
environment:
container: docker
provisioner:
name: ansible
# Runs the verify.yml playbook
verifier:
name: ansible

View File

@@ -0,0 +1,9 @@
---
- name: Verify
hosts: all
tasks:
# We run the BATS tests from the localhost, since they are black box tests
- name: "Run BATS tests for {{ ansible_hostname }}"
shell: SUT_IP={{ ansible_default_ipv4.address }} bats {{ playbook_dir }}/files/dns.bats
delegate_to: localhost
changed_when: false

View File

@@ -0,0 +1,69 @@
# roles/bind/tasks/main.yml
---
# Initialise distribution-specific variables
- name: Source specific variables
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}.yml"
tags: bind,pretask
- name: Check whether `bind_zone_master_server_ip` was set
assert:
that: bind_zone_master_server_ip is defined
- name: Install BIND
package:
pkg: "{{ item }}"
state: present
with_items:
- "{{ bind_packages }}"
tags: bind
- name: Ensure runtime directories referenced in config exist
file:
path: "{{ item }}"
state: directory
owner: root
group: "{{ bind_group }}"
mode: 0770
with_items:
- "{{ bind_dir }}/dynamic"
- "{{ bind_dir }}/data"
- "{{ bind_zone_dir }}"
tags: bind
- name: Create serial, based on UTC UNIX time
command: date -u +%s
register: timestamp
changed_when: false
run_once: true
check_mode: false
tags: bind
# file to set keys for XFR authentication
- name: create extra config file for authenticated XFR request
tags: pretask
template:
src: auth_transfer.j2
dest: "{{ bind_conf_dir }}/{{ auth_file }}"
mode: 0640
owner: root
group: "{{ bind_group }}"
when: bind_dns_keys is defined and bind_dns_keys|length > 0
- name: Set up the machine as a master DNS server
include_tasks: master.yml
when: bind_zone_master_server_ip in ansible_all_ipv4_addresses
- name: Set up the machine as a slave DNS server
include_tasks: slave.yml
when: bind_zone_master_server_ip not in ansible_all_ipv4_addresses
- name: Start BIND service
service:
name: "{{ bind_service }}"
state: started
enabled: true
tags: bind

View File

@@ -0,0 +1,140 @@
# roles/bind/tasks/master.yml
# Set up a BIND master server
---
- name: Read forward zone hashes
shell: 'grep -s "^; Hash:" {{ bind_zone_dir }}/{{ item.name }} || true'
changed_when: false
check_mode: false
register: forward_hashes_temp
with_items:
- "{{ bind_zone_domains }}"
run_once: true
loop_control:
label: "{{ item.name }}"
- name: create dict of forward hashes
set_fact:
forward_hashes: "{{ forward_hashes|default([]) + [ {'hash': item.stdout|default(), 'name': item.item.name} ] }}"
with_items:
- "{{ forward_hashes_temp.results }}"
run_once: true
loop_control:
label: "{{ item.item.name }}"
- name: Read reverse ipv4 zone hashes
shell: "grep -s \"^; Hash:\" {{ bind_zone_dir }}/{{ ('.'.join(item.1.replace(item.1+'.','').split('.')[::-1])) }}.in-addr.arpa || true"
changed_when: false
check_mode: false
register: reverse_hashes_temp
with_subelements:
- "{{ bind_zone_domains }}"
- networks
- flags:
skip_missing: true
run_once: true
loop_control:
label: "{{ item.1 }}"
- name: create dict of reverse hashes
set_fact:
reverse_hashes: "{{ reverse_hashes|default([]) + [ {'hash': item.0.stdout|default(), 'network': item.1} ] }}"
with_subelements:
- "{{ reverse_hashes_temp.results }}"
- item
run_once: true
loop_control:
label: "{{ item.1.name |default(item.0.cmd.split(' ')[4]) }}"
- name: Read reverse ipv6 zone hashes
shell: "grep -s \"^; Hash:\" {{ bind_zone_dir }}/{{ (item.1 | ipaddr('revdns'))[-(9+(item.1|regex_replace('^.*/','')|int)//2):-1] }} || true"
changed_when: false
check_mode: false
register: reverse_hashes_ipv6_temp
with_subelements:
- "{{ bind_zone_domains }}"
- ipv6_networks
- flags:
skip_missing: true
run_once: true
loop_control:
label: "{{ item.1 }}"
- name: create dict of reverse ipv6 hashes
set_fact:
reverse_hashes_ipv6: "{{ reverse_hashes_ipv6|default([]) + [ {'hash': item.0.stdout|default(), 'network': item.1} ] }}"
with_subelements:
- "{{ reverse_hashes_ipv6_temp.results }}"
- item
run_once: true
loop_control:
label: "{{ item.1.name |default(item.0.cmd.split(' ')[4]) }}"
- name: Master | Main BIND config file (master)
template:
src: master_etc_named.conf.j2
dest: "{{ bind_config }}"
owner: "{{ bind_owner }}"
group: "{{ bind_group }}"
mode: '0640'
setype: named_conf_t
validate: 'named-checkconf %s'
notify: reload bind
tags: bind
- name: Master | Create forward lookup zone file
template:
src: bind_zone.j2
dest: "{{ bind_zone_dir }}/{{ item.name }}"
owner: "{{ bind_owner }}"
group: "{{ bind_group }}"
mode: "{{ bind_zone_file_mode }}"
setype: named_zone_t
validate: 'named-checkzone -d {{ item.name }} %s'
with_items:
- "{{ bind_zone_domains }}"
loop_control:
label: "{{ item.name }}"
when: item.create_forward_zones is not defined or item.create_forward_zones
notify: reload bind
tags: bind
- name: Master | Create reverse lookup zone file
template:
src: reverse_zone.j2
dest: "{{ bind_zone_dir }}/{{ ('.'.join(item.1.replace(item.1+'.','').split('.')[::-1])) }}.in-addr.arpa"
owner: "{{ bind_owner }}"
group: "{{ bind_group }}"
mode: "{{ bind_zone_file_mode }}"
setype: named_zone_t
validate: "named-checkzone {{ ('.'.join(item.1.replace(item.1+'.','').split('.')[::-1])) }}.in-addr.arpa %s"
with_subelements:
- "{{ bind_zone_domains }}"
- networks
- flags:
skip_missing: true
loop_control:
label: "{{ item.1 }}"
when: item.create_reverse_zones is not defined or item.create_reverse_zones
notify: reload bind
tags: bind
- name: Master | Create reverse IPv6 lookup zone file
template:
src: reverse_zone_ipv6.j2
dest: "{{ bind_zone_dir }}/{{ (item.1 | ipaddr('revdns'))[-(9+(item.1|regex_replace('^.*/','')|int)//2):-1] }}"
owner: "{{ bind_owner }}"
group: "{{ bind_group }}"
mode: "{{ bind_zone_file_mode }}"
setype: named_zone_t
validate: "named-checkzone {{ (item.1 | ipaddr('revdns'))[-(9+(item.1|regex_replace('^.*/','')|int)//2):] }} %s"
with_subelements:
- "{{ bind_zone_domains }}"
- ipv6_networks
- flags:
skip_missing: true
loop_control:
label: "{{ item.1 }}"
when: item.create_reverse_zones is not defined or item.create_reverse_zones
notify: reload bind
tags: bind

View File

@@ -0,0 +1,24 @@
# roles/bind/tasks/master.yml
# Set up a BIND slave server
---
- name: Slave | Main BIND config file (slave)
template:
src: slave_etc_named.conf.j2
dest: "{{ bind_config }}"
owner: "{{ bind_owner }}"
group: "{{ bind_group }}"
mode: '0640'
setype: named_conf_t
validate: 'named-checkconf %s'
notify: reload bind
tags: bind
- name: Slave | ensure directory for cached slaves zones
file:
path: "{{ bind_dir }}/slaves"
state: directory
owner: "{{ bind_owner }}"
group: "{{ bind_group }}"
mode: '0770'
setype: named_cache_t

View File

@@ -0,0 +1,12 @@
server {{ ansible_default_ipv4.address }} {
keys { {% for mykey in bind_dns_keys %} {{ mykey.name }}; {% endfor %} };
};
{% for mykey in bind_dns_keys %}
key {{ mykey.name }} {
algorithm {{ mykey.algorithm }};
secret "{{ mykey.secret }}";
{% endfor %}
};

View File

@@ -0,0 +1,140 @@
{#
# First create a dict holding the entire zone information and create a hash
# from it, that it can be compared with subsequent task executions. In this
# way the serial will only be updated if there are some content changes.
#}
{% set _zone_data = {} %}
{% set _ = _zone_data.update({'ttl': bind_zone_ttl}) %}
{% set _ = _zone_data.update({'domain': item.name}) %}
{% set _ = _zone_data.update({'mname': item.name_servers|default([])}) %}
{% set _ = _zone_data.update({'aname': item.other_name_servers|default([])}) %}
{% set _ = _zone_data.update({'mail': item.mail_servers|default([])}) %}
{% if item.hostmaster_email is defined %}
{% set _ = _zone_data.update({'rname': (( item.hostmaster_email )) + ('' if (item.hostmaster_email is search('\.')) else ('.' + _zone_data['domain']))}) %}
{% else %}
{% set _ = _zone_data.update({'rname': 'hostmaster.' + _zone_data['domain']}) %}
{% endif %}
{% set _ = _zone_data.update({'refresh': bind_zone_time_to_refresh}) %}
{% set _ = _zone_data.update({'retry': bind_zone_time_to_retry}) %}
{% set _ = _zone_data.update({'expire': bind_zone_time_to_expire}) %}
{% set _ = _zone_data.update({'minimum': bind_zone_minimum_ttl}) %}
{% set _ = _zone_data.update({'hosts': item.hosts|default([])}) %}
{% set _ = _zone_data.update({'delegate': item.delegate|default([])}) %}
{% set _ = _zone_data.update({'services': item.services|default([])}) %}
{% set _ = _zone_data.update({'text': item.text|default([])}) %}
{% set _ = _zone_data.update({'naptr': item.naptr|default([])}) %}
{#
# Compare the zone file hash with the current zone data hash and set serial
# accordingly
#}
{% set _zone = {'hash': _zone_data | string | hash('md5')} %}
{% for _result in forward_hashes if _result.name == item.name %}
{% set _hash_serial = _result.hash.split(' ')[2:] %}
{% if _hash_serial and _hash_serial[0] == _zone['hash'] %}
{% set _ = _zone.update({'serial': _hash_serial[1]}) %}
{% else %}
{% set _ = _zone.update({'serial': timestamp.stdout}) %}
{% endif %}
{% endfor %}
{#
# Eventually output the zone data
#}
; Hash: {{ _zone['hash'] }} {{ _zone['serial'] }}
; Zone file for {{ _zone_data['domain'] }}
{{ ansible_managed | comment(decoration='; ') }}
$ORIGIN {{ _zone_data['domain'] }}.
$TTL {{ _zone_data['ttl'] }}
{% if _zone_data['mname']|length > 0 %}
@ IN SOA {{ _zone_data['mname']|first }}{% if not _zone_data['mname']|first|regex_search('\.$') %}.{{ _zone_data['domain'] }}.{% endif %} {{ _zone_data['rname'] }}. (
{% else %}
@ IN SOA {{ ansible_hostname }}.{{ _zone_data['domain'] }}. {{ _zone_data['rname'] }}. (
{% endif %}
{{ _zone['serial'] }}
{{ _zone_data['refresh'] }}
{{ _zone_data['retry'] }}
{{ _zone_data['expire'] }}
{{ _zone_data['minimum'] }} )
{% if _zone_data['mname']|length > 0 %}
{% for ns in _zone_data['mname'] %}
IN NS {{ ns }}{% if not ns|regex_search('\.$') %}.{{ _zone_data['domain'] }}.{% endif %}
{% endfor %}
{% else %}
IN NS {{ ansible_hostname }}.{{ _zone_data['domain'] }}.
{% endif %}
{% for ns in _zone_data['aname'] %}
IN NS {{ ns }}.
{% endfor %}
{% for mail in _zone_data['mail'] %}
{% if loop.first %}@{% else %} {% endif %} IN MX {{ mail.preference}} {{ mail.name }}{% if not mail.name.endswith('.') %}.{{ _zone_data['domain'] }}.{% endif %}
{% endfor %}
{% if _zone_data['delegate']|length > 0 %}
{% for host in _zone_data['delegate'] %}
{{ host.zone.ljust(20) }} IN NS {{ host.dns }}
{% endfor %}
{% endif %}
{% if _zone_data['hosts']|length > 0 %}
{% for host in _zone_data['hosts'] %}
{% if host.ip is defined %}
{% if host.ip is string %}
{% if "$GENERATE" not in host.name.upper() %}
{{ host.name.ljust(20) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN A {{ host.ip }}
{% endif %}
{% if "$GENERATE" in host.name.upper() %}
{{ host.name.ljust(20) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN A {{ host.ip }}
{% endif %}
{% else %}
{% for ip in host.ip %}
{{ host.name.ljust(20) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN A {{ ip }}
{% endfor %}
{% endif %}
{% endif %}
{% if host.ipv6 is defined %}
{% if host.ipv6 is string %}
{{ host.name.ljust(20) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN AAAA {{ host.ipv6 }}
{% else %}
{% for ip6 in host.ipv6 %}
{{ host.name.ljust(20) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN AAAA {{ ip6 }}
{% endfor %}
{% endif %}
{% endif %}
{% if host.aliases is defined %}
{% for alias in host.aliases %}
{% if "$GENERATE" not in host.name.upper() %}
{{ (alias.name|default(alias)).ljust(20) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN {{ alias.type|default('cname')|upper}} {{ host.name }}
{% endif %}
{% if "$GENERATE" in host.name.upper() %}
{{ alias.ljust(20) }} IN CNAME {{ host.name.rsplit(None, 1)[1] }}
{% endif %}
{% endfor %}
{% endif %}
{% if host.sshfp is defined %}
{% for sshfp in host.sshfp %}
{{ host.name.ljust(20) }} IN SSHFP {{ sshfp}}
{% endfor %}
{% endif %}
{% endfor %}
{% else %}
{{ ansible_hostname.ljust(26) }} IN A {{ ansible_default_ipv4.address }}
{% endif %}
{% for service in _zone_data['services'] %}
{{ service.name.ljust(20) }}{{ (service.ttl|string).rjust(6) if service.ttl is defined else ''.ljust(6) }} IN SRV {{ service.priority|default('0') }} {{ service.weight|default('0') }} {{ service.port }} {{ service.target }}
{% endfor %}
{% for text in _zone_data['text'] %}
{% if text.text is string %}
{{ text.name.ljust(20) }} IN TXT "{{ text.text }}"
{% else %}
{% for entry in text.text %}
{{ text.name.ljust(20) }} IN TXT "{{ entry }}"
{% endfor %}
{% endif %}
{% endfor %}
{% for naptr in _zone_data['naptr'] %}
{{ naptr.name.ljust(20) }} IN NAPTR {{ naptr.order|default('100') }} {{ naptr.pref|default('10') }} "{{ naptr.flags }}" "{{ naptr.service }}" "{{ naptr.regex }}" {{ naptr.replacement }}
{% endfor %}

View File

@@ -0,0 +1,158 @@
//
// named.conf
//
{{ ansible_managed | comment('c') }}
//
{% for acl in bind_acls %}
acl "{{ acl.name }}" {
{% for match in acl.match_list %}
{{ match }};
{% endfor %}
};
{% endfor %}
options {
listen-on port 53 { {{ bind_listen_ipv4|join('; ') }}; };
listen-on-v6 port 53 { {{ bind_listen_ipv6|join('; ') }}; };
directory "{{ bind_dir }}";
dump-file "{{ bind_dir }}/data/cache_dump.db";
statistics-file "{{ bind_dir }}/data/named_stats.txt";
memstatistics-file "{{ bind_dir }}/data/named_mem_stats.txt";
allow-query { {{ bind_allow_query|join('; ') }}; };
{% if bind_acls|length != 0 %}
allow-transfer { {% for acl in bind_acls %}"{{ acl.name }}"; {% endfor %}};
{% endif %}
{% if bind_check_names is defined %}
check-names {{ bind_check_names }};
{% endif %}
recursion {% if bind_recursion %}yes{% else %}no{% endif %};
{% if bind_recursion %}allow-recursion { {{ bind_allow_recursion|join('; ') }}; };
{% endif %}
{% if bind_forwarders|length > 0 %}forwarders { {{ bind_forwarders|join('; ') }}; };{% endif %}
{% if bind_forward_only %}forward only;{% endif %}
rrset-order { order {{ bind_rrset_order }}; };
dnssec-enable {{ bind_dnssec_enable }};
dnssec-validation {{ bind_dnssec_validation }};
/* Path to ISC DLV key */
bindkeys-file "{{ bind_bindkeys_file }}";
managed-keys-directory "{{ bind_dir }}/dynamic";
pid-file "{{ bind_pid_file }}";
session-keyfile "{{ bind_session_keyfile }}";
{% if bind_query_log is defined %}
querylog yes;
{% endif %}
};
{% if bind_statistics_channels %}
statistics-channels {
inet {{ bind_statistics_host }} port {{ bind_statistics_port }} allow { {{ bind_statistics_allow|join('; ') }}; };
};
{% endif %}
logging {
channel default_debug {
file "{{ bind_log }}";
severity dynamic;
print-time yes;
};
{% if bind_query_log is defined %}
channel querylog {
{% if bind_query_log.file is defined %}
file "{{ bind_query_log.file }}" versions {{ bind_query_log.versions }} size {{ bind_query_log.size }};
{% else %}
file "{{ bind_query_log }}" versions 600 size 20m;
{% endif %}
severity dynamic;
print-time yes;
};
category queries { querylog; };
{% endif %}
{% if bind_other_logs is defined %}
{% for log in bind_other_logs %}
channel {{ log.name }} {
file "{{ log.file }}" versions {{ log.versions }} size {{ log.size }};
severity dynamic;
print-time yes;
};
category "{{ log.name }}" { "{{ log.name }}"; };
{% endfor %}
{% endif %}
};
{% for file in bind_default_zone_files %}
include "{{ file }}";
{% endfor %}
{% for file in bind_extra_include_files %}
include "{{ file }}";
{% endfor %}
{% if bind_zone_domains is defined %}
{% for bind_zone in bind_zone_domains %}
{% if bind_zone.create_forward_zones is not defined or bind_zone.create_forward_zones %}
zone "{{ bind_zone.name }}" IN {
type master;
file "{{ bind_zone_dir }}/{{ bind_zone.name }}";
notify yes;
{% if bind_zone.also_notify is defined %}
also-notify { {{ bind_zone.also_notify|join('; ') }}; };
{% endif %}
{% if bind_zone.allow_update is defined %}
allow-update { {{ bind_zone.allow_update|join('; ') }}; };
{% else %}
allow-update { none; };
{% endif %}
{% if bind_zone.delegate is defined %}
forwarders {};
{% endif %}
};
{% endif %}
{% if bind_zone.networks is defined %}
{% if bind_zone.create_reverse_zones is not defined or bind_zone.create_reverse_zones %}
{% for network in bind_zone.networks %}
zone "{{ ('.'.join(network.replace(network+'.','').split('.')[::-1])) }}.in-addr.arpa" IN {
type master;
file "{{ bind_zone_dir }}/{{ ('.'.join(network.replace(network+'.','').split('.')[::-1])) }}.in-addr.arpa";
notify yes;
{% if bind_zone.also_notify is defined %}
also-notify { {{ bind_zone.also_notify|join('; ') }}; };
{% endif %}
{% if bind_zone.allow_update is defined %}
allow-update { {{ bind_zone.allow_update|join('; ') }}; };
{% else %}
allow-update { none; };
{% endif %}
};
{% endfor %}
{% endif %}
{% endif %}
{% if bind_zone.ipv6_networks is defined %}
{% if bind_zone.create_reverse_zones is not defined or bind_zone.create_reverse_zones %}
{% for network in bind_zone.ipv6_networks %}
zone "{{ (network | ipaddr('revdns'))[-(9+(network|regex_replace('^.*/','')|int)//2):] }}" IN {
type master;
file "{{ bind_zone_dir }}/{{ (network | ipaddr('revdns'))[-(9+(network|regex_replace('^.*/','')|int)//2):-1] }}";
notify yes;
{% if bind_zone.also_notify is defined %}
also-notify { {{ bind_zone.also_notify|join('; ') }}; };
{% endif %}
{% if bind_zone.allow_update is defined %}
allow-update { {{ bind_zone.allow_update|join('; ') }}; };
{% else %}
allow-update { none; };
{% endif %}
};
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}

View File

@@ -0,0 +1,101 @@
{#
# First create a dict holding the entire zone information and create a hash
# from it, that it can be compared with subsequent task executions. In this
# way the serial will only be updated if there are some content changes.
#}
{% set _zone_data = {} %}
{% set _ = _zone_data.update({'ttl': bind_zone_ttl}) %}
{% set _ = _zone_data.update({'domain': item.0.name}) %}
{% set _ = _zone_data.update({'mname': item.0.name_servers|default([])}) %}
{% set _ = _zone_data.update({'aname': item.0.other_name_servers|default([])}) %}
{% if item.0.hostmaster_email is defined %}
{% set _ = _zone_data.update({'rname': (( item.0.hostmaster_email )) + ('' if (item.0.hostmaster_email is search('\.')) else ('.' + _zone_data['domain']))}) %}
{% else %}
{% set _ = _zone_data.update({'rname': 'hostmaster.' + _zone_data['domain']}) %}
{% endif %}
{% set _ = _zone_data.update({'refresh': bind_zone_time_to_refresh}) %}
{% set _ = _zone_data.update({'retry': bind_zone_time_to_retry}) %}
{% set _ = _zone_data.update({'expire': bind_zone_time_to_expire}) %}
{% set _ = _zone_data.update({'minimum': bind_zone_minimum_ttl}) %}
{% set _ = _zone_data.update({'hosts': item.0.hosts|default([]) | selectattr('ip', 'defined') | selectattr('ip', 'string') | selectattr('ip', 'search', '^'+item.1) | list}) %}
{% set _ = _zone_data.update({'revip': ('.'.join(item.1.replace(item.1+'.','').split('.')[::-1]))}) %}
{#
# Compare the zone file hash with the current zone data hash and set serial
# accordingly
#}
{% set _zone = {'hash': _zone_data | string | hash('md5')} %}
{% for _result in reverse_hashes if _result.network == item.1 %}
{% set _hash_serial = _result.hash.split(' ')[2:] %}
{% if _hash_serial and _hash_serial[0] == _zone['hash'] %}
{% set _ = _zone.update({'serial': _hash_serial[1]}) %}
{% else %}
{% set _ = _zone.update({'serial': timestamp.stdout}) %}
{% endif %}
{% endfor %}
{#
# Eventually output the zone data
#}
; Hash: {{ _zone['hash'] }} {{ _zone['serial'] }}
; Reverse zone file for {{ _zone_data['domain'] }}
{{ ansible_managed | comment(decoration='; ') }}
$TTL {{ _zone_data['ttl'] }}
$ORIGIN {{ ('.'.join(item.1.replace(item.1+'.','').split('.')[::-1])) }}.in-addr.arpa.
{% if _zone_data['mname']|length > 0 %}
@ IN SOA {{ _zone_data['mname']|first }}{% if not _zone_data['mname']|first|regex_search('\.$') %}.{{ _zone_data['domain'] }}.{% endif %} {{ _zone_data['rname'] }}. (
{% else %}
@ IN SOA {{ ansible_hostname }}.{{ _zone_data['domain'] }}. {{ _zone_data['rname'] }}. (
{% endif %}
{{ _zone['serial'] }}
{{ _zone_data['refresh'] }}
{{ _zone_data['retry'] }}
{{ _zone_data['expire'] }}
{{ _zone_data['minimum'] }} )
{% if _zone_data['mname']|length > 0 %}
{% for ns in _zone_data['mname'] %}
IN NS {{ ns }}{% if not ns|regex_search('\.$') %}.{{ _zone_data['domain'] }}.{% endif %}
{% endfor %}
{% else %}
IN NS {{ ansible_hostname }}.{{ _zone_data['domain'] }}.
{% endif %}
{% for ns in _zone_data['aname'] %}
IN NS {{ ns }}.
{% endfor %}
{% if _zone_data['hosts']|length > 0 %}
{% for host in _zone_data['hosts'] %}
{% if host.ip is defined %}
{% if host.ip == item.1 %}
@ IN PTR {{ host.name }}.{{ _zone_data['domain'] }}.
{% else %}
{% if host.ip is string and host.ip.startswith(item.1) %}
{% if host.name == '@' %}
{{ ('.'.join(host.ip.replace(item.1+'.','').split('.')[::-1])).ljust(16) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ _zone_data['domain'] }}.
{% else %}
{% if "$GENERATE" not in host.name.upper() %}
{{ ('.'.join(host.ip.replace(item.1+'.','').split('.')[::-1])).ljust(16) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ host.name }}.{{ _zone_data['domain'] }}.
{% endif %}
{% if "$GENERATE" in host.name.upper() %}
{{ host.name.rsplit(None, 1)[0] }} {{ ('.'.join(host.ip.replace(item.1+'.','').split('.')[::-1])).ljust(16) }} IN PTR {{ host.name.rsplit(None, 1)[1] }}.{{ _zone_data['domain'] }}.
{% endif %}
{% endif %}
{% else %}
{% for ip in host.ip %}
{% if ip.startswith(item.1) %}
{{ ('.'.join(ip.replace(item.1+'.','').split('.')[::-1])).ljust(16) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ _zone_data['domain'] }}.
{% if host.name == '@' %}
{% else %}
{{ ('.'.join(ip.replace(item.1+'.','').split('.')[::-1])).ljust(16) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ host.name }}.{{ _zone_data['domain'] }}.
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% else %}
{{ ('.'.join(ansible_default_ipv4.address.replace(item.1+'.','').split('.')[::-1])).ljust(16) }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ ansible_hostname }}.{{ _zone_data['domain'] }}.
{% endif %}

View File

@@ -0,0 +1,96 @@
{#
# First create a dict holding the entire zone information and create a hash
# from it, that it can be compared with subsequent task executions. In this
# way the serial will only be updated if there are some content changes.
#}
{% set _zone_data = {} %}
{% set _ = _zone_data.update({'ttl': bind_zone_ttl}) %}
{% set _ = _zone_data.update({'domain': item.0.name}) %}
{% set _ = _zone_data.update({'mname': item.0.name_servers|default([])}) %}
{% set _ = _zone_data.update({'aname': item.0.other_name_servers|default([])}) %}
{% if item.0.hostmaster_email is defined %}
{% set _ = _zone_data.update({'rname': (( item.0.hostmaster_email )) + ('' if (item.0.hostmaster_email is search('\.')) else ('.' + _zone_data['domain']))}) %}
{% else %}
{% set _ = _zone_data.update({'rname': 'hostmaster.' + _zone_data['domain']}) %}
{% endif %}
{% set _ = _zone_data.update({'refresh': bind_zone_time_to_refresh}) %}
{% set _ = _zone_data.update({'retry': bind_zone_time_to_retry}) %}
{% set _ = _zone_data.update({'expire': bind_zone_time_to_expire}) %}
{% set _ = _zone_data.update({'minimum': bind_zone_minimum_ttl}) %}
{% set _ = _zone_data.update({'hosts': item.0.hosts|default([]) | selectattr('ipv6','defined') | selectattr('ipv6','string') | selectattr('ipv6', 'search', '^'+item.1|regex_replace('/.*$','')) | list }) %}
{% set _ = _zone_data.update({'revip': (item.1 | ipaddr('revdns'))[-(9+(item.1|regex_replace('^.*/','')|int)//2):] }) %}
{#
# Compare the zone file hash with the current zone data hash and set serial
# accordingly
#}
{% set _zone = {'hash': _zone_data | string | hash('md5')} %}
{% for _result in reverse_hashes_ipv6 if _result.network == item.1 %}
{% set _hash_serial = _result.hash.split(' ')[2:] %}
{% if _hash_serial and _hash_serial[0] == _zone['hash'] %}
{% set _ = _zone.update({'serial': _hash_serial[1]}) %}
{% else %}
{% set _ = _zone.update({'serial': timestamp.stdout}) %}
{% endif %}
{% endfor %}
{#
# Eventually output the zone data
#}
; Hash: {{ _zone['hash'] }} {{ _zone['serial'] }}
; Reverse zone file for {{ _zone_data['domain'] }}
{{ ansible_managed | comment(decoration='; ') }}
$TTL {{ _zone_data['ttl'] }}
$ORIGIN {{ (item.1 | ipaddr('revdns'))[-(9+(item.1|regex_replace('^.*/','')|int)//2):] }}
{% if _zone_data['mname']|length > 0 %}
@ IN SOA {{ _zone_data['mname']|first }}{% if not _zone_data['mname']|first|regex_search('\.$') %}.{{ _zone_data['domain'] }}.{% endif %} {{ _zone_data['rname'] }}. (
{% else %}
@ IN SOA {{ ansible_hostname }}.{{ _zone_data['domain'] }}. {{ _zone_data['rname'] }}. (
{% endif %}
{{ _zone['serial'] }}
{{ _zone_data['refresh'] }}
{{ _zone_data['retry'] }}
{{ _zone_data['expire'] }}
{{ _zone_data['minimum'] }} )
{% if _zone_data['mname']|length > 0 %}
{% for ns in _zone_data['mname'] %}
IN NS {{ ns }}{% if not ns|regex_search('\.$') %}.{{ _zone_data['domain'] }}.{% endif %}
{% endfor %}
{% else %}
IN NS {{ ansible_hostname }}.{{ _zone_data['domain'] }}.
{% endif %}
{% for ns in _zone_data['aname'] %}
IN NS {{ ns }}.
{% endfor %}
{% if _zone_data['hosts']|length > 0 %}
{% for host in _zone_data['hosts'] %}
{% if host.ipv6 is defined %}
{% if host.ipv6 == item.1 %}
@ IN PTR {{ host.name }}.{{ _zone_data['domain'] }}.
{% else %}
{% if host.ipv6 is string and host.ipv6.startswith(item.1|regex_replace('/.*$','')) %}
{% if host.name == '@' %}
{{ host.ipv6 | ipaddr('revdns') }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ _zone_data['domain'] }}.
{% else %}
{{ host.ipv6 | ipaddr('revdns') }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ host.name }}.{{ _zone_data['domain'] }}.
{% endif %}
{% else %}
{% for ip in host.ipv6 %}
{% if ip.startswith(item.1|regex_replace('/.*$','')) %}
{{ ip | ipaddr('revdns') }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ _zone_data['domain'] }}.
{% if host.name == '@' %}
{% else %}
{{ ip | ipaddr('revdns') }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ host.name }}.{{ _zone_data['domain'] }}.
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% else %}
{{ ansible_default_ipv6.address | ipaddr('revdns') }}{{ (host.ttl|string).rjust(6) if host.ttl is defined else ''.ljust(6) }} IN PTR {{ ansible_hostname }}.{{ _zone_data['domain'] }}.
{% endif %}

View File

@@ -0,0 +1,120 @@
//
// named.conf
//
{{ ansible_managed | comment('c') }}
//
{% for acl in bind_acls %}
acl "{{ acl.name }}" {
{% for match in acl.match_list %}
{{ match }};
{% endfor %}
};
{% endfor %}
options {
listen-on port 53 { {{ bind_listen_ipv4|join(';') }}; };
listen-on-v6 port 53 { {{ bind_listen_ipv6|join(';') }}; };
directory "{{ bind_dir }}";
dump-file "{{ bind_dir }}/data/cache_dump.db";
statistics-file "{{ bind_dir }}/data/named_stats.txt";
memstatistics-file "{{ bind_dir }}/data/named_mem_stats.txt";
allow-query { {{ bind_allow_query|join(';') }}; };
{% if bind_acls|length != 0 %}
allow-transfer { {% for acl in bind_acls %}"{{ acl.name }}"; {% endfor %}};
{% endif %}
recursion {% if bind_recursion %}yes{% else %}no{% endif %};
{% if bind_recursion %}allow-recursion { {{ bind_allow_recursion|join('; ') }}; };
{% endif %}
{% if bind_forwarders|length > 0 %}forwarders { {{ bind_forwarders|join('; ') }}; };{% endif %}
{% if bind_forward_only %}forward only;{% endif %}
rrset-order { order {{ bind_rrset_order }}; };
dnssec-enable {{ bind_dnssec_enable }};
dnssec-validation {{ bind_dnssec_validation }};
/* Path to ISC DLV key */
bindkeys-file "{{ bind_bindkeys_file }}";
managed-keys-directory "{{ bind_dir }}/dynamic";
pid-file "{{ bind_pid_file }}";
session-keyfile "{{ bind_session_keyfile }}";
{% if bind_query_log is defined %}
querylog yes;
{% endif %}
};
{% if bind_statistics_channels %}
statistics-channels {
inet {{ bind_statistics_host }} port {{ bind_statistics_port }} allow { {{ bind_statistics_allow|join('; ') }}; };
};
{% endif %}
logging {
channel default_debug {
file "{{ bind_log }}";
severity dynamic;
print-time yes;
};
{% if bind_query_log is defined %}
channel querylog {
{% if bind_query_log.file is defined %}
file "{{ bind_query_log.file }}" versions {{ bind_query_log.versions }} size {{ bind_query_log.size }};
{% else %}
file "{{ bind_query_log }}" versions 600 size 20m;
{% endif %}
severity dynamic;
print-time yes;
};
category queries { querylog; };
{% endif %}
};
{% for file in bind_default_zone_files %}
include "{{ file }}";
{% endfor %}
{% for file in bind_extra_include_files %}
include "{{ file }}";
{% endfor %}
{% if bind_zone_domains is defined %}
{% for bind_zone in bind_zone_domains %}
{% if bind_zone.create_forward_zones is not defined or bind_zone.create_forward_zones %}
zone "{{ bind_zone.name }}" IN {
type slave;
masters { {{ bind_zone_master_server_ip }}; };
file "{{ bind_slave_dir }}/{{ bind_zone.name }}";
{% if bind_zone.delegate is defined %}
forwarders {};
{% endif %}
};
{% endif %}
{% if bind_zone.create_reverse_zones is not defined or bind_zone.create_reverse_zones %}
{% if bind_zone.networks is defined %}
{% for network in bind_zone.networks %}
zone "{{ ('.'.join(network.replace(network+'.','').split('.')[::-1])) }}.in-addr.arpa" IN {
type slave;
masters { {{ bind_zone_master_server_ip }}; };
file "{{ bind_slave_dir }}/{{ ('.'.join(network.replace(network+'.','').split('.')[::-1])) }}.in-addr.arpa";
};
{% endfor %}
{% endif %}
{% endif %}
{% if bind_zone.create_reverse_zones is not defined or bind_zone.create_reverse_zones %}
{% if bind_zone.ipv6_networks is defined %}
{% for network in bind_zone.ipv6_networks %}
zone "{{ (network | ipaddr('revdns'))[-(9+(network|regex_replace('^.*/','')|int)//2):] }}" IN {
type slave;
masters { {{ bind_zone_master_server_ip }}; };
file "{{ bind_slave_dir }}/{{ (network | ipaddr('revdns'))[-(9+(network|regex_replace('^.*/','')|int)//2):-1] }}";
};
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}

View File

@@ -0,0 +1,32 @@
# roles/bind/vars/RedHat.yml
---
bind_packages:
- python-netaddr
- bind
- bind-tools
bind_service: named
# Main config file
bind_config: /etc/named.conf
# Zone files included in the installation
bind_default_zone_files: []
# Directory with run-time stuff
bind_dir: /var/named
bind_conf_dir: "{{ bind_dir }}"
auth_file: "auth_transfer.conf"
bind_auth_file: "{{ bind_conf_dir }}/{{ auth_file }}"
bind_owner: root
bind_group: named
bind_bindkeys_file: "/etc/named.iscdlv.key"
bind_pid_file: "/run/named/named.pid"
bind_session_keyfile: "/run/named/session.key"
# Custom location for zone files
bind_zone_dir: "{{ bind_dir }}"
bind_slave_dir: "{{ bind_dir }}/slaves"

View File

@@ -0,0 +1,33 @@
# roles/bind/vars/Debian.yml
---
bind_packages:
- python-netaddr
- bind9
- bind9utils
bind_service: bind9
# Main config file
bind_config: /etc/bind/named.conf
# Localhost zone
bind_default_zone_files:
- /etc/bind/named.conf.default-zones
# Directory with run-time stuff
bind_dir: /var/cache/bind
bind_conf_dir: "/etc/bind"
auth_file: "auth_transfer.conf"
bind_auth_file: "{{ bind_conf_dir }}/{{ auth_file }}"
bind_owner: root
bind_group: bind
bind_bindkeys_file: "/etc/named.iscdlv.key"
bind_pid_file: "/run/named/named.pid"
bind_session_keyfile: "/run/named/session.key"
# Custom location for master zone files
bind_zone_dir: "{{ bind_dir }}"
bind_slave_dir: "{{ bind_dir }}/slaves"

View File

@@ -0,0 +1,32 @@
# roles/bind/vars/Debian.yml
---
bind_packages:
- py36-netaddr
- bind911
bind_service: named
# Main config file
bind_config: /usr/local/etc/namedb/named.conf
# Localhost zone
bind_default_zone_files:
- /usr/local/etc/namedb/named.conf.default-zones
# Directory with run-time stuff
bind_dir: /var/cache/named
bind_conf_dir: "/usr/local/etc/namedb/"
auth_file: "auth_transfer.conf"
bind_auth_file: "{{ bind_conf_dir }}/{{ auth_file }}"
bind_owner: bind
bind_group: bind
bind_bindkeys_file: "/usr/local/etc/namedb/bind.keys"
bind_pid_file: "/var/run/named/named.pid"
bind_session_keyfile: "/var/run/named/session.key"
# Custom location for master zone files
bind_zone_dir: "{{ bind_dir }}/master"
bind_slave_dir: "{{ bind_dir }}/slave"

View File

@@ -0,0 +1,34 @@
# roles/bind/vars/RedHat.yml
---
bind_packages:
- "{{ ( ansible_distribution_major_version == '8' ) | ternary( 'python3-netaddr', 'python-netaddr' ) }}"
- bind
- bind-utils
bind_service: named
# Main config file
bind_config: /etc/named.conf
# Zone files included in the installation
bind_default_zone_files:
- /etc/named.root.key
- /etc/named.rfc1912.zones
# Directory with run-time stuff
bind_dir: /var/named
bind_conf_dir: "/etc/named"
auth_file: "auth_transfer.conf"
bind_auth_file: "{{ bind_conf_dir }}/{{ auth_file }}"
bind_owner: root
bind_group: named
bind_bindkeys_file: "/etc/named.iscdlv.key"
bind_pid_file: "/run/named/named.pid"
bind_session_keyfile: "/run/named/session.key"
# Custom location for master zone files
bind_zone_dir: "{{ bind_dir }}"
bind_slave_dir: "{{ bind_dir }}/slaves"

View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
---
github: geerlingguy
patreon: geerlingguy

View File

@@ -0,0 +1,56 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 90
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- pinned
- security
- planned
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
pulls:
markComment: |-
This pull request has been marked 'stale' due to lack of recent activity. If there is no further activity, the PR will be closed in another 30 days. Thank you for your contribution!
Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark pull requests as stale.
unmarkComment: >-
This pull request is no longer marked for closure.
closeComment: >-
This pull request has been closed due to inactivity. If you feel this is in error, please reopen the pull request or file a new PR with the relevant details.
issues:
markComment: |-
This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution!
Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale.
unmarkComment: >-
This issue is no longer marked for closure.
closeComment: >-
This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details.

3
roles/geerlingguy.gitlab/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.retry
*/__pycache__
*.pyc

View File

@@ -0,0 +1,32 @@
---
language: python
services: docker
env:
global:
- ROLE_NAME: gitlab
matrix:
- MOLECULE_DISTRO: centos7
- MOLECULE_DISTRO: ubuntu1804
- MOLECULE_DISTRO: debian9
- MOLECULE_DISTRO: centos7
MOLECULE_PLAYBOOK: playbook-version.yml
- MOLECULE_DISTRO: ubuntu1804
MOLECULE_PLAYBOOK: playbook-version.yml
install:
# Install test dependencies.
- pip install molecule yamllint ansible-lint docker
before_script:
# Use actual Ansible Galaxy role name for the project directory.
- cd ../
- mv ansible-role-$ROLE_NAME geerlingguy.$ROLE_NAME
- cd geerlingguy.$ROLE_NAME
script:
# Run tests.
- molecule test
notifications:
webhooks: https://galaxy.ansible.com/api/v1/notifications/

View File

@@ -0,0 +1,6 @@
---
extends: default
rules:
line-length:
max: 140
level: warning

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2017 Jeff Geerling
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.

View File

@@ -0,0 +1,179 @@
# Ansible Role: GitLab
[![Build Status](https://travis-ci.org/geerlingguy/ansible-role-gitlab.svg?branch=master)](https://travis-ci.org/geerlingguy/ansible-role-gitlab)
Installs GitLab, a Ruby-based front-end to Git, on any RedHat/CentOS or Debian/Ubuntu linux system.
GitLab's default administrator account details are below; be sure to login immediately after installation and change these credentials!
root
5iveL!fe
## Requirements
None.
## Role Variables
Available variables are listed below, along with default values (see `defaults/main.yml`):
gitlab_domain: gitlab
gitlab_external_url: "https://{{ gitlab_domain }}/"
The domain and URL at which the GitLab instance will be accessible. This is set as the `external_url` configuration setting in `gitlab.rb`, and if you want to run GitLab on a different port (besides 80/443), you can specify the port here (e.g. `https://gitlab:8443/` for port 8443).
gitlab_git_data_dir: "/var/opt/gitlab/git-data"
The `gitlab_git_data_dir` is the location where all the Git repositories will be stored. You can use a shared drive or any path on the system.
gitlab_backup_path: "/var/opt/gitlab/backups"
The `gitlab_backup_path` is the location where Gitlab backups will be stored.
gitlab_edition: "gitlab-ce"
The edition of GitLab to install. Usually either `gitlab-ce` (Community Edition) or `gitlab-ee` (Enterprise Edition).
gitlab_version: ''
If you'd like to install a specific version, set the version here (e.g. `11.4.0-ce.0` for Debian/Ubuntu, or `11.4.0-ce.0.el7` for RedHat/CentOS).
gitlab_config_template: "gitlab.rb.j2"
The `gitlab.rb.j2` template packaged with this role is meant to be very generic and serve a variety of use cases. However, many people would like to have a much more customized version, and so you can override this role's default template with your own, adding any additional customizations you need. To do this:
- Create a `templates` directory at the same level as your playbook.
- Create a `templates\mygitlab.rb.j2` file (just choose a different name from the default template).
- Set the variable like: `gitlab_config_template: mygitlab.rb.j2` (with the name of your custom template).
### SSL Configuration.
gitlab_redirect_http_to_https: "true"
gitlab_ssl_certificate: "/etc/gitlab/ssl/{{ gitlab_domain }}.crt"
gitlab_ssl_certificate_key: "/etc/gitlab/ssl/{{ gitlab_domain }}.key"
GitLab SSL configuration; tells GitLab to redirect normal http requests to https, and the path to the certificate and key (the default values will work for automatic self-signed certificate creation, if set to `true` in the variable below).
# SSL Self-signed Certificate Configuration.
gitlab_create_self_signed_cert: "true"
gitlab_self_signed_cert_subj: "/C=US/ST=Missouri/L=Saint Louis/O=IT/CN={{ gitlab_domain }}"
Whether to create a self-signed certificate for serving GitLab over a secure connection. Set `gitlab_self_signed_cert_subj` according to your locality and organization.
# LDAP Configuration.
gitlab_ldap_enabled: "false"
gitlab_ldap_host: "example.com"
gitlab_ldap_port: "389"
gitlab_ldap_uid: "sAMAccountName"
gitlab_ldap_method: "plain"
gitlab_ldap_bind_dn: "CN=Username,CN=Users,DC=example,DC=com"
gitlab_ldap_password: "password"
gitlab_ldap_base: "DC=example,DC=com"
GitLab LDAP configuration; if `gitlab_ldap_enabled` is `true`, the rest of the configuration will tell GitLab how to connect to an LDAP server for centralized authentication.
gitlab_dependencies:
- openssh-server
- postfix
- curl
- openssl
- tzdata
Dependencies required by GitLab for certain functionality, like timezone support or email. You may change this list in your own playbook if, for example, you would like to install `exim` instead of `postfix`.
gitlab_time_zone: "UTC"
Gitlab timezone.
gitlab_backup_keep_time: "604800"
How long to keep local backups (useful if you don't want backups to fill up your drive!).
gitlab_download_validate_certs: true
Controls whether to validate certificates when downloading the GitLab installation repository install script.
# Email configuration.
gitlab_email_enabled: "false"
gitlab_email_from: "gitlab@example.com"
gitlab_email_display_name: "Gitlab"
gitlab_email_reply_to: "gitlab@example.com"
Gitlab system mail configuration. Disabled by default; set `gitlab_email_enabled` to `true` to enable, and make sure you enter valid from/reply-to values.
# SMTP Configuration
gitlab_smtp_enable: "false"
gitlab_smtp_address: "smtp.server"
gitlab_smtp_port: "465"
gitlab_smtp_user_name: "smtp user"
gitlab_smtp_password: "smtp password"
gitlab_smtp_domain: "example.com"
gitlab_smtp_authentication: "login"
gitlab_smtp_enable_starttls_auto: "true"
gitlab_smtp_tls: "false"
gitlab_smtp_openssl_verify_mode: "none"
gitlab_smtp_ca_path: "/etc/ssl/certs"
gitlab_smtp_ca_file: "/etc/ssl/certs/ca-certificates.crt"
Gitlab SMTP configuration; of `gitlab_smtp_enable` is `true`, the rest of the configuration will tell GitLab how to send mails using an smtp server.
gitlab_nginx_listen_port: 8080
If you are running GitLab behind a reverse proxy, you may want to override the listen port to something else.
gitlab_nginx_listen_https: "false"
If you are running GitLab behind a reverse proxy, you may wish to terminate SSL at another proxy server or load balancer
gitlab_nginx_ssl_verify_client: ""
gitlab_nginx_ssl_client_certificate: ""
If you want to enable [2-way SSL Client Authentication](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-2-way-ssl-client-authentication), set `gitlab_nginx_ssl_verify_client` and add a path to the client certificate in `gitlab_nginx_ssl_client_certificate`.
gitlab_default_theme: 2
GitLab includes a number of themes, and you can set the default for all users with this variable. See [the included GitLab themes to choose a default](https://github.com/gitlabhq/gitlabhq/blob/master/config/gitlab.yml.example#L79-L85).
gitlab_extra_settings:
- gitlab_rails:
- key: "trusted_proxies"
value: "['foo', 'bar']"
- key: "env"
type: "plain"
value: |
{
"http_proxy" => "https://my_http_proxy.company.com:3128",
"https_proxy" => "https://my_http_proxy.company.com:3128",
"no_proxy" => "localhost, 127.0.0.1, company.com"
}
- unicorn:
- key: "worker_processes"
value: 5
- key: "pidfile"
value: "/opt/gitlab/var/unicorn/unicorn.pid"
Gitlab have many other settings ([see official documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template)), and you can add them with this special variable `gitlab_extra_settings` with the concerned setting and the `key` and `value` keywords.
## Dependencies
None.
## Example Playbook
- hosts: servers
vars_files:
- vars/main.yml
roles:
- { role: geerlingguy.gitlab }
*Inside `vars/main.yml`*:
gitlab_external_url: "https://gitlab.example.com/"
## License
MIT / BSD
## Author Information
This role was created in 2014 by [Jeff Geerling](http://jeffgeerling.com/), author of [Ansible for DevOps](http://ansiblefordevops.com/).

View File

@@ -0,0 +1,75 @@
---
# General config.
gitlab_domain: gitlab
gitlab_external_url: "https://{{ gitlab_domain }}/"
gitlab_git_data_dir: "/var/opt/gitlab/git-data"
gitlab_edition: "gitlab-ce"
gitlab_version: ''
gitlab_backup_path: "/var/opt/gitlab/backups"
gitlab_config_template: "gitlab.rb.j2"
# SSL Configuration.
gitlab_redirect_http_to_https: "true"
gitlab_ssl_certificate: "/etc/gitlab/ssl/{{ gitlab_domain }}.crt"
gitlab_ssl_certificate_key: "/etc/gitlab/ssl/{{ gitlab_domain }}.key"
# SSL Self-signed Certificate Configuration.
gitlab_create_self_signed_cert: "true"
gitlab_self_signed_cert_subj: "/C=US/ST=Missouri/L=Saint Louis/O=IT/CN={{ gitlab_domain }}"
# LDAP Configuration.
gitlab_ldap_enabled: "false"
gitlab_ldap_host: "example.com"
gitlab_ldap_port: "389"
gitlab_ldap_uid: "sAMAccountName"
gitlab_ldap_method: "plain"
gitlab_ldap_bind_dn: "CN=Username,CN=Users,DC=example,DC=com"
gitlab_ldap_password: "password"
gitlab_ldap_base: "DC=example,DC=com"
# SMTP Configuration
gitlab_smtp_enable: "false"
gitlab_smtp_address: "smtp.server"
gitlab_smtp_port: "465"
gitlab_smtp_user_name: "smtp user"
gitlab_smtp_password: "smtp password"
gitlab_smtp_domain: "example.com"
gitlab_smtp_authentication: "login"
gitlab_smtp_enable_starttls_auto: "true"
gitlab_smtp_tls: "false"
gitlab_smtp_openssl_verify_mode: "none"
gitlab_smtp_ca_path: "/etc/ssl/certs"
gitlab_smtp_ca_file: "/etc/ssl/certs/ca-certificates.crt"
# 2-way SSL Client Authentication support.
gitlab_nginx_ssl_verify_client: ""
gitlab_nginx_ssl_client_certificate: ""
# Probably best to leave this as the default, unless doing testing.
gitlab_restart_handler_failed_when: 'gitlab_restart.rc != 0'
# Dependencies.
gitlab_dependencies:
- openssh-server
- postfix
- curl
- openssl
- tzdata
# Optional settings.
gitlab_time_zone: "UTC"
gitlab_backup_keep_time: "604800"
gitlab_download_validate_certs: true
gitlab_default_theme: '2'
# Email configuration.
gitlab_email_enabled: "false"
gitlab_email_from: "gitlab@example.com"
gitlab_email_display_name: "Gitlab"
gitlab_email_reply_to: "gitlab@example.com"
# Registry configuration.
gitlab_registry_enable: "false"
gitlab_registry_external_url: "https://gitlab.example.com:4567"
gitlab_registry_nginx_ssl_certificate: "/etc/gitlab/ssl/gitlab.crt"
gitlab_registry_nginx_ssl_certificate_key: "/etc/gitlab/ssl/gitlab.key"

View File

@@ -0,0 +1,5 @@
---
- name: restart gitlab
command: gitlab-ctl reconfigure
register: gitlab_restart
failed_when: gitlab_restart_handler_failed_when | bool

View File

@@ -0,0 +1,2 @@
install_date: Wed Jun 24 18:44:32 2020
version: 3.0.0

View File

@@ -0,0 +1,28 @@
---
dependencies: []
galaxy_info:
author: geerlingguy
description: GitLab Git web interface
company: "Midwestern Mac, LLC"
license: "license (BSD, MIT)"
min_ansible_version: 2.0
platforms:
- name: EL
versions:
- 6
- 7
- name: Debian
versions:
- all
- name: Ubuntu
versions:
- all
galaxy_tags:
- development
- web
- gitlab
- git
- repository
- ci
- integration

View File

@@ -0,0 +1,21 @@
---
- name: Converge
hosts: all
become: true
vars:
gitlab_restart_handler_failed_when: false
pre_tasks:
- name: Update apt cache.
apt: update_cache=true cache_valid_time=600
when: ansible_os_family == 'Debian'
changed_when: false
- name: Remove the .dockerenv file so GitLab Omnibus doesn't get confused.
file:
path: /.dockerenv
state: absent
roles:
- role: geerlingguy.gitlab

View File

@@ -0,0 +1,21 @@
---
dependency:
name: galaxy
driver:
name: docker
lint: |
set -e
yamllint .
ansible-lint
platforms:
- name: instance
image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest"
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
privileged: true
pre_build_image: true
provisioner:
name: ansible
playbooks:
converge: ${MOLECULE_PLAYBOOK:-converge.yml}

View File

@@ -0,0 +1,31 @@
---
- name: Converge
hosts: all
become: true
vars:
gitlab_restart_handler_failed_when: false
pre_tasks:
- name: Update apt cache.
apt: update_cache=true cache_valid_time=600
when: ansible_os_family == 'Debian'
changed_when: false
- name: Remove the .dockerenv file so GitLab Omnibus doesn't get confused.
file:
path: /.dockerenv
state: absent
- name: Set the test GitLab version number for Debian.
set_fact:
gitlab_version: '11.4.0-ce.0'
when: ansible_os_family == 'Debian'
- name: Set the test GitLab version number for RedHat.
set_fact:
gitlab_version: '11.4.0-ce.0.el7'
when: ansible_os_family == 'RedHat'
roles:
- role: geerlingguy.gitlab

View File

@@ -0,0 +1,81 @@
---
- name: Include OS-specific variables.
include_vars: "{{ ansible_os_family }}.yml"
- name: Check if GitLab configuration file already exists.
stat: path=/etc/gitlab/gitlab.rb
register: gitlab_config_file
- name: Check if GitLab is already installed.
stat: path=/usr/bin/gitlab-ctl
register: gitlab_file
# Install GitLab and its dependencies.
- name: Install GitLab dependencies.
package:
name: "{{ gitlab_dependencies }}"
state: present
- name: Install GitLab dependencies (Debian).
apt:
name: gnupg2
state: present
when: ansible_os_family == 'Debian'
- name: Download GitLab repository installation script.
get_url:
url: "{{ gitlab_repository_installation_script_url }}"
dest: /tmp/gitlab_install_repository.sh
validate_certs: "{{ gitlab_download_validate_certs }}"
when: not gitlab_file.stat.exists
- name: Install GitLab repository.
command: bash /tmp/gitlab_install_repository.sh
register: output
when: not gitlab_file.stat.exists
- name: Define the Gitlab package name.
set_fact:
gitlab_package_name: "{{ gitlab_edition }}{{ gitlab_package_version_separator }}{{ gitlab_version }}"
when: gitlab_version | default(false)
- name: Install GitLab
package:
name: "{{ gitlab_package_name | default(gitlab_edition) }}"
state: present
async: 300
poll: 5
when: not gitlab_file.stat.exists
# Start and configure GitLab. Sometimes the first run fails, but after that,
# restarts fix problems, so ignore failures on this run.
- name: Reconfigure GitLab (first run).
command: >
gitlab-ctl reconfigure
creates=/var/opt/gitlab/bootstrapped
failed_when: false
- name: Create GitLab SSL configuration folder.
file:
path: /etc/gitlab/ssl
state: directory
owner: root
group: root
mode: 0700
when: gitlab_create_self_signed_cert
- name: Create self-signed certificate.
command: >
openssl req -new -nodes -x509 -subj "{{ gitlab_self_signed_cert_subj }}"
-days 3650 -keyout {{ gitlab_ssl_certificate_key }} -out {{ gitlab_ssl_certificate }} -extensions v3_ca
creates={{ gitlab_ssl_certificate }}
when: gitlab_create_self_signed_cert
- name: Copy GitLab configuration file.
template:
src: "{{ gitlab_config_template }}"
dest: /etc/gitlab/gitlab.rb
owner: root
group: root
mode: 0600
notify: restart gitlab

View File

@@ -0,0 +1,108 @@
# The URL through which GitLab will be accessed.
external_url "{{ gitlab_external_url }}"
# gitlab.yml configuration
gitlab_rails['time_zone'] = "{{ gitlab_time_zone }}"
gitlab_rails['backup_keep_time'] = {{ gitlab_backup_keep_time }}
gitlab_rails['gitlab_email_enabled'] = {{ gitlab_email_enabled }}
{% if gitlab_email_enabled == "true" %}
gitlab_rails['gitlab_email_from'] = "{{ gitlab_email_from }}"
gitlab_rails['gitlab_email_display_name'] = "{{ gitlab_email_display_name }}"
gitlab_rails['gitlab_email_reply_to'] = "{{ gitlab_email_reply_to }}"
{% endif %}
# Default Theme
gitlab_rails['gitlab_default_theme'] = "{{ gitlab_default_theme }}"
# Whether to redirect http to https.
nginx['redirect_http_to_https'] = {{ gitlab_redirect_http_to_https }}
nginx['ssl_certificate'] = "{{ gitlab_ssl_certificate }}"
nginx['ssl_certificate_key'] = "{{ gitlab_ssl_certificate_key }}"
# The directory where Git repositories will be stored.
git_data_dirs({"default" => {"path" => "{{ gitlab_git_data_dir }}"} })
# The directory where Gitlab backups will be stored
gitlab_rails['backup_path'] = "{{ gitlab_backup_path }}"
# These settings are documented in more detail at
# https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example#L118
gitlab_rails['ldap_enabled'] = {{ gitlab_ldap_enabled }}
{% if gitlab_ldap_enabled == "true" %}
gitlab_rails['ldap_host'] = '{{ gitlab_ldap_host }}'
gitlab_rails['ldap_port'] = {{ gitlab_ldap_port }}
gitlab_rails['ldap_uid'] = '{{ gitlab_ldap_uid }}'
gitlab_rails['ldap_method'] = '{{ gitlab_ldap_method}}' # 'ssl' or 'plain'
gitlab_rails['ldap_bind_dn'] = '{{ gitlab_ldap_bind_dn }}'
gitlab_rails['ldap_password'] = '{{ gitlab_ldap_password }}'
gitlab_rails['ldap_allow_username_or_email_login'] = true
gitlab_rails['ldap_base'] = '{{ gitlab_ldap_base }}'
{% endif %}
# GitLab Nginx
## See https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md
{% if gitlab_nginx_listen_port is defined %}
nginx['listen_port'] = "{{ gitlab_nginx_listen_port }}"
{% endif %}
{% if gitlab_nginx_listen_https is defined %}
nginx['listen_https'] = {{ gitlab_nginx_listen_https }}
{% endif %}
# Use smtp instead of sendmail/postfix
# More details and example configuration at
# https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/smtp.md
gitlab_rails['smtp_enable'] = {{ gitlab_smtp_enable }}
{% if gitlab_smtp_enable == "true" %}
gitlab_rails['smtp_address'] = '{{ gitlab_smtp_address }}'
gitlab_rails['smtp_port'] = {{ gitlab_smtp_port }}
{% if gitlab_smtp_user_name %}
gitlab_rails['smtp_user_name'] = '{{ gitlab_smtp_user_name }}'
{% endif %}
{% if gitlab_smtp_password %}
gitlab_rails['smtp_password'] = '{{ gitlab_smtp_password }}'
{% endif %}
gitlab_rails['smtp_domain'] = '{{ gitlab_smtp_domain }}'
{% if gitlab_smtp_authentication %}
gitlab_rails['smtp_authentication'] = '{{ gitlab_smtp_authentication }}'
{% endif %}
gitlab_rails['smtp_enable_starttls_auto'] = {{ gitlab_smtp_enable_starttls_auto }}
gitlab_rails['smtp_tls'] = {{ gitlab_smtp_tls }}
gitlab_rails['smtp_openssl_verify_mode'] = '{{ gitlab_smtp_openssl_verify_mode }}'
gitlab_rails['smtp_ca_path'] = '{{ gitlab_smtp_ca_path }}'
gitlab_rails['smtp_ca_file'] = '{{ gitlab_smtp_ca_file }}'
{% endif %}
# 2-way SSL Client Authentication.
{% if gitlab_nginx_ssl_verify_client %}
nginx['ssl_verify_client'] = "{{ gitlab_nginx_ssl_verify_client }}"
{% endif %}
{% if gitlab_nginx_ssl_client_certificate %}
nginx['ssl_client_certificate'] = "{{ gitlab_nginx_ssl_client_certificate }}"
{% endif %}
# GitLab registry.
registry['enable'] = {{ gitlab_registry_enable }}
{% if gitlab_registry_enable %}
registry_external_url "{{ gitlab_registry_external_url }}"
registry_nginx['ssl_certificate'] = "{{ gitlab_registry_nginx_ssl_certificate }}"
registry_nginx['ssl_certificate_key'] = "{{ gitlab_registry_nginx_ssl_certificate_key }}"
{% endif %}
{% if gitlab_extra_settings is defined %}
# Extra configuration
{% for extra in gitlab_extra_settings %}
{% for setting in extra %}
{% for kv in extra[setting] %}
{% if (kv.type is defined and kv.type == 'plain') or (kv.value is not string) %}
{{ setting }}['{{ kv.key }}'] = {{ kv.value }}
{% else %}
{{ setting }}['{{ kv.key }}'] = '{{ kv.value }}'
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endif %}
# To change other settings, see:
# https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#changing-gitlab-yml-settings

View File

@@ -0,0 +1,3 @@
---
gitlab_package_version_separator: '='
gitlab_repository_installation_script_url: "https://packages.gitlab.com/install/repositories/gitlab/{{ gitlab_edition }}/script.deb.sh"

View File

@@ -0,0 +1,3 @@
---
gitlab_package_version_separator: '-'
gitlab_repository_installation_script_url: "https://packages.gitlab.com/install/repositories/gitlab/{{ gitlab_edition }}/script.rpm.sh"

View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
---
github: geerlingguy
patreon: geerlingguy

View File

@@ -0,0 +1,56 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 90
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- pinned
- security
- planned
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
pulls:
markComment: |-
This pull request has been marked 'stale' due to lack of recent activity. If there is no further activity, the PR will be closed in another 30 days. Thank you for your contribution!
Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark pull requests as stale.
unmarkComment: >-
This pull request is no longer marked for closure.
closeComment: >-
This pull request has been closed due to inactivity. If you feel this is in error, please reopen the pull request or file a new PR with the relevant details.
issues:
markComment: |-
This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution!
Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale.
unmarkComment: >-
This issue is no longer marked for closure.
closeComment: >-
This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details.

View File

@@ -0,0 +1,6 @@
---
extends: default
rules:
line-length:
max: 120
level: warning

View File

@@ -0,0 +1,13 @@
---
- name: Converge
hosts: all
become: true
pre_tasks:
- name: Update apt cache.
apt: update_cache=true cache_valid_time=600
when: ansible_os_family == 'Debian'
changed_when: false
roles:
- role: geerlingguy.java

View File

@@ -0,0 +1,6 @@
---
# JDK version options include:
# - java
# - openjdk-11-jdk
__java_packages:
- openjdk-11-jdk

View File

@@ -0,0 +1,88 @@
[![GoKEV](http://GoKEV.com/GoKEV200.png)](http://GoKEV.com/)
<div style="position: absolute; top: 40px; left: 200px;">
# lightbulb-ansiblered-deck
This project is the "Ansible Red" deck HTML content. Optionally, a daemon will be started up if you don't exclude tag "phpdaemon"
## Example Playbooks
Here's an example of how you could launch this role and deploy the PHP daemon to start on port `php_port` and also place the php redirect in the main `{{ workshop_web_path }}`` directory:
<pre>
## both of these example tags default to "never" and will not execute
## unless you explicitly call them at launch time. Therefore, the default
## nature of this role will ONLY synch content and not start the PHP web
## service or place the HTML redirect in web root unless run with these tags:
ansible-playbook -i ec2.hosts GoKEV-lab-provision.yml --tags "phpdaemon,phpredirect"
</pre>
Here's an example of how you could launch this role and and not start the PHP daemon (only synch the content).
<pre>
ansible-playbook -i ec2.hosts GoKEV-lab-provision.yml
</pre>
## Here's an example of the playbook
<pre>
---
- name: Deploy the Ansible Red deck and run it as a daemon
hosts: myserver
vars:
workshop_web_path: /ansible-php-content/
workshop_image: images/ansible-logo.png
workshop_name: Ansible Essentials Workshop
workshop_presenter: Demo McDemoson
workshop_title: Solution Architect, Red Hat
workshop_message: my email and contact info
php_port: 8000
roles:
- lightbulb-ansiblered-deck
</pre>
## Stuff still needing to be done
* Inside `index.php` there are variables for the github star and download counts... probably should be converted to vars in defaults or `extra_vars` params
* Certain presenters have requested dynamic ways to exclude certain sections (exclude entire dir `010_topic_that_bores_my_audience`)
* The HTML ID tags can be manually (accidentally) set to the same name. This has commonly bitten me when duplicating a slide as a starting point and then forgetting to change the ID. At some point, these should be dynamically generated per slide. Two slides with the same ID cause an issue where advancing forward / backward can navigate you all the way back to the first instance of the slide and really make an awkward presentation.
* `<section id="<?=$pretty_html_dir?>">` or something similar would make a more unique and less likely duplicated tag.
## Easter Eggs
* Not implemented, but capable: Each directory in `html_slides` can have a `labs` directory. Slides in this dir will automatically be presented as LABS at the end of each section (numbered directory) and presented with a gray intro slide when the deck advances past the topic section.
* example: `html_slides/123_some_topic/labs/00_lab1.html`
* Troubleshooting: See what files are being included by running a dry run:
* `http://ansible.red/deck-ansible/?dryrun`
* Changing other dynamic aspects of the content via URL:
* `person=shadd` (if that person has a preferences file, context will switch to it. This parallels and overrides the variable determined by a FQDN of `shadd.ansible.red` )
* `labs` :: `http://ansible.red/deck-ansible/?labs` (no value is required - simply passing this empty variable forces labs-only display mode and will not show the deck
* `nolabs` :: `http://ansible.red/deck-ansible/?nolabs` (no value is required - opposite of `labs`, this variable forces deck-only display mode and will not show the labs
* without `labs` or `nolabs` the default behavior is to show labs at the end of each section.
* `force` :: `http://ansible.red/deck-ansible/?force` (no value is required). This can be used on its own or in combination with labs, nolabs, person as: `?person=shadd&nolabs&force`. This parameter shows the status on the HTML output to display the mode. Output is something like: "LAB LIMIT 2 = No Labs, only deck" on the very top white line of the deck throughout the entire presentation.
## Notes
* index.php includes a lot of stuff as dynamic files from the html_slides directory
* Any file or dir inside `html_slides` can be excluded by starting it with an underscore
* example: `html_slides/_000_skipping_this_section`
* example: `html_slides/001_not_kipping_this_section/_skipping_this_slide.html`
* Lab slides can also include some variables defined by parsing the directory names. Take a look at this file for a better understanding and see how the `<?=$varible_name?>` php tags are used:
* `html_slides/080_Tasks/_labs/00_Tasks_Labs.html`
* all labs (at this point) are committed with underscore prepending the directory name and won't publish until that dir is changed to `labs`.
## Author
- Adapted by [Kevin Holmes](http://GoKEV.com/) from the original lightbulb workshop deck, split into dynamic individual slides
## Changelog
- 2018-11-01 This project was first committed November 1, 2018 by [Kevin Holmes](http://GoKEV.com/).
- 2018-11-02 Added an `index.php` file to deploy to web root, redirecting to `/deck-ansible` directory when called via tag `phpredirect`

View File

@@ -0,0 +1,11 @@
---
# defaults file for ansiblered-deck-ansible
workshop_web_path: /ansible-php-content/
workshop_image: images/ansible-logo.png
workshop_name: Ansible Essentials Workshop
workshop_presenter: '&nbsp;'
workshop_title: '&nbsp;'
workshop_message: '&nbsp;'
php_port: 8000

View File

@@ -0,0 +1 @@
- prefs/default.prefs.php

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
/**
* Some GoKEV-specific styling
*/
div.transbox {
background-color: #000000;
opacity: 0.7;
/*
max-height: 500px;
max-width: 450;
*/
margin: 5%;
text-align: center;
filter: alpha(opacity=60); /* For IE8 and earlier */
border: 2px solid white;
}
div.transbox p {
margin: 5%;
font-weight: bold;
color: #FFFFFF;
text-align: center;
}
div.transbox h1 {
display: block;
font-size: 2.8em;
text-align: center;
margin-top: .5em;
margin-bottom: .3em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
color: #FFFFFF;
}
div.transbox h2 {
display: block;
font-size: 2.8em;
text-align: center;
margin-top: -1em;
margin-bottom: .3em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
color: #FFFFFF;
}

View File

@@ -0,0 +1,600 @@
/**
* An ANSIBLE theme for reveal.js presentations, similar
* to the simple theme.
*/
@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700');
/*********************************************
* GLOBAL STYLES
*********************************************/
*{
outline: none;
}
body {
background: #fff;
background-color: #fff;
}
mark{
background-color: yellow;
color: black;
}
mark span.hljs-number{
color: #286669;
}
mark span.hljs-symbol,
mark span.hljs-string{
color: #af2e2e;
}
.reveal {
font-family: "Open Sans", sans-serif;
font-size: 28px;
font-weight: normal;
color: #555;
text-align: left;
}
.reveal .slides{
text-align: left;
}
::selection {
color: #fff;
background: rgba(0, 0, 0, 0.99);
text-shadow: none;
}
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
font-weight: inherit;
}
.text-center{
text-align: center;
}
.text-small{
font-size: 70% !important;
}
/*********************************************
* HEADERS
*********************************************/
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
margin: 0 0 20px 0;
color: #cc0000;
font-family: "Open Sans", Impact, sans-serif;
font-weight: bold;
letter-spacing: normal;
text-transform: none;
text-shadow: none;
margin-bottom: 0.6em;
word-wrap: break-word; }
.reveal h1 {
font-size: 2em;
}
.cover .reveal h1{
margin: 1em 0;
}
.reveal h2 {
font-size: 1.35em; }
.reveal h3 {
font-size: 1.2em;
color: #555;
}
.reveal h4 {
font-size: 1em;
color: #555;
}
.reveal h1 {
text-shadow: none; }
/*********************************************
* OTHER
*********************************************/
.reveal p {
margin: 20px 0 0.5em;
line-height: 1.3; }
/* Ensure certain elements are never larger than the slide itself */
.reveal img,
.reveal video,
.reveal iframe {
max-width: 95%;
max-height: 95%; }
.reveal strong,
.reveal b {
font-weight: bold; }
.reveal em {
font-style: italic; }
.reveal ol,
.reveal dl,
.reveal ul {
/*display: inline-block;*/
text-align: left;
margin: 0 0 0 1em; }
.reveal li{
margin: 0 0 0.3em;
}
.reveal ol {
list-style-type: decimal; }
.reveal ul {
list-style-type: disc; }
.reveal ul ul {
list-style-type: square; }
.reveal ul ul ul {
list-style-type: circle; }
.reveal ul ul,
.reveal ul ol,
.reveal ol ol,
.reveal ol ul {
display: block;
margin-left: 40px; }
.reveal dt {
font-weight: bold; }
.reveal dd {
margin-left: 40px; }
.reveal q,
.reveal blockquote {
quotes: none; }
.reveal blockquote {
display: block;
position: relative;
width: 70%;
margin: 20px auto;
padding: 5px;
font-style: italic;
background: rgba(255, 255, 255, 0.05);
/*box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2);*/
}
.reveal blockquote p:first-child,
.reveal blockquote p:last-child {
display: inline-block; }
.reveal q {
font-style: italic; }
.reveal pre,
.reveal pre[class*=language-] {
display: block;
position: relative;
margin: 10px auto;
text-align: left;
font-size: 0.55em;
font-family: monospace;
line-height: 1em;
word-wrap: break-word;
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3);
padding: 0px;
}
.reveal code {
font-family: monospace; }
.reveal pre code {
display: block;
padding: 5px;
overflow: auto;
max-height: 55vh;
word-wrap: normal;
}
.reveal table {
margin: auto;
border-collapse: collapse;
border-spacing: 0; }
.reveal table th {
font-weight: bold; }
.reveal table th,
.reveal table td {
text-align: left;
padding: 0.2em 0.5em 0.2em 0.5em;
border-bottom: 1px solid; }
.reveal table th[align="center"],
.reveal table td[align="center"] {
text-align: center; }
.reveal table th[align="right"],
.reveal table td[align="right"] {
text-align: right; }
.reveal table tbody tr:last-child th,
.reveal table tbody tr:last-child td {
border-bottom: none; }
.reveal sup {
vertical-align: super; }
.reveal sub {
vertical-align: sub; }
.reveal small {
display: inline-block;
font-size: 0.6em;
line-height: 1.2em;
vertical-align: top; }
.reveal small * {
vertical-align: top; }
/*********************************************
* LINKS
*********************************************/
.reveal a {
color: #00008B;
text-decoration: none;
-webkit-transition: color .15s ease;
-moz-transition: color .15s ease;
transition: color .15s ease; }
.reveal a:hover {
color: #0000f1;
text-shadow: none;
border: none; }
.reveal .roll span:after {
color: #fff;
background: #00003f; }
/*********************************************
* IMAGES
*********************************************/
.reveal section img {
margin: 15px 0px;
background: rgba(255, 255, 255, 0.12);
max-height: 500px;
}
.reveal section img.plain {
border: 0;
box-shadow: none; }
.reveal a img {
-webkit-transition: all .15s linear;
-moz-transition: all .15s linear;
transition: all .15s linear; }
.reveal a:hover img {
background: rgba(255, 255, 255, 0.2);
border-color: #00008B;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
/*********************************************
* NAVIGATION CONTROLS
*********************************************/
.reveal .controls {
bottom: auto;
top: 10px;
}
.reveal .controls .navigate-left,
.reveal .controls .navigate-left.enabled {
border-right-color: #00008B; }
.reveal .controls .navigate-right,
.reveal .controls .navigate-right.enabled {
border-left-color: #00008B; }
.reveal .controls .navigate-up,
.reveal .controls .navigate-up.enabled {
border-bottom-color: #00008B; }
.reveal .controls .navigate-down,
.reveal .controls .navigate-down.enabled {
border-top-color: #00008B; }
.reveal .controls .navigate-left.enabled:hover {
border-right-color: #0000f1; }
.reveal .controls .navigate-right.enabled:hover {
border-left-color: #0000f1; }
.reveal .controls .navigate-up.enabled:hover {
border-bottom-color: #0000f1; }
.reveal .controls .navigate-down.enabled:hover {
border-top-color: #0000f1; }
/*********************************************
* PROGRESS BAR
*********************************************/
.reveal .progress {
background: rgba(0, 0, 0, 0.2);
}
.reveal .progress span {
background: #00008B;
-webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
-moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
}
/*********************************************
* CUSTOM STYLES
*
*
* colors:
*
* Pool - #5bbdbf;
* Mango - #ff5850;
*********************************************/
.reveal section .ans-logo img{
box-shadow: none;
border: none;
margin: 0px;
background: none;
}
.cover div.ans-logo{
display: block;
}
div.ans-mark{
position: absolute;
width: 6vw; /*vertical-width*/
bottom: 0.5em;
right: 1em;
z-index: 9999;
}
div.ans-mark .circle{
fill:#CC0000;
}
.cover div.ans-mark .circle,
.title.alt div.ans-mark .circle{
fill:#000;
}
svg .a-mark{
fill:#FFFFFF;
}
.reveal {
box-sizing: border-box;
transition: all 300ms ease-in-out;
}
.reveal p,
.reveal li{
width: 80%;
}
.reveal p.fullwidth,
.reveal .col p,
.reveal .col li,
.reveal aside p{
width: 100%;
}
.reveal ul,
.reveal ol{
margin-left: 2em;
}
.slide-background.present{
background-color: #fff;
}
.cover .slide-background.present,
.title.alt .slide-background.present{
background-color: #cc0000;
display: block !important;
}
.lab.alt .slide-background.present{
background-color: #A9A9A9 ;
display: block !important;
}
.cover .present,
.cover .present h1,
.cover .present h2,
.cover .present h3,
.cover .present h4,
.cover .present h5,
.cover .present h6,
.cover .present p,
.cover .present li{
color: #fff;
}
.title .reveal h1,
.title .reveal h2,
.title .reveal h3,
.title .reveal h4{
color: #cc0000;
}
.title.alt .reveal h1,
.title.alt .reveal h2,
.title.alt .reveal h3,
.title.alt .reveal h4,
.title.alt .reveal p{
color: #fff;
}
.columns{
display: flex;
justify-content: flex-start;
}
.reveal .columns > *{
flex-basis: 31%;
margin-right: 2.333%;
flex-grow: 1;
}
.reveal .progress span {
background: #ff5850;
}
.monospace{
font-family: courier, monospace !important;
}
/*********************************************
* CONTROLS
*********************************************/
.reveal .controls .navigate-left, .reveal .controls .navigate-left.enabled{
border-right-color: #ccc;
}
.reveal .controls .navigate-left.enabled:hover {
border-right-color: #999;
opacity: 0.5;
}
.reveal .controls .navigate-right, .reveal .controls .navigate-right.enabled{
border-left-color: #ccc;
}
.reveal .controls .navigate-right.enabled:hover {
border-left-color: #999;
opacity: 0.5;
}
.reveal .controls .navigate-down, .reveal .controls .navigate-down.enabled {
border-top-color: #ccc;
}
.reveal .controls .navigate-down.enabled:hover {
border-top-color: #999;
opacity: 0.5;
}
.reveal .controls .navigate-up, .reveal .controls .navigate-up.enabled {
border-bottom-color: #ccc;
}
.reveal .controls .navigate-up.enabled:hover {
border-bottom-color: #999;
opacity: 0.5;
}
.reveal .controls button {
opacity: 0.1;
}
/*********************************************
* PRINT
*********************************************/
@media print{
/*@page {size: landscape}*/
.ans-logo{
padding: 20px !important;
background: #c00;
display: inline-block;
}
.reveal,
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6,
.reveal p,
.reveal ul,
.reveal ol,
.reveal li,
.reveal blockquote{
font-family: "Open Sans", sans-serif !important;
color: #000 !important;
}
.reveal blockquote{
font-size: 20px !important;
border: none !important;
}
.reveal p,
.reveal li{
font-size: 20px !important;
}
.reveal img{
border: none !important;
}
.reveal .columns .col {
max-width: 50%;
}
.reveal pre code{
max-height: none !important;
}
.reveal section aside.notes {
display: block;
border-top: 1px solid black;
margin-top: 60px;
padding-top: 20px;
}
.reveal section aside.notes *{
font-size: 14px !important;
font-family: sans-serif;
}
div.ans-mark{
position: fixed;
width: 6vw; /*vertical-width*/
z-index: 9999;
}
}
/*
@media print and (orientation:landscape) {
.reveal section aside.notes {
display: none !important;
}
}
*/

View File

@@ -0,0 +1,3 @@
<?php
header("location:/");

View File

@@ -0,0 +1,203 @@
/* Default Print Stylesheet Template
by Rob Glazebrook of CSSnewbie.com
Last Updated: June 4, 2008
Feel free (nay, compelled) to edit, append, and
manipulate this file as you see fit. */
@media print {
/* SECTION 1: Set default width, margin, float, and
background. This prevents elements from extending
beyond the edge of the printed page, and prevents
unnecessary background images from printing */
html {
background: #fff;
width: auto;
height: auto;
overflow: visible;
}
body {
background: #fff;
font-size: 20pt;
width: auto;
height: auto;
border: 0;
margin: 0 5%;
padding: 0;
overflow: visible;
float: none !important;
}
/* SECTION 2: Remove any elements not needed in print.
This would include navigation, ads, sidebars, etc. */
.nestedarrow,
.controls,
.fork-reveal,
.share-reveal,
.state-background,
.reveal .progress,
.reveal .backgrounds,
.reveal .slide-number {
display: none !important;
}
/* SECTION 3: Set body font face, size, and color.
Consider using a serif font for readability. */
body, p, td, li, div {
font-size: 20pt!important;
font-family: Georgia, "Times New Roman", Times, serif !important;
color: #000;
}
/* SECTION 4: Set heading font face, sizes, and color.
Differentiate your headings from your body text.
Perhaps use a large sans-serif for distinction. */
h1,h2,h3,h4,h5,h6 {
color: #000!important;
height: auto;
line-height: normal;
font-family: Georgia, "Times New Roman", Times, serif !important;
text-shadow: 0 0 0 #000 !important;
text-align: left;
letter-spacing: normal;
}
/* Need to reduce the size of the fonts for printing */
h1 { font-size: 28pt !important; }
h2 { font-size: 24pt !important; }
h3 { font-size: 22pt !important; }
h4 { font-size: 22pt !important; font-variant: small-caps; }
h5 { font-size: 21pt !important; }
h6 { font-size: 20pt !important; font-style: italic; }
/* SECTION 5: Make hyperlinks more usable.
Ensure links are underlined, and consider appending
the URL to the end of the link for usability. */
a:link,
a:visited {
color: #000 !important;
font-weight: bold;
text-decoration: underline;
}
/*
.reveal a:link:after,
.reveal a:visited:after {
content: " (" attr(href) ") ";
color: #222 !important;
font-size: 90%;
}
*/
/* SECTION 6: more reveal.js specific additions by @skypanther */
ul, ol, div, p {
visibility: visible;
position: static;
width: auto;
height: auto;
display: block;
overflow: visible;
margin: 0;
text-align: left !important;
}
.reveal pre,
.reveal table {
margin-left: 0;
margin-right: 0;
}
.reveal pre code {
padding: 20px;
border: 1px solid #ddd;
}
.reveal blockquote {
margin: 20px 0;
}
.reveal .slides {
position: static !important;
width: auto !important;
height: auto !important;
left: 0 !important;
top: 0 !important;
margin-left: 0 !important;
margin-top: 0 !important;
padding: 0 !important;
zoom: 1 !important;
overflow: visible !important;
display: block !important;
text-align: left !important;
-webkit-perspective: none;
-moz-perspective: none;
-ms-perspective: none;
perspective: none;
-webkit-perspective-origin: 50% 50%;
-moz-perspective-origin: 50% 50%;
-ms-perspective-origin: 50% 50%;
perspective-origin: 50% 50%;
}
.reveal .slides section {
visibility: visible !important;
position: static !important;
width: auto !important;
height: auto !important;
display: block !important;
overflow: visible !important;
left: 0 !important;
top: 0 !important;
margin-left: 0 !important;
margin-top: 0 !important;
padding: 60px 20px !important;
z-index: auto !important;
opacity: 1 !important;
page-break-after: always !important;
-webkit-transform-style: flat !important;
-moz-transform-style: flat !important;
-ms-transform-style: flat !important;
transform-style: flat !important;
-webkit-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
transform: none !important;
-webkit-transition: none !important;
-moz-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
.reveal .slides section.stack {
padding: 0 !important;
}
.reveal section:last-of-type {
page-break-after: avoid !important;
}
.reveal section .fragment {
opacity: 1 !important;
visibility: visible !important;
-webkit-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
transform: none !important;
}
.reveal section img {
display: block;
margin: 15px 0px;
background: rgba(255,255,255,1);
border: 1px solid #666;
box-shadow: none;
}
.reveal section small {
font-size: 0.8em;
}
}

View File

@@ -0,0 +1,171 @@
/**
* This stylesheet is used to print reveal.js
* presentations to PDF.
*
* https://github.com/hakimel/reveal.js#pdf-export
*/
* {
-webkit-print-color-adjust: exact;
}
body {
margin: 0 auto !important;
border: 0;
padding: 0;
float: none !important;
overflow: visible;
}
html {
width: 100%;
height: 100%;
overflow: visible;
}
/* Remove any elements not needed in print. */
.nestedarrow,
.reveal .controls,
.reveal .progress,
.reveal .playback,
.reveal.overview,
.fork-reveal,
.share-reveal,
.state-background {
display: none !important;
}
h1, h2, h3, h4, h5, h6 {
text-shadow: 0 0 0 #000 !important;
}
.reveal pre code {
overflow: hidden !important;
font-family: Courier, 'Courier New', monospace !important;
}
ul, ol, div, p {
visibility: visible;
position: static;
width: auto;
height: auto;
display: block;
overflow: visible;
margin: auto;
}
.reveal {
width: auto !important;
height: auto !important;
overflow: hidden !important;
}
.reveal .slides {
position: static;
width: 100% !important;
height: auto !important;
zoom: 1 !important;
left: auto;
top: auto;
margin: 0 !important;
padding: 0 !important;
overflow: visible;
display: block;
-webkit-perspective: none;
-moz-perspective: none;
-ms-perspective: none;
perspective: none;
-webkit-perspective-origin: 50% 50%; /* there isn't a none/auto value but 50-50 is the default */
-moz-perspective-origin: 50% 50%;
-ms-perspective-origin: 50% 50%;
perspective-origin: 50% 50%;
}
.reveal .slides .pdf-page {
position: relative;
overflow: hidden;
z-index: 1;
}
.reveal .slides section {
page-break-after: always !important;
visibility: visible !important;
display: block !important;
position: relative !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
min-height: 1px;
opacity: 1 !important;
-webkit-transform-style: flat !important;
-moz-transform-style: flat !important;
-ms-transform-style: flat !important;
transform-style: flat !important;
-webkit-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
transform: none !important;
}
.reveal section.stack {
margin: 0 !important;
padding: 0 !important;
page-break-after: avoid !important;
height: auto !important;
min-height: auto !important;
}
.reveal img {
box-shadow: none;
}
.reveal .roll {
overflow: visible;
line-height: 1em;
}
/* Slide backgrounds are placed inside of their slide when exporting to PDF */
.reveal .slide-background {
display: block !important;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: auto !important;
}
/* Display slide speaker notes when 'showNotes' is enabled */
.reveal .speaker-notes-pdf {
display: block;
width: 100%;
max-height: none;
top: auto;
right: auto;
bottom: auto;
left: auto;
z-index: 100;
}
/* Layout option which makes notes appear on a separate page */
.reveal .speaker-notes-pdf[data-layout="separate-page"] {
position: relative;
color: inherit;
background-color: transparent;
padding: 20px;
page-break-after: always;
}
/* Display slide numbers when 'slideNumber' is enabled */
.reveal .slide-number-pdf {
display: block;
position: absolute;
font-size: 14px;
}

View File

@@ -0,0 +1 @@
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#a67f59;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.function{color:#DD4A68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}/*# sourceMappingURL=prism.min.css.map */

View File

@@ -0,0 +1,80 @@
/*
Zenburn style from voldmar.ru (c) Vladimir Epifanov <voldmar@voldmar.ru>
based on dark.css by Ivan Sagalaev
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #3f3f3f;
color: #dcdcdc;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-tag {
color: #e3ceab;
}
.hljs-template-tag {
color: #dcdcdc;
}
.hljs-number {
color: #8cd0d3;
}
.hljs-variable,
.hljs-template-variable,
.hljs-attribute {
color: #efdcbc;
}
.hljs-literal {
color: #efefaf;
}
.hljs-subst {
color: #8f8f8f;
}
.hljs-title,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-section,
.hljs-type {
color: #efef8f;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link {
color: #dca3a3;
}
.hljs-deletion,
.hljs-string,
.hljs-built_in,
.hljs-builtin-name {
color: #cc9393;
}
.hljs-addition,
.hljs-comment,
.hljs-quote,
.hljs-meta {
color: #7f9f7f;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,110 @@
* { margin: 0; padding: 0; }
.terminal {
border-radius: 5px 5px 0 0;
position: relative;
}
.terminal .top {
background: #E8E6E8;
color: black;
padding: 5px;
border-radius: 3px 3px 0 0;
}
.terminal .btns {
position: absolute;
top: 7px;
left: 5px;
}
.terminal .circle {
width: 12px;
height: 12px;
display: inline-block;
border-radius: 15px;
margin-left: 2px;
border-width: 1px;
border-style: solid;
}
.red { background: #EC6A5F; border-color: #D04E42; }
.green { background: #64CC57; border-color: #4EA73B; }
.yellow{ background: #F5C04F; border-color: #D6A13D; }
.clear{clear: both;}
.title{
text-align: center;
font-size: 8px;
}
.terminal .title {
color: #000000;
padding: 0px;
font-family: verdana;
font-size: 12px;
}
.terminal .bodys {
background: black;
color: #7AFB4C;
padding: 15px;
overflow: auto;
font-family: monospace;
text-align: center;
font-size: 16px;
}
.terminal .bodysw {
background: black;
color: #FFFFFF;
padding: 15px;
overflow: auto;
font-family: monospace;
font-size: 16px;
}
.terminal .bodym {
background: black;
color: #7AFB4C;
padding: 15px;
overflow: auto;
font-family: monospace;
font-size: 24px;
}
.terminal .bodymw {
background: black;
color: #FFFFFF;
padding: 15px;
overflow: auto;
font-family: monospace;
font-size: 24px;
}
.terminal .bodyl {
background: black;
color: #7AFB4C;
padding: 15px;
overflow: auto;
font-family: monospace;
font-size: 36px;
}
.terminal .bodylw {
background: black;
color: #FFFFFF;
padding: 15px;
overflow: auto;
font-family: monospace;
font-size: 36px;
}
.space {
background: black;
margin: 5px;
}
.shadow {
box-shadow: 0px 0px 10px rgba(0,0,0,.4)
}

View File

@@ -0,0 +1,3 @@
<?php
header("location:/");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/css/reveal.css
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
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/css/zenburn.css
https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/themes/prism.min.css
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/js/head.min.js
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/js/reveal.js
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/marked.js
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/markdown/markdown.js
https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js
https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-yaml.min.js
https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/plugin/highlight/highlight.js

View File

@@ -0,0 +1,89 @@
<?php
$this_script = $_SERVER['SCRIPT_NAME'];
$outvars .= "\t<tr>\n\t\t<td colspan=\"100%\"><h1>\$_ENV</h1></td>\n\t</tr>\n";
foreach( $_ENV as $key => $value){
$count++;
$linefront = "\t<tr>\n\t\t<td>$count</td>\n\t\t<td>";
$lineend = "</td>\n\t\t<td>$value</td>\n\t</tr>\n";
$outvars .= "$linefront\$_ENV['$key']$lineend";
}
$outvars .= "\t<tr>\n\t\t<td colspan=\"100%\"><h1>\$_SERVER</h1></td>\n\t</tr>\n";
foreach( $_SERVER as $key => $value){
if ($key == "PHP_AUTH_PW"){
$value = ereg_replace("[^.*]", "*", $value) . " <--- (this value displays in plaintext but has been obfusticated in this script)";
}
$count++;
$linefront = "\t<tr>\n\t\t<td>$count</td>\n\t\t<td>";
$lineend = "</td>\n\t\t<td>$value</td>\n\t</tr>\n";
$outvars .= "$linefront\$_SERVER['$key']$lineend";
}
$outvars .= "\t<tr>\n\t\t<td colspan=\"100%\"><h1>\$_POST</h1></td>\n\t</tr>\n";
foreach( $_POST as $key => $value){
$count++;
$linefront = "\t<tr>\n\t\t<td>$count</td>\n\t\t<td>";
$lineend = "</td>\n\t\t<td>$value</td>\n\t</tr>\n";
$outvars .= "$linefront\$_POST['$key']$lineend";
}
$outvars .= "\t<tr>\n\t\t<td colspan=\"100%\"><h1>\$_GET</h1></td>\n\t</tr>\n";
foreach( $_GET as $key => $value){
$count++;
$linefront = "\t<tr>\n\t\t<td>$count</td>\n\t\t<td>";
$lineend = "</td>\n\t\t<td>$value</td>\n\t</tr>\n";
$outvars .= "$linefront\$_GET['$key']$lineend";
}
?>
<style type="text/css">
FONT,BODY {
font-family: Verdana,sans,arial,Helvetica;
font-size: 36px;
}
table.vars {
border-width: 0px 0px 0px 0px;
border-spacing: 2px;
border-style: double double double double;
border-color: gray gray gray gray;
border-collapse: separate;
background-color: white;
}
table.vars th {
border-width: 1px 1px 1px 1px;
padding: 3px 3px 3px 3px;
border-style: groove groove groove groove;
border-color: gray gray gray gray;
background-color: white;
-moz-border-radius: 9px 9px 9px 9px;
}
table.vars td {
border-width: 1px 1px 1px 1px;
padding: 5px 5px 5px 5px;
border-style: groove groove groove groove;
border-color: gray gray gray gray;
background-color: white;
-moz-border-radius: 9px 9px 9px 9px;
}
table.vars tr {
height: 25px;
}
</style>
<form method="POST" action="<?=$this_script?>">
<table class="vars">
<a href="<?=$this_script?>"><?=$this_script?> (this script)</a><br>
<input type="submit" value="SUBMIT POST"><br>
<input type="text" name="text"><br>
<br>
<?=$outvars?>
</table>
</form>

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

View File

@@ -0,0 +1,17 @@
<section id="Intro-WhatYouWillLearn">
<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? / "The Ansible Way"</li>
<li>How Ansible Works and its Key Components</li>
<li>Automating with Ad-Hoc Commands</li>
<li>Writing Playbooks / 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>

View File

@@ -0,0 +1,13 @@
<section id="Intro-WhatIsAnsible">
<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><br>
<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>

View File

@@ -0,0 +1,14 @@
<section id="Intro-WhatIsTower">
<h2>What is Ansible Tower?</h2>
<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>
<img src="images/ansible-tower3-monitor-1x.png">
<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>

View File

@@ -0,0 +1,38 @@
<section id="WhyAnsible">
<h3>Why Ansible? &nbsp;&nbsp; What Sets Ansible Apart? </h3>
<img src="images/SPA-All.png" />
<aside class="notes">
<p>Ansible has a number of qualities that make it the most rapidly growing automation platform in the world. </p>
<p>What is it about Ansible that makes it worth talking about?</p>
</aisde>
</section>
<section id="WhyAnsible-Simple">
<h3><font color="white">Why Ansible? &nbsp;&nbsp; What Sets Ansible Apart?</font></h3>
<img src="images/SPA-Simple.png" />
<aside class="notes">
<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 dont know Ansible can read an Ansible playbook and understand whats 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>
</aisde>
</section>
<section id="WhyAnsible-Powerful">
<h3><font color="white">Why Ansible? &nbsp;&nbsp; What Sets Ansible Apart?</font></h3>
<img src="images/SPA-Powerful.png" />
<aside class="notes">
<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 youre already using today. </p>
<p>Together, Ansibles capabilities allow you to orchestrate the entire application and environment lifecycle, regardless of where It&apos;s deployed.</p>
</aisde>
</section>
<section id="WhyAnsible-Agentless">
<h3><font color="white">Why Ansible? &nbsp;&nbsp; What Sets Ansible Apart?</font></h3>
<img src="images/SPA-Agentless.png" />
<aside class="notes">
<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>

View File

@@ -0,0 +1,58 @@
<section id="UseCases">
<div style="position:relative" style="border: 30px solid #000000">
<p class="fragment current-visible" style="position:absolute; margin-top: 80px; margin-left: 50;" data-fragment-index="0">
<img src="images/AnsibleUseCases01_ConfigMgmt.png"></p>
<p class="fragment current-visible" style="position:absolute; margin-top: 80px; margin-left: 50;" data-fragment-index="1">
<img src="images/AnsibleUseCases02_AppDeployment.png"></p>
<p class="fragment current-visible" style="position:absolute; margin-top: 80px; margin-left: 50;" data-fragment-index="2">
<img src="images/AnsibleUseCases03_Provisioning.png"></p>
<p class="fragment current-visible" style="position:absolute; margin-top: 80px; margin-left: 50;" data-fragment-index="3">
<img src="images/AnsibleUseCases04_CICD.png"></p>
<p class="fragment current-visible" style="position:absolute; margin-top: 80px; margin-left: 50;" data-fragment-index="4">
<img src="images/AnsibleUseCases05_SecurityCompliance.png"></p>
<p class="fragment current-visible" style="position:absolute; margin-top: 80px; margin-left: 50;" data-fragment-index="5">
<img src="images/AnsibleUseCases06_Orchestration.png"></p>
</div>
<table height="50%" width="100%" style="border: 0px solid #ffffff">
<tr style="border: 0px solid #ffffff">
<td colspan="100%" style="border: 0px solid #ffffff">
<h2>Ansible Provides End To End Goodness</h2>
</td>
</tr>
<tr>
<td width="500">&nbsp;</td>
<td align="right">
<img src="images/AnsibleUseCases01_ConfigMgmt.png" width="200">
</td>
<td align="center">
<img src="images/AnsibleUseCases02_AppDeployment.png" width="200">
</td>
<td align="left">
<img src="images/AnsibleUseCases03_Provisioning.png" width="200">
</td>
</tr>
<tr style="border: 0px solid #ffffff">
<td width="500">&nbsp;</td>
<td align="right" style="border: 0px solid #ffffff">
<img src="images/AnsibleUseCases04_CICD.png" width="200">
</td>
<td align="center">
<img src="images/AnsibleUseCases05_SecurityCompliance.png" width="200">
</td>
<td align="left">
<img src="images/AnsibleUseCases06_Orchestration.png" width="200">
</td>
</tr>
</table>
<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>

View File

@@ -0,0 +1,146 @@
<section id="TheAnsibleWay">
<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 id="TheAnsibleWay-CrossPlatform">
<h2>The Ansible Way - Venture Across The Platform</h2>
<div style="font-size: 0.75em;"><br>
<p style="padding:10px; background-color:gray; color:white"><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 id="TheAnsibleWay-CommunicateClearly">
<h2>The Ansible Way - Communicate Clearly</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 style="padding:10px; background-color:gray; color:white"><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 id="TheAnsibleWay-PreciousRing">
<h2>The Ansible Way - One Source To Rule Them All</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 style="padding:10px; background-color:gray; color:white"><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 id="TheAnsibleWay-VersionControlled">
<h2>The Ansible Way - Version Controlled Goodness</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 style="padding:10px; background-color:gray; color:white"><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 id="TheAnsibleWay-DynInv">
<h2>The Ansible Way - Dynamically Utilize Inventories</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 style="padding:10px; background-color:gray; color:white"><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 id="TheAnsibleWay-PlayNicely">
<h2>The Ansible Way - Play Nicely With Others</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 style="padding:10px; background-color:gray; color:white"><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>

View File

@@ -0,0 +1,63 @@
<section id="BatteriesIncluded">
<h2>Batteries Included</h2>
<p>Ansible comes bundled with hundreds of modules for a wide variety of automation tasks</p>
<div style="position:absolute; right: -125px; top: 100px;">
<p class="fragment current-visible" data-fragment-index="0">
<img src="images/fiero.jpg" width="600">
</p>
</div>
<!-- Kev keeps removing this second fiero,
but it's required for the second click or the
little car disappears when the "batteries not
included" message pops up-->
<div style="position:absolute; right: -125px; top: 100px;">
<p class="fragment current-visible" data-fragment-index="1">
<img src="images/fiero.jpg" width="600">
</p>
</div>
<div style="position:absolute; right: 25px; top: 25px;">
<p class="fragment current-visible" data-fragment-index="1">
<img src="images/BatteriesNotIncluded.png" width="200">
</p>
</div>
<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 youre automating. They can do everything from acting on system files, installing packages, or making API calls to a service framework. Ansible ships with around <?=$module_count?> today -- and this number is always expanding with every release.</p>
</aside>
</section>

View File

@@ -0,0 +1,14 @@
<section id="LanguageOfDevops">
<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">
<p>DevOps is a verb. Rather than think of "DevOps" as an object, think of it as the effort that holds pieces together from the first moment a server is racked to the end user's session.</p>
<p>With DevOps being the effort in the middle of it all, consider how Ansible can act as the catalyst to empower every department... every step of the way.</p>
<p>Ansible can be a powerful <strong>COLLABORATION TOOL</strong></p>
</aside>
</section>

View File

@@ -0,0 +1,19 @@
<section id="EndlessUseCases">
<h1>Ansible: Endless Use Cases</h1>
<p>Ansible fills virtually countless use cases with its versatility.</p>
<li type="circle" class="fragment fade-left">&#x273e;&nbsp;&nbsp;<b>Ansible is NOT just a Config Management Tool.</b></li>
<li type="circle" class="fragment fade-left">&#x2607;&nbsp;&nbsp;<b>Ansible is NOT just an Application Deployment Tool.</b></li>
<li type="circle" class="fragment fade-left">&#x2601;&nbsp;&nbsp;<b>Ansible is NOT just a Provisioning Tool.</b></li>
<li type="circle" class="fragment fade-left">&#x2621;&nbsp;&nbsp;<b>Ansible is NOT just a CI/CD Tool.</b></li>
<li type="circle" class="fragment fade-left">&#x270e;&nbsp;&nbsp;<b>Ansible is NOT just an Audit and Compliance Tool.</b></li>
<li type="circle" class="fragment fade-left">&#x27b0;&nbsp;&nbsp; <b>Ansible is NOT just an Orchestration Tool.</b></li>
<h2 class="fragment fade-up">Ansible is a powerful automation engine...</b></h2>
<h2 class="fragment fade-up">with strong use cases for all of the above tasks.</b></h2>
</p>
<aside class="notes">
<p>Stuff Goes Here</p>
</aside>
</section>

View File

@@ -0,0 +1,17 @@
<section id="TowerAndDevOps" data-background-image="images/AnsibleTowerFlow.png">
<div style="width: 800px; left: 50%; transform: translate(-50%,0); position: absolute; z-index: 1;" data-fragment-index="1" class="fragment fade-left" >
<div class="transbox">
<h1>Practical Workflows</h1>
<p>Deployment and CICD Pipelines </p>
</div>
</div>
<aside class="notes">
<p>Ansiblefest!!!!</p>
</aside>
</section>

View File

@@ -0,0 +1,11 @@
<section>
<section data-state="title alt" id="RedIntro-PeopleLoveAnsible">
<h1>PEOPLE LOVE ANSIBLE.</h1>
<img src="<?=$workshop_image?>" style="background-color: transparent; border: none;" height="250">
<p>Ansible is taking the world by storm with unbelievable popularity.</p>
<aside class="notes">
</aside>
</section>
</section>

View File

@@ -0,0 +1,5 @@
<section id="MeetupsRock" data-background-image="images/most_meetups.svg">
<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>

View File

@@ -0,0 +1,34 @@
<section id="AnsibleFest" data-background-image="images/Ansible-Fest-Row-Background_GoKEV.png">
<div style="width: 420px; height: 450px; position:absolute; left: -25px; top: 175px;" data-fragment-index="0" class="fragment fade-left" >
<div class="transbox">
<h1><?=$gihub_stars?></h1>
<p>Stars on GitHub</p>
</div>
</div>
<div style="width: 420px; max-height: 450px; position:absolute; right: 30px; top: 175px;" data-fragment-index="1" class="fragment fade-left" >
<div class="transbox">
<h1><?=$module_count?></h1>
<p>Ansible Modules</p>
</div>
</div>
<div style="width: 420px; max-height: 450px; left: 50%; transform: translate(-50%,0); position: absolute; top: 240px;" data-fragment-index="2" class="fragment fade-left" >
<div class="transbox">
<h1><?=$download_permonth?></h1>
<p>Downloads Per Month</p>
</div>
</div>
<aside class="notes">
<p>Ansiblefest!!!!</p>
</aside>
</section>

View File

@@ -0,0 +1,5 @@
<section id="GitHubActivity" data-background-image="images/most_contrib.svg">
<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>

View File

@@ -0,0 +1,5 @@
<section id="MostSearched" data-background-image="images/most_searched.svg">
<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>

View File

@@ -0,0 +1,19 @@
<section id="Ansible-Is-Not-Just">
<h1>Ansible: Endless Use Cases</h1>
<p>Ansible fills virtually countless use cases with its versatility.</p>
<li type="circle" class="fragment fade-left" data-fragment-index="1">&#x273e;&nbsp;&nbsp;<b>Ansible is NOT just a Config Management Tool.</b></li>
<li type="circle" class="fragment fade-left" data-fragment-index="2">&#x2607;&nbsp;&nbsp;<b>Ansible is NOT just an Application Deployment Tool.</b></li>
<li type="circle" class="fragment fade-left" data-fragment-index="3">&#x2601;&nbsp;&nbsp;<b>Ansible is NOT just a Provisioning Tool.</b></li>
<li type="circle" class="fragment fade-left" data-fragment-index="4">&#x2621;&nbsp;&nbsp;<b>Ansible is NOT just a CI/CD Tool.</b></li>
<li type="circle" class="fragment fade-left" data-fragment-index="5">&#x270e;&nbsp;&nbsp;<b>Ansible is NOT just an Audit and Compliance Tool.</b></li>
<li type="circle" class="fragment fade-left" data-fragment-index="6">&#x27b0;&nbsp;&nbsp; <b>Ansible is NOT just an Orchestration Tool.</b></li>
<h2 class="fragment fade-up" data-fragment-index="7">Ansible is a powerful automation engine...</b></h2>
<h2 class="fragment fade-up" data-fragment-index="8">with strong use cases for all of the above tasks.</b></h2>
</p>
<aside class="notes">
<p>Stuff Goes Here</p>
</aside>
</section>

View File

@@ -0,0 +1,12 @@
<section data-state="title alt" id="RedIntro-InstallingAnsible">
<h1>INSTALLING ANSIBLE</h1>
<img src="<?=$workshop_image?>" style="background-color: transparent; border: none;" height="250">
<p>It Could Not Be Simpler.</p>
<aside class="notes">
<p>Ansible</p>
</aside>
</section>

View File

@@ -0,0 +1,26 @@
<section id="InstallingAnsibleTerminal">
<div class="terminal space shadow">
<div class="top">
<div class="title">Ansible Terminal</div>
</div>
<pre class="bodyl">
<font color="silver"># RHEL "extras" repo or CentOS EPEL:</font>
$ sudo yum install ansible
<font color="silver"># you will need the PPA repo configured on
# Debian or Ubuntu</font>
$ sudo apt-get install ansible
<font color="silver"># from your MacBook:</font>
$ brew install ansible
<font color="silver"># For bleeding edge python versions,</font>
$ sudo pip install ansible
</pre>
</div>
</section>

View File

@@ -0,0 +1,22 @@
<section id="InstallingAnsibleVideo">
<h3>Simple: Installing Ansible</a></h3>
<script>
document.getElementById('YumInstallAnsible').play();
</script>
<video autoplay muted id="YumInstallAnsible" controls>
<source src="video/yuminstallansible.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<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>

View File

@@ -0,0 +1,12 @@
<section data-state="title alt" id="RedIntro-HowAnsibleWorks">
<h1>HOW ANSIBLE WORKS</h1>
<img src="<?=$workshop_image?>" style="background-color: transparent; border: none;" height="250">
<p>Let's Take A Look At The Technology</p>
<aside class="notes">
<p>Ansible</p>
</aside>
</section>

View File

@@ -0,0 +1,10 @@
<section id="HowAnsibleWorks">
<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>

View File

@@ -0,0 +1,11 @@
<section id="HowAnsibleWorks-YAML">
<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>

View File

@@ -0,0 +1,12 @@
<section id="HowAnsibleWorks-Modules">
<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 dont 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>

View File

@@ -0,0 +1,19 @@
<section id="HowAnsibleWorks-Plugins">
<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 Ansibles 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>

View File

@@ -0,0 +1,14 @@
<section id="HowAnsibleWorks-Inventory">
<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 thats 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>

View File

@@ -0,0 +1,11 @@
<section id="HowAnsibleWorks-DynamicInventory">
<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>

View File

@@ -0,0 +1,12 @@
<section data-state="title alt" id="RedIntro-Modules">
<h1>MODULES</h1>
<img src="<?=$workshop_image?>" style="background-color: transparent; border: none;" height="250">
<p>We leverage modules within our playbooks to do the heavy lifting.</p>
<aside class="notes">
<p>Ansible</p>
</aside>
</section>

View File

@@ -0,0 +1,39 @@
<section id="ModuleList">
<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>

View File

@@ -0,0 +1,208 @@
<section id="ModuleDoc-CLI-InfoScroll">
<h2>Modules Documentation</h2>
<p>Returns a thorough description of the parameters in the module.</p>
<div class="terminal space shadow" onclick="scrollDiv_init('AnsibleDocsInfo','1'); this.onclick = null;" style="cursor: pointer;">
<div class="top">
<div class="title">
<a href="javascript:pauseDiv()" style="none; cursor: pointer;">Ansible Terminal</a>
</div>
</div>
<pre class="bodymw">
<font color="gray"><?=$terminal_prompt?></font> ansible-doc copy
<div id="AnsibleDocsInfo" style="overflow:auto;width:auto;height:700px">
> COPY (/usr/lib/python2.7/site-packages/ansible/modules/files/copy.py)
The `copy' module copies a file from the local or remote machine to a
location on the remote machine. 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. For Windows
targets, use the [win_copy] module instead.
* note: This module has a corresponding action plugin.
OPTIONS (= is mandatory):
- attributes
Attributes the file or directory should have. To get supported flags
look at the man page for `chattr' on the target system. This string
should contain the attributes in the same order as the one displayed by
`lsattr'.
(Aliases: attr)[Default: (null)]
version_added: 2.3
- backup
Create a backup file including the timestamp information so you can get
the original file back if you somehow clobbered it incorrectly.
[Default: no]
type: bool
version_added: 0.7
- checksum
SHA1 checksum of the file being transferred. Used to validate that the
copy of the file was successful.
If this is not provided, ansible will use the local calculated checksum
of the src file.
[Default: (null)]
version_added: 2.5
- content
When used instead of `src', sets the contents of a file directly to the
specified value. For anything advanced or with formatting also look at
the template module.
[Default: (null)]
version_added: 1.1
- decrypt
This option controls the autodecryption of source files using vault.
[Default: Yes]
type: bool
version_added: 2.4
= dest
Remote absolute path where the file should be copied to. If `src' is a
directory, this must be a directory too. If `dest' is a nonexistent path
and if either `dest' ends with "/" or `src' is a directory, `dest' is
created. If `src' and `dest' are files, the parent directory of `dest'
isn't created: the task fails if it doesn't already exist.
- directory_mode
When doing a recursive copy set the mode for the directories. If this is
not set we will use the system defaults. The mode is only set on
directories which are newly created, and will not affect those that
already existed.
[Default: (null)]
version_added: 1.5
- follow
This flag indicates that filesystem links in the destination, if they
exist, should be followed.
[Default: no]
type: bool
version_added: 1.8
- force
the default is `yes', which will replace the remote file when contents
are different than the source. If `no', the file will only be
transferred if the destination does not exist.
(Aliases: thirsty)[Default: yes]
type: bool
version_added: 1.1
- group
Name of the group that should own the file/directory, as would be fed to
`chown'.
[Default: (null)]
- local_follow
This flag indicates that filesystem links in the source tree, if they
exist, should be followed.
[Default: yes]
type: bool
version_added: 2.4
- mode
Mode the file or directory should be. For those used to `/usr/bin/chmod'
remember that modes are actually octal numbers. You must either specify
the leading zero so that Ansible's YAML parser knows it is an octal
number (like `0644' or `01777') or quote it (like `'644'' or `'0644'' so
Ansible receives a string and can do its own conversion from string into
number. Giving Ansible a number without following one of these rules
will end up with a decimal number which will have unexpected results.
As of version 1.8, the mode may be specified as a symbolic mode (for
example, `u+rwx' or `u=rw,g=r,o=r'). As of version 2.3, the mode may
also be the special string `preserve'. `preserve' means that the file
will be given the same permissions as the source file.
[Default: (null)]
- owner
Name of the user that should own the file/directory, as would be fed to
`chown'.
[Default: (null)]
- remote_src
If `no', it will search for `src' at originating/master machine.
If `yes' it will go to the remote/target machine for the `src'. Default
is `no'.
Currently `remote_src' does not support recursive copying.
`remote_src' only works with `mode=preserve' as of version 2.6.
[Default: no]
type: bool
version_added: 2.0
- selevel
Level part of the SELinux file context. This is the MLS/MCS attribute,
sometimes known as the `range'. `_default' feature works as for
`seuser'.
[Default: s0]
- serole
Role part of SELinux file context, `_default' feature works as for
`seuser'.
[Default: (null)]
- setype
Type part of SELinux file context, `_default' feature works as for
`seuser'.
[Default: (null)]
- seuser
User part of SELinux file context. Will default to system policy, if
applicable. If set to `_default', it will use the `user' portion of the
policy if available.
[Default: (null)]
- src
Local path to a file to copy to the remote server; can be absolute or
relative. If path is a directory, it is copied recursively. In this
case, if path ends with "/", only inside contents of that directory are
copied to destination. Otherwise, if it does not end with "/", the
directory itself with all contents is copied. This behavior is similar
to Rsync.
[Default: (null)]
- unsafe_writes
Normally this module uses atomic operations to prevent data corruption
or inconsistent reads from the target files, sometimes systems are
configured or just broken in ways that prevent this. One example are
docker mounted files, they cannot be updated atomically and can only be
done in an unsafe manner.
This boolean option allows ansible to fall back to unsafe methods of
updating files for those cases in which you do not have any other
choice. Be aware that this is subject to race conditions and can lead to
data corruption.
[Default: no]
type: bool
version_added: 2.2
- validate
The validation command to run before copying into place. The path to the
file to validate is passed in via '%s' which must be present as in the
example below. The command is passed securely so shell features like
expansion and pipes won't work.
[Default: (null)]
NOTES:
* The [copy] module recursively copy facility does not scale to lots
(>hundreds) of files. For alternative, see [synchronize] module,
which is a wrapper around `rsync'.
* For Windows targets, use the [win_copy] module instead.
AUTHOR: Ansible Core Team, Michael DeHaan
METADATA:
status:
- stableinterface
supported_by: core
</div>
</pre>
</div>
<aside class="notes">
<p><b>TO Make This List SCROLL</b>, click anywhere on the terminal window</p>
<p><b>TO Make This List STOP</b>, click the "Ansible Terminal" text on top of the console</p>
</aside>
</section>

View File

@@ -0,0 +1,140 @@
<section id="ModuleDoc-CLI-ExampleScroll">
<h2>Modules Documentation</h2>
<p>Also displays usable copy / paste examples of working functional tasks with this module.</p>
<div class="terminal space shadow" onclick="scrollDiv_init('AnsibleDocsExamples','40'); this.onclick = null;" style="cursor: pointer;">
<div class="top">
<div class="title">
<a href="javascript:pauseDiv()" style="none; cursor: pointer;">Ansible Terminal</a>
</div>
</div>
<pre class="bodymw">
<font color="gray"><?=$terminal_prompt?></font> ansible-doc copy
<div id="AnsibleDocsExamples" style="overflow:auto;width:auto;height:700px">
<font color="#FF00FF">EXAMPLES:</font>
<mark>- name: example copying file with owner and permissions </mark>
copy:
src: /srv/myfiles/foo.conf
dest: /etc/foo.conf
owner: foo
group: foo
mode: 0644
<mark>- name: The same example as above, but using a symbolic mode equivalent to 0644 </mark>
copy:
src: /srv/myfiles/foo.conf
dest: /etc/foo.conf
owner: foo
group: foo
mode: u=rw,g=r,o=r
<mark>- name: Another symbolic mode example, adding some permissions and removing others </mark>
copy:
src: /srv/myfiles/foo.conf
dest: /etc/foo.conf
owner: foo
group: foo
mode: u+rw,g-wx,o-rwx
<mark>- name: Copy a new "ntp.conf file into place, backing up the original if it differs from the... </mark>
copy:
src: /mine/ntp.conf
dest: /etc/ntp.conf
owner: root
group: root
mode: 0644
backup: yes
<mark>- name: Copy a new "sudoers" file into place, after passing validation with visudo </mark>
copy:
src: /mine/sudoers
dest: /etc/sudoers
validate: /usr/sbin/visudo -cf %s
<mark>- name: Copy a "sudoers" file on the remote machine for editing </mark>
copy:
src: /etc/sudoers
dest: /etc/sudoers.edit
remote_src: yes
validate: /usr/sbin/visudo -cf %s
<mark>- name: Copy using the 'content' for inline data </mark>
copy:
content: '# This file was moved to /etc/other.conf'
dest: /etc/mine.conf'
<font color="#FF00FF">RETURN VALUES:</font>
dest:
description: destination file/path
returned: success
type: string
sample: /path/to/file.txt
src:
description: source file used for the copy on the target machine
returned: changed
type: string
sample: /home/httpd/.ansible/tmp/ansible-tmp-1423796390.97-147729857856000/source
md5sum:
description: md5 checksum of the file after running copy
returned: when supported
type: string
sample: 2a5aeecc61dc98c4d780b14b330e3282
checksum:
description: sha1 checksum of the file after running copy
returned: success
type: string
sample: 6e642bb8dd5c2e027bf21dd923337cbb4214f827
backup_file:
description: name of backup file created
returned: changed and if backup=yes
type: string
sample: /path/to/file.txt.2015-02-12@22:09~
gid:
description: group id of the file, after execution
returned: success
type: int
sample: 100
group:
description: group of the file, after execution
returned: success
type: string
sample: httpd
owner:
description: owner of the file, after execution
returned: success
type: string
sample: httpd
uid:
description: owner id of the file, after execution
returned: success
type: int
sample: 100
mode:
description: permissions of the target, after execution
returned: success
type: string
sample: 0644
size:
description: size of the target, after execution
returned: success
type: int
sample: 1220
state:
description: state of the target, after execution
returned: success
type: string
sample: file
</div>
</pre>
</div>
<aside class="notes">
<p><b>TO Make This List SCROLL</b>, click anywhere on the terminal window</p>
<p><b>TO Make This List STOP</b>, click the "Ansible Terminal" text on top of the console</p>
</aside>
</section>

Some files were not shown because too many files have changed in this diff Show More