WIP3
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -108,9 +108,8 @@ venv.bak/
|
||||
# Ansible
|
||||
*.retry
|
||||
|
||||
roles/
|
||||
|
||||
.vscode/
|
||||
keys/
|
||||
collections/ansible_collections/
|
||||
.vscode/
|
||||
.vscode/
|
||||
|
||||
19
roles/bertvv.bind/.gitignore
vendored
Normal file
19
roles/bertvv.bind/.gitignore
vendored
Normal 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/
|
||||
48
roles/bertvv.bind/.travis.yml
Normal file
48
roles/bertvv.bind/.travis.yml
Normal 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/
|
||||
56
roles/bertvv.bind/.yamllint
Normal file
56
roles/bertvv.bind/.yamllint
Normal 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
|
||||
250
roles/bertvv.bind/CHANGELOG.md
Normal file
250
roles/bertvv.bind/CHANGELOG.md
Normal 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
|
||||
|
||||
13
roles/bertvv.bind/LICENSE.md
Normal file
13
roles/bertvv.bind/LICENSE.md
Normal 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
317
roles/bertvv.bind/README.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# Ansible role `bind`
|
||||
|
||||
[](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)
|
||||
70
roles/bertvv.bind/defaults/main.yml
Normal file
70
roles/bertvv.bind/defaults/main.yml
Normal 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"
|
||||
7
roles/bertvv.bind/handlers/main.yml
Normal file
7
roles/bertvv.bind/handlers/main.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# roles/bind/handlers/main.yml
|
||||
---
|
||||
|
||||
- name: reload bind
|
||||
service:
|
||||
name: "{{ bind_service }}"
|
||||
state: reloaded
|
||||
2
roles/bertvv.bind/meta/.galaxy_install_info
Normal file
2
roles/bertvv.bind/meta/.galaxy_install_info
Normal file
@@ -0,0 +1,2 @@
|
||||
install_date: Sun Jun 28 14:49:10 2020
|
||||
version: v4.2.0
|
||||
34
roles/bertvv.bind/meta/main.yml
Normal file
34
roles/bertvv.bind/meta/main.yml
Normal 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: []
|
||||
117
roles/bertvv.bind/molecule/default/converge.yml
Normal file
117
roles/bertvv.bind/molecule/default/converge.yml
Normal 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
|
||||
263
roles/bertvv.bind/molecule/default/files/dns.bats
Normal file
263
roles/bertvv.bind/molecule/default/files/dns.bats
Normal 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
|
||||
}
|
||||
|
||||
117
roles/bertvv.bind/molecule/default/files/functional-tests.sh
Executable file
117
roles/bertvv.bind/molecule/default/files/functional-tests.sh
Executable 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
|
||||
53
roles/bertvv.bind/molecule/default/molecule.yml
Normal file
53
roles/bertvv.bind/molecule/default/molecule.yml
Normal 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
|
||||
9
roles/bertvv.bind/molecule/default/verify.yml
Normal file
9
roles/bertvv.bind/molecule/default/verify.yml
Normal 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
|
||||
69
roles/bertvv.bind/tasks/main.yml
Normal file
69
roles/bertvv.bind/tasks/main.yml
Normal 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
|
||||
140
roles/bertvv.bind/tasks/master.yml
Normal file
140
roles/bertvv.bind/tasks/master.yml
Normal 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
|
||||
24
roles/bertvv.bind/tasks/slave.yml
Normal file
24
roles/bertvv.bind/tasks/slave.yml
Normal 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
|
||||
12
roles/bertvv.bind/templates/auth_transfer.j2
Normal file
12
roles/bertvv.bind/templates/auth_transfer.j2
Normal 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 %}
|
||||
};
|
||||
|
||||
140
roles/bertvv.bind/templates/bind_zone.j2
Normal file
140
roles/bertvv.bind/templates/bind_zone.j2
Normal 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 %}
|
||||
158
roles/bertvv.bind/templates/master_etc_named.conf.j2
Normal file
158
roles/bertvv.bind/templates/master_etc_named.conf.j2
Normal 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 %}
|
||||
101
roles/bertvv.bind/templates/reverse_zone.j2
Normal file
101
roles/bertvv.bind/templates/reverse_zone.j2
Normal 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 %}
|
||||
96
roles/bertvv.bind/templates/reverse_zone_ipv6.j2
Normal file
96
roles/bertvv.bind/templates/reverse_zone_ipv6.j2
Normal 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 %}
|
||||
120
roles/bertvv.bind/templates/slave_etc_named.conf.j2
Normal file
120
roles/bertvv.bind/templates/slave_etc_named.conf.j2
Normal 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 %}
|
||||
32
roles/bertvv.bind/vars/Archlinux.yml
Normal file
32
roles/bertvv.bind/vars/Archlinux.yml
Normal 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"
|
||||
33
roles/bertvv.bind/vars/Debian.yml
Normal file
33
roles/bertvv.bind/vars/Debian.yml
Normal 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"
|
||||
32
roles/bertvv.bind/vars/FreeBSD.yml
Normal file
32
roles/bertvv.bind/vars/FreeBSD.yml
Normal 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"
|
||||
34
roles/bertvv.bind/vars/RedHat.yml
Normal file
34
roles/bertvv.bind/vars/RedHat.yml
Normal 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"
|
||||
4
roles/geerlingguy.gitlab/.github/FUNDING.yml
vendored
Normal file
4
roles/geerlingguy.gitlab/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
---
|
||||
github: geerlingguy
|
||||
patreon: geerlingguy
|
||||
56
roles/geerlingguy.gitlab/.github/stale.yml
vendored
Normal file
56
roles/geerlingguy.gitlab/.github/stale.yml
vendored
Normal 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
3
roles/geerlingguy.gitlab/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.retry
|
||||
*/__pycache__
|
||||
*.pyc
|
||||
32
roles/geerlingguy.gitlab/.travis.yml
Normal file
32
roles/geerlingguy.gitlab/.travis.yml
Normal 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/
|
||||
6
roles/geerlingguy.gitlab/.yamllint
Normal file
6
roles/geerlingguy.gitlab/.yamllint
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
extends: default
|
||||
rules:
|
||||
line-length:
|
||||
max: 140
|
||||
level: warning
|
||||
20
roles/geerlingguy.gitlab/LICENSE
Normal file
20
roles/geerlingguy.gitlab/LICENSE
Normal 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.
|
||||
179
roles/geerlingguy.gitlab/README.md
Normal file
179
roles/geerlingguy.gitlab/README.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Ansible Role: GitLab
|
||||
|
||||
[](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/).
|
||||
75
roles/geerlingguy.gitlab/defaults/main.yml
Normal file
75
roles/geerlingguy.gitlab/defaults/main.yml
Normal 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"
|
||||
5
roles/geerlingguy.gitlab/handlers/main.yml
Normal file
5
roles/geerlingguy.gitlab/handlers/main.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
- name: restart gitlab
|
||||
command: gitlab-ctl reconfigure
|
||||
register: gitlab_restart
|
||||
failed_when: gitlab_restart_handler_failed_when | bool
|
||||
2
roles/geerlingguy.gitlab/meta/.galaxy_install_info
Normal file
2
roles/geerlingguy.gitlab/meta/.galaxy_install_info
Normal file
@@ -0,0 +1,2 @@
|
||||
install_date: Wed Jun 24 18:44:32 2020
|
||||
version: 3.0.0
|
||||
28
roles/geerlingguy.gitlab/meta/main.yml
Normal file
28
roles/geerlingguy.gitlab/meta/main.yml
Normal 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
|
||||
21
roles/geerlingguy.gitlab/molecule/default/converge.yml
Normal file
21
roles/geerlingguy.gitlab/molecule/default/converge.yml
Normal 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
|
||||
21
roles/geerlingguy.gitlab/molecule/default/molecule.yml
Normal file
21
roles/geerlingguy.gitlab/molecule/default/molecule.yml
Normal 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}
|
||||
@@ -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
|
||||
81
roles/geerlingguy.gitlab/tasks/main.yml
Normal file
81
roles/geerlingguy.gitlab/tasks/main.yml
Normal 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
|
||||
108
roles/geerlingguy.gitlab/templates/gitlab.rb.j2
Normal file
108
roles/geerlingguy.gitlab/templates/gitlab.rb.j2
Normal 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
|
||||
3
roles/geerlingguy.gitlab/vars/Debian.yml
Normal file
3
roles/geerlingguy.gitlab/vars/Debian.yml
Normal 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"
|
||||
3
roles/geerlingguy.gitlab/vars/RedHat.yml
Normal file
3
roles/geerlingguy.gitlab/vars/RedHat.yml
Normal 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"
|
||||
4
roles/geerlingguy.java/.github/FUNDING.yml
vendored
Normal file
4
roles/geerlingguy.java/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
---
|
||||
github: geerlingguy
|
||||
patreon: geerlingguy
|
||||
56
roles/geerlingguy.java/.github/stale.yml
vendored
Normal file
56
roles/geerlingguy.java/.github/stale.yml
vendored
Normal 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.
|
||||
6
roles/geerlingguy.java/.yamllint
Normal file
6
roles/geerlingguy.java/.yamllint
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
extends: default
|
||||
rules:
|
||||
line-length:
|
||||
max: 120
|
||||
level: warning
|
||||
13
roles/geerlingguy.java/molecule/default/converge.yml
Normal file
13
roles/geerlingguy.java/molecule/default/converge.yml
Normal 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
|
||||
6
roles/geerlingguy.java/vars/Ubuntu-20.yml
Normal file
6
roles/geerlingguy.java/vars/Ubuntu-20.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# JDK version options include:
|
||||
# - java
|
||||
# - openjdk-11-jdk
|
||||
__java_packages:
|
||||
- openjdk-11-jdk
|
||||
88
roles/lightbulb-ansiblered-deck/README.md
Normal file
88
roles/lightbulb-ansiblered-deck/README.md
Normal file
@@ -0,0 +1,88 @@
|
||||
[](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`
|
||||
|
||||
11
roles/lightbulb-ansiblered-deck/defaults/main.yml
Normal file
11
roles/lightbulb-ansiblered-deck/defaults/main.yml
Normal 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: ' '
|
||||
workshop_title: ' '
|
||||
workshop_message: ' '
|
||||
|
||||
php_port: 8000
|
||||
@@ -0,0 +1 @@
|
||||
- prefs/default.prefs.php
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
header("location:/");
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
1
roles/lightbulb-ansiblered-deck/files/deck-ansible/css/dormant/prism.min.css
vendored
Normal file
1
roles/lightbulb-ansiblered-deck/files/deck-ansible/css/dormant/prism.min.css
vendored
Normal 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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
header("location:/");
|
||||
1365
roles/lightbulb-ansiblered-deck/files/deck-ansible/css/reveal.css
Normal file
1365
roles/lightbulb-ansiblered-deck/files/deck-ansible/css/reveal.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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>
|
||||
BIN
roles/lightbulb-ansiblered-deck/files/deck-ansible/favicon.ico
Normal file
BIN
roles/lightbulb-ansiblered-deck/files/deck-ansible/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 393 B |
@@ -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’s guide</a> for more details on using this deck and it’s associated material.</p>
|
||||
</aside>
|
||||
</section>
|
||||
@@ -0,0 +1,13 @@
|
||||
<section id="Intro-WhatIsAnsible">
|
||||
<h2>What is Ansible?</h2>
|
||||
<p>It's a <b>simple automation language</b> that can perfectly describe an IT application infrastructure in Ansible Playbooks.</p>
|
||||
<p>It'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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,38 @@
|
||||
<section id="WhyAnsible">
|
||||
<h3>Why Ansible? 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? 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 – and even people in your IT organization that don’t know Ansible can read an Ansible playbook and understand what’s happening.</p>
|
||||
<p>This simplicity also means that it’s easy to install and get started to do real work with it quickly – usually in just minutes. </p>
|
||||
<p>Ansible also works like you think – 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? 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 you’re already using today. </p>
|
||||
<p>Together, Ansible’s capabilities allow you to orchestrate the entire application and environment lifecycle, regardless of where It's deployed.</p>
|
||||
</aisde>
|
||||
</section>
|
||||
|
||||
<section id="WhyAnsible-Agentless">
|
||||
<h3><font color="white">Why Ansible? 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 – and path forward enabling teams to crush productivity-stealing complexity and overhead.</p>
|
||||
</aisde>
|
||||
</section>
|
||||
|
||||
@@ -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"> </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"> </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"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>
|
||||
@@ -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>
|
||||
@@ -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 you’re automating. They can do everything from acting on system files, installing packages, or making API calls to a service framework. Ansible ships with around <?=$module_count?> today -- and this number is always expanding with every release.</p>
|
||||
</aside>
|
||||
</section>
|
||||
@@ -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>
|
||||
@@ -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">✾ <b>Ansible is NOT just a Config Management Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left">☇ <b>Ansible is NOT just an Application Deployment Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left">☁ <b>Ansible is NOT just a Provisioning Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left">☡ <b>Ansible is NOT just a CI/CD Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left">✎ <b>Ansible is NOT just an Audit and Compliance Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left">➰ <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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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">✾ <b>Ansible is NOT just a Config Management Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left" data-fragment-index="2">☇ <b>Ansible is NOT just an Application Deployment Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left" data-fragment-index="3">☁ <b>Ansible is NOT just a Provisioning Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left" data-fragment-index="4">☡ <b>Ansible is NOT just a CI/CD Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left" data-fragment-index="5">✎ <b>Ansible is NOT just an Audit and Compliance Tool.</b></li>
|
||||
<li type="circle" class="fragment fade-left" data-fragment-index="6">➰ <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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<section id="HowAnsibleWorks-YAML">
|
||||
|
||||
<h2>Plays & 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>
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<section id="HowAnsibleWorks-Modules">
|
||||
|
||||
<h2>Modules & Tasks</h2>
|
||||
<img src="images/how-ansible-works-diagram-03.svg" />
|
||||
<aside class="notes">
|
||||
<p>If playbooks are the instruction manual for setting up and managing your infrastructure, Ansible modules are the tools in your toolkit.</p>
|
||||
<p>Modules are executable bits of code that operate on hosts; however, we don’t need to understand the underlying implementation to get them to work. Modules do the heavy-lifting in Ansible and abstract users from the complexity of the underlying details.</p>
|
||||
<p>For more details see the <a href="http://docs.ansible.com/ansible/modules_intro.html">Introduction to Modules</a> and <a href="http://docs.ansible.com/ansible/modules_by_category.html">Module Index</a> page in the Ansible documentation.</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -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 Ansible’s core functionality. Ansible ships with a number of handy plugins, and you can easily write your own.</p>
|
||||
<p>These are some of the more common plugin types:</p>
|
||||
<ul>
|
||||
<li>Action plugins manage the execution on the controller and deployment of modules to hosts.</li>
|
||||
<li>Callback plugins enable you to hook into Ansible events for display or logging purposes.</li>
|
||||
<li>Connection plugins define how to communicate with inventory hosts.</li>
|
||||
<li>Filters plugins allow you to manipulate data inside Ansible plays and/or templates. This is a Jinja2 feature; Ansible ships extra filter plugins.</li>
|
||||
</ul>
|
||||
<p>For more details see the <a href="http://docs.ansible.com/ansible/dev_guide/developing_plugins.html">Developing Plugins</a> page in the Ansible documentation.</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -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 that’s needed to log into that system remotely. Inventories are ultimately lists of things you want to automate across.</p>
|
||||
<p>Here in this slide was see an example of a simple static inventory list of three hosts (webserver1, webserver2 and dbserver1) in two groups (web and db).</p>
|
||||
<p>For more details see the <a href="http://docs.ansible.com/ansible/intro_inventory.html">Inventory</a> page in the Ansible documentation.</p>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 “batteries” and the “tools in a users toolkit.”</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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -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
Reference in New Issue
Block a user