diff --git a/.ansible-lint b/.ansible-lint index 9245d3d88..2ecf774b7 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -10,7 +10,7 @@ skip_list: - name[missing] # All tasks should be named. - name[casing] # TODO: All names should start with an uppercase letter. - name[template] # Rule for checking task and play names - - jinja[spacing] . # TODO + - jinja[spacing] # TODO - jinja[invalid] # TODO - no-handler - schema[tasks] @@ -21,4 +21,8 @@ skip_list: - fqcn[action] - no-relative-paths +exclude_paths: + - roles/consul/ # TODO - https://github.com/ansible-community/ansible-consul/pull/520 + +# https://ansible-lint.readthedocs.io/configuring/ # https://ansible-lint.readthedocs.io/rules/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e43b0f988 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md index a0a28392f..cc39f886c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![GitHub license](https://img.shields.io/github/license/vitabaks/postgresql_cluster)](https://github.com/vitabaks/postgresql_cluster/blob/master/LICENSE) ![GitHub stars](https://img.shields.io/github/stars/vitabaks/postgresql_cluster) -### Deploy a Production Ready PostgreSQL High-Availability Cluster (based on "Patroni" and "DCS(etcd)"). Automating with Ansible. +### Deploy a Production Ready PostgreSQL High-Availability Cluster (based on "Patroni" and DCS "etcd" or "consul"). Automating with Ansible. This Ansible playbook is designed for deploying a PostgreSQL high availability cluster on dedicated physical servers for a production environment. The cluster can also be deployed on virtual machines and in the Cloud. @@ -23,15 +23,16 @@ In addition to deploying new clusters, this playbook also support the deployment ## Index - [Cluster types](#cluster-types) - - [[Type A] PostgreSQL High-Availability with Load Balancing](#type-a-postgresql-high-availability-with-load-balancing) + - [[Type A] PostgreSQL High-Availability with HAProxy Load Balancing](#type-a-postgresql-high-availability-with-haproxy-load-balancing) - [[Type B] PostgreSQL High-Availability only](#type-b-postgresql-high-availability-only) + - [[Type C] PostgreSQL High-Availability with Consul Service Discovery (DNS)](#type-c-postgresql-high-availability-with-consul-service-discovery-dns) - [Compatibility](#compatibility) - [Supported Linux Distributions:](#supported-linux-distributions) - [PostgreSQL versions:](#postgresql-versions) - [Ansible version](#ansible-version) - [Requirements](#requirements) - [Port requirements](#port-requirements) -- [Recommendations](#recommendations) +- [Recommendations](#recommenations) - [Deployment: quick start](#deployment-quick-start) - [Variables](#variables) - [Cluster Scaling](#cluster-scaling) @@ -54,9 +55,9 @@ In addition to deploying new clusters, this playbook also support the deployment ## Cluster types -You have two options available for deployment "Type A" and "Type B". +You have three schemes available for deployment: -### [Type A] PostgreSQL High-Availability with Load Balancing +### [Type A] PostgreSQL High-Availability with HAProxy Load Balancing ![TypeA](images/TypeA.png) > To use this scheme, specify `with_haproxy_load_balancing: true` in variable file vars/main.yml @@ -91,18 +92,34 @@ In our configuration keepalived checks the status of the HAProxy service and in [**PgBouncer**](https://pgbouncer.github.io/features.html) is a connection pooler for PostgreSQL. - ### [Type B] PostgreSQL High-Availability only ![TypeB](images/TypeB.png) This is simple scheme without load balancing `Used by default` -To provide a single entry point (VIP) for databases access is used "vip-manager". +To provide a single entry point (VIP) for database access is used "vip-manager". If the variable `cluster_vip` is specified (optional). [**vip-manager**](https://github.com/cybertec-postgresql/vip-manager) is a service that gets started on all cluster nodes and connects to the DCS. If the local node owns the leader-key, vip-manager starts the configured VIP. In case of a failover, vip-manager removes the VIP on the old leader and the corresponding service on the new leader starts it there. \ Written in Go. Cybertec Schönig & Schönig GmbH https://www.cybertec-postgresql.com +### [Type C] PostgreSQL High-Availability with Consul Service Discovery (DNS) +![TypeC](images/TypeC.png) + +> To use this scheme, specify `dcs_type: consul` in variable file vars/main.yml + +This scheme is suitable for master-only access and for load balancing (using DNS) for reading across replicas. Consul [Service Discovery](https://developer.hashicorp.com/consul/docs/concepts/service-discovery) with [DNS resolving ](https://developer.hashicorp.com/consul/docs/discovery/dns) is used as a client access point to the database. + +Client access point (example): + +- `master.postgres-cluster.service.consul` +- `replica.postgres-cluster.service.consul` + +Besides, it can be useful for a distributed cluster across different data centers. We can specify in advance which data center the database server is located in and then use this for applications running in the same data center. + +Example: `replica.postgres-cluster.service.dc1.consul`, `replica.postgres-cluster.service.dc2.consul` + +It requires the installation of a consul in client mode on each application server for service DNS resolution (or use [forward DNS](https://developer.hashicorp.com/consul/tutorials/networking/dns-forwarding?utm_source=docs) to the remote consul server instead of installing a local consul client). --- ## Compatibility @@ -149,6 +166,10 @@ This playbook requires root privileges or sudo. Ansible ([What is Ansible](https://www.ansible.com/resources/videos/quick-start-video)?) +if `dcs_type: "consul"`, please install consul role requirements on the control node: + +`ansible-galaxy install -r roles/consul/requirements.yml` + ## Port requirements List of required TCP ports that must be open for the database cluster: @@ -157,7 +178,7 @@ List of required TCP ports that must be open for the database cluster: - `8008` (patroni rest api) - `2379`, `2380` (etcd) -additionally, for the scheme "[Type A] PostgreSQL High-Availability with Load Balancing": +for the scheme "[Type A] PostgreSQL High-Availability with Load Balancing": - `5000` (haproxy - (read/write) master) - `5001` (haproxy - (read only) all replicas) @@ -165,7 +186,16 @@ additionally, for the scheme "[Type A] PostgreSQL High-Availability with Load Ba - `5003` (haproxy - (read only) asynchronous replicas only) - `7000` (optional, haproxy stats) -## Recommendations +for the scheme "[Type C] PostgreSQL High-Availability with Consul Service Discovery (DNS)": + +- `8300` (Consul Server RPC) +- `8301` (Consul Serf LAN) +- `8302` (Consul Serf WAN) +- `8500` (Consul HTTP API) +- `8600` (Consul DNS server) + + +## Recommenations - **linux (Operation System)**: Update your operating system on your target servers before deploying; @@ -173,15 +203,15 @@ Update your operating system on your target servers before deploying; Make sure you have time synchronization is configured (NTP). Specify `ntp_enabled:'true'` and `ntp_servers` if you want to install and configure the ntp service. -- **DCS (Distributed Configuration Store)**: +- **DCS (Distributed Consensus Store)**: -Fast drives and a reliable network are the most important factors for the performance and stability of an etcd cluster. +Fast drives and a reliable network are the most important factors for the performance and stability of an etcd (or consul) cluster. -Avoid storing etcd data on the same drive along with other processes (such as the database) that are intensively using the resources of the disk subsystem! -Store the etcd and postgresql data on **different** disks (see `etcd_data_dir` variable), use ssd drives if possible. -See [hardware recommendations](https://etcd.io/docs/v3.3.12/op-guide/hardware/) and [tuning](https://etcd.io/docs/v3.3.12/tuning/) guides. +Avoid storing etcd (or consul) data on the same drive along with other processes (such as the database) that are intensively using the resources of the disk subsystem! +Store the etcd and postgresql data on **different** disks (see `etcd_data_dir`, `consul_data_path` variables), use ssd drives if possible. +See [hardware recommendations](https://etcd.io/docs/v3.3/op-guide/hardware/) and [tuning](https://etcd.io/docs/v3.3/tuning/) guides. -Overloaded (highload) database clusters may require the installation of the etcd cluster on dedicated servers, separate from the database servers. +It is recommended to deploy the DCS cluster on dedicated servers, separate from the database servers. - **Placement of cluster members in different data centers**: @@ -227,18 +257,16 @@ To minimize the risk of losing data on autofailover, you can configure settings ###### Minimum set of variables: - `proxy_env` # if required (*for download packages*) - -example: -``` -proxy_env: - http_proxy: http://proxy_server_ip:port - https_proxy: http://proxy_server_ip:port -``` - `cluster_vip` # for client access to databases in the cluster (optional) - `patroni_cluster_name` -- `with_haproxy_load_balancing` `'true'` (Type A) or `'false'`/default (Type B) - `postgresql_version` - `postgresql_data_dir` +- `with_haproxy_load_balancing` `'true'` (Type A) or `'false'`/default (Type B) +- `dcs_type` # "etcd" (default) or "consul" (Type C) + +if `dcs_type: "consul"`, please install consul role requirements on the control node: + +`ansible-galaxy install -r roles/consul/requirements.yml` 5. Try to connect to hosts diff --git a/consul.yml b/consul.yml new file mode 100644 index 000000000..e7a75a6d6 --- /dev/null +++ b/consul.yml @@ -0,0 +1,97 @@ +--- +- hosts: localhost + any_errors_fatal: true + gather_facts: false + vars_files: + - vars/main.yml + tasks: + - name: Check if the consul role requirements (ansible.utils) are installed + command: ansible-galaxy collection list ansible.utils + changed_when: false + failed_when: false + register: ansible_utils_result + + - name: Consul role requirements + fail: + msg: + - "Please install consul role requirements (ansible.utils)" + - "ansible-galaxy install -r roles/consul/requirements.yml" + when: + - ansible_utils_result.stderr is search("unable to find") + +- hosts: consul_instances + become: true + become_method: sudo + any_errors_fatal: true + gather_facts: true + vars_files: + - vars/main.yml + - vars/system.yml + environment: "{{ proxy_env | default({}) }}" + + pre_tasks: + - name: Include OS-specific variables + include_vars: "vars/{{ ansible_os_family }}.yml" + when: not ansible_os_family == 'Rocky' and not ansible_os_family == 'AlmaLinux' + tags: always + + # For compatibility with Ansible old versions + # (support for RockyLinux and AlmaLinux has been added to Ansible 2.11) + - name: Include OS-specific variables + include_vars: "vars/RedHat.yml" + when: ansible_os_family == 'Rocky' or ansible_os_family == 'AlmaLinux' + tags: always + + - name: Update apt cache + apt: + update_cache: true + cache_valid_time: 3600 + when: ansible_os_family == "Debian" and installation_method == "repo" + + - name: Make sure the gnupg and apt-transport-https packages are present + apt: + pkg: + - gnupg + - apt-transport-https + state: present + when: ansible_os_family == "Debian" and installation_method == "repo" + + - name: Make sure the python3-pip package are present + package: + name: python3-pip + state: present + + - name: Build a firewall_ports_dynamic_var + set_fact: + firewall_ports_dynamic_var: "{{ firewall_ports_dynamic_var | default([]) + (firewall_allowed_tcp_ports_for[item]) }}" + loop: "{{ hostvars[inventory_hostname].group_names }}" + when: firewall_enabled_at_boot|bool + tags: firewall + + - name: Build a firewall_rules_dynamic_var + set_fact: + firewall_rules_dynamic_var: "{{ firewall_rules_dynamic_var | default([]) + (firewall_additional_rules_for[item]) }}" + loop: "{{ hostvars[inventory_hostname].group_names }}" + when: firewall_enabled_at_boot|bool + tags: firewall + + roles: + - role: ansible-role-firewall + vars: + firewall_allowed_tcp_ports: "{{ firewall_ports_dynamic_var | unique }}" + firewall_additional_rules: "{{ firewall_rules_dynamic_var | unique }}" + when: firewall_enabled_at_boot|bool + tags: firewall + + - role: hostname + - role: resolv_conf + vars: + nameservers: [127.0.0.1] # add a nameserver entry poining to localhost for dnsmasq. + - role: etc_hosts + - role: sysctl + - role: timezone + - role: ntp + + - role: consul + +... diff --git a/deploy_pgcluster.yml b/deploy_pgcluster.yml index 6f6e2e188..268755f70 100644 --- a/deploy_pgcluster.yml +++ b/deploy_pgcluster.yml @@ -13,15 +13,71 @@ msg: "Ansible version must be {{ minimal_ansible_version }} or higher" when: ansible_version.full is version(minimal_ansible_version, '<') -- name: Gathering facts from all servers +- name: Gathering facts from all servers and preparing the system hosts: all + become: true + become_method: sudo gather_facts: true tags: always + vars_files: + - vars/main.yml + - vars/system.yml + environment: "{{ proxy_env | default({}) }}" + + roles: + - role: resolv_conf + - role: hostname + - role: etc_hosts + - role: timezone + + tasks: + - name: Clean yum cache + command: yum clean all + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version == '7' + + - name: Clean dnf cache + command: dnf clean all + when: + - ansible_os_family == "RedHat" + - ansible_distribution_major_version is version('8', '>=') + + - name: Update apt cache + apt: + update_cache: true + cache_valid_time: 3600 + when: ansible_os_family == "Debian" + + - name: Make sure the gnupg and apt-transport-https packages are present + apt: + pkg: + - gnupg + - apt-transport-https + state: present + when: ansible_os_family == "Debian" + + # Ansible requires the iproute package for network facts to be populated + - name: Make sure that the iproute is installed + package: + name: iproute + state: present + when: ansible_os_family == "RedHat" + + - name: Make sure that the iproute is installed + apt: + name: iproute2 + state: present + when: ansible_os_family == "Debian" - import_playbook: etcd_cluster.yml when: not dcs_exists|bool and dcs_type == "etcd" tags: etcd +- import_playbook: consul.yml + when: dcs_type == "consul" + tags: consul + - hosts: postgres_cluster become: true become_method: sudo @@ -54,24 +110,6 @@ msg: "{{ ansible_distribution_version }} of {{ ansible_distribution }} is not supported" when: ansible_distribution_version is version_compare(os_minimum_versions[ansible_distribution], '<') - - name: Update apt cache - apt: - update_cache: true - cache_valid_time: 3600 - environment: "{{ proxy_env | default({}) }}" - when: ansible_os_family == "Debian" and installation_method == "repo" - tags: add_repo, install_packages, install_postgres - - - name: Make sure the gnupg and apt-transport-https packages are present - apt: - pkg: - - gnupg - - apt-transport-https - state: present - environment: "{{ proxy_env | default({}) }}" - when: ansible_os_family == "Debian" and installation_method == "repo" - tags: add_repo, install_packages, install_postgres - - name: Build a firewall_ports_dynamic_var set_fact: firewall_ports_dynamic_var: "{{ firewall_ports_dynamic_var | default([]) + (firewall_allowed_tcp_ports_for[item]) }}" @@ -95,9 +133,6 @@ when: firewall_enabled_at_boot|bool tags: firewall - - role: hostname - - role: resolv_conf - - role: etc_hosts - role: add-repository - role: packages - role: sudo @@ -107,7 +142,6 @@ - role: pam_limits - role: io-scheduler - role: locales - - role: timezone - role: ntp - role: ssh-keys - role: copy diff --git a/images/TypeC.png b/images/TypeC.png new file mode 100644 index 000000000..6a6fb5dd9 Binary files /dev/null and b/images/TypeC.png differ diff --git a/inventory b/inventory index 76faf9f7a..c17e2dd20 100644 --- a/inventory +++ b/inventory @@ -1,24 +1,32 @@ -# This is example inventory file! # Please specify the ip addresses and connection settings for your environment # The specified ip addresses will be used to listen by the cluster components. # "postgresql_exists='true'" if PostgreSQL is already exists and running # "hostname=" variable is optional (used to change the server name) -# if dcs_exists: false and dcs_type: "etcd" (in vars/main.yml) -[etcd_cluster] # recommendation: 3 or 5-7 nodes +# In this example, all components will be installed on PostgreSQL nodes. +# You can deploy the haproxy balancers and the etcd or consul cluster on other dedicated servers (recomended). + +# if dcs_exists: false and dcs_type: "etcd" +[etcd_cluster] # recommendation: 3, or 5-7 nodes 10.128.64.140 10.128.64.142 10.128.64.143 +# if dcs_exists: false and dcs_type: "consul" +[consul_instances] # recommendation: 3 or 5-7 nodes +10.128.64.140 consul_node_role=server consul_bootstrap_expect=true consul_datacenter=dc1 +10.128.64.142 consul_node_role=server consul_bootstrap_expect=true consul_datacenter=dc1 +10.128.64.143 consul_node_role=server consul_bootstrap_expect=true consul_datacenter=dc1 +#10.128.64.144 consul_node_role=client consul_datacenter=dc1 +#10.128.64.145 consul_node_role=client consul_datacenter=dc2 -# if with_haproxy_load_balancing: true (in vars/main.yml) +# if with_haproxy_load_balancing: true [balancers] 10.128.64.140 10.128.64.142 10.128.64.143 - # PostgreSQL nodes [master] 10.128.64.140 hostname=pgnode01 postgresql_exists='false' @@ -31,12 +39,7 @@ master replica - -# In this example, all components will be installed on PostgreSQL nodes -# You can deploy the etcd cluster and the haproxy balancers on other dedicated servers. - - -# if pgbackrest_install: true and "repo_host" is set (in vars/main.yml) +# if pgbackrest_install: true and "repo_host" is set [pgbackrest] # optional (Dedicated Repository Host) @@ -46,8 +49,8 @@ ansible_connection='ssh' ansible_ssh_port='22' ansible_user='root' ansible_ssh_pass='secretpassword' # "sshpass" package is required for use "ansible_ssh_pass" -# ansible_ssh_private_key_file= -# ansible_python_interpreter='/usr/bin/python3' # is required for use python3 +#ansible_ssh_private_key_file= +#ansible_python_interpreter='/usr/bin/python3' # is required for use python3 [pgbackrest:vars] ansible_user='postgres' diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 9cd587eb5..30e37aa04 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -6,26 +6,16 @@ tasks: - name: Set variables for molecule set_fact: - firewall_enabled_at_boot: true + firewall_enabled_at_boot: false firewall_enable_ipv6: false # Added to prevent test failures in CI. swap_file_create: false # Added to prevent test failures in CI. sysctl_set: false # Added to prevent test failures in CI. nameservers: ["8.8.8.8", "9.9.9.9"] with_haproxy_load_balancing: true + consul_node_role: server # if dcs_type: "consul" + consul_bootstrap_expect: true # if dcs_type: "consul" cacheable: true - - name: Prepare | Clean yum cache - command: yum clean all - when: - - ansible_os_family == "RedHat" - - ansible_distribution_major_version == '7' - - - name: Prepare | Clean dnf cache - command: dnf clean all - when: - - ansible_os_family == "RedHat" - - ansible_distribution_major_version is version('8', '>=') - - import_playbook: ../../deploy_pgcluster.yml ... diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 1f9800c39..d10bba81b 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -7,7 +7,7 @@ driver: name: docker platforms: - name: 10.172.0.17 - hostname: etcd01 + hostname: dcs-node01 image: "${IMAGE_NAMESPACE:-geerlingguy}/docker-${IMAGE_DISTRO:-centos8}-ansible:${IMAGE_TAG:-latest}" # docker_networks: # TODO github.com/ansible-community/molecule/pull/2696 # - name: test_docker_network @@ -18,8 +18,13 @@ platforms: - name: test_docker_network ipv4_address: 10.172.0.17 exposed_ports: - - 2379/tcp - - 2380/tcp + - 2379/tcp # if dcs_type: "etcd" + - 2380/tcp # if dcs_type: "etcd" + - 8300/tcp # if dcs_type: "consul" + - 8301/tcp # if dcs_type: "consul" + - 8302/tcp # if dcs_type: "consul" + - 8500/tcp # if dcs_type: "consul" + - 8600/tcp # if dcs_type: "consul" command: "" volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw @@ -27,10 +32,11 @@ platforms: privileged: true pre_build_image: true groups: - - etcd_cluster + - etcd_cluster # if dcs_type: "etcd" + - consul_instances # if dcs_type: "consul" - name: 10.172.0.18 - hostname: etcd02 + hostname: dcs-node02 image: "${IMAGE_NAMESPACE:-geerlingguy}/docker-${IMAGE_DISTRO:-centos8}-ansible:${IMAGE_TAG:-latest}" networks: - name: test_docker_network @@ -38,6 +44,11 @@ platforms: exposed_ports: - 2379/tcp - 2380/tcp + - 8300/tcp + - 8301/tcp + - 8302/tcp + - 8500/tcp + - 8600/tcp command: "" volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw @@ -46,9 +57,10 @@ platforms: pre_build_image: true groups: - etcd_cluster + - consul_instances - name: 10.172.0.19 - hostname: etcd03 + hostname: dcs-node03 image: "${IMAGE_NAMESPACE:-geerlingguy}/docker-${IMAGE_DISTRO:-centos8}-ansible:${IMAGE_TAG:-latest}" networks: - name: test_docker_network @@ -56,6 +68,11 @@ platforms: exposed_ports: - 2379/tcp - 2380/tcp + - 8300/tcp + - 8301/tcp + - 8302/tcp + - 8500/tcp + - 8600/tcp command: "" volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw @@ -64,6 +81,7 @@ platforms: pre_build_image: true groups: - etcd_cluster + - consul_instances - name: 10.172.0.20 hostname: pgnode01 @@ -75,6 +93,11 @@ platforms: - 8008/tcp - 5432/tcp - 6432/tcp + - 8300/tcp # if dcs_type: "consul" + - 8301/tcp # if dcs_type: "consul" + - 8302/tcp # if dcs_type: "consul" + - 8500/tcp # if dcs_type: "consul" + - 8600/tcp # if dcs_type: "consul" command: "" volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw @@ -85,6 +108,7 @@ platforms: - master - postgres_cluster - balancers + - consul_instances - name: 10.172.0.21 hostname: pgnode02 @@ -96,6 +120,11 @@ platforms: - 8008/tcp - 5432/tcp - 6432/tcp + - 8300/tcp + - 8301/tcp + - 8302/tcp + - 8500/tcp + - 8600/tcp command: "" volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw @@ -106,6 +135,7 @@ platforms: - replica - postgres_cluster - balancers + - consul_instances provisioner: name: ansible diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index b7ab340d6..969d03ea5 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -18,4 +18,9 @@ labels: owner: molecule + - name: "Install netaddr dependency on controlling host" + pip: + name: netaddr + become: false + ... diff --git a/roles/consul/CHANGELOG.md b/roles/consul/CHANGELOG.md new file mode 100644 index 000000000..9115a723d --- /dev/null +++ b/roles/consul/CHANGELOG.md @@ -0,0 +1,1093 @@ +## 2.6.1 + +- Update CONTRIBUTORS +- Prevent gathering facts for the same servers in loop. (thanks Pavel Zinchuk) +- Update consul\_systemd.service.j2 (thanks Han Sooloo) +- Allow "Connect" for any and all nodes (#401) (thanks adawalli) +- Increment to 1.7.3 (#395) (thanks Stuart Low) +- fix: Stop sending logs to syslog through systemd (#393) (thanks Samuel Mutel) +- Don't create TLS folder if consul\_tls\_copy\_keys is false (#369) (thanks Samuel Mutel) +- Setup the role to be used in check mode (thanks Louis Paret) +- Use consul\_node\_name as empty by default to use hostname (#373) (thanks Louis Paret) +- Corrected version Fedora dropped libselinux-python. (#385) (thanks jebas) +- add leave\_on\_terminate (thanks Le Minh Duc) +- Allow consul connect on bootstrap nodes (thanks Robert Edström) +- Fix unarchive consul package to run_once (thanks schaltiemi) + +## 2.6.0 + +- Consul v1.7.0 +- Add GitHub workflows (thanks @gofrolist ) +- Modernize PID path (thanks @smutel) +- Add Consul automatic startup to systemd in Nix tasks (thanks @smutel) +- Add verify_incoming_rpc option (thanks @smutel) +- Update CONTRIBUTORS +- Update documentation + +## v2.5.4 + +- Consul v1.6.3 +- consul_manage_group now defaults to true +- Set consul_node_name to ansible_hostname, resolves #337 +- Enable consul Connect (thanks @imcitius) +- Cloud auto discovery (thanks @imcitius) +- Use generated password as token UUID source (thanks @jmariondev) +- Fix ACL Replication Token sed pattern (thanks @jmariondev) +- Add when_false to ACL master lookup (thanks @jmariondev) +- Ensure enable_tag_override is json (thanks @slomo) +- Add suport for -alt-domain (thanks @soloradish) +- Add enable_token_persistence option (thanks @smutel) +- Support new ARM builds for Consul 1.6.2+ (thanks @KyleOndy) +- Add CAP_NET_BIND_SERVICE to systemd unit (thanks @smutel) +- Fix configuration template (thanks @imcitius) +- Update documentation (thanks @karras) + +## v2.5.3 + +- Consul v1.6.2 +- Update documentation + +## v2.5.2 + +- Fix path / drop with_fileglob in install_remote (thanks @bbaassssiiee) +- Handle consul_encrypt_enable variable for Nix (thanks @bbaassssiiee) +- Parse acl_master_token from config (thanks @bbaassssiiee) +- Fix start service on Windows (thanks @imcitius) +- Preserve custom config (thanks @slomo) +- Update Windows for win_service usage (thanks @FozzY1234) +- Restart when TLS material changes (Thanks @bbaassssiiee) +- No tokens in logging (Thanks @bbaassssiiee) +- Flush handlers at the end of main (Thanks @bbaassssiiee) +- Read tokens from from previously bootstrapped server (Thanks @bbaassssiiee) +- Rename `consul_server_key` variable +- Sort keys in service configuration (thanks @slomo) + +## v2.5.1 + +- Consul v1.6.1 +- Add run_once to delegated tasks (thanks @liuxu623) +- Fix service restart on upgrades (thanks @jpiron) +- Fix log directory ownership (@thanks liuxu623) +- Handle missing unzip on control host (thanks @bbaassssiiee) +- Add Added version check for log_rotate_max_files (thanks @jasonneurohr) +- Update documentation + +## v2.5.0 + +- Consul v1.6.0 +- Add documentation for new TLS options (thanks @jasonneurohr) +- Add support for translate_wan_address (@calmacara) +- Add `-log-file` (thanks @liuxu623) + +## v2.4.5 + +- Consul v1.5.3 +- Update molecule configuration (thanks @gofrolist) +- Support TLS files in subdirectories - resolves #297 +- Update some bare variable comparisons - resolves #293 +- Update server address for usage with --limit (thanks @danielkucera) +- Update snapshot configuration for TLS (thanks @jasonneurohr) +- Add TLS minimum version and ciper suite preferences (thanks @jasonneurohr) +- Update documentation +- Update CONTRIBUTORS + +## v2.4.4 + +- Consul v1.5.2 (thanks @patsevanton) +- Add Molecule support (thanks @gofrolist) +- Correct several task issues (thanks @gofrolist) + +## v2.4.3 + +- Consul v1.5.1 +- Update documentation + +## v2.4.2 + +- Correct ACL typo correction (thanks @bewiwi) +- Fix unarchive failure case (thanks @cyril-dussert) +- Update CONTRIBUTORS + +## v2.4.1 + +- Add LimitNOFILE option to systemd unit (thanks @liuxu623) +- Fix typo in in replication token check (thanks @evilhamsterman) + +## v2.4.0 + +- Consul v1.5.0 +- Specify a token for a service (thanks @xeivieni) +- Empty consul_acl_master_token check (thanks @evilhamsterman) +- Separate Unix and Linux tasks from Windows tasks (thanks @evilhamsterman) + +## v2.3.6 + +- Continue with task cleanup +- Fix deleting of unregistered services (thanks @Shaiou) +- Fix issue in Amazon variables (thanks @ToROxI) +- Add bool filter to templates (thanks @eeroniemi) +- Fix CONSUL_ACL_POLICY (thanks @eeroniemi) +- Correct cleanup task fileglob bogusness +- Switch to SIGTERM in sysvinit stop + +## v2.3.5 + +- Consul v1.5.0 +- fixed multiarch deployment race condition (thanks @lanefu) +- Switched from systemctl command to systemd module [lint] +- Update for E504 use 'delegate_to: localhost' [lint] + - asserts + - install + - encrypt_gossip +- Update for E104 in with_fileglob for install_remote [lint] +- Update for E601 in syslog [lint] +- Update for E602 in tasks [lint] + - acl + - main +- Update example site playbook roles format +- Support install on Debian Testing (thanks @gfeun) +- Fix consul_bind_address (thanks @danielkucera) +- Custom bootstrap expect value (thanks @Roviluca) +- Fix Windows support for registering services (thanks @gyorgynadaban) +- Update documentation + +## v2.3.4 + +- Consul v1.4.3 +- Update documentation + +## v2.3.3 + +- Add services management (thanks @Sispheor) +- Add enable_local_script_checks configuration (thanks @canardleteer) +- Add ability to enable legacy GUI (thanks @imcitius) +- Optional domain datacenter delegation with `consul_delegate_datacenter_dns` + +## v2.3.2 + +- Consul v1.4.2 +- Remove token generation/retrieval on clients (thanks @jpiron) +- Add listen to all the handler tasks (@pwae) +- retry_join setup independent from the hosts servers (thanks @Fuochi-YNAP) + +## v2.3.1 + +- Add Consul 1.4.0 ACL configuration syntax support (thanks @jpiron) +- Fix unzip installation check task check mode (thanks @jpiron) +- Fix systemd configuration task handler notification (thanks @jpiron) + +## v2.3.0 + +- The role no longer attempts to install the unzip binary locally onto + the Ansible control host; it is now a hard dependency and role execution + will fail if unzip is not in the PATH on the control host. +- Snapshot agent installation and configuration (thanks @drewmullen) +- Delegate Consul datacenter DNS domain to Consul (thanks @teralype) +- Allow DNSmasq binding to particular interfaces (thanks @teralype) +- Update local tasks (thanks @sgrimm-sg) +- Update documentation + +## v2.2.0 + +- Consul v1.4.0 +- Update documentation + +## v2.1.1 + +- Consul v1.3.1 +- Configuration and documentation for gRPC (thanks @RavisMsk) +- Consistent boolean use +- Fix Consul restart handler reference (thanks @blaet) +- Write gossip key on all hosts (thanks @danielkucera) +- Protect local consul cluster key file (thanks @blaet) +- Support Amazon Linux (thanks @soloradish) +- Quite ACL replication token retrieval (thanks @jpiron) +- disable_keyring_file configuration option (thanks @vincepii) +- Update tests +- Update documentation + +## v2.1.0 + +- Consul v1.3.0 +- Fix undefined is_virtualenv condition (thanks @jpiron) +- Ensure idempotent folder permissions (thanks @jpiron) +- Add configurable systemd restart time (@thanks abarbare) +- Update documentation (thanks @jeffwelling, @megamorf) + +## v2.0.9 + +- Consul v1.2.3 +- Update documentation + +## v2.0.8 + +- Normalize conditionals in all tasks +- Update documentation + +## v2.0.7 + +- Add initial support for Alpine Linux (thanks @replicajune) +- Add support for verify_incoming_https (thanks @jeffwelling) +- Fix ACL token behavior on existing configuration (thanks @abarbare) +- Windows enhancements and fixes (thanks @imcitius) +- Update CONTRIBUTORS +- Update Meta +- Update documentation + +## v2.0.6 + +- Update meta for ArchLinux to allow Galaxy import + +## v2.0.4 + +- Consul 1.2.2 +- Update remaining deprecated tests (thanks @viruzzo) +- Added handler to reload configuration on Linux (thanks @viruzzo) +- Add support for Oracle Linux (thanks @TheLastChosenOne) +- Fix generate `consul_acl_master_token` when not provided (thanks @abarbare) +- Update CONTRIBUTORS + +## v2.0.3 + +- Fix jinja2 retry_join loops (thanks @Logan2211) +- Dependency Management Improvements (thanks @Logan2211) +- Update some deprecated tests in main tasks +- Update CONTRIBUTORS +- Update documentation + +## v2.0.2 + +- Consul v1.2.0 +- Update documentation + +## v2.0.1 + +- Add beta UI flag (thanks @coughlanio) +- Clean up dir tasks (thanks @soloradish) + +## v2.0.0 + +- Consul v1.1.0 +- Update configuration directory permissions (thanks @Rtzq0) +- Update service script dependency (thanks @mattburgess) +- Assert if consul_group_name missing from groups (thanks @suzuki-shunsuke) +- Add Archlinux support +- Change syslog user to root (no syslog user on Debian/dir task fails) +- Updated CHANGELOG ordering 🎉 +- Updated CONTRIBUTORS + +## v1.60.0 + +- Consul v1.0.7 +- Option for TLS files already on the remote host (thanks @calebtonn) +- Raise minimum Ansible version to 2.4.0.0 +- Update documentation +- Update Vagrant documentation + +## v1.50.1 + +- Revert to old style retry_join which doesn't fail in all cases + +## v1.50.0 + +- Consul v1.0.6 +- Add support for setting syslog facility and syslog file (thanks @ykhemani) +- Update configuration +- Update tests +- Update documentation (thanks also to @ChrisMcKee) + +## v1.40.0 + +- Consul v1.0.3 +- It's 2018! +- Update configuration +- Update documentation + +## v1.30.2 + +- Correct retry_join block (@thanks hwmrocker) + +## v1.30.1 + +- Add performance tuning configuration (thanks @t0k4rt) + - Set raft multiplier to 1 +- Conditionally install Python dependency baed on virtualenv or --user + Addresses https://github.com/brianshumate/ansible-consul/issues/129#issuecomment-356095611 +- Update includes to import_tasks and include_tasks +- Remove invalid consul_version key from configuration +- Update Vagrantfile + - Set client address to 0.0.0.0 so Vagrant based deploy checks now pass +- Update documentation + +## v1.30.0 + +- Consul v1.0.2 +- Update documentation + +## v1.29.0 + +- Consul v1.0.1 +- Fix idempotency (thanks @issmirnov) +- Make gossip encryption optional (thanks @hwmrocker) +- Install netaddr with `--user` +- Update documentation +- Update CONTRIBUTORS + +## v1.28.1 + +- Remove deprecated advertise_addrs to resolve #123 so that role works again + +## v1.28.0 + +- Consul 1.0! +- Fix python3 compatibility for meta data (thanks @groggemans) + + +## v1.27.0 + +- Consul v0.9.3 +- Update server joining (thanks @groggemans) +- Fix types that should be lists (thanks @vincent-legoll) + +## v1.26.1 + +- Fix deprecation notice on include +- Change example server hostnames + +## v1.26.0 + +- Add node_meta config (thanks @groggemans) +- Add additional retry-join parameters (thanks @groggemans) +- Add DNSMasq for Red Hat (thanks @giannidallatorre) +- Fix typo (thanks @vincent-legoll) +- Allow post setup bootstrapping of ACLs (thanks @groggemans) +- Add disable_update_check to config options (thanks @groggemans) +- Fix list example data type (thanks @vincent-legoll) +- Remove tasks for installation of python-consul (thanks @vincent-legoll) + +## v1.25.4 + +- Add raft_protocol parameter, fix version compares (thanks @groggemans) +- Add missing address and port config (thanks @groggemans) +- Add missing ACL config options (thanks @groggemans) +- Prefer retry_join and retry_join_wan instead of start_join / start_join_wan +- DNSMasq updates (thanks @groggemans) + +## v1.25.3 + +- Consul v0.9.2 +- Add enable_script_checks parameter (thanks @groggemans) +- Update documentation + +## v1.25.2 + +- Rename `cluster_nodes` label to `consul_instances` + +## v1.25.1 + +- Support rolling upgrades on systemd based Linux (thanks oliverprater) +- Fix breaking change in paths and runtime warnings (thanks oliverprater) +- Set CONSUL_TLS_DIR default to `/etc/consul/ssl` for #95 + +## v1.25.0 + +- Consul version 0.9.0 +- Add `consul_tls_verify_server_hostname` to TLS configuration template +- Begin to add relevant Consul docs links to variable descriptions in README +- Fix formatting in README_VAGRANT (thanks @jstoja) +- Update CONTRIBUTORS + +## v1.24.3 + +- Consul v0.8.5 +- Fix "Check Consul HTTP API" via unix socket (thanks @vincent-legoll) +- Avoid warning about already existing directory (thanks @vincent-legoll) +- Fix typos in messages (thanks @vincent-legoll) +- Fix documentation about `consul_node_role` (thanks @vincent-legoll) +- Update documentation + +## v1.24.2 + +- Use consul_run_path variable (thanks @vincent-legoll) +- Replace remaining hardcoded paths (thanks @vincent-legoll) +- Factorize LOCK_FILE (thanks @vincent-legoll) +- CHANGELOG++ +- Update CONTRIBUTORS +- Update README + +## v1.24.1 + +- Add `ansible.cfg` for examples and install netaddr (thanks @arehmandev) +- Improve HTTP API check (thanks @dmke) +- Update CONTRIBUTORS + +## v1.24.0 + +- Consul 0.8.4 +- Remove `user_acl_policy.hcl.j2` and `user_custom.json.j2` +- Update configuration template with new ACL variables +- Remove consul_iface from vagrant_hosts +- Simplify ACL configuration +- Remove checks for `consul_acl_replication_token_display` +- Update Vagrantfile +- Update README + +## v1.23.1 + +- Add files directory + +## v1.23.0 + +- Combines all (client/server/bootstrap) config templates (thanks @groggemans) +- Template for dnsmasq settings (thanks @groggemans) + +## v1.22.0 + +- Revert changes from v1.21.2 and v1.21.1 + +## v1.21.2 + +Actually add new template files :facepalm: + +## v1.21.1 + +Update ACL tasks +Rename configd_50custom.json.j2 template tp user_custom.json.j2 +Rename configd_50acl_policy.hcl template to user_acl_policy.hcl.j2 +Do not enable a default set of ACL policies + +## v1.20.2 + +- Correct meta for Windows platform +- Update supported versions +- Update documentation + +## v1.20.1 + +- Update main tasks to move Windows specific tasks into blocks + +## v1.20.0 + +- Initial Windows support (thanks @judy) +- Update documentation +- Update CONTRIBUTORS + +## v1.19.1 + +- Consul version 0.8.3 +- Recurse perms through config, data, and log directories (thanks @misho-kr) +- Update documentation + +## v1.19.0 + +- Consul version 0.8.2 +- Enable consul_manage_group var and conditional in user_group tasks +- Initial multi datacenter awareness bits (thanks @groggemans) + +## v1.18.5 + +- Set `| bool` where needed to stop warnings about template delimiters +- Add consul group when managing the consul user + +## v1.18.4 + +- Correct links in README (thanks @MurphyMarkW) +- Lower minimum Debian version from 8.5. to 8 (addresses #63) + +## v1.18.3 + +- Generate correct JSON with TLS and ACL enabled (thanks @tbartelmess) +- Switch local tasks to `delegate_to` which should cover most concerns + +## v1.18.2 + +- Remove check from install_remote + +## v1.18.1 + +- Update stat task + +## v1.18.0 + +- Add new vars + - `consul_run_path` for the PID file +- Add bootstrap-expect toggle option (thanks @groggemans) +- Use directory variables in dirs tasks +- Do not attempt to install Consul binary if already found on consul_bin_path + - Fixes #60 +- Rename intermediate `boostrap_marker` var +- Formatting on CONTRIBUTING +- Update CONTRIBUTORS +- Updated tested versions +- Update documentation + +## v1.17.4 + +- Clean up task names and make more detailed; use consistent verb intros +- Switch to local_action on all local install tasks +- Already using grep, so let's just awk for the SHA and then register it + +## v1.17.3 + +- Revert local_action tasks + - Ansible generally spazzes out with "no action detected in task" + for any variation of local_task I tried + +## v1.17.2 + +- Switch to local_action for local tasks +- Wrap IPv6 addresses (thanks @tbartelmess) + +## v1.17.1 + +- Fix template filename (addresses #58) + +## v1.17.0 + +- Updated configuration directory structure (thanks @groggemans) + - Updated `consul_config_path` to point to `/etc/consul` + - Added `consul_configd_path` defaulting to `/etc/consul.d` +- Added `consul_debug` variable - defaults to *no* (thanks @groggemans) +- Moved all config related tasks to `tasks/config.yml` (thanks @groggemans) +- Added ACL and TLS parameters to the main `config.json` (thanks @groggemans) +- Now using `/etc/consul/config.json` for all consul roles (thanks @groggemans) +- Fix small bug preventing RPC gossip key to be read (thanks @groggemans) +- Exposed `consul_node_role` as a fact (thanks @groggemans) +- Update documentation + +## v1.16.3 + +- Consul 0.8.1 +- Update documentation + +## v1.16.2 + +- Standing corrected - put node_role back into defaults as it will still be + overridden by host vars (sorry @groggemans) +- Update documentation + +## v1.16.1 + +- Revert node_role addition to default vars so clusters will still properly + come up since we basically lost access the bootstrap role + +## v1.16.0 + +- Cleanup templates and default vars (thanks @groggemans) +- Add default consul_node_role (client) (thanks @groggemans) +- Update 'gather server facts' task/option (thanks @groggemans) +- Make user management optional + move to own file (thanks @groggemans) +- Properly name-space all vars (thanks @groggemans) +- Move directory settings to own file (thanks @groggemans) +- Replace unsupported Jinja do with if/else (thanks @groggemans) +- Fix missing endif in server configuration template (thanks @groggemans) +- Re-expose consul_bind_address as fact (thanks @groggemans) +- Template output improvements and style changes (thanks @groggemans) +- Add spaces at front end back of JSON arrays (thanks @groggemans) +- Update Vagrantfile +- Update documentation + +## v1.15.0 + +- Add option to download binaries directly to remotes (thanks @jonhatalla) +- Add environment variable overrides for the following default variables: + - `consul_bind_address` + - `consul_datacenter` + - `consul_domain` + - `consul_group_name` + - `consul_log_level` + - `consul_syslog_enable` + - `consul_acl_default_policy` + - `consul_acl_down_policy` + - Rename `consul_src_files` variable + - Rename `consul_copy_keys` variable + - Rename `consul_ca_crt` variable + - Rename `consul_server_crt` variable + - Rename `consul_tls_server_key` variable + - Rename `consul_verify_outgoing` variable + - Rename `consul_verify_server_hostname` variable + - Move `consul_iface` default to value of `hostvars.consul_iface` + - Override with elsewhere or with `CONSUL_IFACE` environment variable + - Closes #40 +- Update documentation + +## v1.14.0 + +- Fix bootstrapping (thanks @groggemans) + +## v1.13.1 + +- Finish documentation updates + +## v1.13.0 + +- Cleanup of variables +- Fix statement preventing key transfer to new servers (thanks @groggemans) +- Change custom configuration naming convention +- Update documentation + +## v1.12.1 + +- Fix defaults, shake fist at YAML + +## v1.12.0 + +- Consul version 0.8.0 +- Update documentation + +## v1.11.3 + +- Update for config generation on only one host (thanks @misho-kr) +- Update meta + +## v1.11.2 + +- Fix documentation formatting issues +- Add support for Ubuntu 15.04 + + +## v1.11.1 + +- Updated known good versions +- Format file names +- Look for existing config on all hosts (thanks @misho-kr) +- Update CONTRIBUTORS + +## v1.11.0 + +- File permission updates (thanks @arledesma) +- Explicit consul_user/consul_group ownership of configurations + (thanks @arledesma) +- Use consul_bin_path throughout (thanks @arledesma) + + +## v1.10.5 + +- Additional fixes to debian init +- Add consul_config_custom for role users to specify new or overwrite + existing configuration (thanks @arledesma) + +## v1.10.4 + +- Corrections to config_debianint.j2 for #34 +- Update main task to prefer open Consul HTTP API port over PID file +- Update package cache before installing OS packages + (watch for and refuse reversion of this as it's occurred once now) + +## v1.10.3 + +- Allow specification of ports object (thanks @arledesma) +- Strict TLS material file permissions (thanks @arledesma) +- Update permissions modes to add leading zero +- Random task cleanup +- Update documentation + +## v1.10.2 + +- Update main task to create a mo better consul user (addresses #31) + +## v1.10.1 + +- Fixup client hosts in template (thanks @violuke) +- Optimize systemd unit file + +## v1.10.0 + +- Initial FreeBSD support +- Vagrantfile updated for FreeBSD +- Added checks for interface addresses for differences (obj vs. literal list) + in ipv4 addresses as returned by Linux vs. BSD/SmartOS +- New `consul_os` var gets operating system name as lowercase string +- Add AMD64 pass-through/kludge to consul_architecture_map configuration +- Update Vagrantfile + - Decrease RAM to 1024MB + - Add FreeBSD specific checks in inline script + - Add FreeBSD hard requirements (explicit MAC address, disable share, shell) +- Update documentation + +## v1.9.7 + +- Initial ARM support (thanks @lanefu) +- Update CONTRIBUTORS + +## v1.9.6 + +- Update license +- Update preinstall script +- Fix consul_bind_address (thanks @arledesma) +- Better config.json ingress with slurp (thanks @arledesma) + +## v1.9.5 + +- Initial SmartOS support (thanks @sperreault) +- Updated CONTRIBUTORS + +## v1.9.4 + +- Issue with ACL tasks + +## v1.9.3 + +- Fix local_action tasks + +## v1.9.2 + +- Keep gossip encryption in main tasks until we sort cross play var +- Compact YAML style for all tasks +- Fix task items, shorten timeouts +- Update documentation + +## v1.9.1 + +- Split gossip encryption out into separate task file + +## v1.9.0 + +- Local TLS keys (thanks @dggreenbaum) +- Remove Atlas support +- Update documentation + +## v1.8.2 + +- Update Consul bin path in keygen task + +## v1.8.1 + +- Consul 0.7.5 +- Update documentation +- Contributors correction + +## v1.8.0 + +- Consul 0.7.5 +- BREAKING CHANGE: Deprecate read/write of ACL tokens from file system + functionality and prefer setting tokens from existing cluster nodes with + `CONSUL_ACL_MASTER_TOKEN` and `CONSUL_ACL_REPLICATION_TOKEN` environment + variables instead +- Update documentation + +## v1.7.4 + +- Consul 0.7.3 +- Update documentation + +## v1.7.3 + +- Version updates +- Task edits +- add CONTRIBUTING.md + +## v1.7.2 + +- Fix non-working cleanup task +- Update README + +## v1.7.0 + +- Consul version 0.7.2 + +## v1.6.3 + +- Ensure that all local_action tasks have become: no (thanks @itewk) + +## v1.6.2 + +- Stop reconfiguring bootstrap node as it's not really necessary and + spurious races cause failure to re-establish cluster quorum when doing so +- CONSUL_VERSION environment variable +- Deprecated default variables cleanup + +## v1.6.1 + +- Drop Trusty support from meta for now (for #19) + +## v1.6.0 + +- Update task logic around initscripts (for #19) +- Fix issues in initscripts +- Rename Debian init script template +- Update documentation +- Fixing bug with deleting file. Better regex. Formatting. (Thanks @violuke) +- Remember ACL master/replication tokens between runs. + Actually set replication token. (Thanks @violuke) +- Typo fix (Thanks @violuke) +- Allowing re-running to add new nodes. More HA too. (Thanks @violuke) + +## v1.5.7 + +- Remove unnecessary code (thanks @kostyrevaa) +- Determine binary's SHA 256 from releases.hashicorp.com (for #16) +- Update documentation + +## v1.5.6 + +- Correct Atlas variable names + +## v1.5.5 + +- Initial attempts at idempotency in main tasks (for #14, #15) + +## v1.5.4 + +- Recursors as env var + +## v1.5.3 + +- Update start_join for client configuration template + +## v1.5.3 + +- Consul version 0.7.1 +- Consistent template names +- Update documentation + +## v1.5.1 + +- Fail when ethernet interface specified by consul_iface not found on + the system (addresses #13) + +## v1.5.0 + +- Add initial TLS support +- Update documentation + +## v1.4.1 + +- Move Dnsmasq restart to inside of tasks +- Add client dependencies for further configuration (thanks @crumohr) +- Fix error using predefined encryption key (thanks @crumohr) +- Removal of redundant includes (thanks @crumohr) + +## v1.4.0 + +- Compatibility with Ubuntu 16.04 (thanks @crumohr) +- iptables support (thanks @crumohr) +- Booleans instead of strings for variables (thanks @crumohr) +- Runnable if DNS is broken (thanks @crumohr) +- Remove unused variables +- Update block conditional for ACLs +- Update documentation + +## v1.3.4 + +- Update documentation + +## v1.3.3 + +- Update/validate CentOS 7 box +- Update documentation +- Updated failure cases for CentOS + +# v1.3.2 + +- Correct CONSUL_DNSMASQ_ENABLE var name + +## v1.3.1 + +- Correct variable names +- Add token display variables +- Update documentation +- Remove deprecated variables + +## v1.3.0 + +- Initial ACL support +- Initial Atlas support +- Streamline main tasks +- Update documentation +- Update variables + +## v1.2.16 + +- Clean up variables (thanks @jessedefer) +- Update documentation (thanks @jessedefer) +- Update CONTRIBUTORS + +## v1.2.15 + +- Fail on older versions +- Move distro vars to defaults +- Remove vars + +## v1.2.14 + +- Documentation updates + +## v1.2.13 + +- Doc meta + +## v1.2.12 + +- Update documentation + +## v1.2.11 + +- Update supported versions +- Fix up unarchive task quoting + +## v1.2.10 + +- Added consul_rpc_bind_address +- Updated documentation + +## v1.2.9 + +- Download once, copy many for Consul binary +- Rename package variables + +## v1.2.8 + +- Stop creating UI directory +- Set correct RAM in Vagrantfile + +## v1.2.7 + +- Secondary nodes now join only the bootstrap node +- Added consul_bootstrap_interface variable +- Add PIDFile to systemd unit +- Updated documentation + +## v1.2.6 + +- Update documentation +- Add `consul_node_name` variable +- Add `consul_dns_bind_address` variable +- Add `consul_http_bind_address` variable +- Add `consul_https_bind_address` variable +- Add initial ACL variables + +## v1.2.5 + +- Add LICENSE.txt for Apache 2.0 license + +## v1.2.4 + +- Updated README +- Undo 125bd4bb369bb85f58a09b5dc81839e2779bd29f as dots in node_name breaks + DNS API (without recursor option) and also breaks dnsmasq option + +## v1.2.3 + +- Still with the tests + +## v1.2.3 + +- Updated README + +## v1.2.1 + +- Tests work locally but not in Travis; trying an env var instead of cfg + +## v1.2.0 + +- Consul version 0.7.0 +- UI is built in now, so no longer downloaded / installed separately +- Usability improvements (thanks @Rodjers) + +## v1.1.0 + +- Bare role now installs and bootstraps cluster; included site.yml will also + reconfigure bootstrap node as server and optionally enable dnsmasq + forwarding for all cluster agents +- Remove bad client_addr bind in favor of default (localhost) + Some weirdness was occurring whereby the client APIs were listening on + TCP6/UDP6 sockets but not TCP4/UDP4 when client_addr set to 0.0.0.0 +- Adjust timeouts for cluster UI check +- Default configurable domain to "consul" so that examples from docs work, etc. +- Combine all OS vars into main (addresses undefined var warnings) +- Removed separate OS var files +- Updated known working software versions +- Any errors are fatal for the site.yml example playbook +- Explicit pid-file to use in wait_for +- Remove cruft from init script +- Update documentation + +## v1.0.15 + +- Meta update + +## v1.0.14 + +- Initial test +- Initial Travis CI setup + +## v1.0.13 + +- Add initial dnsmasq front end bits +- Reconfigure bootstrap node for normal operation (remove bootstrap-expect) + after initial cluster formation and restart bootstrap node + +## v1.0.12 + +- FIX: No such file or directory /etc/init.d/functions (thanks @oliverprater) +- FIX: Using bare variables is deprecated (thanks @oliverprater) +- Added CONTRIBUTORS.md +- Updated documentation + +## v1.0.11 + +- Renamed bootstrap template + +## v1.0.10 + +- Remove extra datacenter definition + +## v1.0.9 + +- Change datacenter value + +## v1.0.8 + +- Update documentation + +## v1.0.7 + +- Update supported versions +- Update documentation + +## v1.0.6 + +- Updated to Consul 0.6.4 +- Make bind_address configurable for #1 +- Cleaned up deprecaed bare variables +- Updated supporting software versions +- Updated documentation + +## v1.0.5 + +- Updated defaults and Consul version (thanks @bscott) +- Made cluster bootable and switch to become_user + other Ansibel best + practices (thanks @Rodjers) +- Updated minimum Ansible version required in meta + +## v1.0.4 + +- Renamed consul_nodes label for better compatibility with my other roles + +## v1.0.3 + +- Prefix /usr/local/bin in PATH for cases where the consul binary is not found +- Changed UI path +- Add generic SysV init script +- Add Debian init script +- Use systemd for distribution major versions >= 7 +- Remove Upstart script +- Updated configuration files + +## v1.0.2 + +- Removed the need for cluster_nodes variable +- Fix client template task +- Fix invalid JSON in the config.json outputs +- Updated documentation + +## v1.0.1 + +- Updated README + +## v1.0.0 + +- Installs Consul and Consul UI to each node +- Installs example configuration for bootstrap, server, and client +- Installs example upstart script diff --git a/roles/consul/CONTRIBUTING.md b/roles/consul/CONTRIBUTING.md new file mode 100644 index 000000000..f847a4647 --- /dev/null +++ b/roles/consul/CONTRIBUTING.md @@ -0,0 +1,96 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish +to make via issue, email, or any other method with the owners of this repository before making a change. + +Do note that this project has a code of conduct; please be sure to follow it +in all of your project interactions. + +## Pull Request Process + +1. Ensure any install or build artifacts are removed before the end of + the layer when doing a build +2. Update the README.md or README_VAGRANT.md with details of changes to the + interface, this includes new environment variables, exposed ports, useful + file locations and container parameters +3. Increase the version numbers in any examples files and the README.md + to the new version that this Pull Request would represent. The versioning scheme we use is (mostly) [SemVer](http://semver.org/) +4. You may merge the Pull Request in once you have the sign-off of two other + project contributors, or if you do not have permission to do that, you can + request the second reviewer to merge it for you + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project +and our community a harassment-free experience for everyone, regardless of age, +body size, disability, ethnicity, gender identity and expression, level of +experience, nationality, personal appearance, race, religion, or sexual +identity and orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Showing empathy towards other community members +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community + +Examples of unacceptable behavior by participants include: + +* Use of sexualized language or imagery and unwelcome sexual attention + or advances +* Insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +### Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an +appointed representative at an online or offline event. Representation of a +project may be further defined and clarified by project maintainers. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project leadership: bas.meijer me com. + +All complaints will be reviewed and investigated and will result in a response +that is deemed necessary and appropriate to the circumstances. The project +team is obligated to maintain confidentiality with regard to the reporter of +an incident. Further details of specific enforcement policies may be posted +separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/roles/consul/CONTRIBUTORS.md b/roles/consul/CONTRIBUTORS.md new file mode 100644 index 000000000..119a1c952 --- /dev/null +++ b/roles/consul/CONTRIBUTORS.md @@ -0,0 +1,90 @@ +# Contributors + +Thank you to all these fine folks for helping with ansible-consul! + +- [@abarbare](https://github.com/abarbare) +- [@adawalli](https://github.com/adawalli) +- [@arehmandev](https://github.com/arehmandev) +- [@arledesma](https://github.com/arledesma) +- [@arouene](https://github.com/arouene) +- [@bbaassssiiee](https://github.com/bbaassssiiee) +- [@blaet](https://github.com/blaet) +- [@bscott](https://github.com/bscott) +- [@calebtonn](https://github.com/calebtonn) +- [@calmacara](https://github.com/calmacara) +- [@canardleteer](https://github.com/canardleteer) +- [@ChrisMcKee](https://github.com/ChrisMcKee) +- [@chrisparnin](https://github.com/chrisparnin) +- [@coughlanio)](https://github.com/coughlanio) +- [@crumohr](https://github.com/crumohr) +- [@danielkucera](https://github.com/danielkucera) +- [@dggreenbaum](https://github.com/dggreenbaum) +- [@dmke](https://github.com/dmke) +- [@ducminhle](https://github.com/ducminhle) +- [@ecyril-dussert](https://github.com/cyril-dussert) +- [@eeroniemi](https://github.com/eeroniemi) +- [@evilhamsterman](https://github.com/evilhamsterman) +- [@FozzY1234](https://github.com/FozzY1234) +- [@Fuochi-YNAP](https://github.com/Fuochi-YNAP) +- [@giannidallatorre](https://github.com/giannidallatorre) +- [@GnomeZworc](https://github.com/GnomeZworc) +- [@gofrolist](https://github.com/gofrolist) +- [@groggemans](https://github.com/groggemans) +- [@gyorgynadaban](https://github.com/gyorgynadaban) +- [@HanSooloo](https://github.com/HanSooloo) +- [@hwmrocker](https://github.com/hwmrocker) +- [@imcitius](https://github.com/imcitius) +- [@issmirnov](https://github.com/issmirnov) +- [@itewk](https://github.com/itewk) +- [@jasonneurohr](https://github.com/jasonneurohr) +- [@jebas](https://github.com/jebas) +- [@jeffwelling](https://github.com/jeffwelling) +- [@jessedefer](https://github.com/jessedefer) +- [@jmariondev](https://github.com/jmariondev) +- [@jonhatalla](https://github.com/jonhatalla) +- [@jpiron](https://github.com/jpiron) +- [@jstoja](https://github.com/jstoja) +- [@judy](http://judy.github.io) +- [@kostyrevaa](https://github.com/kostyrevaa) +- [@KyleOndy](https://github.com/KyleOndy) +- [@lanefu](https://github.com/lanefu) +- [@Legogris](https://github.com/Legogris) +- [@Logan2211](https://github.com/Logan2211) +- [@MattBurgess](https://github.com/MattBurgess) +- [@megamorf](https://github.com/megamorf) +- [@misho-kr](https://github.com/misho-kr) +- [@MurphyMarkW](https://github.com/MurphyMarkW) +- [@oliverprater](https://github.com/oliverprater) +- [@paretl](https://github.com/paretl) +- [@patsevanton](https://github.com/patsevanton) +- [@pavel-z1](https://github.com/pavel-z1) +- [@pwae](https://github.com/perlboy) +- [@perlboy](https://github.com/pwae) +- [@RavisMsk](https://github.com/RavisMsk) +- [@replicajune](https://github.com/replicajune) +- [@Rodjers](https://github.com/Rodjers) +- [@Roviluca](https://github.com/Roviluca) +- [@Rtzq0](https://github.com/Rtzq0) +- [@schaltiemi](https://github.com/schaltiemi) +- [@Shaiou](https://github.com/Shaiou) +- [@Sispheor](https://github.com/Sispheor) +- [@slomo](https://github.com/jpiron/slomo) +- [@smutel](https://github.com/smutel) +- [@soloradish](https://github.com/soloradish) +- [@sperreault](https://github.com/sperreault) +- [@suzuki-shunsuke](https://github.com/suzuki-shunsuke) +- [@t0k4rt](https://github.com/@t0k4rt) +- [@tbartelmess](https://github.com/tbartelmess) +- [@teralype](https://github.com/teralype) +- [@TheLastChosenOne](https://github.com/TheLastChosenOne) +- [@timvaillancourt](https://github.com/timvaillancourt) +- [@vincent-legoll](https://github.com/vincent-legoll) +- [@vincepii](https://github.com/vincepii) +- [@violuke](https://github.com/violuke) +- [@viruzzo](https://github.com/viruzzo) +- [@xeivieni](https://github.com/xeivieni) +- [@ykhemani](https://github.com/ykhemani) + +If you have contributed but do not appear here, please fear not and accept +apologies for the omission. Contact `bas.meijer me com` and +please let me know! diff --git a/roles/consul/LICENSE.txt b/roles/consul/LICENSE.txt new file mode 100644 index 000000000..9e1b15a46 --- /dev/null +++ b/roles/consul/LICENSE.txt @@ -0,0 +1,10 @@ +Copyright (c) 2018, Brian Shumate +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. diff --git a/roles/consul/README.md b/roles/consul/README.md new file mode 100644 index 000000000..7583fab18 --- /dev/null +++ b/roles/consul/README.md @@ -0,0 +1,1283 @@ +# Consul + +![Molecule](https://github.com/ansible-community/ansible-consul/workflows/Molecule/badge.svg?branch=master&event=pull_request) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/ansible-community/ansible-consul.svg)](http://isitmaintained.com/project/ansible-community/ansible-consul "Average time to resolve an issue") +[![Percentage of issues still open](http://isitmaintained.com/badge/open/ansible-community/ansible-consul.svg)](http://isitmaintained.com/project/ansible-community/ansible-consul "Percentage of issues still open") + +This Ansible role installs [Consul](https://consul.io/), including establishing a filesystem structure and server or client agent configuration with support for some common operational features. + +It can also bootstrap a development or evaluation cluster of 3 server agents running in a Vagrant and VirtualBox based environment. See [README_VAGRANT.md](https://github.com/ansible-community/ansible-consul/blob/master/examples/README_VAGRANT.md) and the associated [Vagrantfile](https://github.com/ansible-community/ansible-consul/blob/master/examples/Vagrantfile) for more details. + +## Role Philosophy + +> “Another flaw in the human character is that everybody wants to build and nobody wants to do maintenance.”
+> ― Kurt Vonnegut, Hocus Pocus + +Please note that the original design goal of this role was more concerned with the initial installation and bootstrapping of a Consul server cluster environment and so it does not currently concern itself (all that much) with performing ongoing maintenance of a cluster. + +Many users have expressed that the Vagrant based environment makes getting a working local Consul server cluster environment up and running an easy process — so this role will target that experience as a primary motivator for existing. + +If you get some mileage from it in other ways, then all the better! + +## Role migration and installation +This role was originally developed by Brian Shumate and was known on Ansible Galaxy as **brianshumate.consul**. Brian asked the community to be relieved of the maintenance burden, and therefore Bas Meijer transferred the role to **ansible-community** so that a team of volunteers can maintain it. At the moment there is no membership of ansible-community on https://galaxy.ansible.com and therefore to install this role into your project you should create a file `requirements.yml` in the subdirectory `roles/` of your project with this content: + +``` +--- +- src: https://github.com/ansible-community/ansible-consul.git + name: ansible-consul + scm: git + version: master +``` + +This repo has tagged releases that you can use to pin the version. + +Tower will install the role automatically, if you use the CLI to control ansible, then install it like: + +``` +ansible-galaxy install -p roles -r roles/requirements.yml +``` + +## Requirements + +This role requires a FreeBSD, Debian, or Red Hat Enterprise Linux distribution or Windows Server 2012 R2. + +The role might work with other OS distributions and versions, but is known to function well with the following software versions: + +* Consul: 1.8.7 +* Ansible: 2.8.2 +* Alpine Linux: 3.8 +* CentOS: 7, 8 +* Debian: 9 +* FreeBSD: 11 +* Mac OS X: 10.15 (Catalina) +* RHEL: 7, 8 +* Rocky Linux: 8 +* OracleLinux: 7, 8 +* Ubuntu: 16.04 +* Windows: Server 2012 R2 + +Note that for the "local" installation mode (the default), this role will locally download only one instance of the Consul archive, unzip it and install the resulting binary on all desired Consul hosts. + +To do so requires that `unzip` is available on the Ansible control host and the role will fail if it doesn't detect `unzip` in the PATH. + +Collection requirements for this role are listed in the [`requirements.yml`](requirements.yml) file. It is your responsibility to make sure that you install these collections to ensure that the role runs properly. Usually, this can be done with: + +``` +ansible-galaxy collection install -r requirements.yml +``` + +## Caveats + +This role does not fully support the limit option (`ansible -l`) to limit the hosts, as this will break populating required host variables. If you do use the limit option with this role, you can encounter template errors like: + +``` +Undefined is not JSON serializable. +``` + +## Role Variables + +The role uses variables defined in these 3 places: + +- Hosts inventory file (see `examples/vagrant_hosts` for an example) +- `vars/*.yml` (primarily OS/distributions specific variables) +- `defaults/main.yml` (everything else) + +> :warning: **NOTE**: The role relies on the inventory host group for the consul servers to be defined as the variable `consul_group_name` and it will not function properly otherwise. Alternatively the consul servers can be placed in the default host group `[consul_instances]` in the inventory as shown in the examples below. + +Many role variables can also take their values from environment variables as well; those are noted in the description where appropriate. + +### `consul_version` + +- Version to install +- Set value as `latest` for the latest available version of consul +- Default value: 1.8.7 + +### `consul_architecture_map` + +- Dictionary for translating _ansible_architecture_ values to Go architecture values + naming convention +- Default value: dict + +### `consul_architecture` + +- System architecture as determined by `{{ consul_architecture_map[ansible_architecture] }}` +- Default value (determined at runtime): amd64, arm, or arm64 + +### `consul_os` + +- Operating system name in lowercase representation +- Default value: `{{ ansible_os_family | lower }}` + +### `consul_install_dependencies` + +- Install python and package dependencies required for the role functions. +- Default value: true + +### `consul_zip_url` + +- Consul archive file download URL +- Default value: `https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_{{ consul_os }}_{{ consul_architecture }}.zip` + +### `consul_checksum_file_url` + +- Package SHA256 summaries file URL +- Default value: `https://releases.hashicorp.com/consul/{{ consul_version }}/{{ consul_version }}_SHA256SUMS` + +### `consul_bin_path` + +- Binary installation path +- Default Linux value: `/usr/local/bin` +- Default Windows value: `C:\ProgramData\consul\bin` + +### `consul_config_path` + +- Base configuration file path +- Default Linux value: `/etc/consul` +- Default Windows value: `C:\ProgramData\consul\config` + +### `consul_configd_path` + +- Additional configuration directory +- Default Linux value: `{{ consul_config_path }}/consul.d` +- Default Windows value: `C:\ProgramData\consul\config.d` + +### `consul_data_path` + +- Data directory path as defined in [data_dir or -data-dir](https://www.consul.io/docs/agent/options.html#_data_dir) +- Default Linux value: `/opt/consul` +- Default Windows value: `C:\ProgramData\consul\data` + +### `consul_configure_syslogd` + +- Enable configuration of rsyslogd or syslog-ng on Linux. If disabled, Consul will still log to syslog if `consul_syslog_enable` is true, but the syslog daemon won't be configured to write Consul logs to their own logfile. + - Override with `CONSUL_CONFIGURE_SYSLOGD` environment variable +- Default Linux value: *false* + +### `consul_log_path` +- If `consul_syslog_enable` is false + - Log path for use in [log_file or -log-file](https://www.consul.io/docs/agent/options.html#_log_file) +- If `consul_syslog_enable` is true + - Log path for use in rsyslogd configuration on Linux. Ignored if `consul_configure_syslogd` is false. +- Default Linux value: `/var/log/consul` + - Override with `CONSUL_LOG_PATH` environment variable +- Default Windows value: `C:\ProgramData\consul\log` + +### `consul_log_file` + +- If `consul_syslog_enable` is false + - Log file for use in [log_file or -log-file](https://www.consul.io/docs/agent/options.html#_log_file) +- If `consul_syslog_enable` is true + - Log file for use in rsyslogd configuration on Linux. Ignored if `consul_configure_syslogd` is false. +- Override with `CONSUL_LOG_FILE` environment variable +- Default Linux value: `consul.log` + +### `consul_log_rotate_bytes` + +- Log rotate bytes as defined in [log_rotate_bytes or -log-rotate-bytes](https://www.consul.io/docs/agent/options.html#_log_rotate_bytes) + - Override with `CONSUL_LOG_ROTATE_BYTES` environment variable +- Ignored if `consul_syslog_enable` is true +- Default value: 0 + +### `consul_log_rotate_duration` + +- Log rotate bytes as defined in [log_rotate_duration or -log-rotate-duration](https://www.consul.io/docs/agent/options.html#_log_rotate_duration) + - Override with `CONSUL_LOG_ROTATE_DURATION` environment variable +- Ignored if `consul_syslog_enable` is true +- Default value: 24h + +### `consul_log_rotate_max_files` + +- Log rotate bytes as defined in [log_rotate_max_files or -log-rotate-max-files](https://www.consul.io/docs/agent/options.html#_log_rotate_max_files) + - Override with `CONSUL_LOG_ROTATE_MAX_FILES` environment variable +- Ignored if `consul_syslog_enable` is true +- Default value: 0 + +### `consul_syslog_facility` + +- Syslog facility as defined in [syslog_facility](https://www.consul.io/docs/agent/options.html#syslog_facility) + - Override with `CONSUL_SYSLOG_FACILITY` environment variable +- Default Linux value: local0 + +### `syslog_user` + +- Owner of `rsyslogd` process on Linux. `consul_log_path`'s ownership is set to this user on Linux. Ignored if `consul_configure_syslogd` is false. + - Override with `SYSLOG_USER` environment variable +- Default Linux value: syslog + +### `syslog_group` + +- Group of user running `rsyslogd` process on Linux. `consul_log_path`'s group ownership is set to this group on Linux. Ignored if `consul_configure_syslogd` is false. + - Override with `SYSLOG_GROUP` environment variable +- Default value: adm + +### `consul_run_path` + +- Run path for process identifier (PID) file +- Default Linux value: `/run/consul` +- Default Windows value: `C:\ProgramData\consul` + +### `consul_user` + +- OS user +- Default Linux value: consul +- Default Windows value: LocalSystem + +### `consul_manage_user` + +- Whether to create the user defined by `consul_user` or not +- Default value: true + +### `consul_group` + +- OS group +- Default value: bin + +### `consul_manage_group` + +- Whether to create the group defined by `consul_group` or not +- Default value: true + +### `consul_group_name` + +- Inventory group name + - Override with `CONSUL_GROUP_NAME` environment variable +- Default value: consul_instances + +### `consul_retry_interval` + +- Interval for reconnection attempts to LAN servers +- Default value: 30s + +### `consul_retry_interval_wan` + +- Interval for reconnection attempts to WAN servers +- Default value: 30s + +### `consul_retry_join_skip_hosts` + +- If true, the config value for retry_join won't be populated by the default hosts servers. The value can be initialized using consul_join +- Default value: false + +### `consul_retry_max` + +- Max reconnection attempts to LAN servers before failing (0 = infinite) +- Default value: 0 + +### `consul_retry_max_wan` + +- Max reconnection attempts to WAN servers before failing (0 = infinite) +- Default value: *0* + +### `consul_join` + +- List of LAN servers, not managed by this role, to join (IPv4 IPv6 or DNS addresses) +- Default value: [] + +### `consul_join_wan` + +- List of WAN servers, not managed by this role, to join (IPv4 IPv6 or DNS addresses) +- Default value: [] + +### `consul_servers` + +It's typically not necessary to manually alter this list. + +- List of server nodes +- Default value: List of all nodes in `consul_group_name` with + `consul_node_role` set to server or bootstrap + +### `consul_bootstrap_expect` + +- Boolean that adds bootstrap_expect value on Consul servers's config file +- Default value: false + +### `consul_bootstrap_expect_value` + +- Integer to define the minimum number of consul servers joined to the cluster in order to elect the leader. +- Default value: Calculated at runtime based on the number of nodes + +### `consul_gather_server_facts` + +This feature makes it possible to gather the `consul_advertise_address(_wan)` from servers that are currently not targeted by the playbook. + +To make this possible the `delegate_facts` option is used; note that his option has been problematic. + +- Gather facts from servers that are not currently targeted +- Default value: false + +### `consul_datacenter` + +- Datacenter label + - Override with `CONSUL_DATACENTER` environment variable- Default value: *dc1* +- Default value: dc1 + +### `consul_domain` + +- Consul domain name as defined in [domain or -domain](https://www.consul.io/docs/agent/options.html#_domain) + - Override with `CONSUL_DOMAIN` environment variable +- Default value: consul + +### `consul_alt_domain` + +- Consul domain name as defined in [alt_domain or -alt-domain](https://www.consul.io/docs/agent/options.html#_alt_domain) + - Override with `CONSUL_ALT_DOMAIN` environment variable +- Default value: Empty string + +### `consul_node_meta` + +- Consul node meta data (key-value) +- Supported in Consul version 0.7.3 or later +- Default value: *{}* +- Example: +```yaml +consul_node_meta: + node_type: "my-custom-type" + node_meta1: "metadata1" + node_meta2: "metadata2" +``` + +### `consul_log_level` + +- Log level as defined in [log_level or -log-level](https://www.consul.io/docs/agent/options.html#_log_level) + - Override with `CONSUL_LOG_LEVEL` environment variable +- Default value: INFO + +### `consul_syslog_enable` + +- Log to syslog as defined in [enable_syslog or -syslog](https://www.consul.io/docs/agent/options.html#_syslog) + - Override with `CONSUL_SYSLOG_ENABLE` environment variable +- Default Linux value: false +- Default Windows value: false + +### `consul_iface` + +- Consul network interface + - Override with `CONSUL_IFACE` environment variable +- Default value: `{{ ansible_default_ipv4.interface }}` + +### `consul_bind_address` + +- Bind address + - Override with `CONSUL_BIND_ADDRESS` environment variable +- Default value: default ipv4 address, or address of interface configured by + `consul_iface` + +### `consul_advertise_address` + +- LAN advertise address +- Default value: `consul_bind_address` + +### `consul_advertise_address_wan` + +- Wan advertise address +- Default value: `consul_bind_address` + +### `consul_translate_wan_address` + +- Prefer a node's configured WAN address when serving DNS +- Default value: false + +### `consul_advertise_addresses` + +- Advanced advertise addresses settings +- Individual addresses can be overwritten using the `consul_advertise_addresses_*` variables +- Default value: + ```yaml + consul_advertise_addresses: + serf_lan: "{{ consul_advertise_addresses_serf_lan | default(consul_advertise_address+':'+consul_ports.serf_lan) }}" + serf_wan: "{{ consul_advertise_addresses_serf_wan | default(consul_advertise_address_wan+':'+consul_ports.serf_wan) }}" + rpc: "{{ consul_advertise_addresses_rpc | default(consul_bind_address+':'+consul_ports.server) }}" + ``` + +### `consul_client_address` + +- Client address +- Default value: 127.0.0.1 + +### `consul_addresses` + +- Advanced address settings +- Individual addresses kan be overwritten using the `consul_addresses_*` variables +- Default value: + ```yaml + consul_addresses: + dns: "{{ consul_addresses_dns | default(consul_client_address, true) }}" + http: "{{ consul_addresses_http | default(consul_client_address, true) }}" + https: "{{ consul_addresses_https | default(consul_client_address, true) }}" + rpc: "{{ consul_addresses_rpc | default(consul_client_address, true) }}" + grpc: "{{ consul_addresses_grpc | default(consul_client_address, true) }}" + ``` + +### `consul_ports` + +- The official documentation on the [Ports Used](https://www.consul.io/docs/agent/options.html#ports) +- The ports mapping is a nested dict object that allows setting the bind ports for the following keys: + - dns - The DNS server, -1 to disable. Default 8600. + - http - The HTTP API, -1 to disable. Default 8500. + - https - The HTTPS API, -1 to disable. Default -1 (disabled). + - rpc - The CLI RPC endpoint. Default 8400. This is deprecated in Consul 0.8 and later. + - grpc - The gRPC endpoint, -1 to disable. Default -1 (disabled). + - serf_lan - The Serf LAN port. Default 8301. + - serf_wan - The Serf WAN port. Default 8302. + - server - Server RPC address. Default 8300. + +For example, to enable the consul HTTPS API it is possible to set the variable as follows: + +- Default values: +```yaml + consul_ports: + dns: "{{ consul_ports_dns | default('8600', true) }}" + http: "{{ consul_ports_http | default('8500', true) }}" + https: "{{ consul_ports_https | default('-1', true) }}" + rpc: "{{ consul_ports_rpc | default('8400', true) }}" + serf_lan: "{{ consul_ports_serf_lan | default('8301', true) }}" + serf_wan: "{{ consul_ports_serf_wan | default('8302', true) }}" + server: "{{ consul_ports_server | default('8300', true) }}" + grpc: "{{ consul_ports_grpc | default('-1', true) }}" +``` + +Notice that the dict object has to use precisely the names stated in the documentation! And all ports must be specified. Overwriting one or multiple ports can be done using the `consul_ports_*` variables. + +### `consul_node_name` + +- Define a custom node name (should not include dots) + See [node_name](https://www.consul.io/docs/agent/options.html#node_name) + - The default value on Consul is the hostname of the server. +- Default value: '' + +### `consul_recursors` + +- List of upstream DNS servers + See [recursors](https://www.consul.io/docs/agent/options.html#recursors) + - Override with `CONSUL_RECURSORS` environment variable +- Default value: Empty list + +### `consul_iptables_enable` + +- Whether to enable iptables rules for DNS forwarding to Consul + - Override with `CONSUL_IPTABLES_ENABLE` environment variable +- Default value: false + +### `consul_acl_policy` + +- Add basic ACL config file + - Override with `CONSUL_ACL_POLICY` environment variable +- Default value: false + +### `consul_acl_enable` + +- Enable ACLs + - Override with `CONSUL_ACL_ENABLE` environment variable +- Default value: false + +### `consul_acl_ttl` + +- TTL for ACL's + - Override with `CONSUL_ACL_TTL` environment variable +- Default value: 30s + +### `consul_acl_token_persistence` + +- Define if tokens set using the API will be persisted to disk or not + - Override with `CONSUL_ACL_TOKEN_PERSISTENCE` environment variable +- Default value: true + +### `consul_acl_datacenter` + +- ACL authoritative datacenter name + - Override with `CONSUL_ACL_DATACENTER` environment variable +- Default value: `{{ consul_datacenter }}` (`dc1`) + +### `consul_acl_down_policy` + +- Default ACL down policy + - Override with `CONSUL_ACL_DOWN_POLICY` environment variable +- Default value: allow + +### `consul_acl_token` + +- Default ACL token, only set if provided + - Override with `CONSUL_ACL_TOKEN` environment variable +- Default value: '' + +### `consul_acl_agent_token` + +- Used for clients and servers to perform internal operations to the service catalog. See: [acl_agent_token](https://www.consul.io/docs/agent/options.html#acl_agent_token) + - Override with `CONSUL_ACL_AGENT_TOKEN` environment variable +- Default value: '' + +### `consul_acl_agent_master_token` + +- A [special access token](https://www.consul.io/docs/agent/options.html#acl_agent_master_token) that has agent ACL policy write privileges on each agent where it is configured + - Override with `CONSUL_ACL_AGENT_MASTER_TOKEN` environment variable +- Default value: '' + +### `consul_acl_default_policy` + +- Default ACL policy + - Override with `CONSUL_ACL_DEFAULT_POLICY` environment variable +- Default value: allow + +### `consul_acl_master_token` + +- ACL master token + - Override with `CONSUL_ACL_MASTER_TOKEN` environment variable +- Default value: UUID + +### `consul_acl_master_token_display` + +- Display generated ACL Master Token + - Override with `CONSUL_ACL_MASTER_TOKEN_DISPLAY` environment variable +- Default value: false + +### `consul_acl_replication_enable` + +- Enable ACL replication without token (makes it possible to set the token + trough the API) + - Override with `CONSUL_ACL_REPLICATION_TOKEN_ENABLE` environment variable +- Default value: '' + +### `consul_acl_replication_token` + +- ACL replication token + - Override with `CONSUL_ACL_REPLICATION_TOKEN_DISPLAY` environment variable +- Default value: *SN4K3OILSN4K3OILSN4K3OILSN4K3OIL* + +### `consul_tls_enable` + +- Enable TLS + - Override with `CONSUL_ACL_TLS_ENABLE` environment variable +- Default value: false + +### `consul_tls_copy_keys` + +- Enables or disables the management of the TLS files + - Disable it if you enable TLS (`consul_tls_enable`) but want to manage the + TLS files on your own +- Default value: true + +### `consul_tls_dir` + +- Target directory for TLS files + - Override with `CONSUL_TLS_DIR` environment variable +- Default value: `/etc/consul/ssl` + +### `consul_tls_ca_crt` + +- CA certificate filename + - Override with `CONSUL_TLS_CA_CRT` environment variable +- Default value: `ca.crt` + +### `consul_tls_server_crt` + +- Server certificate + - Override with `CONSUL_TLS_SERVER_CRT` environment variable +- Default value: `server.crt` + +### `consul_tls_server_key` + +- Server key + - Override with `CONSUL_TLS_SERVER_KEY` environment variable +- Default value: `server.key` + +### `consul_tls_files_remote_src` + +- Copy from remote source if TLS files are already on host +- Default value: false + +### `consul_encrypt_enable` + +- Enable Gossip Encryption +- Default value: true + +### `consul_encrypt_verify_incoming` + +- Verify incoming Gossip connections +- Default value: true + +### `consul_encrypt_verify_outgoing` + +- Verify outgoing Gossip connections +- Default value: true + +### `consul_disable_keyring_file` + +- If set, the keyring will not be persisted to a file. Any installed keys will be lost on shutdown, and only the given -encrypt key will be available on startup. +- Default value: false + +### `consul_raw_key` + +- Set the encryption key; should be the same across a cluster. If not present the key will be generated & retrieved from the bootstrapped server. +- Default value: '' + +### `consul_tls_verify_incoming` + +- Verify incoming connections + - Override with `CONSUL_TLS_VERIFY_INCOMING` environment variable +- Default value: false + +### `consul_tls_verify_outgoing` + +- Verify outgoing connections + - Override with `CONSUL_TLS_VERIFY_OUTGOING` environment variable +- Default value: true + +### `consul_tls_verify_incoming_rpc` +- Verify incoming connections on RPC endpoints (client certificates) + - Override with `CONSUL_TLS_VERIFY_INCOMING_RPC` environment variable +- Default value: false + +### `consul_tls_verify_incoming_https` +- Verify incoming connections on HTTPS endpoints (client certificates) + - Override with `CONSUL_TLS_VERIFY_INCOMING_HTTPS` environment variable +- Default value: false + +### `consul_tls_verify_server_hostname` + +- Verify server hostname + - Override with `CONSUL_TLS_VERIFY_SERVER_HOSTNAME` environment variable +- Default value: false + +### `consul_tls_min_version` + +- [Minimum acceptable TLS version](https://www.consul.io/docs/agent/options.html#tls_min_version) + - Can be overridden with `CONSUL_TLS_MIN_VERSION` environment variable +- Default value: tls12 + +### `consul_tls_cipher_suites` + +- [Comma-separated list of supported ciphersuites](https://www.consul.io/docs/agent/options.html#tls_cipher_suites) +- Default value: "" + +### `consul_tls_prefer_server_cipher_suites` + +- [Prefer server's cipher suite over client cipher suite](https://www.consul.io/docs/agent/options.html#tls_prefer_server_cipher_suites) + - Can be overridden with `CONSUL_TLS_PREFER_SERVER_CIPHER_SUITES` environment variable +- Default value: false + +### `auto_encrypt` +- [Auto encrypt](https://www.consul.io/docs/agent/options#auto_encrypt) +- Default value: +```yaml +auto_encrypt: + enabled: false +``` +- Example: + +```yaml +auto_encrypt: + enabled: true + dns_san: ["consul.com"] + ip_san: ["127.0.0.1"] +``` + +### `consul_force_install` + +- If true, then always install consul. Otherwise, consul will only be installed either if + not present on the host, or if the installed version differs from `consul_version`. +- The role does not handle the orchestration of a rolling update of servers followed by client nodes +- Default value: false + +### `consul_install_remotely` + +- Whether to download the files for installation directly on the remote hosts +- This is the only option on Windows as WinRM is somewhat limited in this scope +- Default value: false + +### `consul_install_from_repo` + +- Boolean, whether to install consul from repository as opposed to installing the binary directly. +- Supported distros: Amazon Linux, CentOS, Debian, Fedora, Ubuntu, Red Hat, Rocky. +- Default value: false + +### `consul_ui` + +- Enable the consul ui? +- Default value: true + +### `consul_ui_legacy` + +- Enable legacy consul ui mode +- Default value: false + +### `consul_disable_update_check` + +- Disable the consul update check? +- Default value: false + +### `consul_enable_script_checks` + +- Enable script based checks? +- Default value: false +- This is discouraged in favor of `consul_enable_local_script_checks`. + +### `consul_enable_local_script_checks` + +- Enable locally defined script checks? +- Default value: false + +### `consul_raft_protocol` + +- Raft protocol to use. +- Default value: + - Consul versions <= 0.7.0: 1 + - Consul versions > 0.7.0: 3 + +### `consul_node_role` + +- The Consul role of the node, one of: *bootstrap*, *server*, or *client* +- Default value: client + +One server should be designated as the bootstrap server, and the other +servers will connect to this server. You can also specify *client* as the +role, and Consul will be configured as a client agent instead of a server. + +There are two methods to setup a cluster, the first one is to explicitly choose the bootstrap server, the other one is to let the servers elect a leader among +themselves. + +Here is an example of how the hosts inventory could be defined for a simple +cluster of 3 servers, the first one being the designated bootstrap / leader: + +```yaml +[consul_instances] +consul1.consul consul_node_role=bootstrap +consul2.consul consul_node_role=server +consul3.consul consul_node_role=server +consul4.local consul_node_role=client +``` + +Or you can use the simpler method of letting them do their election process: + +```yaml +[consul_instances] +consul1.consul consul_node_role=server consul_bootstrap_expect=true +consul2.consul consul_node_role=server consul_bootstrap_expect=true +consul3.consul consul_node_role=server consul_bootstrap_expect=true +consul4.local consul_node_role=client +``` + +> Note that this second form is the preferred one, because it is simpler. + +### `consul_autopilot_enable` + +Autopilot is a set of new features added in Consul 0.8 to allow for automatic operator-friendly management of Consul servers. It includes cleanup of dead servers, monitoring the state of the Raft cluster, and stable server introduction. + +https://www.consul.io/docs/guides/autopilot.html + +- Enable Autopilot config (will be written to bootsrapper node) + - Override with `CONSUL_AUTOPILOT_ENABLE` environment variable +- Default value: false + +#### `consul_autopilot_cleanup_dead_Servers` + +Dead servers will periodically be cleaned up and removed from the Raft peer set, to prevent them from interfering with the quorum size and leader elections. This cleanup will also happen whenever a new server is successfully added to the cluster. + +- Enable Autopilot config (will be written to bootsrapper node) + - Override with `CONSUL_AUTOPILOT_CLEANUP_DEAD_SERVERS` environment variable +- Default value: false + +#### `consul_autopilot_last_contact_threshold` + +Used in the serf health check to determine node health. + +- Sets the threshold for time since last contact + - Override with `CONSUL_AUTOPILOT_LAST_CONTACT_THRESHOLD` environment variable +- Default value: 200ms + +#### `consul_autopilot_max_trailing_logs` + +- Used in the serf health check to set a max-number of log entries nodes can trail the leader + - Override with `CONSUL_AUTOPILOT_MAX_TRAILING_LOGS` environment variable +- Default value: 250 + + +#### `consul_autopilot_server_stabilization_time` + +- Time to allow a new node to stabilize + - Override with `CONSUL_AUTOPILOT_SERVER_STABILIZATION_TIME` environment variable +- Default value: 10s + +#### `consul_autopilot_redundancy_zone_tag` + +_Consul Enterprise Only (requires that CONSUL_ENTERPRISE is set to true)_ + +- Override with `CONSUL_AUTOPILOT_REDUNDANCY_ZONE_TAG` environment variable +- Default value: az + +#### `consul_autopilot_disable_upgrade_migration` + +_Consul Enterprise Only (requires that CONSUL_ENTERPRISE is set to true)_ + +- Override with `CONSUL_AUTOPILOT_DISABLE_UPGRADE_MIGRATION` environment variable +- Default value: *false* + +#### `consul_autopilot_upgrade_version_tag` + +_Consul Enterprise Only (requires that CONSUL_ENTERPRISE is set to true)_ + +- Override with `CONSUL_AUTOPILOT_UPGRADE_VERSION_TAG` environment variable +- Default value: '' + +### `consul_debug` + +- Enables the generation of additional config files in the Consul config + directory for debug purpose +- Default value: false + +### `consul_config_template_path` + + - If the default config template does not suit your needs, you can replace it with your own. + - Default value: `templates/config.json.j2`. + +#### Custom Configuration Section + +As Consul loads the configuration from files and directories in lexical order, typically merging on top of previously parsed configuration files, you may set custom configurations via `consul_config_custom`, which will be expanded into a file named `config_z_custom.json` within your `consul_config_path` which will be loaded after all other configuration by default. + +An example usage for enabling `telemetry`: + +```yaml + vars: + consul_config_custom: + telemetry: + dogstatsd_addr: "localhost:8125" + dogstatsd_tags: + - "security" + - "compliance" + disable_hostname: true +``` + +## Consul Snapshot Agent + +_Consul snapshot agent takes backup snaps on a set interval and stores them. Must have enterprise_ + +### `consul_snapshot` + +- Bool, true will setup and start snapshot agent (enterprise only) +- Default value: false + +### `consul_snapshot_storage` + +- Location snapshots will be stored. NOTE: path must end in snaps +- Default value: `{{ consul_config_path }}/snaps` + +### `consul_snapshot_interval` + +- Default value: 1h + +### `consul_snapshot_retain` + +## OS and Distribution Variables + +The `consul` binary works on most Linux platforms and is not distribution +specific. However, some distributions require installation of specific OS +packages with different package names. + +### `consul_centos_pkg` + +- Consul package filename +- Default value: `{{ consul_version }}_linux_amd64.zip` + +### `consul_centos_url` + +- Consul package download URL +- Default value: `{{ consul_zip_url }}` + +### `consul_centos_sha256` + +- Consul download SHA256 summary +- Default value: SHA256 summary + +### `consul_centos_os_packages` + +- List of OS packages to install +- Default value: list + +### `consul_debian_pkg` + +- Consul package filename +- Default value: `{{ consul_version }}_linux_amd64.zip` + +### `consul_debian_url` + +- Consul package download URL +- Default value: `{{ consul_zip_url }}` + +### `consul_debian_sha256` + +- Consul download SHA256 summary +- Default value: SHA256 SUM + +### `consul_debian_os_packages` + +- List of OS packages to install +- Default value: list + +### `consul_redhat_pkg` + +- Consul package filename +- Default value: `{{ consul_version }}_linux_amd64.zip` + +### `consul_redhat_url` + +- Consul package download URL +- Default value: `{{ consul_zip_url }}` + +### `consul_redhat_sha256` + +- Consul download SHA256 summary +- Default value: SHA256 summary + +### `consul_redhat_os_packages` + +- List of OS packages to install +- Default value: list + +### consul_systemd_restart_sec + +- Integer value for systemd unit `RestartSec` option +- Default value: 42 + +### consul_systemd_limit_nofile + +- Integer value for systemd unit `LimitNOFILE` option +- Default value: 65536 + +### consul_systemd_restart + +- String value for systemd unit `Restart` option +- Default value: `on-failure` + +### `consul_ubuntu_pkg` + +- Consul package filename +- Default value: `{{ consul_version }}_linux_amd64.zip` + +### `consul_ubuntu_url` + +- Consul package download URL +- Default value: `{{ consul_zip_url }}` + +### `consul_ubuntu_sha256` + +- Consul download SHA256 summary +- Default value: SHA256 summary + +### `consul_ubuntu_os_packages` + +- List of OS packages to install +- Default value: list + +### `consul_windows_pkg` + +- Consul package filename +- Default value: `{{ consul_version }}_windows_amd64.zip` + +### `consul_windows_url` + +- Consul package download URL +- Default value: `{{ consul_zip_url }}` + +### `consul_windows_sha256` + +- Consul download SHA256 summary +- Default value: SHA256 summary + +### `consul_windows_os_packages` + +- List of OS packages to install +- Default value: list + +### `consul_performance` + +- List of Consul performance tuning items +- Default value: list + +#### `raft_multiplier` + +- [Raft multiplier](https://www.consul.io/docs/agent/options.html#raft_multiplier) scales key Raft timing parameters +- Default value: 1 + +#### `leave_drain_time` + +- [Node leave drain time](https://www.consul.io/docs/agent/options.html#leave_drain_time) is the dwell time for a server to honor requests while gracefully leaving + +- Default value: 5s + +#### `rpc_hold_timeout` + +- [RPC hold timeout](https://www.consul.io/docs/agent/options.html#rpc_hold_timeout) is the duration that a client or server will retry internal RPC requests during leader elections +- Default value: 7s + +#### `leave_on_terminate` +- [leave_on_terminate](https://www.consul.io/docs/agent/options.html#leave_on_terminate) If enabled, when the agent receives a TERM signal, it will send a Leave message to the rest of the cluster and gracefully leave. The default behavior for this feature varies based on whether or not the agent is running as a client or a server. On agents in client-mode, this defaults to true and for agents in server-mode, this defaults to false. + +### `consul_limit` + +- Consul node limits (key-value) +- Supported in Consul version 0.9.3 or later +- Default value: *{}* +- Example: +```yaml +consul_limits: + http_max_conns_per_client: 250 + rpc_max_conns_per_client: 150 +``` + +## Dependencies + +Ansible requires GNU tar and this role performs some local use of the unarchive module for efficiency, so ensure that your system has `gtar` and `unzip` installed and in the PATH. If you don't this role will install `unzip` on the remote machines to unarchive the ZIP files. + +If you're on system with a different (i.e. BSD) `tar`, like macOS and you see odd errors during unarchive tasks, you could be missing `gtar`. + +Installing Ansible on Windows requires the PowerShell Community Extensions. These already installed on Windows Server 2012 R2 and onward. If you're attempting this role on Windows Server 2008 or earlier, you'll want to install the extensions [here](https://pscx.codeplex.com/). + +## Example Playbook + +Basic installation is possible using the included `site.yml` playbook: + +``` +ansible-playbook -i hosts site.yml +``` + +You can also pass variables in using the `--extra-vars` option to the +`ansible-playbook` command: + +``` +ansible-playbook -i hosts site.yml --extra-vars "consul_datacenter=maui" +``` + +Be aware that for clustering, the included `site.yml` does the following: + +1. Executes consul role (installs Consul and bootstraps cluster) +2. Reconfigures bootstrap node to run without bootstrap-expect setting +3. Restarts bootstrap node + +### ACL Support + +Basic support for ACLs is included in the role. You can set the environment variables `CONSUL_ACL_ENABLE` to true, and also set the `CONSUL_ACL_DATACENTER` environment variable to its correct value for your environment prior to executing your playbook; for example: + +``` +CONSUL_ACL_ENABLE=true CONSUL_ACL_DATACENTER=maui \ +CONSUL_ACL_MASTER_TOKEN_DISPLAY=true ansible-playbook -i uat_hosts aloha.yml +``` + +If you want the automatically generated ACL Master Token value emitted to standard out during the play, set the environment variable `CONSUL_ACL_MASTER_TOKEN_DISPLAY` to true as in the above example. + +If you want to use existing tokens, set the environment variables `CONSUL_ACL_MASTER_TOKEN` and `CONSUL_ACL_REPLICATION_TOKEN` as well, for example: + +``` +CONSUL_ACL_ENABLE=true CONSUL_ACL_DATACENTER=stjohn \ +CONSUL_ACL_MASTER_TOKEN=0815C55B-3AD2-4C1B-BE9B-715CAAE3A4B2 \ +CONSUL_ACL_REPLICATION_TOKEN=C609E56E-DD0B-4B99-A0AD-B079252354A0 \ +CONSUL_ACL_MASTER_TOKEN_DISPLAY=true ansible-playbook -i uat_hosts sail.yml +``` + +There are a number of Ansible ACL variables you can override to further refine your initial ACL setup. They are not all currently picked up from environment variables, but do have some sensible defaults. + +Check `defaults/main.yml` to see how some of he defaults (i.e. tokens) are automatically generated. + +### Dnsmasq DNS Forwarding Support + +The role now includes support for [DNS forwarding](https://www.consul.io/docs/guides/forwarding.html) with [Dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html). + +Enable like this: + +``` +ansible-playbook -i hosts site.yml --extra-vars "consul_dnsmasq_enable=true" +``` + +Then, you can query any of the agents via DNS directly via port 53, +for example: + +``` +dig @consul1.consul consul3.node.consul + +; <<>> DiG 9.8.3-P1 <<>> @consul1.consul consul3.node.consul +; (1 server found) +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29196 +;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 + +;; QUESTION SECTION: +;consul3.node.consul. IN A + +;; ANSWER SECTION: +consul3.node.consul. 0 IN A 10.1.42.230 + +;; Query time: 42 msec +;; SERVER: 10.1.42.210#53(10.1.42.210) +;; WHEN: Sun Aug 7 18:06:32 2016 +;; +``` + +### `consul_delegate_datacenter_dns` +- Whether to delegate Consul datacenter DNS domain to Consul +- Default value: false + +### `consul_dnsmasq_enable` + +- Whether to install and configure DNS API forwarding on port 53 using DNSMasq + - Override with `CONSUL_DNSMASQ_ENABLE` environment variable +- Default value: false + +### `consul_dnsmasq_bind_interfaces` + +- Setting this option to _true_ prevents DNSmasq from binding by default 0.0.0.0, but instead instructs it to bind to the specific network interfaces that correspond to the `consul_dnsmasq_listen_addresses` option +- Default value: false + +### `consul_dnsmasq_consul_address` + +- Address used by DNSmasq to query consul +- Default value: `consul_address.dns` +- Defaults to 127.0.0.1 if consul's DNS is bound to all interfaces (eg `0.0.0.0`) + +### `consul_dnsmasq_cache` + +- dnsmasq cache-size +- If smaller then 0, the default dnsmasq setting will be used. +- Default value: *-1* + +### `consul_dnsmasq_servers` + +- Upstream DNS servers used by dnsmasq +- Default value: *8.8.8.8* and *8.8.4.4* + +### `consul_dnsmasq_revservers` + +- Reverse lookup subnets +- Default value: *[]* + +### `consul_dnsmasq_no_poll` + +- Do not poll /etc/resolv.conf +- Default value: false + +### `consul_dnsmasq_no_resolv` + +- Ignore /etc/resolv.conf file +- Default value: false + +### `consul_dnsmasq_local_service` + +- Only allow requests from local subnets +- Default value: false + +### `consul_dnsmasq_listen_addresses` + +- Custom list of addresses to listen on. +- Default value: *[]* + +### `consul_connect_enabled` + +- Enable Consul Connect feature +- Default value: false + +### `consul_cleanup_ignore_files` + +- List of files to ignore during cleanup steps +- Default value: *[{{ consul_configd_path }}/consul.env]* + +### iptables DNS Forwarding Support + +This role can also use iptables instead of Dnsmasq for forwarding DNS queries to Consul. You can enable it like this: + +``` +ansible-playbook -i hosts site.yml --extra-vars "consul_iptables_enable=true" +``` + +> Note that iptables forwarding and DNSmasq forwarding cannot be used +> simultaneously and the execution of the role will stop with error if such +> a configuration is specified. + +### TLS Support + +You can enable TLS encryption by dropping a CA certificate, server certificate, and server key into the role's `files` directory. + +By default these are named: + +- `ca.crt` (can be overridden by {{ consul_tls_ca_crt }}) +- `server.crt` (can be overridden by {{ consul_tls_server_crt }}) +- `server.key` (can be overridden by {{ consul_tls_server_key }}) + +Then either set the environment variable `CONSUL_TLS_ENABLE=true` or use the Ansible variable `consul_tls_enable=true` at role runtime. + +### Service management Support + +You can create a configuration file for [consul services](https://www.consul.io/docs/agent/services.html). +Add a list of service in the `consul_services`. + +| name | Required | Type | Default | Comment | +| --------------- | -------- | ---- | ------- | ---------------------------------- | +| consul_services | False | List | `[]` | List of service object (see below) | + +Services object: + +| name | Required | Type | Default | Comment | +| ------------------- | -------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------- | +| name | True | string | | Name of the service | +| id | False | string | | Id of the service | +| tags | False | list | | List of string tags | +| address | False | string | | service-specific IP address | +| meta | False | dict | | Dict of 64 key/values with string semantics | +| port | False | int | | Port of the service | +| enable_tag_override | False | bool | | enable/disable the anti-entropy feature for the service | +| kind | False | string | | identify the service as a Connect proxy instance | +| proxy | False | dict | | [proxy configuration](https://www.consul.io/docs/connect/proxies.html#complete-configuration-example) | +| checks | False | list | | List of [checks configuration](https://www.consul.io/docs/agent/checks.html) | +| connect | False | dict | | [Connect object configuration](https://www.consul.io/docs/connect/index.html) | +| weights | False | dict | | [Weight of a service in DNS SRV responses](https://www.consul.io/docs/agent/services.html#dns-srv-weights) | +| token | False | string | | ACL token to use to register this service | + + +Configuration example: +```yaml +consul_services: + - name: "openshift" + tags: ['production'] + - name: "redis" + id: "redis" + tags: ['primary'] + address: "" + meta: + meta: "for my service" + proxy: + destination_service_name: "redis" + destination_service_id: "redis1" + local_service_address: "127.0.0.1" + local_service_port: 9090 + config: {} + upstreams: [] + checks: + - args: ["/home/consul/check.sh"] + interval: "10s" +``` + +Then you can check that the service is well added to the catalog +``` +> consul catalog services +consul +openshift +redis +``` + +>**Note:** to delete a service that has been added from this role, remove it from the `consul_services` list and apply the role again. + +### Vagrant and VirtualBox + +See [examples/README_VAGRANT.md](https://github.com/ansible-community/ansible-consul/blob/master/examples/README_VAGRANT.md) for details on quick Vagrant deployments under VirtualBox for development, evaluation, testing, etc. + +## License + +BSD + +## Author Information + +[Brian Shumate](http://brianshumate.com) + +## Contributors + +Special thanks to the folks listed in [CONTRIBUTORS.md](https://github.com/ansible-community/ansible-consul/blob/master/CONTRIBUTORS.md) for their contributions to this project. + +Contributions are welcome, provided that you can agree to the terms outlined in [CONTRIBUTING.md](https://github.com/ansible-community/ansible-consul/blob/master/CONTRIBUTING.md). diff --git a/roles/consul/defaults/main.yml b/roles/consul/defaults/main.yml new file mode 100644 index 000000000..44061611f --- /dev/null +++ b/roles/consul/defaults/main.yml @@ -0,0 +1,268 @@ +--- +# yamllint disable rule:braces +# File: main.yml - Default variables for Consul + +## Core +consul_debug: false +is_virtualenv: "{{ lookup('env','VIRTUAL_ENV') | default('', true) }}" +consul_install_dependencies: true + +### Package +consul_version: "{{ lookup('env','CONSUL_VERSION') | default('1.8.7', true) }}" +consul_architecture_map: + # this first entry seems redundant + # (but it's required for reasons) + amd64: amd64 + x86_64: amd64 + # todo: arm32 / armelv5 + armv6l: armhfv6 + armv7l: armhfv6 + aarch64: arm64 + # Used by Apple Silicon Macs + arm64: arm64 + 32-bit: "386" + 64-bit: amd64 +consul_architecture: "{{ consul_architecture_map[ansible_architecture] }}" +consul_os: "\ + {% if ansible_os_family == 'Windows' %}\ + {{ 'windows' }}\ + {% else %}\ + {{ ansible_system | lower }}\ + {% endif %}" +consul_pkg: "consul{% if consul_enterprise %}-enterprise{% else %}{%endif%}_{{ consul_version }}_{{ consul_os }}_{{ consul_architecture }}.zip" +consul_zip_url: "https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_{{ consul_os }}_{{ consul_architecture }}.zip" +consul_checksum_file_url: "https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version}}_SHA256SUMS" + +### Install Method +consul_force_install: false +consul_install_remotely: false +consul_install_from_repo: false + +### Paths +consul_bin_path: "/usr/local/bin" +consul_config_path: "/etc/consul" +consul_config_template_path: "templates/config.json.j2" +consul_configd_path: "/etc/consul.d" +consul_bootstrap_state: "{{ consul_config_path }}/.consul_bootstrapped" +consul_data_path: "/opt/consul" +consul_log_path: "{{ lookup('env','CONSUL_LOG_PATH') | default('/var/log/consul', true) }}" +consul_log_file: "{{ lookup('env','CONSUL_LOG_FILE') | default('consul.log', true) }}" +consul_run_path: "/run/consul" +consul_binary: "{{ consul_bin_path }}/consul" + +### System user and group +consul_manage_user: true +consul_user: "consul" +consul_manage_group: true +consul_group: "consul" +consul_systemd_restart: "on-failure" +consul_systemd_restart_sec: 42 +consul_systemd_limit_nofile: 65536 +consul_systemd_unit_path: "/lib/systemd/system" + +### Log user, group, facility +syslog_user: "{{ lookup('env','SYSLOG_USER') | default('root', true) }}" +syslog_group: "{{ lookup('env','SYSLOG_GROUP') | default('adm', true) }}" +consul_log_level: "{{ lookup('env','CONSUL_LOG_LEVEL') | default('INFO', true) }}" +consul_log_rotate_bytes: "{{ lookup('env','CONSUL_LOG_ROTATE_BYTES') | default(0, true) }}" +consul_log_rotate_duration: "{{ lookup('env','CONSUL_LOG_ROTATE_DURATION') | default('24h', true) }}" +consul_log_rotate_max_files: "{{ lookup('env','CONSUL_LOG_ROTATE_MAX_FILES') | default(0, true) }}" +consul_syslog_enable: "{{ lookup('env','CONSUL_SYSLOG_ENABLE') | default(false, true) }}" +consul_syslog_facility: "{{ lookup('env','CONSUL_SYSLOG_FACILITY') | default('local0', true) }}" +consul_configure_syslogd: "{{ lookup('env','CONSUL_CONFIGURE_SYSLOGD') | default(false, true) }}" + +### Consul settings +consul_datacenter: "{{ lookup('env','CONSUL_DATACENTER') | default('dc1', true) }}" +consul_domain: "{{ lookup('env','CONSUL_DOMAIN') | default('consul', true) }}" +consul_alt_domain: "{{ lookup('env','CONSUL_ALT_DOMAIN') | default('', true) }}" +consul_node_meta: {} +consul_iface: "\ + {% if ansible_os_family == 'Windows' %}\ + {{ lookup('env','CONSUL_IFACE') | default(ansible_interfaces[0].interface_name, true) }}\ + {% else %}\ + {{ lookup('env','CONSUL_IFACE') | default(ansible_default_ipv4.interface, true) }}\ + {% endif %}" +consul_node_role: "{{ lookup('env','CONSUL_NODE_ROLE') | default('client', true) }}" +consul_recursors: "{{ lookup('env','CONSUL_RECURSORS') | default('[]', true) }}" +consul_bootstrap_expect: "{{ lookup('env','CONSUL_BOOTSTRAP_EXPECT') | default(false, true) }}" +consul_bootstrap_expect_value: "{{ _consul_lan_servercount | int }}" +consul_ui: "{{ lookup('env', 'CONSUL_UI') | default(true, true) }}" +consul_ui_legacy: "{{ lookup('env', 'CONSUL_UI_LEGACY') | default(false, false) }}" +consul_disable_update_check: false +consul_enable_script_checks: false +consul_enable_local_script_checks: false +consul_raft_protocol: "\ + {% if consul_version is version_compare('0.7.0', '<=') %}\ + 1\ + {% else %}\ + 3\ + {% endif %}" +consul_retry_join_skip_hosts: false +consul_retry_interval: "30s" +consul_retry_interval_wan: "30s" +consul_retry_max: 0 +consul_retry_max_wan: 0 +consul_env_vars: + - "CONSUL_UI_BETA=false" + +### Autopilot +consul_autopilot_enable: "{{ lookup('env', 'CONSUL_AUTOPILOT_ENABLE') | default(false, true) }}" +consul_autopilot_cleanup_dead_Servers: "{{ lookup('env', 'CONSUL_AUTOPILOT_CLEANUP_DEAD_SERVERS') | default(false, true) }}" +consul_autopilot_last_contact_threshold: "{{ lookup('env', 'CONSUL_AUTOPILOT_LAST_CONTACT_THRESHOLD') | default('200ms', true) }}" +consul_autopilot_max_trailing_logs: "{{ lookup('env', 'CONSUL_AUTOPILOT_MAX_TRAILING_LOGS') | default(250, true) }}" +consul_autopilot_server_stabilization_time: "{{ lookup('env', 'CONSUL_AUTOPILOT_SERVER_STABILIZATION_TIME') | default('10s', true) }}" +consul_autopilot_redundancy_zone_tag: "{{ lookup('env', 'CONSUL_AUTOPILOT_REDUNDANCY_ZONE_TAG') | default('az', true) }}" +consul_autopilot_disable_upgrade_migration: "{{ lookup('env', 'CONSUL_AUTOPILOT_DISABLE_UPGRADE_MIGRATION') | default(false, true) }}" +consul_autopilot_upgrade_version_tag: "{{ lookup('env', 'CONSUL_AUTOPILOT_UPGRADE_VERSION_TAG') | default('', true) }}" + +### Cloud auto discovery settings +consul_cloud_autodiscovery: false +consul_cloud_autodiscovery_provider: "" +consul_cloud_autodiscovery_params: "" +consul_cloud_autodiscovery_string: "provider={{ consul_cloud_autodiscovery_provider }} {{ consul_cloud_autodiscovery_params }}" + +### Addresses +consul_bind_address: "\ + {% if ansible_system == 'FreeBSD' or ansible_system == 'Darwin' %}\ + {{ lookup('env','CONSUL_BIND_ADDRESS') | default(hostvars[inventory_hostname]['ansible_'+ consul_iface ]['ipv4'][0]['address'], true) }}\ + {% elif ansible_os_family == 'Windows' %}\ + {{ lookup('env','CONSUL_BIND_ADDRESS') | default(hostvars[inventory_hostname]['ansible_ip_addresses'][0], true) }}\ + {% else %}\ + {{ lookup('env','CONSUL_BIND_ADDRESS') | default(hostvars[inventory_hostname]['ansible_'+ consul_iface | replace('-', '_')]['ipv4']['address'], true) }}\ + {% endif %}" +consul_advertise_address: "{{ consul_bind_address }}" +consul_advertise_address_wan: "{{ consul_bind_address }}" +consul_translate_wan_address: false +consul_advertise_addresses: + serf_lan: "{{ consul_advertise_addresses_serf_lan | default(consul_advertise_address+':'+consul_ports.serf_lan) }}" + serf_wan: "{{ consul_advertise_addresses_serf_wan | default(consul_advertise_address_wan+':'+consul_ports.serf_wan) }}" + rpc: "{{ consul_advertise_addresses_rpc | default(consul_bind_address+':'+consul_ports.server) }}" +consul_client_address: '127.0.0.1' +consul_addresses: + dns: "{{ consul_addresses_dns | default(consul_client_address, true) }}" + http: "{{ consul_addresses_http | default(consul_client_address, true) }}" + https: "{{ consul_addresses_https | default(consul_client_address, true) }}" + rpc: "{{ consul_addresses_rpc | default(consul_client_address, true) }}" + grpc: "{{ consul_addresses_grpc | default(consul_client_address, true) }}" + +### Ports +consul_ports: + dns: "{{ consul_ports_dns | default('8600', true) }}" + http: "{{ consul_ports_http | default('8500', true) }}" + https: "{{ consul_ports_https | default('-1', true) }}" + rpc: "{{ consul_ports_rpc | default('8400', true) }}" + serf_lan: "{{ consul_ports_serf_lan | default('8301', true) }}" + serf_wan: "{{ consul_ports_serf_wan | default('8302', true) }}" + server: "{{ consul_ports_server | default('8300', true) }}" + grpc: "{{ consul_ports_grpc | default('-1', true) }}" + +### Servers +consul_group_name: "{{ lookup('env','CONSUL_GROUP_NAME') | default('consul_instances', true) }}" +consul_join: [] +consul_join_wan: [] +consul_servers: "\ + {% set _consul_servers = [] %}\ + {% for host in groups[consul_group_name] %}\ + {% set _consul_node_role = hostvars[host]['consul_node_role'] | default('client', true) %}\ + {% if ( _consul_node_role == 'server' or _consul_node_role == 'bootstrap') %}\ + {% if _consul_servers.append(host) %}{% endif %}\ + {% endif %}\ + {% endfor %}\ + {{ _consul_servers }}" +consul_gather_server_facts: false + +## ACL +consul_acl_policy: "{{ lookup('env','CONSUL_ACL_POLICY') | default(false, true) }}" + +### Shared ACL config ### +consul_acl_enable: "{{ lookup('env','CONSUL_ACL_ENABLE') | default(false, true) }}" +consul_acl_ttl: "{{ lookup('env','CONSUL_ACL_TTL') | default('30s', true)}}" +consul_acl_token_persistence: "{{ lookup('env','CONSUL_ACL_TOKEN_PERSISTENCE') | default(true, true)}}" +consul_acl_datacenter: "{{ lookup('env','CONSUL_ACL_DATACENTER') | default(consul_datacenter, true) }}" +consul_acl_down_policy: "{{ lookup('env','CONSUL_ACL_DOWN_POLICY') | default('extend-cache', true) }}" +consul_acl_token: "{{lookup('env','CONSUL_ACL_TOKEN') | default('', true) }}" +consul_acl_agent_token: "{{ lookup('env','CONSUL_ACL_AGENT_TOKEN') | default('', true) }}" +consul_acl_agent_master_token: "{{ lookup('env','CONSUL_ACL_AGENT_MASTER_TOKEN') | default('', true) }}" + +### Server ACL settings ### +consul_acl_default_policy: "{{ lookup('env','CONSUL_ACL_DEFAULT_POLICY') | default('allow', true) }}" +consul_acl_master_token: "{{ lookup('env','CONSUL_ACL_MASTER_TOKEN') | default('', true) }}" +consul_acl_master_token_display: "{{ lookup('env','CONSUL_ACL_MASTER_TOKEN_DISPLAY') | default(false, true) }}" +consul_acl_replication_enable: "{{ lookup('env','CONSUL_ACL_REPLICATION_ENABLE') | default('',true) }}" +consul_acl_replication_token: "{{ lookup('env','CONSUL_ACL_REPLICATION_TOKEN') | default('', true) }}" + +## gossip encryption +consul_encrypt_enable: "{{ lookup('env','CONSUL_ENCRYPT_ENABLE') | default(true, true) }}" +consul_encrypt_verify_incoming: true +consul_encrypt_verify_outgoing: true +consul_disable_keyring_file: "{{ lookup('env','CONSUL_DISABLE_KEYRING_FILE') | default(false, true) }}" + +## TLS +consul_tls_enable: "{{ lookup('env','CONSUL_TLS_ENABLE') | default(false, true) }}" +consul_tls_dir: "{{ lookup('env','CONSUL_TLS_DIR') | default('/etc/consul/ssl', true) }}" +consul_tls_ca_crt: "{{ lookup('env','CONSUL_TLS_CA_CRT') | default('ca.crt', true) }}" +consul_tls_server_crt: "{{ lookup('env','CONSUL_SERVER_CRT') | default('server.crt', true) }}" +consul_tls_server_key: "{{ lookup('env','CONSUL_SERVER_KEY') | default('server.key', true) }}" +consul_tls_copy_keys: true +consul_tls_verify_incoming: "{{ lookup('env','CONSUL_TLS_VERIFY_INCOMING') | default(false, true) }}" +consul_tls_verify_outgoing: "{{ lookup('env','CONSUL_TLS_VERIFY_OUTGOING') | default(true, true) }}" +consul_tls_verify_incoming_rpc: "{{ lookup('env','CONSUL_TLS_VERIFY_INCOMING_RPC') | default(false, true) }}" +consul_tls_verify_incoming_https: "{{ lookup('env','CONSUL_TLS_VERIFY_INCOMING_HTTPS') | default(false, true) }}" +consul_tls_verify_server_hostname: "{{ lookup('env','CONSUL_TLS_VERIFY_SERVER_HOSTNAME') | default(false, true) }}" +consul_tls_files_remote_src: false +consul_tls_min_version: "{{ lookup('env','CONSUL_TLS_MIN_VERSION') | default('TLSv1_2', true) }}" +consul_tls_cipher_suites: "" +consul_tls_prefer_server_cipher_suites: "{{ lookup('env','CONSUL_TLS_PREFER_SERVER_CIPHER_SUITES') | default('false', true) }}" +auto_encrypt: + enabled: false + +## DNS +consul_delegate_datacenter_dns: "{{ lookup('env','CONSUL_DELEGATE_DATACENTER_DNS') | default(false, true) }}" +consul_dnsmasq_enable: "{{ lookup('env','CONSUL_DNSMASQ_ENABLE') | default(false, true) }}" +consul_dnsmasq_bind_interfaces: false +consul_dnsmasq_consul_address: "\ + {# Use localhost if DNS is listening on all interfaces #}\ + {% if consul_addresses.dns == '0.0.0.0' %}\ + 127.0.0.1\ + {% else %}\ + {{ consul_addresses.dns }}\ + {% endif %}" +consul_dnsmasq_cache: -1 +consul_dnsmasq_servers: + - 8.8.8.8 + - 8.8.4.4 +consul_dnsmasq_revservers: [] +consul_dnsmasq_no_poll: false +consul_dnsmasq_no_resolv: false +consul_dnsmasq_local_service: false +consul_dnsmasq_listen_addresses: [] +consul_iptables_enable: "{{ lookup('env','CONSUL_IPTABLES_ENABLE') | default(false, true) }}" + +# Consul Enterprise +consul_enterprise: "{{ lookup('env','CONSUL_ENTERPRISE') | default(false, true) }}" + +# Performance +consul_performance: + raft_multiplier: 1 + leave_drain_time: 5s + rpc_hold_timeout: 7s + +# Snapshot +consul_snapshot: false +consul_snapshot_storage: "{{ consul_config_path }}/snaps" +consul_snapshot_interval: 1h +consul_snapshot_retain: 30 +consul_snapshot_stale: false + +# services +consul_services: [] + +# enable Consul Connect +consul_connect_enabled: false + +# system limits +consul_limits: {} + +# files clean up +consul_cleanup_ignore_files: + - '{{ consul_configd_path }}/consul.env' diff --git a/roles/consul/files/README.md b/roles/consul/files/README.md new file mode 100644 index 000000000..2943511c3 --- /dev/null +++ b/roles/consul/files/README.md @@ -0,0 +1,4 @@ +# files + +This directory is used for holding temporary files and should be present +in the role even when empty. diff --git a/roles/consul/files/consul_1.14.3_SHA256SUMS b/roles/consul/files/consul_1.14.3_SHA256SUMS new file mode 100644 index 000000000..bc9cb3903 --- /dev/null +++ b/roles/consul/files/consul_1.14.3_SHA256SUMS @@ -0,0 +1,11 @@ +fa94124d8d115523ff16bba89565304258641ec72f3cb59c85ca87265969ec66 consul_1.14.3_darwin_amd64.zip +387b8c4194e21fb3c6ef5f64adb031a585325eb335cb373279c2a187c7d025f8 consul_1.14.3_darwin_arm64.zip +fa71ff774d5fa697bc9920185879cc3b13c7956a008b62fd2b292a80b80450ce consul_1.14.3_freebsd_386.zip +7a634ed9576b6d2ecea020e251729f8400e99ce2876a33b55f6a282325418bb7 consul_1.14.3_freebsd_amd64.zip +2a80b23180d1a8b2603fd7ef25342e464bf501dc6f8a9fee514dfa18a95d7c91 consul_1.14.3_linux_386.zip +2971959d50fae1aa3f6b624219c85e0a4f34cd7232ea14d77d3cfb05f9ce7b8f consul_1.14.3_linux_amd64.zip +90d637bbd5d8f739424e0b9a809b7c7639d1df1ce939eca08b222808feb07720 consul_1.14.3_linux_arm.zip +37b79f7c6949203fb889a13583352e0961a66b39f2463018dd6c9fd6d731456f consul_1.14.3_linux_arm64.zip +04785c7bc689b261db28815ba9419f6b60ab67336ffd87932847c2eba263564e consul_1.14.3_solaris_amd64.zip +8f2fb286417a076327765a0d555c6fa57d64f95955e004acfe6ce8282a8ab06b consul_1.14.3_windows_386.zip +b4fad9d5bcbece307777524d1411d41f96089385ff8c29ad7e170d6d12c238d4 consul_1.14.3_windows_amd64.zip diff --git a/roles/consul/files/consul_1.14.3_linux_amd64.zip b/roles/consul/files/consul_1.14.3_linux_amd64.zip new file mode 100644 index 000000000..b7d722cbb Binary files /dev/null and b/roles/consul/files/consul_1.14.3_linux_amd64.zip differ diff --git a/roles/consul/handlers/main.yml b/roles/consul/handlers/main.yml new file mode 100644 index 000000000..4a39aa0bf --- /dev/null +++ b/roles/consul/handlers/main.yml @@ -0,0 +1,35 @@ +--- +# File: main.yml - Handlers for Consul + +- name: restart consul + import_tasks: restart_consul.yml + +- name: start consul + import_tasks: start_consul.yml + +- name: reload consul configuration + import_tasks: reload_consul_conf.yml + +- name: restart dnsmasq + service: + name: dnsmasq + enabled: true + state: restarted + become: true + +- name: restart rsyslog + import_tasks: restart_rsyslog.yml + +- name: restart syslog-ng + import_tasks: restart_syslogng.yml + +- name: restart syslog-ng + import_tasks: restart_syslogng.yml + +- name: start snapshot + import_tasks: start_snapshot.yml + +- name: systemctl daemon-reload + systemd: + daemon_reload: true + become: true diff --git a/roles/consul/handlers/reload_consul_conf.yml b/roles/consul/handlers/reload_consul_conf.yml new file mode 100644 index 000000000..9cae88ee0 --- /dev/null +++ b/roles/consul/handlers/reload_consul_conf.yml @@ -0,0 +1,8 @@ +--- +# Use SIGHUP to reload most configurations as per https://www.consul.io/docs/agent/options.html +# Cannot use `consul reload` because it requires the HTTP API to be bound to a non-loopback interface + +- name: reload consul configuration on unix + command: "pkill --pidfile '{{ consul_run_path }}/consul.pid' --signal SIGHUP" + when: ansible_os_family != "Windows" + listen: 'reload consul configuration' diff --git a/roles/consul/handlers/restart_consul.yml b/roles/consul/handlers/restart_consul.yml new file mode 100644 index 000000000..75984809b --- /dev/null +++ b/roles/consul/handlers/restart_consul.yml @@ -0,0 +1,36 @@ +--- +- name: Daemon reload systemd in case the binaries upgraded + systemd: + daemon_reload: true + become: true + when: ansible_service_mgr == "systemd" + listen: 'reload systemd daemon' + +- name: restart consul on unix + service: + name: consul + state: restarted + when: + - ansible_os_family != "Darwin" + - ansible_os_family != "Windows" + listen: 'restart consul' + +- name: restart consul on Mac + include_tasks: "{{ role_path }}/handlers/restart_consul_mac.yml" + when: ansible_os_family == "Darwin" + listen: 'restart consul' + +- name: restart consul on windows + win_service: + name: consul + state: restarted + # Some tasks with `become: true` end up calling this task. Unfortunately, the `become` + # property is evaluated before the `when` condition and this results in an Ansible + # error. + become: false + when: ansible_os_family == "Windows" + register: windows_service_started + retries: 3 + delay: 1 + until: windows_service_started is succeeded + listen: 'restart consul' diff --git a/roles/consul/handlers/restart_consul_mac.yml b/roles/consul/handlers/restart_consul_mac.yml new file mode 100644 index 000000000..3d81b6757 --- /dev/null +++ b/roles/consul/handlers/restart_consul_mac.yml @@ -0,0 +1,4 @@ +--- +- import_tasks: "stop_consul_mac.yml" + +- import_tasks: "start_consul_mac.yml" diff --git a/roles/consul/handlers/restart_rsyslog.yml b/roles/consul/handlers/restart_rsyslog.yml new file mode 100644 index 000000000..ff3689fbf --- /dev/null +++ b/roles/consul/handlers/restart_rsyslog.yml @@ -0,0 +1,9 @@ +--- +- name: restart rsyslog + service: + name: rsyslog + state: restarted + when: + - ansible_os_family != "Darwin" + - ansible_os_family != "Windows" + listen: 'restart rsyslog' diff --git a/roles/consul/handlers/restart_syslogng.yml b/roles/consul/handlers/restart_syslogng.yml new file mode 100644 index 000000000..d769164cf --- /dev/null +++ b/roles/consul/handlers/restart_syslogng.yml @@ -0,0 +1,6 @@ +--- +- name: restart syslog-ng + service: + name: syslog-ng + state: restarted + listen: 'restart syslog-ng' diff --git a/roles/consul/handlers/start_consul.yml b/roles/consul/handlers/start_consul.yml new file mode 100644 index 000000000..fe5143e26 --- /dev/null +++ b/roles/consul/handlers/start_consul.yml @@ -0,0 +1,21 @@ +--- +- name: start consul on unix + service: + name: consul + state: started + when: + - ansible_os_family != "Darwin" + - ansible_os_family != "Windows" + listen: 'start consul' + +- name: start consul on Mac + include_tasks: "{{ role_path }}/handlers/start_consul_mac.yml" + when: ansible_os_family == "Darwin" + listen: 'start consul' + +- name: start consul on windows + win_service: + name: consul + state: started + when: ansible_os_family == "Windows" + listen: 'start consul' diff --git a/roles/consul/handlers/start_consul_mac.yml b/roles/consul/handlers/start_consul_mac.yml new file mode 100644 index 000000000..05baee915 --- /dev/null +++ b/roles/consul/handlers/start_consul_mac.yml @@ -0,0 +1,31 @@ +--- +- name: See if consul service exists + become: true + become_user: "{{ consul_user }}" + command: "launchctl list {{ consul_launchctl_ident }}" + changed_when: false + ignore_errors: true + register: consul_service_list + +- name: Get UID for consul user + command: "id -u {{ consul_user }}" + changed_when: false + register: uid + when: consul_service_list is failed + +- name: Load consul service + become: true + become_user: "{{ consul_user }}" + command: "launchctl bootstrap gui/{{ uid.stdout }} {{ consul_launchctl_plist }}" + when: consul_service_list is failed + +- name: Assert that consul service is running + # Normally we'd want to use `launchctl list` for this, but it has a nasty habit of + # randomly not returning the PID in its output, which makes it hard for us to see if the + # service is running. + command: "pgrep consul" + changed_when: false + register: consul_mac_service_pgrep + retries: 20 + delay: 3 + until: consul_mac_service_pgrep is succeeded diff --git a/roles/consul/handlers/start_snapshot.yml b/roles/consul/handlers/start_snapshot.yml new file mode 100644 index 000000000..f96da3036 --- /dev/null +++ b/roles/consul/handlers/start_snapshot.yml @@ -0,0 +1,10 @@ +--- +- name: start consul snapshot on unix + service: + name: consul_snapshot + state: started + enabled: true + when: + - ansible_os_family != "Darwin" + - ansible_os_family != "Windows" + listen: 'start snapshot' diff --git a/roles/consul/handlers/stop_consul_mac.yml b/roles/consul/handlers/stop_consul_mac.yml new file mode 100644 index 000000000..585967373 --- /dev/null +++ b/roles/consul/handlers/stop_consul_mac.yml @@ -0,0 +1,29 @@ +--- +- name: See if consul service exists + become: true + become_user: "{{ consul_user }}" + command: "launchctl list {{ consul_launchctl_ident }}" + changed_when: false + ignore_errors: true + register: consul_service_list + +- name: Get UID for consul user + command: "id -u {{ consul_user }}" + changed_when: false + register: uid + when: consul_service_list is succeeded + +- name: Unload consul service + become: true + become_user: "{{ consul_user }}" + command: "launchctl bootout gui/{{ uid.stdout }} {{ consul_launchctl_plist }}" + changed_when: false + register: unload_consul_service + # Code 113 is returned by launchctl for the error "Could not find service in domain for + # port". This can also mean that the service hasn't yet been configured, so we don't + # want to treat that as as error. + failed_when: unload_consul_service.rc != 0 and unload_consul_service.rc != 113 + retries: 3 + delay: 3 + until: unload_consul_service is not failed + when: consul_service_list is succeeded diff --git a/roles/consul/requirements.txt b/roles/consul/requirements.txt new file mode 100644 index 000000000..800d79405 --- /dev/null +++ b/roles/consul/requirements.txt @@ -0,0 +1,7 @@ +rich>=10.0.0,<11.0.0 +molecule===2.22 +docker +netaddr +testinfra +flake8 +yamllint diff --git a/roles/consul/requirements.yml b/roles/consul/requirements.yml new file mode 100644 index 000000000..94d14f009 --- /dev/null +++ b/roles/consul/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: ansible.utils + version: 2.6.1 diff --git a/roles/consul/tasks/acl.yml b/roles/consul/tasks/acl.yml new file mode 100644 index 000000000..3caf8b7d9 --- /dev/null +++ b/roles/consul/tasks/acl.yml @@ -0,0 +1,104 @@ +--- +# File: acl.yml - ACL tasks for Consul +- block: + - name: Read ACL master token from previously boostrapped server + command: "cat {{ consul_config_path }}/config.json" + register: config_read + no_log: true + changed_when: false + run_once: true + + - name: Save acl_master_token from existing configuration + set_fact: + consul_acl_master_token: "{{ config_read.stdout | from_json | json_query(query) }}" + vars: + query: "acl.tokens.master" + no_log: true + + - name: Save acl_initial_management from existing configuration if acl_master_token not found + set_fact: + consul_acl_master_token: "{{ config_read.stdout | from_json | json_query(query) }}" + vars: + query: "acl.tokens.initial_management" + no_log: true + when: consul_acl_master_token | length == 0 + + when: + - bootstrap_state.stat.exists | bool + - (consul_acl_master_token is not defined or consul_acl_master_token | length == 0) + - consul_node_role == 'server' + +- block: + + - name: Generate ACL master token + command: "echo {{ lookup('password', '/dev/null length=32 chars=ascii_letters') | to_uuid }}" + register: consul_acl_master_token_keygen + run_once: true + no_log: true + + - name: Save ACL master token + set_fact: + consul_acl_master_token: "{{ consul_acl_master_token_keygen.stdout }}" + no_log: true + + when: + - (consul_acl_master_token is not defined or consul_acl_master_token | length == 0) + - not bootstrap_state.stat.exists | bool + - consul_node_role == 'server' + +- name: Display ACL Master Token + debug: + msg: "{{ consul_acl_master_token }}" + run_once: true + when: + - consul_acl_master_token_display | bool + - consul_node_role == 'server' + +- block: + - name: Read ACL master token from previously boostrapped server + command: "cat {{ consul_config_path }}/config.json" + register: config_read + no_log: true + changed_when: false + run_once: true + + - name: Save acl_replication_token from existing configuration + set_fact: + consul_acl_replication_token: "{{ config_read.stdout | from_json | json_query(query) }}" + vars: + query: "acl.tokens.replication" + no_log: true + + when: + - bootstrap_state.stat.exists | bool + - (consul_acl_replication_token is not defined or consul_acl_replication_token | length == 0) + - consul_node_role == 'server' + +- block: + + - name: Generate ACL replication token + command: "echo {{ lookup('password', '/dev/null length=32 chars=ascii_letters') | to_uuid }}" + register: consul_acl_replication_token_keygen + no_log: true + run_once: true + + - name: Save ACL replication token + set_fact: + consul_acl_replication_token: "{{ consul_acl_replication_token_keygen.stdout }}" + no_log: true + + when: + - (consul_acl_replication_token is not defined or consul_acl_replication_token | length == 0) + - not bootstrap_state.stat.exists | bool + - consul_node_role == 'server' + +- name: Create ACL policy configuration + template: + src: configd_50acl_policy.hcl.j2 + dest: "{{ consul_configd_path }}/50acl_policy.hcl" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0600 + notify: + - restart consul + when: consul_acl_policy | bool diff --git a/roles/consul/tasks/asserts.yml b/roles/consul/tasks/asserts.yml new file mode 100644 index 000000000..1548271ec --- /dev/null +++ b/roles/consul/tasks/asserts.yml @@ -0,0 +1,131 @@ +--- +# File: asserts.yml - Asserts for this playbook + +- name: Define supported *nix distributions + set_fact: + _consul_nix_distros: + - 'RedHat' + - 'CentOS' + - 'Rocky' + - 'AlmaLinux' + - 'OracleLinux' + - 'Fedora' + - 'Debian' + - 'FreeBSD' + - 'SmartOS' + - 'Ubuntu' + - 'Archlinux' + - 'Alpine' + - 'Amazon' + - 'Flatcar' + - 'VMware Photon OS' + - 'MacOSX' + +- name: Check distribution compatibility + fail: + msg: "{{ ansible_distribution }} is not currently supported by this role." + when: + - ansible_distribution not in _consul_nix_distros + - ansible_os_family != 'Windows' + +- name: Check Photon version + fail: + msg: "{{ ansible_distribution_version }} is not a supported version." + when: + - ansible_distribution in ['VMware Photon OS'] + - ansible_distribution_version is version_compare(4, '<') + +- name: Check CentOS, Red Hat or Oracle Linux version + fail: + msg: "{{ ansible_distribution_version }} is not a supported version." + when: + - ansible_distribution in ['RedHat', 'CentOS', 'OracleLinux', 'Rocky', 'AlmaLinux'] + - ansible_distribution_version is version_compare(6, '<') + +- name: Check Debian version + fail: + msg: "{{ ansible_distribution_version }} is not a supported version." + when: + - ansible_distribution == "Debian" + - (ansible_distribution_version != 'buster/sid') and (ansible_distribution_version is version_compare(8, '<')) + +- name: Check FreeBSD version + fail: + msg: "{{ ansible_distribution_version }} is not a supported version." + when: + - ansible_distribution == "FreeBSD" + - ansible_distribution_version is version_compare(10, '<') + +- name: Check Ubuntu version + fail: + msg: "{{ ansible_distribution_version }} is not a supported version." + when: + - ansible_distribution == "Ubuntu" + - ansible_distribution_version is version_compare(13.04, '<') + +- name: Check specified ethernet interface + fail: + msg: "The ethernet interface specified by consul_iface was not found." + when: + - ansible_os_family != 'Windows' + - consul_iface not in ansible_interfaces + +- name: Check iptables on Red Hat, CentOS or Oracle Linux + fail: + msg: "Use DNSmasq instead of iptables on {{ ansible_distribution }}." + when: + - consul_iptables_enable | bool + - ansible_distribution in ['RedHat', 'CentOS', 'OracleLinux', 'Rocky', 'AlmaLinux'] + - ansible_distribution_version is version_compare(6, '>=') + +- name: Check for both Dnsmasq and iptables enabled + fail: + msg: "EONEORTHEOTHER: DNSmasq and iptables together is not supported." + when: + - consul_dnsmasq_enable | bool + - consul_iptables_enable | bool + +- name: Check for iptables enabled but no recursors + fail: + msg: "Recursors are required if iptables is enabled." + when: + - consul_iptables_enable | bool + - consul_recursors | length == 0 + +- name: Check consul_group_name is included in groups + fail: + msg: "consul_group_name must be included in groups." + when: consul_group_name not in groups + +- name: Fail if more than one bootstrap server is defined + fail: + msg: "You can not define more than one bootstrap server." + when: + - _consul_bootstrap_servers | length > 1 + +- name: Fail if a bootstrap server is defined and bootstrap_expect is true + fail: + msg: "Can't use a bootstrap server and bootstrap_expect at the same time." + when: + - _consul_bootstrap_servers | length > 0 + - consul_bootstrap_expect | bool + +# Check for unzip binary + +- name: Check if unzip is installed on control host + shell: "command -v unzip -h >/dev/null 2>&1" + become: false + changed_when: false + check_mode: false + run_once: true + register: is_unzip_installed + ignore_errors: true + delegate_to: 127.0.0.1 + vars: + ansible_become: false + +- name: Install remotely if unzip is not installed on control host + set_fact: + consul_install_remotely: true + when: + - is_unzip_installed is failed diff --git a/roles/consul/tasks/config.yml b/roles/consul/tasks/config.yml new file mode 100644 index 000000000..9fbdbcccb --- /dev/null +++ b/roles/consul/tasks/config.yml @@ -0,0 +1,46 @@ +--- +# File: config.yml - Consul configuration tasks + +- name: Create configuration + copy: + dest: "{{ config_item.dest }}" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + content: "{{ lookup('template', consul_config_template_path, convert_data=True) | to_nice_json }}" + mode: 0600 + with_items: + - dest: "{{ consul_config_path }}/config.json" + config_version: "{{ consul_node_role }}" + when: true + - dest: "{{ consul_config_path }}/bootstrap.json" + config_version: bootstrap + when: "{{ consul_debug | bool }}" + - dest: "{{ consul_config_path }}/server.json" + config_version: server + when: "{{ consul_debug | bool }}" + - dest: "{{ consul_config_path }}/client.json" + config_version: client + when: "{{ consul_debug | bool }}" + loop_control: + loop_var: config_item + when: + - config_item.when + notify: + - restart consul + +- name: Create custom configuration + copy: + dest: "{{ consul_configd_path }}/50custom.json" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + content: "{{ lookup('template', 'templates/configd_50custom.json.j2', convert_data=True) | to_nice_json }}" + mode: 0600 + when: + - consul_config_custom is defined + notify: + - restart consul + +- name: Set fact list with custom configuration file + set_fact: + managed_files: "{{ managed_files |default([]) }} + \ + [ '{{ consul_configd_path }}/50custom.json' ]" diff --git a/roles/consul/tasks/config_windows.yml b/roles/consul/tasks/config_windows.yml new file mode 100644 index 000000000..71be3ea90 --- /dev/null +++ b/roles/consul/tasks/config_windows.yml @@ -0,0 +1,46 @@ +--- +# File: config_windows.yml - Consul configuration tasks for Windows + +- name: Create configuration + win_copy: + dest: "{{ config_item.dest }}" + content: "{{ lookup('template', consul_config_template_path, convert_data=True) | to_nice_json }}" + with_items: + - dest: "{{ consul_config_path }}/config.json" + config_version: "{{ consul_node_role }}" + when: true + - dest: "{{ consul_config_path }}/bootstrap.json" + config_version: "bootstrap" + when: "{{ consul_debug | bool }}" + - dest: "{{ consul_config_path }}/server.json" + config_version: "server" + when: "{{ consul_debug | bool }}" + - dest: "{{ consul_config_path }}/client.json" + config_version: "client" + when: "{{ consul_debug | bool }}" + loop_control: + loop_var: config_item + when: + - config_item.when + notify: + - restart consul + +- name: Create custom configuration + win_copy: + dest: "{{ consul_configd_path }}/50custom.json" + content: "{{ lookup('template', 'templates/configd_50custom.json.j2', convert_data=True) | to_nice_json }}" + when: + - consul_config_custom is defined + notify: + - restart consul + +- name: Get Windows path for custom configuration file + win_stat: + path: "{{ consul_configd_path }}/50custom.json" + register: custom_config_win_path + +- name: Set fact list with custom configuration file + set_fact: + managed_files: "{{ managed_files |default([]) }} + \ + [ '{{ custom_config_win_path.results[0].stat.path }}' ]" + when: custom_config_win_path.stat.exists diff --git a/roles/consul/tasks/dirs.yml b/roles/consul/tasks/dirs.yml new file mode 100644 index 000000000..f561eaeb0 --- /dev/null +++ b/roles/consul/tasks/dirs.yml @@ -0,0 +1,84 @@ +--- +# File: dirs.yml - Consul directories + +- name: Create directories + when: ansible_os_family != 'Windows' + block: + - name: Configuration and data directories + file: + dest: "{{ dir_item }}" + state: directory + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0700 + with_items: + - "{{ consul_config_path }}" + - "{{ consul_configd_path }}" + - "{{ consul_data_path }}" + loop_control: + loop_var: dir_item + - name: Run directory + file: + dest: "{{ consul_run_path }}" + state: directory + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0750 + when: not consul_install_from_repo | bool + +- name: Create log directory + file: + dest: "{{ consul_log_path }}" + state: directory + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0700 + when: + - ansible_os_family != 'Windows' + - not consul_syslog_enable | bool + - not consul_configure_syslogd | bool + +- name: Create log directory + file: + dest: "{{ log_item }}" + state: directory + owner: "{{ syslog_user }}" + group: "{{ syslog_group }}" + mode: 0700 + with_items: + - "{{ consul_log_path }}" + loop_control: + loop_var: log_item + when: + - ansible_os_family != 'Windows' + - consul_syslog_enable | bool + - consul_configure_syslogd | bool + +- name: Verify binary path + file: + path: "{{ consul_bin_path }}" + state: directory + owner: root + mode: 0755 + when: + # On macOS, we should not alter consul_bin_path, since it may be owned by the homebrew + # user. This may cause the role to fail on macOS systems where homebrew is not + # present, but in that case, the user should create the directory from their playbook + # before running this role. + - ansible_os_family != 'Darwin' + - ansible_os_family != 'Windows' + - not consul_install_from_repo | bool + +- name: Create directories on Windows + win_file: + dest: "{{ dir_item }}" + state: directory + with_items: + - "{{ consul_config_path }}" + - "{{ consul_configd_path }}" + - "{{ consul_data_path }}" + - "{{ consul_log_path }}" + - "{{ consul_bin_path }}" + loop_control: + loop_var: dir_item + when: ansible_os_family == 'Windows' diff --git a/roles/consul/tasks/dnsmasq.yml b/roles/consul/tasks/dnsmasq.yml new file mode 100644 index 000000000..9100bd89f --- /dev/null +++ b/roles/consul/tasks/dnsmasq.yml @@ -0,0 +1,94 @@ +--- +# File: dnsmasq.yml - Dnsmasq tasks for Consul + +- name: Install Dnsmasq package + package: + name: "{{ dnsmasq_package }}" + state: present + become: true + tags: dnsmasq, installation + +- name: Create Dnsmasq configuration directory + file: + path: /usr/local/etc/dnsmasq.d + state: directory + owner: root + group: wheel + mode: 0700 + become: true + when: ansible_os_family == "FreeBSD" + tags: dnsmasq + +- name: Include Dnsmasq configuration directory + lineinfile: + dest: /usr/local/etc/dnsmasq.conf + line: 'conf-dir=/usr/local/etc/dnsmasq.d/,*.conf' + become: true + notify: restart dnsmasq + when: ansible_os_family == "FreeBSD" + tags: dnsmasq + +- name: Create Dnsmasq configuration + template: + src: dnsmasq-10-consul.j2 + dest: "{{ dnsmasq_item.dest }}" + owner: root + group: "{{ dnsmasq_item.group }}" + mode: 0644 + become: true + notify: restart dnsmasq + when: "{{ dnsmasq_item.when }}" + tags: dnsmasq + loop: + - { dest: '/etc/dnsmasq.d/10-consul', group: 'root', when: ansible_os_family|lower != "freebsd" } + - { dest: '/usr/local/etc/dnsmasq.d/consul.conf', group: 'wheel', when: ansible_os_family|lower == "freebsd" } + loop_control: + loop_var: dnsmasq_item + +- name: Disable systemd-resolved + when: ansible_service_mgr == "systemd" + block: + + - name: Check if systemd-resolved service exists + stat: + path: /lib/systemd/system/systemd-resolved.service + register: systemd_resolved_service + + - name: Disable systemd-resolved service + service: + name: systemd-resolved + enabled: false + state: stopped + become: true + when: systemd_resolved_service.stat.exists + + - name: Check if resolv.conf is pointing to systemd-resolved + stat: + path: /etc/resolv.conf + register: resolv_dot_conf + + - block: + - name: Remove resolv.conf association with systemd-resolved + file: + path: /etc/resolv.conf + state: absent + + - name: Create /etc/resolv.conf + file: + path: /etc/resolv.conf + state: touch + owner: root + group: root + mode: u=rw,g=r,o=r + + - name: Add a nameserver entry poining to localhost for dnsmasq + lineinfile: + path: /etc/resolv.conf + regexp: "^nameserver 127.0.0.1" + line: "nameserver 127.0.0.1" + unsafe_writes: true # to prevent failures in CI + become: true + when: + - resolv_dot_conf.stat.islnk is defined + - resolv_dot_conf.stat.islnk + - resolv_dot_conf.stat.lnk_source == "/run/systemd/resolve/stub-resolv.conf" diff --git a/roles/consul/tasks/encrypt_gossip.yml b/roles/consul/tasks/encrypt_gossip.yml new file mode 100644 index 000000000..9326c91c2 --- /dev/null +++ b/roles/consul/tasks/encrypt_gossip.yml @@ -0,0 +1,59 @@ +--- +# File: encrypt_gossip.yml - Gossip encryption tasks for Consul + +- block: + - name: Read gossip encryption key from previously boostrapped server + shell: 'cat {{ consul_config_path }}/bootstrap/config.json | grep "encrypt" | sed -E ''s/"encrypt": "(.+)",?/\1/'' | sed ''s/^ *//;s/ *$//''' + register: consul_key_read + run_once: true + + - name: Save gossip encryption key from existing configuration + set_fact: consul_raw_key={{ consul_key_read.stdout }} + ignore_errors: true + + when: + - consul_raw_key is not defined + - bootstrap_state.stat.exists | bool + +- name: Write gossip encryption key locally for use with new servers + copy: + content: "{{ consul_raw_key }}" + dest: /tmp/consul_raw.key + mode: 0600 + become: false + vars: + ansible_become: false + when: + - consul_raw_key is defined + - bootstrap_state.stat.exists | bool + delegate_to: 127.0.0.1 + +- name: Read gossip encryption key for servers that require it + set_fact: consul_raw_key="{{ lookup('file', '/tmp/consul_raw.key') }}" + when: + - consul_raw_key is not defined + - bootstrap_state.stat.exists | bool + +- name: Delete gossip encryption key file + file: + path: /tmp/consul_raw.key + state: absent + become: false + vars: + ansible_become: false + when: + - consul_raw_key is defined + - bootstrap_state.stat.exists | bool + delegate_to: 127.0.0.1 + +- block: + - name: Generate gossip encryption key + shell: "PATH={{ consul_bin_path }}:$PATH consul keygen" + register: consul_keygen + run_once: true + + - name: Write gossip encryption key to fact + set_fact: consul_raw_key={{ consul_keygen.stdout }} + when: + - consul_raw_key is not defined + - not bootstrap_state.stat.exists | bool diff --git a/roles/consul/tasks/install.yml b/roles/consul/tasks/install.yml new file mode 100644 index 000000000..3a123035a --- /dev/null +++ b/roles/consul/tasks/install.yml @@ -0,0 +1,139 @@ +--- +# File: install.yml - package installation tasks for Consul + +- name: Install OS packages + package: + name: "{{ consul_os_packages }}" + state: present + tags: installation + when: not ansible_facts['os_family'] == "VMware Photon OS" and (consul_os_packages | length > 0) + +- name: Install OS packages + command: "tdnf install -y {{ package_item }}" + with_items: "{{ consul_os_packages }}" + loop_control: + loop_var: package_item + tags: installation + when: ansible_facts['os_family'] == "VMware Photon OS" + +- name: Update Alpine Package Manager (APK) + apk: + update_cache: true + run_once: true + when: ansible_os_family == "Alpine" + delegate_to: 127.0.0.1 + +- name: Read package checksum file + stat: + path: "{{ role_path }}/files/consul_{{ consul_version }}_SHA256SUMS" + become: false + vars: + ansible_become: false + run_once: true + register: consul_checksum + tags: installation + delegate_to: 127.0.0.1 + +- name: Download package checksum file + get_url: + url: "{{ consul_checksum_file_url }}" + dest: "{{ role_path }}/files/consul_{{ consul_version }}_SHA256SUMS" + become: false + vars: + ansible_become: false + run_once: true + tags: installation + when: not consul_checksum.stat.exists | bool + delegate_to: 127.0.0.1 + +- name: Read package checksum + shell: grep "{{ consul_pkg }}" "{{ role_path }}/files/consul_{{ consul_version }}_SHA256SUMS" | awk '{print $1}' + become: false + vars: + ansible_become: false + register: consul_sha256 + tags: + - installation + - skip_ansible_lint + run_once: true + delegate_to: 127.0.0.1 + +- name: Check Consul package file + stat: + path: "{{ role_path }}/files/{{ consul_pkg }}" + become: false + vars: + ansible_become: false + register: consul_package + tags: installation + run_once: true + delegate_to: 127.0.0.1 + +- name: Download Consul package + get_url: + url: "{{ consul_zip_url }}" + dest: "{{ role_path }}/files/{{ consul_pkg }}" + checksum: "sha256:{{ consul_sha256.stdout }}" + timeout: "42" + become: false + vars: + ansible_become: false + tags: installation + when: not consul_package.stat.exists | bool + run_once: true + delegate_to: 127.0.0.1 + ignore_errors: "{{ ansible_check_mode }}" + +- name: Create Temporary Directory for Extraction + tempfile: + state: directory + prefix: ansible-consul. + become: false + vars: + ansible_become: false + register: install_temp + tags: installation + run_once: true + delegate_to: 127.0.0.1 + +- name: Unarchive and install Consul + block: + - name: Unarchive Consul package + unarchive: + src: "{{ role_path }}/files/{{ consul_pkg }}" + dest: "{{ install_temp.path }}/" + creates: "{{ install_temp.path }}/consul" + become: false + vars: + ansible_become: false + tags: + - installation + - skip_ansible_lint + run_once: true + delegate_to: 127.0.0.1 + ignore_errors: "{{ ansible_check_mode }}" + + - name: Install Consul + copy: + src: "{{ install_temp.path }}/consul" + dest: "{{ consul_bin_path }}/consul" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0755 + notify: + - restart consul + - reload systemd daemon + tags: installation + ignore_errors: "{{ ansible_check_mode }}" + always: + - name: Cleanup + file: + path: "{{ install_temp.path }}" + state: "absent" + become: false + vars: + ansible_become: false + tags: installation + run_once: true + delegate_to: 127.0.0.1 + ignore_errors: "{{ ansible_check_mode }}" diff --git a/roles/consul/tasks/install_linux_repo.yml b/roles/consul/tasks/install_linux_repo.yml new file mode 100644 index 000000000..7bcc527a7 --- /dev/null +++ b/roles/consul/tasks/install_linux_repo.yml @@ -0,0 +1,116 @@ +--- +# File: install_linux_repo.yml - package installation tasks for Consul + +- name: Install OS packages + package: + name: "{{ consul_repo_prerequisites }}" + state: present + become: true + when: (consul_os_repo_prerequisites) + tags: installation + +- name: Gather the package facts + package_facts: + manager: auto + +- name: Clean up previous consul data + block: + - name: Populate service facts + service_facts: + + - name: Stop service consul, if running + service: + name: consul + state: stopped + when: ansible_facts.services | join is match('.*consul.*') + + - name: Remove consul service unit files from previous installation + file: + path: "{{ service_unit_item }}" + state: absent + loop: + - /usr/lib/systemd/system/consul.service + - /etc/init.d/consul + loop_control: + loop_var: service_unit_item + + - name: Remove the user 'consul' + user: + name: consul + state: absent + remove: true + + when: "'consul' not in ansible_facts.packages" + become: true + +- name: Install repository + block: + - name: Add Redhat/CentOS/Fedora/Amazon Linux repository + command: "yum-config-manager --add-repo {{ consul_repo_url }}" + args: + creates: /etc/yum.repos.d/hashicorp.repo + when: > + ansible_distribution|lower == 'redhat' or + ansible_distribution|lower == 'centos' or + ansible_distribution|lower == 'fedora' or + ansible_distribution|lower == 'amazon' or + ansible_distribution|lower == 'rocky' or + ansible_distribution|lower == 'almalinux' + + - name: Add an Apt signing key, uses whichever key is at the URL + apt_key: + url: "{{ consul_repo_url }}/gpg" + state: present + when: "ansible_os_family|lower == 'debian'" + + - name: Add Debian/Ubuntu Linux repository + apt_repository: + repo: "deb {{ consul_repo_url }} {{ ansible_distribution_release }} main" + state: present + update_cache: true + when: "ansible_os_family|lower == 'debian'" + + when: "ansible_os_family|lower in [ 'debian', 'redhat' ]" + become: true + +- name: Install consul package + package: + name: "consul{{ '=' if ansible_pkg_mgr == 'apt' else '-' }}{{ consul_version }}" + state: present + become: true + +- name: Create a directory /etc/systemd/system/consul.service.d + file: + path: /etc/systemd/system/consul.service.d + state: directory + mode: '0755' + owner: root + group: root + register: systemd_override + become: true + when: ansible_service_mgr == "systemd" + +- name: Override systemd service params + template: + src: consul_systemd_service.override.j2 + dest: /etc/systemd/system/consul.service.d/override.conf + owner: root + group: root + mode: 0644 + register: systemd_override + become: true + notify: + - systemctl daemon-reload + - restart consul + when: + - ansible_service_mgr == "systemd" + - consul_install_from_repo | bool + +- name: Flush handlers + meta: flush_handlers + +- name: As, this role work with json conf file only - delete file /etc/consul.d/consul.hcl + file: + path: /etc/consul.d/consul.hcl + state: absent + become: true diff --git a/roles/consul/tasks/install_remote.yml b/roles/consul/tasks/install_remote.yml new file mode 100644 index 000000000..4dc0e36ce --- /dev/null +++ b/roles/consul/tasks/install_remote.yml @@ -0,0 +1,69 @@ +--- +# File: install_remote.yml - package installation tasks for Consul + +- name: Install OS packages + package: + name: "{{ consul_os_packages }}" + state: present + tags: installation + +- name: Validate remote Consul directory + tempfile: + state: directory + prefix: ansible-consul. + register: consul_temp_dir + +- name: Download and unarchive Consul + block: + - name: Read Consul package checksum file + stat: + path: "{{ consul_temp_dir.path }}/consul_{{ consul_version }}_SHA256SUMS" + register: consul_checksum + changed_when: false + tags: installation + + - name: Download Consul package checksum file + get_url: + url: "{{ consul_checksum_file_url }}" + dest: "{{ consul_temp_dir.path }}/consul_{{ consul_version }}_SHA256SUMS" + validate_certs: false + tags: installation + when: not consul_checksum.stat.exists | bool + + - name: Read Consul package checksum + shell: "grep {{ consul_pkg }} {{ consul_temp_dir.path }}/consul_{{ consul_version }}_SHA256SUMS" + register: consul_sha256 + changed_when: false + tags: + - installation + - skip_ansible_lint + + - name: Download Consul + get_url: + url: "{{ consul_zip_url }}" + dest: "{{ consul_temp_dir.path }}/{{ consul_pkg }}" + checksum: "sha256:{{ consul_sha256.stdout.split(' ')|first }}" + timeout: 42 + register: consul_download + tags: installation + + - name: Unarchive Consul and install binary + unarchive: + remote_src: true + src: "{{ consul_temp_dir.path }}/{{ consul_pkg }}" + dest: "{{ consul_bin_path }}" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0755 + register: consul_install + notify: + - restart consul + - reload systemd daemon + when: consul_download is changed + tags: installation + always: + - name: Cleanup + file: + path: "{{ consul_temp_dir.path }}" + state: absent + tags: installation diff --git a/roles/consul/tasks/install_windows.yml b/roles/consul/tasks/install_windows.yml new file mode 100644 index 000000000..8f414421e --- /dev/null +++ b/roles/consul/tasks/install_windows.yml @@ -0,0 +1,68 @@ +--- +# File: install_remote.yml - package installation tasks for Consul + +- name: Verify TLS1.2 is used + win_regedit: + path: HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 + name: SchUseStrongCrypto + data: 1 + type: dword + +- name: Create temporary directory to download Consul + win_tempfile: + state: directory + prefix: ansible-consul. + register: consul_temp_dir + +- name: Download and unarchive Consul + block: + - name: Read Consul package checksum file + win_stat: + path: "{{ consul_temp_dir.path }}\\consul_{{ consul_version }}_SHA256SUMS" + register: consul_checksum + tags: installation + + - name: Download Consul package checksum file + win_get_url: + url: "{{ consul_checksum_file_url }}" + dest: "{{ consul_temp_dir.path }}\\consul_{{ consul_version }}_SHA256SUMS" + tags: installation + when: not consul_checksum.stat.exists | bool + + - name: Read Consul package checksum + win_shell: "findstr {{ consul_pkg }} {{ consul_temp_dir.path }}\\consul_{{ consul_version }}_SHA256SUMS" + args: + chdir: "{{ consul_temp_dir.path }}" + register: consul_pkg_checksum + tags: installation + + - name: Download Consul + win_get_url: + url: "{{ consul_zip_url }}" + dest: "{{ consul_temp_dir.path }}\\{{ consul_pkg }}" + tags: installation + + - name: Calculate checksum + win_stat: + path: "{{ consul_temp_dir.path }}\\{{ consul_pkg }}" + checksum_algorithm: sha256 + register: consul_pkg_hash + tags: installation + + - name: Compare checksum to hashfile + fail: + msg: "Checksum {{ consul_pkg_checksum.stdout.split(' ') | first }} did not match calculated SHA256 {{ consul_pkg_hash.stat.checksum }}!" + when: + - consul_pkg_hash.stat.checksum != (consul_pkg_checksum.stdout.split(' ') | first) + + - name: Unarchive Consul and install binary + win_unzip: + src: "{{ consul_temp_dir.path }}\\{{ consul_pkg }}" + dest: "{{ consul_bin_path }}" + tags: installation + always: + - name: Cleanup + win_file: + path: "{{ consul_temp_dir.path }}" + state: absent + tags: installation diff --git a/roles/consul/tasks/iptables.yml b/roles/consul/tasks/iptables.yml new file mode 100644 index 000000000..f5c1919f2 --- /dev/null +++ b/roles/consul/tasks/iptables.yml @@ -0,0 +1,48 @@ +--- +# File: iptables.yml - iptables tasks for Consul + +- name: Install iptables + apt: + name: iptables + +- name: Redirect local DNS (1/4) + iptables: + table: nat + chain: PREROUTING + protocol: udp + match: udp + destination_port: 53 + jump: REDIRECT + to_ports: 8600 + +- name: Redirect local DNS (2/4) + iptables: + table: nat + chain: PREROUTING + protocol: tcp + match: tcp + destination_port: 53 + jump: REDIRECT + to_ports: 8600 + +- name: Redirect local DNS (3/4) + iptables: + table: nat + chain: OUTPUT + protocol: udp + match: udp + destination_port: 53 + jump: REDIRECT + to_ports: 8600 + destination: localhost + +- name: Redirect local DNS (4/4) + iptables: + table: nat + chain: OUTPUT + protocol: tcp + match: tcp + destination_port: 53 + jump: REDIRECT + to_ports: 8600 + destination: localhost diff --git a/roles/consul/tasks/main.yml b/roles/consul/tasks/main.yml new file mode 100644 index 000000000..832227c24 --- /dev/null +++ b/roles/consul/tasks/main.yml @@ -0,0 +1,70 @@ +--- +# File: main.yml - Main tasks for Consul +- name: Looking up latest version of Consul + set_fact: + consul_version: "{{ (lookup('url', 'https://api.github.com/repos/hashicorp/consul/releases/latest', split_lines=False) | + from_json).get('tag_name') | replace('v', '') }}" + when: 'consul_version == "latest"' + +- name: Install python dependencies + when: + - consul_install_dependencies | bool + block: + - name: Install netaddr dependency on controlling host (with --user) + pip: + name: netaddr + extra_args: --user + delegate_to: 127.0.0.1 + become: false + vars: + ansible_become: false + run_once: true + when: not is_virtualenv or is_virtualenv == None + + - name: Install netaddr dependency on controlling host (virtualenv) + pip: + name: netaddr + delegate_to: 127.0.0.1 + become: false + vars: + ansible_become: false + run_once: true + when: is_virtualenv is defined + +- name: Include checks/asserts + import_tasks: asserts.yml + +- name: Include OS-specific variables + include_vars: "{{ vars_file_item }}" + with_first_found: + - files: + - '{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml' + - "{{ ansible_os_family }}.yml" + loop_control: + loop_var: vars_file_item + tags: always + +# ----------------------------------------------------------------------- +# Tasks for all *NIX operating systems +# ----------------------------------------------------------------------- +- name: Include NIX tasks + include_tasks: nix.yml + when: ansible_os_family != 'Windows' + +# ----------------------------------------------------------------------- +# Tasks for Windows +# ----------------------------------------------------------------------- +- name: Include Windows tasks + include_tasks: windows.yml + when: ansible_os_family == 'Windows' + +- name: Include services management + import_tasks: services.yml + when: + - consul_services is defined and consul_services|length>0 + - inventory_hostname in groups['postgres_cluster'] + tags: + - consul_services + +- name: flush_handlers + meta: flush_handlers diff --git a/roles/consul/tasks/nix.yml b/roles/consul/tasks/nix.yml new file mode 100644 index 000000000..3436b4792 --- /dev/null +++ b/roles/consul/tasks/nix.yml @@ -0,0 +1,317 @@ +--- +# Gathers facts (bind address) from servers not currently targeted. +# 'delegate_facts' is currently rather buggy in Ansible so this might not +# always work. Hence 'consul_gather_server_facts' defaults to 'no'. +- name: Gather facts from other servers + setup: + delegate_to: "{{ host_item }}" + delegate_facts: true + with_items: "{{ consul_servers | difference(play_hosts) }}" + loop_control: + loop_var: host_item + ignore_errors: true + run_once: true + when: consul_gather_server_facts | bool + +- name: Expose advertise_address(_wan) datacenter and node_role as facts + set_fact: + consul_advertise_address_wan: "{{ consul_advertise_address_wan }}" + consul_advertise_address: "{{ consul_advertise_address }}" + consul_bind_address: "{{ consul_bind_address }}" + consul_datacenter: "{{ consul_datacenter }}" + consul_node_role: "{{ consul_node_role }}" + +- name: Read bootstrapped state + stat: + path: "{{ consul_bootstrap_state }}" + register: bootstrap_state + ignore_errors: true + tags: always + +- name: Include user and group settings + import_tasks: user_group.yml + +- name: Install OS packages and consul - from the repository + include_tasks: install_linux_repo.yml + when: + - consul_install_from_repo | bool + +- name: Include directory settings + import_tasks: dirs.yml + +- name: Check for existing Consul binary + stat: + path: "{{ consul_binary }}" + register: consul_binary_installed + when: not consul_force_install + +- name: Get current Consul version + command: "{{ consul_binary }} --version" + changed_when: false + when: + - not consul_force_install + - consul_binary_installed.stat.exists + register: consul_installed_version + +- name: Calculate whether to install consul binary + set_fact: + consul_install_binary: "{{ consul_force_install or \ + not consul_binary_installed.stat.exists or \ + consul_installed_version.stdout_lines[0] != _consul_expected_version_string }}" + +- name: Install OS packages and consul - locally + include_tasks: install.yml + when: + - consul_install_binary | bool + - not consul_install_remotely | bool + - not consul_install_from_repo | bool + +- name: Install OS packages and consul - remotely + include_tasks: install_remote.yml + when: + - consul_install_binary | bool + - consul_install_remotely | bool + - not consul_install_from_repo | bool + +# XXX: Individual gossip tasks are deprecated and need to be removed +# - include_tasks: ../tasks/encrypt_gossip.yml +- block: + - block: + - name: Check for gossip encryption key on previously boostrapped server + slurp: + src: "{{ consul_config_path }}/config.json" + register: consul_config_b64 + ignore_errors: true + + - name: Deserialize existing configuration + set_fact: + consul_config: "{{ consul_config_b64.content | b64decode | from_json }}" + when: consul_config_b64.content is defined + + - name: Save gossip encryption key from existing configuration + set_fact: + consul_raw_key: "{{ consul_config.encrypt }}" + when: consul_config is defined + + no_log: true + when: + - consul_raw_key is not defined + - bootstrap_state.stat.exists | bool + - inventory_hostname in consul_servers + + # Key provided by extra vars or the above block + - name: Write gossip encryption key locally for use with new servers + copy: + content: "{{ consul_raw_key }}" + dest: '/tmp/consul_raw.key' + mode: 0600 + become: false + vars: + ansible_become: false + no_log: true + delegate_to: localhost + changed_when: false + when: consul_raw_key is defined + + # Generate new key if none was found + - block: + - name: Generate gossip encryption key + shell: "PATH={{ consul_bin_path }}:$PATH consul keygen" + register: consul_keygen + + - name: Write key locally to share with other nodes + copy: + content: "{{ consul_keygen.stdout }}" + dest: '/tmp/consul_raw.key' + become: false + vars: + ansible_become: false + delegate_to: localhost + + no_log: true + run_once: true + when: + # if files '/tmp/consul_raw.key' exist + - lookup('first_found', dict(files=['/tmp/consul_raw.key'], skip=true)) | ternary(false, true) + - not bootstrap_state.stat.exists | bool + + - name: Read gossip encryption key for servers that require it + set_fact: + consul_raw_key: "{{ lookup('file', '/tmp/consul_raw.key') }}" + no_log: true + when: + - consul_raw_key is not defined + + - name: Delete gossip encryption key file + file: + path: '/tmp/consul_raw.key' + state: absent + become: false + vars: + ansible_become: false + run_once: true + delegate_to: localhost + changed_when: false + no_log: true + when: + - consul_encrypt_enable | bool + +- name: Create ACL configuration + include_tasks: acl.yml + when: consul_acl_enable | bool + +- name: Create Consul configuration + import_tasks: config.yml + +- name: Create TLS configuration + include_tasks: tls.yml + when: consul_tls_enable | bool + +- name: Create syslog configuration + import_tasks: syslog.yml + +- name: Create BSD init script + template: + src: consul_bsdinit.j2 + dest: /etc/rc.d/consul + owner: root + group: wheel + mode: 0755 + when: ansible_os_family == "FreeBSD" + +- name: Create SYSV init script + template: + src: consul_sysvinit.j2 + dest: /etc/init.d/consul + owner: root + group: root + mode: 0755 + when: + - not ansible_service_mgr == "systemd" + - not ansible_os_family == "Debian" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - not ansible_os_family == "Darwin" + +- name: Create Debian init script + template: + src: consul_debianinit.j2 + dest: /etc/init.d/consul + owner: root + group: root + mode: 0755 + when: + - not ansible_service_mgr == "systemd" + - ansible_os_family == "Debian" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - not ansible_os_family == "Darwin" + +- name: Create systemd script + template: + src: consul_systemd.service.j2 + dest: "{{ consul_systemd_unit_path }}/consul.service" + owner: root + group: root + mode: 0644 + register: systemd_unit + notify: restart consul + when: + - ansible_service_mgr == "systemd" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - not ansible_os_family == "Darwin" + - not consul_install_from_repo | bool + +- name: Reload systemd + systemd: + daemon_reload: true + when: systemd_unit is changed + +- name: Enable consul at startup (systemd) + systemd: + name: consul + enabled: true + when: + - ansible_service_mgr == "systemd" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - not ansible_os_family == "Darwin" + +- name: Create launchctl plist file + template: + src: "consul_launchctl.plist.j2" + dest: "{{ consul_launchctl_plist }}" + mode: "0644" + validate: "plutil -lint %s" + when: ansible_os_family == "Darwin" + notify: restart consul + +- name: Create smf manifest + template: + src: consul_smf_manifest.j2 + dest: "{{ consul_smf_manifest }}" + owner: root + group: root + mode: 0644 + when: ansible_os_family == "Solaris" + register: smfmanifest + +- name: Import smf manifest + shell: "svccfg import {{ consul_smf_manifest }}" + when: + - smfmanifest is changed + - ansible_os_family == "Solaris" + tags: skip_ansible_lint +- name: Import smf script + shell: "svcadm refresh consul" + when: + - smfmanifest is changed + - ansible_os_family == "Solaris" + tags: skip_ansible_lint + +- name: Enable Consul Snapshots on servers + include_tasks: snapshot.yml + when: + - ansible_service_mgr == "systemd" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - not ansible_os_family == "Darwin" + - consul_snapshot | bool + +- block: + + - name: Start Consul + service: + name: consul + state: started + enabled: true + + - name: Check Consul HTTP API (via TCP socket) + wait_for: + delay: 15 + port: "{{ consul_ports.http|int }}" + host: "{{ consul_addresses.http }}" + when: (consul_ports.http|int > -1) and (consul_addresses.http|ansible.utils.ipaddr) + + - name: Check Consul HTTP API (via unix socket) + wait_for: + delay: 15 + path: "{{ consul_addresses.http | replace('unix://', '', 1) }}" + when: consul_addresses.http is match("unix://*") + + - name: Create bootstrapped state file + file: + dest: "{{ consul_bootstrap_state }}" + state: touch + mode: 0600 + + - include_tasks: ../tasks/iptables.yml + when: consul_iptables_enable | bool + + when: + - not bootstrap_state.stat.exists + - not ansible_os_family == "Darwin" + +- include_tasks: ../tasks/dnsmasq.yml + when: consul_dnsmasq_enable | bool diff --git a/roles/consul/tasks/services.yml b/roles/consul/tasks/services.yml new file mode 100644 index 000000000..9e0b125ae --- /dev/null +++ b/roles/consul/tasks/services.yml @@ -0,0 +1,102 @@ +--- +## File: services.yml - services configuration + +- name: Configure consul services + template: + dest: "{{ consul_configd_path }}/service_{{ service_item.id }}.json" + src: service.json.j2 + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0644 + with_items: "{{ consul_services }}" + loop_control: + loop_var: service_item + notify: + - restart consul + +- name: Get the list of service config files + find: + paths: "{{ consul_configd_path }}" + file_type: file + register: services_enabled_unix + when: ansible_os_family != 'Windows' + +- name: Get the list of service config files [Windows] + win_find: + paths: "{{ consul_configd_path }}" + file_type: file + register: services_enabled_windows + when: ansible_os_family == 'Windows' + +- name: Set var for enabled services + set_fact: + services_enabled_files: "{{ services_enabled_unix['files'] }}" + when: ansible_os_family != 'Windows' + +- name: Set var for enabled services [Windows] + set_fact: + services_enabled_files: "{{ services_enabled_windows['files'] }}" + when: ansible_os_family == 'Windows' + +- name: Set fact with list of existing configuration files + set_fact: + list_current_service_config: "{{ list_current_service_config |default([]) + [ config_file_item.path ] }}" + with_items: "{{ services_enabled_files }}" + loop_control: + loop_var: config_file_item + +- name: Set fact with list of services we manage + set_fact: + managed_files: "{{ managed_files |default([]) }} + \ + [ '{{ consul_configd_path }}/service_{{ service_item.id }}.json' ]" + with_items: "{{ consul_services }}" + loop_control: + loop_var: service_item + when: ansible_os_family != 'Windows' + +- name: Find all service config files that we manage [Windows] + win_stat: + path: "{{ consul_configd_path }}/service_{{ service_config_item.id }}.json" + with_items: "{{ consul_services }}" + loop_control: + loop_var: service_config_item + register: managed_files_win_paths + when: ansible_os_family == 'Windows' + +- name: Set fact with list of services we manage [Windows] + set_fact: + managed_files: "{{ managed_files | default([]) }} + [ '{{ service_item.stat.path }}' ]" + with_items: "{{ managed_files_win_paths.results }}" + loop_control: + loop_var: service_item + when: ansible_os_family == 'Windows' + +- name: Delete non declared services + file: + path: "{{ non_declared_service_item }}" + state: absent + when: + - ansible_os_family != 'Windows' + - non_declared_service_item not in managed_files + - non_declared_service_item not in consul_cleanup_ignore_files + with_items: "{{ list_current_service_config }}" + loop_control: + loop_var: non_declared_service_item + ignore_errors: "{{ ansible_check_mode }}" + notify: + - restart consul + +- name: Delete non declared services [Windows] + win_file: + path: "{{ non_declared_service_item }}" + state: absent + when: + - ansible_os_family == 'Windows' + - non_declared_service_item not in managed_files + - non_declared_service_item not in consul_cleanup_ignore_files + with_items: "{{ list_current_service_config }}" + loop_control: + loop_var: non_declared_service_item + ignore_errors: "{{ ansible_check_mode }}" + notify: + - restart consul diff --git a/roles/consul/tasks/snapshot.yml b/roles/consul/tasks/snapshot.yml new file mode 100644 index 000000000..d248f1b3b --- /dev/null +++ b/roles/consul/tasks/snapshot.yml @@ -0,0 +1,53 @@ +--- +# File: snapshot.yml - Create snapshot service +# template: consul_snapshot.service +# template: consul_snapshot.config /etc/consul/ +# set snaps to {{ snap storage location }} +# create snaps folder +# handler: start / enable service +# add entry to tasks/main.yml +# update readme +# update defaults/main.yml +# update my vars file + +- name: Create snapshot systemd script + template: + src: consul_systemd_snapshot.service.j2 + dest: /lib/systemd/system/consul_snapshot.service + owner: root + group: root + mode: 0644 + register: systemd_unit + notify: start snapshot + when: + - ansible_service_mgr == "systemd" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - consul_snapshot | bool + +- name: Create snapshot agent config + template: + src: consul_snapshot.json.j2 + dest: "{{ consul_config_path }}/consul_snapshot.json" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0644 + notify: start snapshot + when: + - ansible_service_mgr == "systemd" + - not ansible_os_family == "FreeBSD" + - not ansible_os_family == "Solaris" + - consul_snapshot | bool + +- name: Reload systemd + systemd: + daemon_reload: true + when: systemd_unit | changed + +- name: Create snaps storage folder + file: + state: directory + path: "{{ consul_snapshot_storage }}" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0744 diff --git a/roles/consul/tasks/syslog.yml b/roles/consul/tasks/syslog.yml new file mode 100644 index 000000000..f607079e7 --- /dev/null +++ b/roles/consul/tasks/syslog.yml @@ -0,0 +1,42 @@ +--- +# File: syslog.yml - syslog config for Consul logging + +- name: Detect syslog program + stat: + path: /usr/sbin/syslog-ng + register: stat_syslogng + when: + - ansible_os_family != 'Windows' + - consul_configure_syslogd | bool + +- name: Install syslog-ng config + template: + src: syslogng_consul.conf.j2 + dest: /etc/syslog-ng/conf.d/consul.conf + owner: root + group: root + mode: 0444 + when: + - ansible_os_family != 'Windows' + - consul_syslog_enable | bool + - consul_configure_syslogd | bool + - stat_syslogng.stat.exists + notify: + - restart syslog-ng + - restart consul + +- name: Install rsyslogd config + template: + src: rsyslogd_00-consul.conf.j2 + dest: /etc/rsyslog.d/00-consul.conf + owner: root + group: root + mode: 0444 + when: + - ansible_os_family != 'Windows' + - consul_syslog_enable | bool + - consul_configure_syslogd | bool + - not stat_syslogng.stat.exists + notify: + - restart rsyslog + - restart consul diff --git a/roles/consul/tasks/tls.yml b/roles/consul/tasks/tls.yml new file mode 100644 index 000000000..aafdc14d3 --- /dev/null +++ b/roles/consul/tasks/tls.yml @@ -0,0 +1,49 @@ +--- +# File: tls.yml - TLS tasks for Consul + +- block: + - name: Create SSL directory + file: + dest: "{{ consul_tls_dir }}" + state: directory + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0755 + + - name: Copy CA certificate + copy: + remote_src: "{{ consul_tls_files_remote_src }}" + src: "{{ consul_tls_ca_crt }}" + dest: "{{ consul_tls_dir }}/{{ consul_tls_ca_crt | basename }}" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0644 + notify: restart consul + + when: + - consul_tls_copy_keys | bool + +- block: + - name: Copy server certificate + copy: + remote_src: "{{ consul_tls_files_remote_src }}" + src: "{{ consul_tls_server_crt }}" + dest: "{{ consul_tls_dir }}/{{ consul_tls_server_crt | basename }}" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0644 + notify: restart consul + + - name: Copy server key + copy: + remote_src: "{{ consul_tls_files_remote_src }}" + src: "{{ consul_tls_server_key }}" + dest: "{{ consul_tls_dir }}/{{ consul_tls_server_key | basename }}" + owner: "{{ consul_user }}" + group: "{{ consul_group }}" + mode: 0600 + notify: restart consul + + when: + - consul_tls_copy_keys | bool + - auto_encrypt is not defined or (auto_encrypt is defined and not auto_encrypt.enabled | bool) or (consul_node_role != 'client') | bool diff --git a/roles/consul/tasks/user_group.yml b/roles/consul/tasks/user_group.yml new file mode 100644 index 000000000..bf94c8daa --- /dev/null +++ b/roles/consul/tasks/user_group.yml @@ -0,0 +1,22 @@ +--- +# File: user_group.yml - User and group settings + +# Add group +- name: Add Consul group + group: + name: "{{ consul_group }}" + state: present + when: + - consul_manage_group | bool + - not consul_install_from_repo | bool + +# Add user +- name: Add Consul user + user: + name: "{{ consul_user }}" + comment: "Consul user" + group: "{{ consul_group }}" + system: true + when: + - consul_manage_user | bool + - not consul_install_from_repo | bool diff --git a/roles/consul/tasks/windows.yml b/roles/consul/tasks/windows.yml new file mode 100644 index 000000000..2ce4b7a93 --- /dev/null +++ b/roles/consul/tasks/windows.yml @@ -0,0 +1,197 @@ +--- +# Gathers facts (bind address) from servers not currently targeted. +# 'delegate_facts' is currently rather buggy in Ansible so this might not +# always work. Hence 'consul_gather_server_facts' defaults to 'no'. +- name: (Windows) Gather facts from other servers + setup: + delegate_to: "{{ host_item }}" + delegate_facts: true + with_items: "{{ consul_servers | difference(play_hosts) }}" + loop_control: + loop_var: host_item + ignore_errors: true + when: consul_gather_server_facts | bool + +- name: (Windows) Expose bind_address, datacenter and node_role as facts + set_fact: + consul_bind_address: "{{ consul_bind_address }}" + consul_datacenter: "{{ consul_datacenter }}" + consul_node_role: "{{ consul_node_role }}" + +- name: (Windows) Read bootstrapped state + win_stat: + path: "{{ consul_bootstrap_state }}" + register: bootstrap_state + ignore_errors: true + tags: always + +- name: (Windows) Include directory settings + import_tasks: dirs.yml + +- name: (Windows) Check for existing Consul binary + win_stat: + path: "{{ consul_binary }}" + register: consul_binary_installed + +- name: (Windows) Get current Consul version + win_command: "{{ consul_binary }} --version" + changed_when: false + when: + - not consul_force_install + - consul_binary_installed.stat.exists + register: consul_installed_version + +- name: (Windows) Calculate whether to install consul binary + set_fact: + consul_install_binary: "{{ consul_force_install or \ + not consul_binary_installed.stat.exists or \ + consul_installed_version.stdout_lines[0] != _consul_expected_version_string }}" + +- name: (Windows) Install OS packages and consul + include_tasks: install_windows.yml + when: consul_install_binary | bool + +- block: + - block: + - name: (Windows) Check for gossip encryption key on previously boostrapped server + slurp: + src: "{{ consul_config_path }}/config.json" + register: consul_config_b64 + ignore_errors: true + + - name: (Windows) Deserialize existing configuration + set_fact: + consul_config: "{{ consul_config_b64.content | b64decode | from_json }}" + when: consul_config_b64.content is defined + + - name: (Windows) Save gossip encryption key from existing configuration + set_fact: + consul_raw_key: "{{ consul_config.encrypt }}" + when: consul_config is defined + + no_log: true + when: + - consul_raw_key is not defined + - bootstrap_state.stat.exists | bool + - inventory_hostname in consul_servers + + # Key provided by extra vars or the above block + - name: (Windows) Write gossip encryption key locally for use with new servers + copy: + content: "{{ consul_raw_key }}" + dest: '/tmp/consul_raw.key' + mode: 0600 + become: false + vars: + ansible_become: false + no_log: true + run_once: true + register: consul_local_key + delegate_to: localhost + when: consul_raw_key is defined + + # Generate new key if non was found + - block: + + - name: (Windows) Generate gossip encryption key + win_shell: "{{ consul_binary }} keygen" + register: consul_keygen + + - name: (Windows) Write key locally to share with other nodes + copy: + content: "{{ consul_keygen.stdout }}" + dest: '/tmp/consul_raw.key' + mode: 0600 + become: false + vars: + ansible_become: false + delegate_to: localhost + + no_log: true + run_once: true + when: + - not consul_local_key.changed + - not bootstrap_state.stat.exists | bool + + - name: (Windows) Read gossip encryption key for servers that require it + set_fact: + consul_raw_key: "{{ lookup('file', '/tmp/consul_raw.key') }}" + no_log: true + when: + - consul_raw_key is not defined + + - name: (Windows) Delete gossip encryption key file + file: + path: '/tmp/consul_raw.key' + state: absent + become: false + vars: + ansible_become: false + run_once: true + delegate_to: localhost + no_log: true + when: + - consul_encrypt_enable + +- name: (Windows) Create Consul configuration + import_tasks: config_windows.yml + +- name: (Windows) Ensure neither ACL nor TLS are requested + fail: + msg: "ACL and TLS are not supported on Windows hosts yet." + when: + - (consul_acl_enable | bool) or (consul_tls_enable | bool) + +- name: (Windows) Create ACL configuration + include_tasks: acl.yml + when: consul_acl_enable | bool + +- name: (Windows) Create TLS configuration + include_tasks: tls.yml + when: consul_tls_enable | bool + +- block: + - name: Convert consul_binary from Unix -> Windows + win_stat: + path: "{{ consul_binary }}" + register: consul_binary_win + + - name: Convert consul_config_path from Unix -> Windows + win_stat: + path: "{{ consul_config_path }}" + register: consul_config_path_win + + - name: Convert consul_configd_path from Unix -> Windows + win_stat: + path: "{{ consul_configd_path }}" + register: consul_configd_path_win + + - name: Create Consul as a service + win_service: + name: Consul + path: "{{ consul_binary_win.stat.path }} agent \ + -config-file={{ consul_config_path_win.stat.path }}\\config.json \ + -config-dir={{ consul_configd_path_win.stat.path }}" + display_name: Consul Service + description: Consul + start_mode: auto + state: started + + - name: (Windows) Check Consul HTTP API + win_wait_for: + delay: 5 + port: 8500 + + - name: (Windows) Create bootstrapped state file + win_file: + dest: "{{ consul_bootstrap_state }}" + state: touch + when: ansible_os_family == "Windows" + + - include_tasks: ../tasks/iptables.yml + when: consul_iptables_enable | bool + + when: not bootstrap_state.stat.exists + +- include_tasks: ../tasks/dnsmasq.yml + when: consul_dnsmasq_enable | bool diff --git a/roles/consul/templates/config.json.j2 b/roles/consul/templates/config.json.j2 new file mode 100644 index 000000000..8a9bfdc0c --- /dev/null +++ b/roles/consul/templates/config.json.j2 @@ -0,0 +1,351 @@ +{# This template will be passed through the 'to_nice_json' filter #} +{# The filter fixes whitespace, indentation and comma's on the last item #} +{ + {# Common Settings #} + + {## Node ##} + {% if consul_node_name is defined %} + "node_name": "{{ consul_node_name }}", + {% endif %} + "datacenter": "{{ consul_datacenter }}", + "domain": "{{ consul_domain }}", + {% if consul_alt_domain %} + "alt_domain": "{{ consul_alt_domain }}", + {% endif %} + {% if consul_version is version_compare('0.7.3', '>=') and consul_node_meta | length > 0 %} + "node_meta": {{ consul_node_meta | default({})| to_json }}, + {% endif %} + {# Performance Settings #} + "performance": {{ consul_performance | to_json }}, + + {## Addresses ##} + "bind_addr": "{{ consul_bind_address }}", + "advertise_addr": "{{ consul_advertise_address }}", + "advertise_addr_wan": "{{ consul_advertise_address_wan }}", + "translate_wan_addrs": {{ consul_translate_wan_address | bool | to_json }}, + "client_addr": "{{ consul_client_address }}", + "addresses": { + {% if consul_version is version_compare('0.8.0', '<') %} + "rpc": "{{ consul_addresses.rpc }}", + {% endif %} + "dns": "{{ consul_addresses.dns }}", + "http": "{{ consul_addresses.http }}", + "https": "{{ consul_addresses.https }}", + {% if consul_version is version_compare('1.3.0', '>=') %} + "grpc": "{{ consul_addresses.grpc }}" + {% endif %} + }, + {## Ports Used ##} + "ports": { + {% if consul_version is version_compare('0.8.0', '<') %} + "rpc": {{ consul_ports.rpc}}, + {% endif %} + "dns": {{ consul_ports.dns }}, + "http": {{ consul_ports.http }}, + "https": {{ consul_ports.https }}, + "serf_lan": {{ consul_ports.serf_lan }}, + "serf_wan": {{ consul_ports.serf_wan }}, + "server": {{ consul_ports.server }}, + {% if consul_version is version_compare('1.3.0', '>=') %} + "grpc": {{ consul_ports.grpc }} + {% endif %} + }, + + {## Raft protocol ##} + "raft_protocol": {{ consul_raft_protocol }}, + + {## DNS ##} + {% if consul_recursors | length > 0 %} + "recursors": {{ consul_recursors | to_json }}, + {% endif %} + + {## Agent ##} + "data_dir": "{{ consul_data_path }}", + "log_level": "{{ consul_log_level }}", + {% if consul_syslog_enable | bool %} + "enable_syslog": {{ consul_syslog_enable | bool | to_json }}, + "syslog_facility": "{{ consul_syslog_facility }}", + {% else %} + "log_file": "{{ consul_log_path }}/{{ consul_log_file }}", + "log_rotate_bytes": {{ consul_log_rotate_bytes }}, + "log_rotate_duration": "{{ consul_log_rotate_duration }}", + {% if consul_version is version_compare('1.5.3', '>=') %} + "log_rotate_max_files": {{ consul_log_rotate_max_files }}, + {% endif %} + {% endif %} + "disable_update_check": {{ consul_disable_update_check | bool | to_json }}, + "enable_script_checks": {{ consul_enable_script_checks | bool | to_json }}, + "enable_local_script_checks": {{ consul_enable_local_script_checks | bool | to_json }}, + {% if leave_on_terminate is defined %} + "leave_on_terminate": {{ leave_on_terminate | bool | to_json }}, + {% endif %} + + {## Encryption and TLS ##} + {% if consul_encrypt_enable | bool %} + "encrypt": "{{ consul_raw_key }}", + "encrypt_verify_incoming": {{ consul_encrypt_verify_incoming | bool | to_json }}, + "encrypt_verify_outgoing": {{ consul_encrypt_verify_outgoing | bool | to_json }}, + {% endif %} + {% if consul_disable_keyring_file | bool %} + "disable_keyring_file": true, + {% endif %} + {% if consul_tls_enable | bool %} + {% if consul_version is version_compare('1.12.0', '>=') %} + "tls": { + "defaults": { + "ca_file": "{{ consul_tls_dir }}/{{ consul_tls_ca_crt | basename }}", + {% if auto_encrypt is not defined or (auto_encrypt is defined and not auto_encrypt.enabled | bool) + or (config_item.config_version != 'client') | bool %} + "cert_file": "{{ consul_tls_dir }}/{{ consul_tls_server_crt | basename }}", + "key_file": "{{ consul_tls_dir }}/{{ consul_tls_server_key | basename }}", + "verify_incoming": {{ consul_tls_verify_incoming | bool | to_json }}, + {% else %} + "verify_incoming": false, + {% endif %} + "verify_outgoing": {{ consul_tls_verify_outgoing | bool | to_json }}, + "tls_min_version": "{{ consul_tls_min_version }}", + {% if consul_tls_cipher_suites is defined and consul_tls_cipher_suites %} + "tls_cipher_suites": "{{ consul_tls_cipher_suites}}", + {% endif %} + }, + {% if consul_tls_verify_incoming_rpc is defined or consul_tls_verify_server_hostname is defined %} + "internal_rpc": { + "verify_incoming": {{consul_tls_verify_incoming_rpc | bool| to_json }}, + "verify_server_hostname": {{ consul_tls_verify_server_hostname | bool | to_json }}, + }, + {% endif %} + {% if consul_tls_verify_incoming_https is defined %} + "https": { + "verify_incoming": {{consul_tls_verify_incoming_https | bool| to_json }}, + }, + {% endif %} + }, + {% else %} + "ca_file": "{{ consul_tls_dir }}/{{ consul_tls_ca_crt | basename }}", + {% if auto_encrypt is not defined or (auto_encrypt is defined and not auto_encrypt.enabled | bool) + or (config_item.config_version != 'client') | bool %} + "cert_file": "{{ consul_tls_dir }}/{{ consul_tls_server_crt | basename }}", + "key_file": "{{ consul_tls_dir }}/{{ consul_tls_server_key | basename }}", + "verify_incoming": {{ consul_tls_verify_incoming | bool | to_json }}, + {% else %} + "verify_incoming": false, + {% endif %} + "verify_outgoing": {{ consul_tls_verify_outgoing | bool | to_json }}, + "verify_incoming_rpc": {{consul_tls_verify_incoming_rpc | bool| to_json }}, + "verify_incoming_https": {{consul_tls_verify_incoming_https | bool| to_json }}, + "verify_server_hostname": {{ consul_tls_verify_server_hostname | bool | to_json }}, + "tls_min_version": "{{ consul_tls_min_version }}", + {% if consul_tls_cipher_suites is defined and consul_tls_cipher_suites %} + "tls_cipher_suites": "{{ consul_tls_cipher_suites}}", + {% endif %} + {% if consul_version is version_compare('1.11.0', '<') %} + "tls_prefer_server_cipher_suites": {{ consul_tls_prefer_server_cipher_suites | bool | to_json }}, + {% endif %} + {% endif %} + {% if auto_encrypt is defined %} + "auto_encrypt": { + {% if auto_encrypt.enabled | bool and (config_item.config_version != 'client') | bool %} + "allow_tls": true, + {% endif %} + {% if auto_encrypt.enabled | bool and (config_item.config_version == 'client') | bool %} + "tls": true, + {% endif %} + {% if auto_encrypt.dns_san is defined %} + "dns_san": {{ auto_encrypt.dns_san | list | to_json }}, + {% endif %} + {% if auto_encrypt.ip_san is defined %} + "ip_san": {{ auto_encrypt.ip_san | list | to_json }}, + {% endif %} + }, + {% endif %} + {% endif %} + + {## LAN Join ##} + "retry_interval": "{{ consul_retry_interval }}", + "retry_max": {{ consul_retry_max | int }}, + + "retry_join": + {% if not consul_cloud_autodiscovery | bool %} + {% if not consul_retry_join_skip_hosts %} + {% for server in _consul_lan_servers %} + {% set _ = consul_join.append(hostvars[server]['consul_advertise_address'] | default(hostvars[server]['consul_bind_address']) | default(hostvars[server]['ansible_default_ipv4']['address']) | mandatory) %} + {% endfor %} + {% endif %} + {{ consul_join | map('ansible.utils.ipwrap') | list | to_json }}, + {% else %} + ["{{ consul_cloud_autodiscovery_string }}"], + {% endif %} + + {## Server/Client ##} + "server": {{ (config_item.config_version != 'client') | bool | to_json }}, + + {## Enable Connect on Server ##} + {% if consul_connect_enabled | bool %} + "connect": { + "enabled": true + }, + {% endif %} + + {# Client Settings #} + {% if (config_item.config_version == 'client') %} + {## ACLs ##} + {% if consul_acl_enable | bool %} + {% if consul_version is version_compare('1.4.0', '>=') %} + "primary_datacenter": "{{ consul_acl_datacenter }}", + "acl": { + "enabled": true, + "default_policy": "{{ consul_acl_default_policy }}", + "down_policy": "{{ consul_acl_down_policy }}", + "token_ttl": "{{ consul_acl_ttl }}", + "enable_token_persistence": {{ consul_acl_token_persistence | bool | to_json}}, + "tokens": { + {% if consul_acl_token | trim != '' %} + "default": "{{ consul_acl_token }}", + {% endif %} + {% if consul_acl_agent_token | trim != '' %} + "agent": "{{ consul_acl_agent_token }}", + {% endif %} + {% if consul_acl_agent_master_token | trim != '' %} + {% if consul_version is version_compare('1.11.0', '>=') %} + "agent_recovery": "{{ consul_acl_agent_master_token }}", + {% else %} + "agent_master": "{{ consul_acl_agent_master_token }}", + {% endif %} + {% endif %} + } + }, + {% else %} + {% if consul_acl_token | trim != '' %} + "acl_token": "{{ consul_acl_token }}", + {% endif %} + {% if consul_acl_agent_token | trim != '' %} + "acl_agent_token": "{{ consul_acl_agent_token }}", + {% endif %} + {% if consul_acl_agent_master_token | trim != '' %} + "acl_agent_master_token": "{{ consul_acl_agent_master_token }}", + {% endif %} + "acl_ttl": "{{ consul_acl_ttl }}", + "acl_datacenter": "{{ consul_acl_datacenter }}", + "acl_down_policy": "{{ consul_acl_down_policy }}", + {% endif %} + {% endif %} + {% endif %} + + {# Server Settings #} + {% if (config_item.config_version == 'server') or (config_item.config_version == 'bootstrap') %} + + {## Bootstrap settings ##} + "bootstrap": {{ (config_item.config_version == 'bootstrap') | bool | to_json }}, + {% if consul_bootstrap_expect and not (config_item.config_version == 'bootstrap') %} + "bootstrap_expect": {{ consul_bootstrap_expect_value }}, + + {## AutoPilot ##} + {% if consul_autopilot_enable | bool %} + "autopilot": { + "cleanup_dead_servers": {{ consul_autopilot_cleanup_dead_Servers | bool | to_json }}, + "last_contact_threshold": "{{ consul_autopilot_last_contact_threshold }}", + "max_trailing_logs": {{ consul_autopilot_max_trailing_logs }}, + "server_stabilization_time": "{{ consul_autopilot_server_stabilization_time }}"{{ ',' if consul_enterprise else '' }} + {% if consul_enterprise %} + "redundancy_zone_tag": "{{ consul_autopilot_redundancy_zone_tag }}", + "disable_upgrade_migration": {{ consul_autopilot_disable_upgrade_migration | bool | to_json }}, + "upgrade_version_tag": "{{ consul_autopilot_upgrade_version_tag }}" + {% endif %} + }, + {% endif %} + + {% endif %} + + {## WAN Join ##} + "retry_interval_wan": "{{ consul_retry_interval_wan }}", + "retry_max_wan": {{ consul_retry_max_wan | int }}, + + {% if _consul_wan_servercount | int > 0 %} + "retry_join_wan": + {% for server in _consul_wan_servers %} + {% set _ = consul_join_wan.append(hostvars[server]['consul_advertise_address_wan'] | default(hostvars[server]['consul_bind_address'])) %} + {% endfor %} + {{ consul_join_wan | map('ansible.utils.ipwrap') | list | to_json }}, + {% endif %} + + {## ACLs ##} + {% if consul_acl_enable | bool %} + {% if consul_acl_replication_enable | trim != '' %} + "enable_acl_replication": {{ consul_acl_replication_enable | bool | to_json }}, + {% endif %} + {% if consul_version is version_compare('1.4.0', '>=') %} + "primary_datacenter": "{{ consul_acl_datacenter }}", + "acl": { + "enabled": true, + "default_policy": "{{ consul_acl_default_policy }}", + "down_policy": "{{ consul_acl_down_policy }}", + "token_ttl": "{{ consul_acl_ttl }}", + "enable_token_persistence": {{ consul_acl_token_persistence | bool | to_json}}, + "tokens": { + {% if consul_acl_token | trim != '' %} + "default": "{{ consul_acl_token }}", + {% endif %} + {% if consul_acl_agent_token | trim != '' %} + "agent": "{{ consul_acl_agent_token }}", + {% endif %} + {% if consul_acl_agent_master_token | trim != '' %} + {% if consul_version is version_compare('1.11.0', '>=') %} + "agent_recovery": "{{ consul_acl_agent_master_token }}", + {% else %} + "agent_master": "{{ consul_acl_agent_master_token }}", + {% endif %} + {% endif %} + {% if consul_version is version_compare('0.9.1', '<') or consul_acl_master_token | trim != '' %} + {% if consul_version is version_compare('1.11.0', '>=') %} + "initial_management": "{{ consul_acl_master_token }}", + {% else %} + "master": "{{ consul_acl_master_token }}", + {% endif %} + {% endif %} + {% if consul_acl_replication_token | trim != '' %} + "replication": "{{ consul_acl_replication_token }}", + {% endif %} + } + }, + {% else %} + {% if consul_acl_token | trim != '' %} + "acl_token": "{{ consul_acl_token }}", + {% endif %} + {% if consul_acl_agent_token | trim != '' %} + "acl_agent_token": "{{ consul_acl_agent_token }}", + {% endif %} + {% if consul_acl_agent_master_token | trim != '' %} + "acl_agent_master_token": "{{ consul_acl_agent_master_token }}", + {% endif %} + "acl_ttl": "{{ consul_acl_ttl }}", + "acl_datacenter": "{{ consul_acl_datacenter }}", + "acl_down_policy": "{{ consul_acl_down_policy }}", + {% if consul_version is version_compare('0.9.1', '<') or + consul_acl_master_token | trim != '' %} + "acl_master_token": "{{ consul_acl_master_token }}", + {% endif %} + {% if consul_acl_replication_enable | trim != '' %} + "enable_acl_replication": {{ consul_acl_replication_enable | bool | to_json }}, + {% endif %} + {% if consul_acl_replication_token | trim != '' %} + "acl_replication_token": "{{ consul_acl_replication_token }}", + {% endif %} + "acl_default_policy": "{{ consul_acl_default_policy }}", + {% endif %} + {% endif %} + {% endif %} + + {## Limits ##} + {% if consul_version is version_compare('0.9.3', '>=') and consul_limits | length > 0 %} + "limits": {{ consul_limits | default({})| to_json }}, + {% endif %} + + {## UI ##} + {% if consul_version is version_compare('1.9.0', '>=') %} + "ui_config": { + "enabled": {{ consul_ui | bool | to_json }} + } + {% else %} + "ui": {{ consul_ui | bool | to_json }} + {% endif %} +} diff --git a/roles/consul/templates/configd_50acl_policy.hcl.j2 b/roles/consul/templates/configd_50acl_policy.hcl.j2 new file mode 100644 index 000000000..557a7859c --- /dev/null +++ b/roles/consul/templates/configd_50acl_policy.hcl.j2 @@ -0,0 +1,44 @@ +# Default all keys to read-only +key "" { + policy = "read" +} +key "foo/" { + policy = "write" +} +key "foo/private/" { + # Deny access to the dir "foo/private" + policy = "deny" +} + +# Default all services to allow registration. Also permits all +# services to be discovered. +service "" { + policy = "write" +} + +# Deny registration access to services prefixed "secure-". +# Discovery of the service is still allowed in read mode. +service "secure-" { + policy = "read" +} + +# Allow firing any user event by default. +event "" { + policy = "write" +} + +# Deny firing events prefixed with "destroy-". +event "destroy-" { + policy = "deny" +} + +# Default prepared queries to read-only. +query "" { + policy = "read" +} + +# Read-only mode for the encryption keyring by default (list only) +keyring = "read" + +# Read-only mode for Consul operator interfaces (list only) +operator = "read" \ No newline at end of file diff --git a/roles/consul/templates/configd_50custom.json.j2 b/roles/consul/templates/configd_50custom.json.j2 new file mode 100644 index 000000000..ed892645b --- /dev/null +++ b/roles/consul/templates/configd_50custom.json.j2 @@ -0,0 +1,6 @@ +{# consul_config_custom variables are free-style, passed through a hash -#} +{% if consul_config_custom -%} +{{ consul_config_custom | to_nice_json }} +{% else %} +{} +{% endif %} \ No newline at end of file diff --git a/roles/consul/templates/consul_bsdinit.j2 b/roles/consul/templates/consul_bsdinit.j2 new file mode 100644 index 000000000..46b934fc8 --- /dev/null +++ b/roles/consul/templates/consul_bsdinit.j2 @@ -0,0 +1,49 @@ +#!/bin/sh + +# PROVIDE: consul +# REQUIRE: LOGIN +# KEYWORD: shutdown + +# shellcheck disable=SC1091 +. /etc/rc.subr + +name="consul" +# shellcheck disable=2034 +rcvar=$(set_rcvar) + + +load_rc_config $name +# shellcheck disable=2154 +: "${consul_enable="NO"}" +# shellcheck disable=2154 +: "${consul_users="consul"}" + +# shellcheck disable=2034 +restart_cmd=consul_restart +# shellcheck disable=2034 +start_cmd=consul_start +# shellcheck disable=2034 +stop_cmd=consul_stop + +consul_start() { + echo "Starting ${name}." + for user in ${consul_users}; do + mkdir {{ consul_run_path }} + chown -R "{{ consul_user }}:{{ consul_group }}" {{ consul_run_path }} + su -m "${user}" -c "{{ consul_bin_path }}/consul agent -config-file={{ consul_config_path }}/config.json -config-dir={{ consul_configd_path }} -pid-file={{ consul_run_path }}/consul.pid&" + done +} + +consul_stop() { + echo "Stopping $name." + pids=$(pgrep consul) + pkill consul + wait_for_pids "${pids}" +} + +consul_restart() { + consul_stop + consul_start +} + +run_rc_command "$1" diff --git a/roles/consul/templates/consul_debianinit.j2 b/roles/consul/templates/consul_debianinit.j2 new file mode 100644 index 000000000..0537754b3 --- /dev/null +++ b/roles/consul/templates/consul_debianinit.j2 @@ -0,0 +1,129 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: consul +# Required-Start: $local_fs $remote_fs +# Required-Stop: $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: S 0 1 6 +# Short-Description: Distributed service discovery framework +# Description: Distributed service discovery / health check framework +### END INIT INFO + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script + +PATH="{{ consul_bin_path }}:/usr/sbin:/usr/bin:/sbin:/bin" +DESC="Consul service discovery framework" +NAME="consul" +DAEMON="{{ consul_bin_path }}/${NAME}" +PIDFILE="{{ consul_run_path }}/${NAME}.pid" +DAEMON_ARGS="agent -config-file={{ consul_config_path }}/config.json -config-dir={{ consul_configd_path }}" +USER={{ consul_user }} +SCRIPTNAME=/etc/init.d/"${NAME}" + +# Exit if Consul is not installed +[ -x "${DAEMON}" ] || exit 0 + +# Read default variables file +[ -r /etc/default/"${NAME}" ] && . /etc/default/"${NAME}" + +# Source rcS variables +[ -f /etc/default/rcS ] && . /etc/default/rcS + +# Source LSB functions +. /lib/lsb/init-functions + +# Make sure PID dir exists +mkrundir() { + [ ! -d {{ consul_run_path }} ] && mkdir -p {{ consul_run_path }} + chown {{ consul_user }} {{ consul_run_path }} +} + +# Start the Consul service +do_start() { + echo "Starting consul and backgrounding" + mkrundir + start-stop-daemon --start --quiet --pidfile "${PIDFILE}" --exec "${DAEMON}" --chuid "${USER}" --background --make-pidfile --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile "${PIDFILE}" --exec "${DAEMON}" --chuid "${USER}" --background --make-pidfile -- \ + ${DAEMON_ARGS} \ + || return 2 + + echo -n "Waiting for Consul service..." + for i in `seq 1 30`; do + if ! start-stop-daemon --quiet --stop --test --pidfile "${PIDFILE}" --exec "${DAEMON}" --user "${USER}"; then + echo " FAIL: consul process died" + return 2 + fi + if "${DAEMON}" info >/dev/null; then + echo " OK" + return 0 + fi + echo -n . + sleep 1 + done + echo " FAIL: consul process is alive, but is not listening." + return 2 +} + +# Stop the Consul service +do_stop() { + "${DAEMON}" leave + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile "${PIDFILE}" --name "${NAME}" + RETVAL="$?" + [ "${RETVAL}" = 2 ] && return 2 + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec "${DAEMON}" + [ "$?" = 2 ] && return 2 + rm -f "${PIDFILE}" + return "${RETVAL}" +} + +# Reload Consul +do_reload() { + start-stop-daemon --stop --signal 1 --quiet --pidfile "${PIDFILE}" --name "${NAME}" + return 0 +} + +case "$1" in + start) + [ "${VERBOSE}" != no ] && log_daemon_msg "Starting ${DESC}" "${NAME}" + do_start + case "$?" in + 0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;; + 2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "${VERBOSE}" != no ] && log_daemon_msg "Stopping ${DESC}" "${NAME}" + do_stop + case "$?" in + 0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;; + 2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;; + esac + ;; + restart|force-reload) + log_daemon_msg "Restarting ${DESC}" "${NAME}" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; + *) log_end_msg 1 ;; + esac + ;; + *) + # Stop failed + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: ${SCRIPTNAME} {start|stop|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/roles/consul/templates/consul_launchctl.plist.j2 b/roles/consul/templates/consul_launchctl.plist.j2 new file mode 100644 index 000000000..ed3ddf625 --- /dev/null +++ b/roles/consul/templates/consul_launchctl.plist.j2 @@ -0,0 +1,38 @@ + + + + + EnvironmentVariables + + PATH + {{ consul_bin_path }} + + KeepAlive + + Label + {{ consul_launchctl_ident }} + MachServices + + {{ consul_launchctl_ident }} + + + ProcessType + Background + ProgramArguments + + {{ consul_bin_path }}/consul + agent + -config-file={{ consul_config_path }}/config.json + -config-dir={{ consul_configd_path }} + -pid-file={{ consul_run_path }}/consul.pid + + RunAtLoad + + StandardErrorPath + {{ consul_log_path }}/log.stderr + StandardOutPath + {{ consul_log_path }}/log.stdout + UserName + {{ consul_user }} + + diff --git a/roles/consul/templates/consul_smf_manifest.j2 b/roles/consul/templates/consul_smf_manifest.j2 new file mode 100644 index 000000000..187c8dad1 --- /dev/null +++ b/roles/consul/templates/consul_smf_manifest.j2 @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/roles/consul/templates/consul_snapshot.json.j2 b/roles/consul/templates/consul_snapshot.json.j2 new file mode 100644 index 000000000..66ecebf33 --- /dev/null +++ b/roles/consul/templates/consul_snapshot.json.j2 @@ -0,0 +1,27 @@ +{ +"snapshot_agent": { + "http_addr": "{% if consul_tls_enable | bool %}https://{% endif %}{{ consul_client_address }}:{% if consul_tls_enable | bool %}{{ consul_ports.https }}{% else %}{{ consul_ports.http }}{% endif %}", + {% if consul_tls_enable | bool -%} + "ca_file": "{{ consul_tls_dir }}/{{ consul_tls_ca_crt }}", + "cert_file": "{{ consul_tls_dir }}/{{ consul_tls_server_crt }}", + "key_file": "{{ consul_tls_dir }}/{{ consul_tls_server_key }}", + {% endif %} + "log": { + "level": "INFO", + "enable_syslog": true, + "syslog_facility": "LOCAL0" + }, + "snapshot": { + "interval": "{{ consul_snapshot_interval }}", + "retain": {{ consul_snapshot_retain }}, + "stale": false, + "service": "consul_snapshot", + "deregister_after": "72h", + "lock_key": "consul_snapshot/lock", + "max_failures": 3 + }, + "local_storage": { + "path": "{{ consul_snapshot_storage }}" + } +} +} diff --git a/roles/consul/templates/consul_systemd.service.j2 b/roles/consul/templates/consul_systemd.service.j2 new file mode 100644 index 000000000..0a4883bb8 --- /dev/null +++ b/roles/consul/templates/consul_systemd.service.j2 @@ -0,0 +1,44 @@ +### BEGIN INIT INFO +# Provides: consul +# Required-Start: $local_fs $remote_fs +# Required-Stop: $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Consul agent +# Description: Consul service discovery framework +### END INIT INFO + +[Unit] +Description=Consul agent +Requires=network-online.target +After=network-online.target + +[Service] +User={{ consul_user }} +Group={{ consul_group }} +PIDFile={{ consul_run_path }}/consul.pid +PermissionsStartOnly=true +{% if consul_ui_legacy %} +Environment=CONSUL_UI_LEGACY=true +{% endif %} +ExecStartPre=-/bin/mkdir -m 0750 -p {{ consul_run_path }} +ExecStartPre=/bin/chown -R {{ consul_user }}:{{ consul_group }} {{ consul_run_path }} +ExecStart={{ consul_bin_path }}/consul agent \ + -config-file={{ consul_config_path }}/config.json \ + -config-dir={{ consul_configd_path}} \ + -pid-file={{ consul_run_path }}/consul.pid +ExecReload=/bin/kill -HUP $MAINPID +KillMode=process +KillSignal=SIGTERM +Restart={{ consul_systemd_restart }} +RestartSec={{ consul_systemd_restart_sec }}s +StandardOutput=null +StandardError=null +{% for var in consul_env_vars %} +Environment={{ var }} +{% endfor %} +LimitNOFILE={{ consul_systemd_limit_nofile }} +AmbientCapabilities=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target diff --git a/roles/consul/templates/consul_systemd_service.override.j2 b/roles/consul/templates/consul_systemd_service.override.j2 new file mode 100644 index 000000000..642704ab9 --- /dev/null +++ b/roles/consul/templates/consul_systemd_service.override.j2 @@ -0,0 +1,10 @@ +# WARNING!!! Ansible managed. + +[Unit] +ConditionFileNotEmpty= +ConditionFileNotEmpty={{ consul_config_path }}/config.json + +[Service] +ExecStart= +ExecStart=/usr/bin/consul agent -config-file={{ consul_config_path }}/config.json -config-dir={{ consul_configd_path }} + diff --git a/roles/consul/templates/consul_systemd_snapshot.service.j2 b/roles/consul/templates/consul_systemd_snapshot.service.j2 new file mode 100644 index 000000000..0fa70df8a --- /dev/null +++ b/roles/consul/templates/consul_systemd_snapshot.service.j2 @@ -0,0 +1,33 @@ +### BEGIN INIT INFO +# Provides: consul +# Required-Start: $local_fs $remote_fs +# Required-Stop: $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Consul snapshot agent +# Description: Consul service snapshot agent +### END INIT INFO + +[Unit] +Description=Consul snapshot agent +Requires=network-online.target +Requisite=consul.service +After=network-online.target + +[Service] +User={{ consul_user }} +Group={{ consul_group }} +PIDFile={{ consul_run_path }}/consul_snapshot.pid +PermissionsStartOnly=true +ExecStart={{ consul_bin_path }}/consul snapshot agent \ +-config-file={{ consul_config_path }}/consul_snapshot.json +ExecReload=/bin/kill -HUP $MAINPID +KillSignal=SIGTERM +Restart={{ consul_systemd_restart }} +RestartSec=42s +{% for var in consul_env_vars %} +Environment={{ var }} +{% endfor %} + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/consul/templates/consul_sysvinit.j2 b/roles/consul/templates/consul_sysvinit.j2 new file mode 100644 index 000000000..895e2b538 --- /dev/null +++ b/roles/consul/templates/consul_sysvinit.j2 @@ -0,0 +1,96 @@ +#!/bin/bash +# +# chkconfig: 2345 95 95 +# description: Consul service discovery framework +# processname: consul +# pidfile: {{ consul_run_path }}/consul.pid + +{% if ansible_distribution == "Ubuntu" %} +. /lib/lsb/init-functions +{% else %} +. /etc/init.d/functions +{% endif %} + +CONSUL={{ consul_bin_path }}/consul +CONFIG={{ consul_config_path }}/config.json +CONFIGD={{ consul_configd_path }} +PID_FILE={{ consul_run_path }}/consul.pid +LOCK_FILE=/var/lock/subsys/consul +{% if consul_ui_legacy %} +CONSUL_UI_LEGACY=true +{% endif %} + +[ -e /etc/sysconfig/consul ] && . /etc/sysconfig/consul + +export GOMAXPROCS=$(nproc) + +mkrundir() { + [ ! -d {{ consul_run_path }} ] && mkdir -p {{ consul_run_path }} + chown {{ consul_user }} {{ consul_run_path }} +} + +KILLPROC_OPT="-p ${PID_FILE}" +mkpidfile() { + mkrundir + [ ! -f "${PID_FILE}" ] && pidofproc "${CONSUL}" > "${PID_FILE}" + chown -R {{ consul_user }} {{ consul_run_path }} + if [ $? -ne 0 ] ; then + rm "${PID_FILE}" + KILLPROC_OPT="" + fi +} + +start() { + echo -n "Starting consul: " + mkrundir + mkpidfile + # [ -f "${PID_FILE}" ] && rm "${PID_FILE}" + daemon --user={{ consul_user }} \ + --pidfile="${PID_FILE}" \ + "${CONSUL}" agent -config-file="${CONFIG}" -config-dir="${CONFIGD}" -pid-file="${PID_FILE}" & + retcode=$? + touch ${LOCK_FILE} + return "${retcode}" +} + +stop() { + echo -n "Shutting down consul: " + if ("${CONSUL}" info 2>/dev/null | grep -q 'server = false' 2>/dev/null) ; then + "${CONSUL}" leave + fi + + mkpidfile + killproc "${KILLPROC_OPT}" "${CONSUL}" -SIGTERM + + retcode=$? + rm -f "${LOCK_FILE}" "${PID_FILE}" + return "${retcode}" +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + "${CONSUL}" info + ;; + restart) + stop + start + ;; + reload) + mkpidfile + killproc "${KILLPROC_OPT}" "${CONSUL}" -HUP + ;; + condrestart) + [ -f ${LOCK_FILE} ] && restart || : + ;; + *) + echo "Usage: consul {start|stop|status|reload|restart}" + exit 1 + ;; +esac +exit $? diff --git a/roles/consul/templates/dnsmasq-10-consul.j2 b/roles/consul/templates/dnsmasq-10-consul.j2 new file mode 100644 index 000000000..1aea4e5d1 --- /dev/null +++ b/roles/consul/templates/dnsmasq-10-consul.j2 @@ -0,0 +1,52 @@ +{# Enable forward lookups for the consul domain with conditional delegation -#} +{% if consul_delegate_datacenter_dns | bool -%} +server=/{{ consul_datacenter }}.{{ consul_domain }}/{{ consul_dnsmasq_consul_address }}#{{ consul_ports.dns }} +{% if consul_alt_domain -%} +server=/{{ consul_datacenter }}.{{ consul_alt_domain }}/{{ consul_dnsmasq_consul_address }}#{{ consul_ports.dns }} +{% endif -%} +{% else %} +server=/{{ consul_domain }}/{{ consul_dnsmasq_consul_address }}#{{ consul_ports.dns }} +{% if consul_alt_domain -%} +server=/{{ consul_alt_domain }}/{{ consul_dnsmasq_consul_address }}#{{ consul_ports.dns }} +{% endif -%} +{% endif -%} + +{# Only bind to specific interfaces -#} +{% if consul_dnsmasq_bind_interfaces | bool -%} +bind-interfaces +{% endif -%} + +{# Reverse DNS lookups -#} +{% for revserver in consul_dnsmasq_revservers -%} + rev-server={{ revserver }},{{ consul_dnsmasq_consul_address }}#{{ consul_ports.dns }} +{% endfor -%} + +{# Only accept DNS queries from hosts in the local subnet -#} +{% if consul_dnsmasq_local_service | bool -%} + local-service +{% endif -%} + +{# Don't poll /etc/resolv.conf for changes -#} +{% if consul_dnsmasq_no_poll | bool -%} + no-poll +{% endif -%} + +{# Dont use /etc/resolv.conf to get upstream servers -#} +{% if consul_dnsmasq_no_resolv | bool -%} + no-resolv +{% endif -%} + +{# Upstream DNS servers -#} +{% for server in consul_dnsmasq_servers -%} + server={{ server }} +{% endfor -%} + +{# Custom listen addresses -#} +{% for address in consul_dnsmasq_listen_addresses -%} + listen-address={{ address }} +{% endfor -%} + +{# Cache size -#} +{% if consul_dnsmasq_cache > 0 -%} + cache-size={{ consul_dnsmasq_cache }} +{% endif -%} diff --git a/roles/consul/templates/rsyslogd_00-consul.conf.j2 b/roles/consul/templates/rsyslogd_00-consul.conf.j2 new file mode 100644 index 000000000..f51db5f1f --- /dev/null +++ b/roles/consul/templates/rsyslogd_00-consul.conf.j2 @@ -0,0 +1 @@ +{{ consul_syslog_facility }}.* {{ consul_log_path }}/{{ consul_log_file }} diff --git a/roles/consul/templates/service.json.j2 b/roles/consul/templates/service.json.j2 new file mode 100644 index 000000000..0db5cf89e --- /dev/null +++ b/roles/consul/templates/service.json.j2 @@ -0,0 +1,39 @@ +{ + "service": { + "name": "{{ service_item.name }}", + {% if service_item.id is defined -%} + "id": "{{ service_item.id }}", + {% endif -%} + {% if service_item.port is defined -%} + "port": {{ service_item.port }}, + {% endif -%} + {% if service_item.address is defined -%} + "address": "{{ service_item.address }}", + {% endif -%} + {% if service_item.enable_tag_override is defined -%} + "enable_tag_override": {{ service_item.enable_tag_override | bool | to_json }}, + {% endif -%} + {% if service_item.kind is defined -%} + "kind": "{{ service_item.kind }}", + {% endif -%} + {% if service_item.proxy is defined -%} + "proxy": {{ service_item.proxy | to_json(sort_keys=True) }}, + {% endif -%} + {% if service_item.meta is defined -%} + "meta": {{ service_item.meta | to_json(sort_keys=True) }}, + {% endif -%} + {% if service_item.checks is defined -%} + "checks": {{ service_item.checks | to_json(sort_keys=True) }}, + {% endif -%} + {% if service_item.connect is defined -%} + "connect": {{ service_item.connect | to_json(sort_keys=True) }}, + {% endif -%} + {% if service_item.weights is defined -%} + "weights": {{ service_item.weights | to_json(sort_keys=True) }}, + {% endif -%} + {% if service_item.token is defined -%} + "token": {{ service_item.token | to_json }}, + {% endif -%} + "tags": {{ service_item.tags|default([])|to_json(sort_keys=True) }} + } +} diff --git a/roles/consul/templates/syslogng_consul.conf.j2 b/roles/consul/templates/syslogng_consul.conf.j2 new file mode 100644 index 000000000..861774464 --- /dev/null +++ b/roles/consul/templates/syslogng_consul.conf.j2 @@ -0,0 +1,3 @@ +destination d_consul { file("{{ consul_log_path }}/{{ consul_log_file }}"); }; +filter f_consul { facility({{ consul_syslog_facility }}); }; +log { source(s_sys); filter(f_consul); destination(d_consul); }; diff --git a/roles/consul/vars/Amazon.yml b/roles/consul/vars/Amazon.yml new file mode 100644 index 000000000..cdf9e7fc3 --- /dev/null +++ b/roles/consul/vars/Amazon.yml @@ -0,0 +1,12 @@ +--- +# File: Amazon.yml - Amazonlinux variables for Consul +consul_os_packages: + - git + - unzip + +consul_syslog_enable: false + +consul_repo_prerequisites: + - yum-utils + +consul_repo_url: https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo diff --git a/roles/consul/vars/Archlinux.yml b/roles/consul/vars/Archlinux.yml new file mode 100644 index 000000000..3fe0aa949 --- /dev/null +++ b/roles/consul/vars/Archlinux.yml @@ -0,0 +1,7 @@ +--- +# File: Archlinux.yml - Archlinux variables for Consul + +consul_os_packages: + - unzip + +consul_syslog_enable: false diff --git a/roles/consul/vars/Darwin.yml b/roles/consul/vars/Darwin.yml new file mode 100644 index 000000000..efddcbd41 --- /dev/null +++ b/roles/consul/vars/Darwin.yml @@ -0,0 +1,16 @@ +--- +# File: MacOSX.yml - Mac OS X variables for Consul + +consul_config_path: "/Users/{{ consul_user }}/Library/Preferences/io.consul" + +consul_configd_path: "{{ consul_config_path }}/consul.d" + +consul_launchctl_ident: "io.consul" + +consul_launchctl_plist: "/Library/LaunchAgents/{{ consul_launchctl_ident }}.plist" + +consul_log_path: "/Users/{{ consul_user }}/Library/Logs/consul" + +consul_os_packages: [] + +consul_run_path: "/Users/{{ consul_user }}/Library/Caches/io.consul" diff --git a/roles/consul/vars/Debian.yml b/roles/consul/vars/Debian.yml new file mode 100644 index 000000000..589562341 --- /dev/null +++ b/roles/consul/vars/Debian.yml @@ -0,0 +1,12 @@ +--- +# File: Debian.yml - Debian OS variables for Consul + +consul_os_packages: + - unzip + +dnsmasq_package: dnsmasq + +consul_repo_prerequisites: + - gpg + +consul_repo_url: "https://apt.releases.hashicorp.com" diff --git a/roles/consul/vars/Flatcar.yml b/roles/consul/vars/Flatcar.yml new file mode 100644 index 000000000..9337bdb05 --- /dev/null +++ b/roles/consul/vars/Flatcar.yml @@ -0,0 +1,6 @@ +--- +# File: Flatcar.yml - Flatcar variables for Consul + +consul_os_packages: [] + +consul_systemd_unit_path: "/etc/systemd/system" diff --git a/roles/consul/vars/FreeBSD.yml b/roles/consul/vars/FreeBSD.yml new file mode 100644 index 000000000..4511196a7 --- /dev/null +++ b/roles/consul/vars/FreeBSD.yml @@ -0,0 +1,7 @@ +--- +# File: FreeBSD.yml - FreeBSD OS variables for Consul + +consul_os_packages: + - unzip + +dnsmasq_package: dnsmasq diff --git a/roles/consul/vars/RedHat-8.yml b/roles/consul/vars/RedHat-8.yml new file mode 100644 index 000000000..c1b1b475d --- /dev/null +++ b/roles/consul/vars/RedHat-8.yml @@ -0,0 +1,7 @@ +--- +# File: RedHat-8.yml - Red Hat OS version 8.x variables for Consul + +consul_os_packages: + - python3-libselinux + - unzip +dnsmasq_package: dnsmasq diff --git a/roles/consul/vars/RedHat.yml b/roles/consul/vars/RedHat.yml new file mode 100644 index 000000000..cf014617f --- /dev/null +++ b/roles/consul/vars/RedHat.yml @@ -0,0 +1,25 @@ +--- +# File: RedHat.yml - Red Hat OS variables for Consul + +consul_os_packages: + - "{% if ( ansible_distribution == 'Fedora' and ansible_distribution_version is version('28', '<') ) or \ + ( ansible_distribution == 'CentOS' and ansible_distribution_version is version('8', '<') ) or \ + ( ansible_distribution == 'Amazon' and ansible_distribution_version is version('3', '<') ) or \ + ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is version('8', '<') ) \ + %}\ + libselinux-python\ + {% else %}\ + python3-libselinux\ + {% endif %}" + - unzip + +consul_repo_prerequisites: + - yum-utils + +consul_repo_url: "{% if ( ansible_distribution == 'Fedora') %}\ + https://rpm.releases.hashicorp.com/fedora/hashicorp.repo\ + {% else %}\ + https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo\ + {% endif %}" + +dnsmasq_package: dnsmasq diff --git a/roles/consul/vars/Rocky-8.yml b/roles/consul/vars/Rocky-8.yml new file mode 100644 index 000000000..a15ecaf66 --- /dev/null +++ b/roles/consul/vars/Rocky-8.yml @@ -0,0 +1,6 @@ +--- +# File: Rocky-8.yml - Rocky Linux version 8.x variables for Consul + +consul_os_packages: + - python3-libselinux + - unzip diff --git a/roles/consul/vars/Solaris.yml b/roles/consul/vars/Solaris.yml new file mode 100644 index 000000000..3a1369565 --- /dev/null +++ b/roles/consul/vars/Solaris.yml @@ -0,0 +1,8 @@ +--- +# File: Solaris.yml - Solaris OS variables for Consul + +consul_os_packages: + - unzip + +consul_pkg: "consul_{{ consul_version }}_solaris_amd64.zip" +consul_smf_manifest: "/opt/local/lib/svc/manifest/consul.xml" diff --git a/roles/consul/vars/VMware Photon OS.yml b/roles/consul/vars/VMware Photon OS.yml new file mode 100644 index 000000000..eb10477ed --- /dev/null +++ b/roles/consul/vars/VMware Photon OS.yml @@ -0,0 +1,3 @@ +--- +consul_os_packages: + - unzip diff --git a/roles/consul/vars/Windows.yml b/roles/consul/vars/Windows.yml new file mode 100644 index 000000000..807e61344 --- /dev/null +++ b/roles/consul/vars/Windows.yml @@ -0,0 +1,17 @@ +--- +# File: Windows.yml - Windows OS variables for Consul + +# paths +consul_windows_path: /ProgramData/consul +consul_bin_path: "{{consul_windows_path}}/bin" +consul_config_path: "{{consul_windows_path}}/config" +consul_configd_path: "{{consul_config_path}}.d/" +consul_bootstrap_state: "{{consul_windows_path}}/.consul_bootstrapped" +consul_data_path: "{{consul_windows_path}}/data" +consul_log_path: "{{consul_windows_path}}/log" +consul_run_path: "{{consul_windows_path}}" +consul_binary: "{{consul_windows_path}}/bin/consul.exe" +consul_syslog_enable: false + +# users +consul_user: LocalSystem diff --git a/roles/consul/vars/main.yml b/roles/consul/vars/main.yml new file mode 100644 index 000000000..24f9e6c94 --- /dev/null +++ b/roles/consul/vars/main.yml @@ -0,0 +1,37 @@ +--- +# Pure internal helper variables + +_consul_lan_servers: "\ + {% set __consul_lan_servers = [] %}\ + {% for server in consul_servers %}\ + {% set _consul_datacenter = hostvars[server]['consul_datacenter'] | default('dc1', true) %}\ + {% if _consul_datacenter == consul_datacenter %}\ + {% if __consul_lan_servers.append(server) %}{% endif %}\ + {% endif %}\ + {% endfor %}\ + {{ __consul_lan_servers }}" +_consul_lan_servercount: "{{ (_consul_lan_servers | length) + (consul_join | length) }}" + +_consul_wan_servers: "\ + {% set __consul_wan_servers = [] %}\ + {% for server in consul_servers %}\ + {% set _consul_datacenter = hostvars[server]['consul_datacenter'] | default('dc1', true) %}\ + {% if _consul_datacenter != consul_datacenter %}\ + {% if __consul_wan_servers.append(server) %}{% endif %}\ + {% endif %}\ + {% endfor %}\ + {{ __consul_wan_servers }}" +_consul_wan_servercount: "{{ (_consul_wan_servers | length) + (consul_join_wan | length) }}" + +_consul_bootstrap_servers: "\ + {% set __consul_bootstrap_servers = [] %}\ + {% for server in _consul_lan_servers %}\ + {% set _consul_node_role = hostvars[server]['consul_node_role'] | default('client', true) %}\ + {% if _consul_node_role == 'bootstrap' %}\ + {% if __consul_bootstrap_servers.append(server) %}{% endif %}\ + {% endif %}\ + {% endfor %}\ + {{ __consul_bootstrap_servers }}" +_consul_bootstrap_server: "{{ _consul_bootstrap_servers[0] }}" + +_consul_expected_version_string: "Consul v{{ consul_version }}" diff --git a/roles/consul/version.txt b/roles/consul/version.txt new file mode 100644 index 000000000..752d2e754 --- /dev/null +++ b/roles/consul/version.txt @@ -0,0 +1 @@ +commit: 6251974 on Nov 15, 2022 diff --git a/roles/deploy-finish/tasks/main.yml b/roles/deploy-finish/tasks/main.yml index 48f76ab1a..6fa5b9285 100644 --- a/roles/deploy-finish/tasks/main.yml +++ b/roles/deploy-finish/tasks/main.yml @@ -59,7 +59,7 @@ ignore_errors: true tags: databases, db_list, cluster_info, cluster_status, point_in_time_recovery -- block: +- block: # if cluster_vip is defined - name: PostgreSQL Cluster connection info run_once: true debug: @@ -71,8 +71,9 @@ - port {{ haproxy_listen_port.replicas_sync }} (read only) synchronous replica only - port {{ haproxy_listen_port.replicas_async }} (read only) asynchronous replicas only - +------------------------------------------------+ - when: with_haproxy_load_balancing|bool and - synchronous_mode|bool + when: + - with_haproxy_load_balancing | bool + - synchronous_mode | bool - name: PostgreSQL Cluster connection info run_once: true @@ -83,8 +84,9 @@ - port {{ haproxy_listen_port.master }} (read/write) master - port {{ haproxy_listen_port.replicas }} (read only) all replicas - +------------------------------------------------+ - when: with_haproxy_load_balancing|bool and - not synchronous_mode|bool + when: + - with_haproxy_load_balancing | bool + - not synchronous_mode | bool - name: PostgreSQL Cluster connection info run_once: true @@ -92,22 +94,13 @@ msg: - +------------------------------------------------+ - address (VIP) {{ cluster_vip }} - - port {{ pgbouncer_listen_port }} (pgbouncer) + - port {% if pgbouncer_install %}{{ pgbouncer_listen_port }} (pgbouncer){% else %}{{ postgresql_port }}{% endif %} - +------------------------------------------------+ - when: not with_haproxy_load_balancing|bool and - pgbouncer_install|bool - - - name: PostgreSQL Cluster connection info - run_once: true - debug: - msg: - - +------------------------------------------------+ - - address (VIP) {{ cluster_vip }} - - port {{ postgresql_port }} - - +------------------------------------------------+ - when: not with_haproxy_load_balancing|bool and - not pgbouncer_install|bool - when: cluster_vip is defined and cluster_vip | length > 0 + when: + - not with_haproxy_load_balancing | bool + when: + - (cluster_vip is defined and cluster_vip | length > 0) + - dcs_type == "etcd" ignore_errors: true tags: conn_info, cluster_info, cluster_status @@ -124,7 +117,9 @@ "Cluster ip address (VIP) {{ cluster_vip }} is running on server {{ ansible_hostname }}" when: man_ip is defined and man_ip == cluster_vip - when: cluster_vip is defined and cluster_vip | length > 0 + when: + - (cluster_vip is defined and cluster_vip | length > 0) + - dcs_type == "etcd" ignore_errors: true tags: vip_owner, vip_status, cluster_info, cluster_status @@ -147,8 +142,9 @@ - port {{ haproxy_listen_port.replicas_sync }} (read only) synchronous replica only - port {{ haproxy_listen_port.replicas_async }} (read only) asynchronous replicas only - +------------------------------------------------+ - when: with_haproxy_load_balancing|bool and - synchronous_mode|bool + when: + - with_haproxy_load_balancing | bool + - synchronous_mode | bool - name: PostgreSQL Cluster connection info run_once: true @@ -159,8 +155,9 @@ - port {{ haproxy_listen_port.master }} (read/write) master - port {{ haproxy_listen_port.replicas }} (read only) all replicas - +------------------------------------------------+ - when: with_haproxy_load_balancing|bool and - not synchronous_mode|bool + when: + - with_haproxy_load_balancing | bool + - not synchronous_mode | bool - name: PostgreSQL Cluster connection info run_once: true @@ -168,23 +165,43 @@ msg: - +------------------------------------------------+ - address {{ postgres_cluster_nodes }} - - port {{ pgbouncer_listen_port }} (pgbouncer) + - port {% if pgbouncer_install %}{{ pgbouncer_listen_port }} (pgbouncer){% else %}{{ postgresql_port }}{% endif %} + - +------------------------------------------------+ + when: + - not with_haproxy_load_balancing | bool + ignore_errors: true + when: + - (cluster_vip is not defined or cluster_vip | length < 1) + - dcs_type == "etcd" + tags: conn_info, cluster_info, cluster_status + + +- block: # if dcs_type: "consul" + - name: PostgreSQL Cluster connection info + run_once: true + debug: + msg: + - +------------------------------------------------+ + - "Client access point (DNS):" + - " master.{{ patroni_cluster_name }}.service.consul " + - " replica.{{ patroni_cluster_name }}.service.consul " + - port {% if pgbouncer_install %}{{ pgbouncer_listen_port }} (pgbouncer){% else %}{{ postgresql_port }}{% endif %} - +------------------------------------------------+ - when: not with_haproxy_load_balancing|bool and - pgbouncer_install|bool + when: not synchronous_mode | bool - name: PostgreSQL Cluster connection info run_once: true debug: msg: - +------------------------------------------------+ - - address {{ postgres_cluster_nodes }} - - port {{ postgresql_port }} + - "Client access point (DNS):" + - " master.{{ patroni_cluster_name }}.service.consul " + - " replica.{{ patroni_cluster_name }}.service.consul " + - " sync-replica.{{ patroni_cluster_name }}.service.consul " + - " async-replica.{{ patroni_cluster_name }}.service.consul " + - port {% if pgbouncer_install %}{{ pgbouncer_listen_port }} (pgbouncer){% else %}{{ postgresql_port }}{% endif %} - +------------------------------------------------+ - when: not with_haproxy_load_balancing|bool and - not pgbouncer_install|bool - ignore_errors: true - when: cluster_vip is not defined or cluster_vip | length < 1 - tags: conn_info, cluster_info, cluster_status + when: synchronous_mode | bool + when: dcs_type == "consul" ... diff --git a/roles/patroni/templates/patroni.yml.j2 b/roles/patroni/templates/patroni.yml.j2 index c26fb12a9..b196ba1dd 100644 --- a/roles/patroni/templates/patroni.yml.j2 +++ b/roles/patroni/templates/patroni.yml.j2 @@ -38,6 +38,11 @@ etcd: hosts: {% for etcd_hosts in patroni_etcd_hosts %}{{etcd_hosts.host}}:{{etcd_hosts.port}}{% if not loop.last %},{% endif %}{% endfor %} {% endif %} +{% if dcs_type == 'consul' %} +consul: + host: 127.0.0.1:8500 + checks: [] +{% endif %} bootstrap: method: {{ patroni_cluster_bootstrap_method }} diff --git a/tags.md b/tags.md index 0578e7884..ebb7c9c9d 100644 --- a/tags.md +++ b/tags.md @@ -33,6 +33,7 @@ - - etcd_conf - - etcd_start - - etcd_status +- consul - patroni - - pip - - patroni_install diff --git a/vars/Debian.yml b/vars/Debian.yml index e2b2020ef..e40c252fd 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -47,6 +47,7 @@ system_packages: - jq - iptables - acl + - dnsutils postgresql_packages: - postgresql-{{ postgresql_version }} diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 8ba0093fc..cadb545be 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -60,6 +60,7 @@ system_packages: - jq - iptables - acl + - bind-utils # The glibc-langpack package includes the basic information required to support the language in your applications. # for RHEL version 8 (only) diff --git a/vars/main.yml b/vars/main.yml index cc207cc6f..e20605ea1 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -48,17 +48,16 @@ vip_manager_mask: "24" # netmask for the virtual ip # DCS (Distributed Consensus Store) -dcs_exists: false # or 'true' if you do not want to install and configure the etcd cluster -dcs_type: "etcd" +dcs_exists: false # or 'true' if you don't want to deploy a new etcd cluster +dcs_type: "etcd" # or 'consul' -# if dcs_exists: false and dcs_type: "etcd" +# if dcs_type: "etcd" and dcs_exists: false etcd_ver: "v3.3.27" # version for deploy etcd cluster etcd_data_dir: "/var/lib/etcd" etcd_cluster_name: "etcd-{{ patroni_cluster_name }}" # ETCD_INITIAL_CLUSTER_TOKEN -# if dcs_exists: true and dcs_type: "etcd" - specify ip address your etcd cluster in the "patroni_etcd_hosts" variable -# example (use existing cluster of 3 nodes) -patroni_etcd_hosts: [] +# if dcs_type: "etcd" and dcs_exists: true +patroni_etcd_hosts: [] # list of servers of an existing etcd cluster # - { host: "10.128.64.140", port: "2379" } # - { host: "10.128.64.142", port: "2379" } # - { host: "10.128.64.143", port: "2379" } @@ -67,6 +66,67 @@ patroni_etcd_hosts: [] # https://patroni.readthedocs.io/en/latest/SETTINGS.html#etcd # https://patroni.readthedocs.io/en/latest/SETTINGS.html#consul +# if dcs_type: "consul" +consul_version: "1.14.3" +consul_config_path: "/etc/consul" +consul_configd_path: "{{ consul_config_path }}/conf.d" +consul_data_path: "/var/lib/consul" +consul_domain: "consul" # Consul domain name +consul_datacenter: "dc1" # Datacenter label (can be specified for each host in the inventory) +consul_disable_update_check: true # Disables automatic checking for security bulletins and new version releases +consul_enable_script_checks: true # This controls whether health checks that execute scripts are enabled on this agent +consul_enable_local_script_checks: true # Enable them when they are defined in the local configuration files +consul_ui: false # Enable the consul UI? +consul_syslog_enable: true # Enable logging to syslog +# TLS +# You can enable TLS encryption by dropping a CA certificate, server certificate, and server key in roles/consul/files/ +consul_tls_enable: false +consul_tls_ca_crt: "ca.crt" +consul_tls_server_crt: "server.crt" +consul_tls_server_key: "server.key" +# DNS +consul_recursors: [] # List of upstream DNS servers +consul_dnsmasq_enable: true # Enable DNS forwarding with Dnsmasq +consul_dnsmasq_cache: 0 # dnsmasq cache-size (0 - disable caching) +consul_dnsmasq_servers: # Upstream DNS servers used by dnsmasq + - "8.8.8.8" + - "9.9.9.9" +consul_join: [] # List of LAN servers of an existing consul cluster, to join. +# - "10.128.64.140" +# - "10.128.64.142" +# - "10.128.64.143" + +# https://developer.hashicorp.com/consul/docs/discovery/services +consul_services: + - name: "{{ patroni_cluster_name }}" + id: "{{ patroni_cluster_name }}-master" + tags: ['master'] + port: "{{ pgbouncer_listen_port }}" # or "{{ pgbouncer_listen_port }}" if pgbouncer_install: false + checks: + - { http: "http://{{ hostvars[inventory_hostname]['inventory_hostname'] }}:8008/master", interval: "2s" } + - { args: ["systemctl", "status", "pgbouncer"], interval: "5s" } # comment out this check if pgbouncer_install: false + - name: "{{ patroni_cluster_name }}" + id: "{{ patroni_cluster_name }}-replica" + tags: ['replica'] + port: "{{ pgbouncer_listen_port }}" + checks: + - { http: "http://{{ hostvars[inventory_hostname]['inventory_hostname'] }}:8008/replica", interval: "2s" } + - { args: ["systemctl", "status", "pgbouncer"], interval: "5s" } +# - name: "{{ patroni_cluster_name }}" +# id: "{{ patroni_cluster_name }}-sync-replica" +# tags: ['sync-replica'] +# port: "{{ pgbouncer_listen_port }}" +# checks: +# - { http: "http://{{ hostvars[inventory_hostname]['inventory_hostname'] }}:8008/sync", interval: "2s" } +# - { args: ["systemctl", "status", "pgbouncer"], interval: "5s" } +# - name: "{{ patroni_cluster_name }}" +# id: "{{ patroni_cluster_name }}-async-replica" +# tags: ['async-replica'] +# port: "{{ pgbouncer_listen_port }}" +# checks: +# - { http: "http://{{ hostvars[inventory_hostname]['inventory_hostname'] }}:8008/async", interval: "2s" } +# - { args: ["systemctl", "status", "pgbouncer"], interval: "5s" } + # PostgreSQL variables postgresql_version: "14" diff --git a/vars/system.yml b/vars/system.yml index 02f6b290e..6bf701812 100644 --- a/vars/system.yml +++ b/vars/system.yml @@ -42,6 +42,7 @@ sysctl_set: true # or 'false' # these parameters for example! Specify kernel options for your system sysctl_conf: etcd_cluster: [] + consul_instances: [] master: [] replica: [] postgres_cluster: @@ -142,6 +143,12 @@ firewall_allowed_tcp_ports_for: - "2379" # ETCD port - "2380" # ETCD port # - "" + consul_instances: + - 8300 + - 8301 + - 8302 + - 8500 + - 8600 balancers: - "{{ ansible_ssh_port | default(22) }}" - "{{ haproxy_listen_port.master }}" # HAProxy (read/write) master