diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 00000000..b8c04701 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,4 @@ +--- +warn_list: + - '106' + - '303' diff --git a/.github/actions/default/Dockerfile b/.github/actions/default/Dockerfile deleted file mode 100644 index 9dffbde8..00000000 --- a/.github/actions/default/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM quay.io/ansible/molecule:2.20 - -VOLUME [ "/sys/fs/cgroup", "/run", "/run/lock" ] - -COPY ./entrypoint.sh /entrypoint.sh -RUN chmod 755 /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/actions/default/action.yml b/.github/actions/default/action.yml deleted file mode 100644 index a9b38478..00000000 --- a/.github/actions/default/action.yml +++ /dev/null @@ -1,6 +0,0 @@ -name: molecule-test -description: Molecule tests for Wazuh Ansible -runs: - using: docker - image: 'Dockerfile' - diff --git a/.github/actions/default/entrypoint.sh b/.github/actions/default/entrypoint.sh deleted file mode 100644 index 158e9f08..00000000 --- a/.github/actions/default/entrypoint.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -eu - -molecule test \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 26cb0e32..34184a9e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,13 +1,127 @@ - +--- name: Molecule tests for Wazuh Ansible - -on: [push] +on: [pull_request, workflow_dispatch, release] jobs: - default: + + scenario-default: + name: Default scenario (smoke) runs-on: ubuntu-latest steps: - - name: Check out code - uses: actions/checkout@v2 - - name: Default scenario - uses: './.github/actions/default' + - name: Check out the codebase. + uses: actions/checkout@v2 + + - name: Hack to get setup-python to work on act. See act issue 251 + run: | + # Hack to get setup-python to work on act + if [ ! -f "/etc/lsb-release" ] ; then + echo "DISTRIB_RELEASE=18.04" > /etc/lsb-release + fi + + - name: Set up Python 3. + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install poetry + run: pip3 install poetry + + - name: Install dependencies + run: poetry install + + - name: Run Molecule tests. + run: poetry run molecule test -s default + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' + + scenario-distributed-wazuh-elk: + name: Distributed ELK + Wazuh + runs-on: ubuntu-latest + steps: + - name: Check out the codebase. + uses: actions/checkout@v2 + + - name: Hack to get setup-python to work on act. See act issue 251 + run: | + if [ ! -f "/etc/lsb-release" ] ; then + echo "DISTRIB_RELEASE=18.04" > /etc/lsb-release + fi + + - name: Set up Python 3. + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install poetry + run: pip3 install poetry + + - name: Install dependencies + run: poetry install + + + - name: Run Molecule tests. + run: poetry run molecule test -s distributed-wazuh-elk + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' + + scenario-distributed-wazuh-elk-xpack: + name: Distributed ELK + XPack + Wazuh + runs-on: ubuntu-latest + steps: + - name: Check out the codebase. + uses: actions/checkout@v2 + + - name: Hack to get setup-python to work on act. See act issue 251 + run: | + if [ ! -f "/etc/lsb-release" ] ; then + echo "DISTRIB_RELEASE=18.04" > /etc/lsb-release + fi + + - name: Set up Python 3. + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install poetry + run: pip3 install poetry + + - name: Install dependencies + run: poetry install + + - name: Run Molecule tests. + run: poetry run molecule test -s distributed-wazuh-elk-xpack + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' + + scenario-distributed-wazuh-odfe: + name: Distributed ODFE + Wazuh + runs-on: ubuntu-latest + steps: + - name: Check out the codebase. + uses: actions/checkout@v2 + + - name: Hack to get setup-python to work on act. See act issue 251 + run: | + if [ ! -f "/etc/lsb-release" ] ; then + echo "DISTRIB_RELEASE=18.04" > /etc/lsb-release + fi + + - name: Set up Python 3. + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install poetry + run: pip3 install poetry + + - name: Install dependencies + run: poetry install + + - name: Run Molecule tests. + run: poetry run molecule test -s distributed-wazuh-odfe + env: + PY_COLORS: '1' + ANSIBLE_FORCE_COLOR: '1' diff --git a/.gitignore b/.gitignore index 107a85d0..38bf9b6c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,8 @@ wazuh-elastic.yml wazuh-kibana.yml wazuh-manager.yml *.pyc +.mypy_cache Pipfile.lock *.swp +molecule/**/es_certs/ +molecule/**/opendistro/ \ No newline at end of file diff --git a/.yamllint b/.yamllint index a74c7d25..88276760 100644 --- a/.yamllint +++ b/.yamllint @@ -1,3 +1,5 @@ +--- +# Based on ansible-lint config extends: default rules: @@ -7,10 +9,25 @@ rules: brackets: max-spaces-inside: 1 level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + comments: disable + comments-indentation: disable + document-start: disable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: disable + key-duplicates: enable line-length: disable - # NOTE(retr0h): Templates no longer fail this lint rule. - # Uncomment if running old Molecule templates. - # truthy: disable -ignore: | - .travis.yml - config.yml + new-line-at-end-of-file: disable + new-lines: + type: unix + trailing-spaces: disable + truthy: disable diff --git a/molecule/default/Dockerfile.j2 b/molecule/default/Dockerfile.j2 deleted file mode 100644 index 19692c20..00000000 --- a/molecule/default/Dockerfile.j2 +++ /dev/null @@ -1,14 +0,0 @@ -# Molecule managed - -{% if item.registry is defined %} -FROM {{ item.registry.url }}/{{ item.image }} -{% else %} -FROM {{ item.image }} -{% endif %} - -RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ - elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python2-dnf bash && dnf clean all; \ - elif [ $(command -v yum) ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ - elif [ $(command -v zypper) ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash python-xml && zypper clean -a; \ - elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ - elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 00000000..ef634b65 --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,17 @@ +--- +- name: Converge + hosts: all + roles: + - role: ../../roles/wazuh/ansible-wazuh-manager + vars: + - { role: ../../roles/wazuh/ansible-filebeat, filebeat_output_elasticsearch_hosts: "elasticsearch_centos7:9200" } + vars: + pre_tasks: + - name: (converge) fix missing packages in cloud images + apt: + name: + - unzip + - gpg-agent + state: present + update_cache: yes + when: ansible_distribution == "Ubuntu" \ No newline at end of file diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index cd184961..3e21dce2 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -1,34 +1,53 @@ --- +# Smoke test: basic manager run dependency: name: galaxy driver: name: docker -lint: - name: yamllint - enabled: false +lint: | + yamllint . + ansible-lint roles + flake8 molecule platforms: - - - name: manager_centos7 - image: milcom/centos7-systemd + - name: wazuh_manager_centos7 + hostname: wazuh-mgr01 + image: geerlingguy/docker-centos7-ansible command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m ulimits: - nofile:262144:262144 - privileged: true - memory_reservation: 2048m + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro - - name: ubuntu20 - image: jrei/systemd-ubuntu:20.04 - privileged: true - - - name: debian9 - image: jrei/systemd-debian:9 + - name: wazuh_manager_debian9 + hostname: wazuh-mgr02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro provisioner: name: ansible + ansible_args: + - -vv config_options: defaults: hash_behaviour: merge + playbooks: + create: create.yml + converge: converge.yml + #destroy: destroy.yml env: ANSIBLE_ROLES_PATH: ./roles lint: @@ -43,11 +62,8 @@ scenario: - prepare - converge #- idempotence - - verify + #- verify - cleanup - destroy verifier: name: testinfra - lint: - name: flake8 - enabled: false diff --git a/molecule/default/playbook.yml b/molecule/default/playbook.yml deleted file mode 100644 index 0e6bf98d..00000000 --- a/molecule/default/playbook.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Converge - hosts: all - roles: - - role: ../../roles/wazuh/ansible-wazuh-manager - vars: - - { role: ../../roles/wazuh/ansible-filebeat, filebeat_output_elasticsearch_hosts: "elasticsearch_centos7:9200" } diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py index 289e4f86..a6a86674 100644 --- a/molecule/default/tests/test_default.py +++ b/molecule/default/tests/test_default.py @@ -1,7 +1,6 @@ import os import pytest import testinfra.utils.ansible_runner -import re testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') diff --git a/molecule/distributed-wazuh-elk-xpack/INSTALL.rst b/molecule/distributed-wazuh-elk-xpack/INSTALL.rst new file mode 100644 index 00000000..e26493b8 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/INSTALL.rst @@ -0,0 +1,16 @@ +******* +Install +******* + +Requirements +============ + +* Docker Engine +* docker-py + +Install +======= + +.. code-block:: bash + + $ sudo pip install docker-py diff --git a/molecule/distributed-wazuh-elk-xpack/converge.yml b/molecule/distributed-wazuh-elk-xpack/converge.yml new file mode 100644 index 00000000..36186c89 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/converge.yml @@ -0,0 +1,94 @@ +--- + + +- name: Generate certificates prior to converging + hosts: all + become: true + become_user: root + vars: + endpoints_hostvars: '{{ managers_hostvars | union(elastic_hostvars) | union(kibana_hostvars) }}' + roles: + - role: ../../roles/elastic-stack/ansible-elasticsearch + vars: + node_certs_generator: true + instances: '{{ elk_endpoint_list }}' + when: + - inventory_hostname in groups['elastic'] + - ansible_hostname == 'wazuh-es01' + pre_tasks: + - name: (converge) build instances list dynamically for cert generator consumption + set_fact: + elk_endpoint_list: "{{ elk_endpoint_list | default({}) | combine({ instance_hostname: instance_item }) }}" + vars: + instance_hostname: '{{ item.ansible_facts.hostname }}' + instance_item: + name: '{{ item.private_ip}}' + ip: '{{ item.private_ip }}' + loop: '{{ endpoints_hostvars }}' + no_log: true + - name: overview of cert configuration + debug: + var: elk_endpoint_list + +- name: Converge + hosts: all + become: true + become_user: root + vars: + endpoints_hostvars: '{{ managers_hostvars | union(elastic_hostvars) | union(kibana_hostvars) }}' + # arguments common to all managers + wazuh_managers_common: + port: 1514 + protocol: tcp + api_port: 55000 + api_proto: 'http' + api_user: ansible + max_retries: 5 + retry_interval: 5 + roles: + # 1. Elasticsearch + - role: ../../roles/elastic-stack/ansible-elasticsearch + vars: + instances: '{{ elk_endpoint_list }}' + when: inventory_hostname in groups['elastic'] + # 2. Managers + - role: ../../roles/wazuh/ansible-wazuh-manager + when: inventory_hostname in groups['managers'] + - role: ../../roles/wazuh/ansible-filebeat + when: inventory_hostname in groups['managers'] + # 3. Kibana + - role: ../../roles/elastic-stack/ansible-kibana + when: inventory_hostname in groups['kibana'] + # 4. Agents: + - role: ../../roles/wazuh/ansible-wazuh-agent + vars: + wazuh_managers: '{{ wazuh_managers_list }}' + when: inventory_hostname in groups['agents'] + pre_tasks: + + - name: (converge) build wazuh_managers list dynamically for agents to consume + set_fact: + wazuh_managers_list: '{{ wazuh_managers_list | default([]) | union([manager_item]) }}' + vars: + manager_item: '{{ wazuh_managers_common | combine({"address": item}) }}' + loop: '{{ manager_addresses }}' + + - name: (converge) build instances list dynamically for cert generator consumption + set_fact: + elk_endpoint_list: "{{ elk_endpoint_list | default({}) | combine({ instance_hostname: instance_item }) }}" + vars: + instance_hostname: '{{ item.ansible_facts.hostname }}' + instance_item: + name: '{{ item.private_ip}}' + ip: '{{ item.private_ip }}' + loop: '{{ endpoints_hostvars }}' + no_log: true + + - name: (converge) fix ubuntu repository key task in thin images where gpg-agent is missing + apt: + name: gpg-agent + state: present + update_cache: yes + when: + - ansible_distribution == "Ubuntu" + - inventory_hostname in groups['agents'] \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk-xpack/group_vars/agents.yml b/molecule/distributed-wazuh-elk-xpack/group_vars/agents.yml new file mode 100644 index 00000000..042a77c5 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/group_vars/agents.yml @@ -0,0 +1,25 @@ +--- + +wazuh_agent_config: + enrollment: + enabled: 'yes' + #manager_address: '' + #port: 1515 + agent_name: '{{ ansible_hostname }}' + #groups: '' + #agent_address: '' + #ssl_cipher: HIGH:!ADH:!EXP:!MD5:!RC4:!3DES:!CAMELLIA:@STRENGTH + #server_ca_path: '' + #agent_certificate_path: '' + #agent_key_path: '' + #authorization_pass_path : /var/ossec/etc/authd.pass + #auto_method: 'no' + #delay_after_enrollment: 20 + #use_source_ip: 'no' + +wazuh_agent_authd: + registration_address: '{{ manager_addresses | random }}' + enable: true + port: 1515 + ssl_agent_ca: null + ssl_auto_negotiate: 'no' \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk-xpack/group_vars/all.yml b/molecule/distributed-wazuh-elk-xpack/group_vars/all.yml new file mode 100644 index 00000000..fcf3b407 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/group_vars/all.yml @@ -0,0 +1,27 @@ +--- + +######################################################## +# Helper variables +private_ip: '{{ ansible_default_ipv4.address }}' + +managers_hostvars: "{{ groups['managers'] | map('extract', hostvars) | list }}" +elastic_hostvars: "{{ groups['elastic'] | map('extract', hostvars) | list }}" +kibana_hostvars: "{{ groups['kibana'] | map('extract', hostvars) | list }}" + +manager_addresses: "{{ managers_hostvars | map(attribute='private_ip') | list }}" +elastic_addresses: "{{ elastic_hostvars | map(attribute='private_ip') | list }}" +kibana_addresses: "{{ kibana_hostvars | map(attribute='private_ip') | list }}" + +######################################################## +# General ELK stack variables + +# Xpack Security: autogenerate CA +generate_CA: true +filebeat_xpack_security: true +kibana_xpack_security: true +elasticsearch_xpack_security: true +elasticsearch_xpack_security_user: elastic +elasticsearch_xpack_security_password: elastic_pass + +elastic_stack_version: 7.9.1 +filebeat_version: 7.9.1 \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk-xpack/group_vars/elastic.yml b/molecule/distributed-wazuh-elk-xpack/group_vars/elastic.yml new file mode 100644 index 00000000..1490dff3 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/group_vars/elastic.yml @@ -0,0 +1,17 @@ +--- + +single_node: false +elasticsearch_node_master: true +minimum_master_nodes: 1 + +elasticsearch_network_host: '{{ private_ip }}' +elasticsearch_node_name: '{{ private_ip }}' + +elasticsearch_reachable_host: '{{ private_ip }}' +elasticsearch_http_port: 9200 + +elasticsearch_bootstrap_node: true +elasticsearch_cluster_nodes: '{{ elastic_addresses }}' +elasticsearch_discovery_nodes: '{{ elastic_addresses }}' + +elasticsearch_jvm_xms: 1024 \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk-xpack/group_vars/kibana.yml b/molecule/distributed-wazuh-elk-xpack/group_vars/kibana.yml new file mode 100644 index 00000000..4d9142b4 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/group_vars/kibana.yml @@ -0,0 +1,19 @@ +--- + +kibana_server_name: '{{ ansible_hostname }}' +kibana_node_name: '{{ private_ip }}' + +elasticsearch_network_host: "{{ elastic_addresses[0] }}" +#elasticsearch_http_port: 9200 + +elasticsearch_node_master: false +elasticsearch_node_ingest: false +elasticsearch_node_data: false + +wazuh_api_credentials: + - id: default + url: 'https://{{ manager_addresses[0] }}' + port: 55000 + #port: 1514 + username: wazuh + password: wazuh diff --git a/molecule/distributed-wazuh-elk-xpack/group_vars/managers.yml b/molecule/distributed-wazuh-elk-xpack/group_vars/managers.yml new file mode 100644 index 00000000..6f9c9af3 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/group_vars/managers.yml @@ -0,0 +1,21 @@ +--- + +wazuh_manager_fqdn: '{{ ansible_hostname }}' + +filebeat_node_name: '{{ private_ip }}' +filebeat_output_elasticsearch_hosts: '{{ elastic_addresses }}' + +wazuh_manager_config: + connection: + - type: 'secure' + port: '1514' + protocol: 'tcp' + queue_size: 131072 + api: + https: 'yes' + cluster: + disable: 'no' + node_name: '{{ ansible_hostname }}' + node_type: "{{ 'master' if ansible_hostname == 'wazuh-mgr01' else 'worker' }}" + nodes: '{{ manager_addresses }}' + hidden: 'no' \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk-xpack/molecule.yml b/molecule/distributed-wazuh-elk-xpack/molecule.yml new file mode 100644 index 00000000..6ed46105 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/molecule.yml @@ -0,0 +1,162 @@ +--- +# Distributed scenario: clustered manager scenario + connected agents +# 2-core CPU +# 7 GB of RAM memory +# 14 GB of SSD disk space +# +# Source: https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners + +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint roles + flake8 molecule +platforms: + ################################################ + # Wazuh Managers + ################################################ + - name: molecule_xpack_manager_centos7 + hostname: wazuh-mgr01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: molecule_xpack_manager_debian9 + hostname: wazuh-mgr02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Elastic Cluster + ################################################ + - name: molecule_xpack_elasticsearch_centos7 + hostname: wazuh-es01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 4096m + memory_reservation: 2048m + groups: + - elastic + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: molecule_xpack_elasticsearch_debian9 + hostname: wazuh-es02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 4096m + memory_reservation: 2048m + groups: + - elastic + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Wazuh Agents + ################################################ + - name: molecule_xpack_agent_centos7 + hostname: wazuh-agent01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 1024m + memory_reservation: 512m + groups: + - agents + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: molecule_xpack_agent_debian9 + hostname: wazuh-agent02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 1024m + memory_reservation: 512m + groups: + - agents + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Kibana + ################################################ + + - name: molecule_xpack_kibana_centos7 + hostname: wazuh-kib01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 2048m + memory_reservation: 512m + groups: + - kibana + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + +provisioner: + name: ansible + ansible_args: + - -vv + inventory: + links: + group_vars: group_vars + playbooks: + create: create.yml + converge: converge.yml + #destroy: destroy.yml + config_options: + defaults: + hash_behaviour: merge + env: + ANSIBLE_ROLES_PATH: ./roles + lint: + name: ansible-lint + enabled: false +scenario: + name: distributed-wazuh-elk-xpack + test_sequence: + - dependency + - syntax + - create + - prepare + - converge + #- idempotence + #- verify + - cleanup + - destroy +verifier: + name: testinfra \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk-xpack/tests/test_default.py b/molecule/distributed-wazuh-elk-xpack/tests/test_default.py new file mode 100644 index 00000000..a6a86674 --- /dev/null +++ b/molecule/distributed-wazuh-elk-xpack/tests/test_default.py @@ -0,0 +1,64 @@ +import os +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def get_wazuh_version(): + """This return the version of Wazuh.""" + return "4.0.0" + + +def test_wazuh_packages_are_installed(host): + """Test the main packages are installed.""" + manager = host.package("wazuh-manager") + assert manager.is_installed + assert manager.version.startswith(get_wazuh_version()) + + +def test_wazuh_services_are_running(host): + """Test the services are enabled and running. + + When assert commands are commented, this means that the service command has + a wrong exit code: https://github.com/wazuh/wazuh-ansible/issues/107 + """ + # This currently doesn't work with out current Docker base images + # manager = host.service("wazuh-manager") + # api = host.service("wazuh-api") + # assert manager.is_running + # assert api.is_running + output = host.check_output( + 'ps aux | grep ossec | tr -s " " | cut -d" " -f11' + ) + assert 'ossec-authd' in output + assert 'wazuh-modulesd' in output + assert 'wazuh-db' in output + assert 'ossec-execd' in output + assert 'ossec-monitord' in output + assert 'ossec-remoted' in output + assert 'ossec-logcollector' in output + assert 'ossec-analysisd' in output + assert 'ossec-syscheckd' in output + + +@pytest.mark.parametrize("wazuh_file, wazuh_owner, wazuh_group, wazuh_mode", [ + ("/var/ossec/etc/sslmanager.cert", "root", "root", 0o640), + ("/var/ossec/etc/sslmanager.key", "root", "root", 0o640), + ("/var/ossec/etc/rules/local_rules.xml", "ossec", "ossec", 0o640), + ("/var/ossec/etc/lists/audit-keys", "ossec", "ossec", 0o660), +]) +def test_wazuh_files(host, wazuh_file, wazuh_owner, wazuh_group, wazuh_mode): + """Test Wazuh related files exist and have proper owners and mode.""" + wazuh_file_host = host.file(wazuh_file) + assert wazuh_file_host.user == wazuh_owner + assert wazuh_file_host.group == wazuh_group + assert wazuh_file_host.mode == wazuh_mode + + +def test_filebeat_is_installed(host): + """Test the elasticsearch package is installed.""" + filebeat = host.package("filebeat") + assert filebeat.is_installed + assert filebeat.version.startswith('7.9.1') diff --git a/molecule/distributed-wazuh-elk/INSTALL.rst b/molecule/distributed-wazuh-elk/INSTALL.rst new file mode 100644 index 00000000..e26493b8 --- /dev/null +++ b/molecule/distributed-wazuh-elk/INSTALL.rst @@ -0,0 +1,16 @@ +******* +Install +******* + +Requirements +============ + +* Docker Engine +* docker-py + +Install +======= + +.. code-block:: bash + + $ sudo pip install docker-py diff --git a/molecule/distributed-wazuh-elk/converge.yml b/molecule/distributed-wazuh-elk/converge.yml new file mode 100644 index 00000000..be8c903d --- /dev/null +++ b/molecule/distributed-wazuh-elk/converge.yml @@ -0,0 +1,60 @@ +--- + +- name: Converge + hosts: all + become: true + become_user: root + vars: + # arguments common to all managers + wazuh_managers_common: + port: 1514 + protocol: tcp + api_port: 55000 + api_proto: 'http' + api_user: ansible + max_retries: 5 + retry_interval: 5 + roles: + # 1. Elasticsearch + - role: ../../roles/elastic-stack/ansible-elasticsearch + when: inventory_hostname in groups['elastic'] + # 2. Managers + - role: ../../roles/wazuh/ansible-wazuh-manager + when: inventory_hostname in groups['managers'] + - role: ../../roles/wazuh/ansible-filebeat + when: inventory_hostname in groups['managers'] + # 3. Kibana + - role: ../../roles/elastic-stack/ansible-kibana + when: inventory_hostname in groups['kibana'] + # 4. Agents: + - role: ../../roles/wazuh/ansible-wazuh-agent + vars: + wazuh_managers: '{{ wazuh_managers_list }}' + when: inventory_hostname in groups['agents'] + pre_tasks: + + - name: (converge) build wazuh_managers list dynamically for agents to consume + set_fact: + wazuh_managers_list: '{{ wazuh_managers_list | default([]) | union([merged_dict]) }}' + vars: + merged_dict: '{{ wazuh_managers_common | combine({"address": item}) }}' + loop: '{{ manager_addresses }}' + + - name: (converge) fix ubuntu repository key task in thin images where gpg-agent is missing + apt: + name: gpg-agent + state: present + update_cache: yes + when: + - ansible_distribution == "Ubuntu" + - inventory_hostname in groups['agents'] + + - debug: + msg: | + ----------------------------------------- + managers: {{ managers_hostvars | length }} + addresses: {{ manager_addresses }} + ----------------------------------------- + elastic: {{ elastic_hostvars | length }} + addresses: {{ elastic_addresses }} + ----------------------------------------- diff --git a/molecule/distributed-wazuh-elk/group_vars/agents.yml b/molecule/distributed-wazuh-elk/group_vars/agents.yml new file mode 100644 index 00000000..a4e064e3 --- /dev/null +++ b/molecule/distributed-wazuh-elk/group_vars/agents.yml @@ -0,0 +1,18 @@ +--- + +wazuh_agent_config: + enrollment: + enabled: 'yes' + #manager_address: '' + #port: 1515 + agent_name: '{{ ansible_hostname }}' + #groups: '' + #agent_address: '' + #ssl_cipher: HIGH:!ADH:!EXP:!MD5:!RC4:!3DES:!CAMELLIA:@STRENGTH + #server_ca_path: '' + #agent_certificate_path: '' + #agent_key_path: '' + #authorization_pass_path : /var/ossec/etc/authd.pass + #auto_method: 'no' + #delay_after_enrollment: 20 + #use_source_ip: 'no' diff --git a/molecule/distributed-wazuh-elk/group_vars/all.yml b/molecule/distributed-wazuh-elk/group_vars/all.yml new file mode 100644 index 00000000..a706caae --- /dev/null +++ b/molecule/distributed-wazuh-elk/group_vars/all.yml @@ -0,0 +1,13 @@ +--- + +######################################################## +# Helper variables +private_ip: '{{ ansible_default_ipv4.address }}' + +managers_hostvars: "{{ groups['managers'] | map('extract', hostvars) | list }}" +elastic_hostvars: "{{ groups['elastic'] | map('extract', hostvars) | list }}" + +manager_addresses: "{{ managers_hostvars | map(attribute='private_ip') | list }}" +elastic_addresses: "{{ elastic_hostvars | map(attribute='private_ip') | list }}" + +elastic_stack_version: 7.9.1 diff --git a/molecule/distributed-wazuh-elk/group_vars/elastic.yml b/molecule/distributed-wazuh-elk/group_vars/elastic.yml new file mode 100644 index 00000000..f53be2a7 --- /dev/null +++ b/molecule/distributed-wazuh-elk/group_vars/elastic.yml @@ -0,0 +1,21 @@ +--- + +single_node: false +elasticsearch_node_master: true +minimum_master_nodes: 1 + +elasticsearch_network_host: '{{ private_ip }}' +elasticsearch_node_name: '{{ ansible_hostname }}' + +elasticsearch_reachable_host: '{{ private_ip }}' +elasticsearch_http_port: 9200 + +# This scenario runs without xpack-security +elasticsearch_xpack_security: false +node_certs_generator: false + +elasticsearch_bootstrap_node: true +elasticsearch_cluster_nodes: '{{ elastic_addresses }}' +elasticsearch_discovery_nodes: '{{ elastic_addresses }}' + +elasticsearch_jvm_xms: 1024 diff --git a/molecule/distributed-wazuh-elk/group_vars/kibana.yml b/molecule/distributed-wazuh-elk/group_vars/kibana.yml new file mode 100644 index 00000000..1c0861a2 --- /dev/null +++ b/molecule/distributed-wazuh-elk/group_vars/kibana.yml @@ -0,0 +1,19 @@ +--- + +kibana_node_name: '{{ ansible_hostname }}' +kibana_server_name: '{{ ansible_hostname }}' + +elasticsearch_network_host: "{{ elastic_addresses | random }}" +#elasticsearch_http_port: 9200 + +elasticsearch_node_master: false +elasticsearch_node_ingest: false +elasticsearch_node_data: false + +wazuh_api_credentials: + - id: default + url: 'https://{{ manager_addresses[0] }}' + port: 55000 + #port: 1514 + username: wazuh + password: wazuh \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk/group_vars/managers.yml b/molecule/distributed-wazuh-elk/group_vars/managers.yml new file mode 100644 index 00000000..e191ad10 --- /dev/null +++ b/molecule/distributed-wazuh-elk/group_vars/managers.yml @@ -0,0 +1,20 @@ +--- + +wazuh_manager_fqdn: '{{ ansible_hostname }}' +filebeat_node_name: '{{ ansible_hostname }}' +filebeat_output_elasticsearch_hosts: '{{ elastic_addresses }}' + +wazuh_manager_config: + connection: + - type: 'secure' + port: '1514' + protocol: 'tcp' + queue_size: 131072 + api: + https: 'yes' + cluster: + disable: 'no' + node_name: '{{ ansible_hostname }}' + node_type: "{{ 'master' if ansible_hostname == 'wazuh-mgr01' else 'worker' }}" + nodes: '{{ manager_addresses }}' + hidden: 'no' \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk/host_vars/wazuh_agent_centos7.yml b/molecule/distributed-wazuh-elk/host_vars/wazuh_agent_centos7.yml new file mode 100644 index 00000000..b4b37153 --- /dev/null +++ b/molecule/distributed-wazuh-elk/host_vars/wazuh_agent_centos7.yml @@ -0,0 +1,7 @@ +--- +wazuh_agent_authd: + registration_address: '{{ manager_addresses | random }}' + enable: true + port: 1515 + ssl_agent_ca: null + ssl_auto_negotiate: 'no' \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk/molecule.yml b/molecule/distributed-wazuh-elk/molecule.yml new file mode 100644 index 00000000..cb2cc95b --- /dev/null +++ b/molecule/distributed-wazuh-elk/molecule.yml @@ -0,0 +1,163 @@ +--- +# Distributed scenario: clustered manager scenario + connected agents +# 2-core CPU +# 7 GB of RAM memory +# 14 GB of SSD disk space +# +# Source: https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners + +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint roles + flake8 molecule +platforms: + ################################################ + # Wazuh Managers + ################################################ + - name: wazuh_manager_centos7 + hostname: wazuh-mgr01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: wazuh_manager_debian9 + hostname: wazuh-mgr02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Elastic Cluster + ################################################ + - name: wazuh_elasticsearch_centos7 + hostname: wazuh-es01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 4096m + memory_reservation: 2048m + groups: + - elastic + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: wazuh_elasticsearch_debian9 + hostname: wazuh-es02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 4096m + memory_reservation: 2048m + groups: + - elastic + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Wazuh Agents + ################################################ + - name: wazuh_agent_centos7 + hostname: wazuh-agent01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 1024m + memory_reservation: 512m + groups: + - agents + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: wazuh_agent_debian9 + hostname: wazuh-agent01 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 1024m + memory_reservation: 512m + groups: + - agents + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Kibana + ################################################ + + - name: wazuh_kibana_centos7 + hostname: wazuh-kib01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 2048m + memory_reservation: 512m + groups: + - kibana + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + +provisioner: + name: ansible + ansible_args: + - -vv + inventory: + links: + group_vars: group_vars + host_vars: host_vars + playbooks: + create: create.yml + converge: converge.yml + #destroy: destroy.yml + config_options: + defaults: + hash_behaviour: merge + env: + ANSIBLE_ROLES_PATH: ./roles + lint: + name: ansible-lint + enabled: false +scenario: + name: distributed-wazuh-elk + test_sequence: + - dependency + - syntax + - create + - prepare + - converge + #- idempotence + #- verify + - cleanup + - destroy +verifier: + name: testinfra \ No newline at end of file diff --git a/molecule/distributed-wazuh-elk/tests/test_default.py b/molecule/distributed-wazuh-elk/tests/test_default.py new file mode 100644 index 00000000..a6a86674 --- /dev/null +++ b/molecule/distributed-wazuh-elk/tests/test_default.py @@ -0,0 +1,64 @@ +import os +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def get_wazuh_version(): + """This return the version of Wazuh.""" + return "4.0.0" + + +def test_wazuh_packages_are_installed(host): + """Test the main packages are installed.""" + manager = host.package("wazuh-manager") + assert manager.is_installed + assert manager.version.startswith(get_wazuh_version()) + + +def test_wazuh_services_are_running(host): + """Test the services are enabled and running. + + When assert commands are commented, this means that the service command has + a wrong exit code: https://github.com/wazuh/wazuh-ansible/issues/107 + """ + # This currently doesn't work with out current Docker base images + # manager = host.service("wazuh-manager") + # api = host.service("wazuh-api") + # assert manager.is_running + # assert api.is_running + output = host.check_output( + 'ps aux | grep ossec | tr -s " " | cut -d" " -f11' + ) + assert 'ossec-authd' in output + assert 'wazuh-modulesd' in output + assert 'wazuh-db' in output + assert 'ossec-execd' in output + assert 'ossec-monitord' in output + assert 'ossec-remoted' in output + assert 'ossec-logcollector' in output + assert 'ossec-analysisd' in output + assert 'ossec-syscheckd' in output + + +@pytest.mark.parametrize("wazuh_file, wazuh_owner, wazuh_group, wazuh_mode", [ + ("/var/ossec/etc/sslmanager.cert", "root", "root", 0o640), + ("/var/ossec/etc/sslmanager.key", "root", "root", 0o640), + ("/var/ossec/etc/rules/local_rules.xml", "ossec", "ossec", 0o640), + ("/var/ossec/etc/lists/audit-keys", "ossec", "ossec", 0o660), +]) +def test_wazuh_files(host, wazuh_file, wazuh_owner, wazuh_group, wazuh_mode): + """Test Wazuh related files exist and have proper owners and mode.""" + wazuh_file_host = host.file(wazuh_file) + assert wazuh_file_host.user == wazuh_owner + assert wazuh_file_host.group == wazuh_group + assert wazuh_file_host.mode == wazuh_mode + + +def test_filebeat_is_installed(host): + """Test the elasticsearch package is installed.""" + filebeat = host.package("filebeat") + assert filebeat.is_installed + assert filebeat.version.startswith('7.9.1') diff --git a/molecule/distributed-wazuh-odfe/INSTALL.rst b/molecule/distributed-wazuh-odfe/INSTALL.rst new file mode 100644 index 00000000..e26493b8 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/INSTALL.rst @@ -0,0 +1,16 @@ +******* +Install +******* + +Requirements +============ + +* Docker Engine +* docker-py + +Install +======= + +.. code-block:: bash + + $ sudo pip install docker-py diff --git a/molecule/distributed-wazuh-odfe/converge.yml b/molecule/distributed-wazuh-odfe/converge.yml new file mode 100644 index 00000000..874df159 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/converge.yml @@ -0,0 +1,75 @@ +--- + +- name: Build Facts + hosts: all + become: true + become_user: root + vars: + endpoints_hostvars: '{{ managers_hostvars | union(elastic_hostvars) | union(kibana_hostvars) }}' + wazuh_managers_common: + port: 1514 + protocol: tcp + api_port: 55000 + api_proto: 'http' + api_user: ansible + max_retries: 5 + retry_interval: 5 + pre_tasks: + - name: (converge) build instances list dynamically for cert generator consumption + set_fact: + odfe_endpoint_list: "{{ odfe_endpoint_list | default({}) | combine({ instance_hostname: instance_item }) }}" + vars: + instance_hostname: '{{ item.ansible_facts.hostname }}' + instance_item: + name: '{{ instance_hostname }}' + ip: '{{ item.private_ip }}' + loop: '{{ endpoints_hostvars }}' + no_log: true + + - name: (converge) build wazuh_managers list dynamically for agents to consume + set_fact: + wazuh_managers_list: '{{ wazuh_managers_list | default([]) | union([manager_item]) }}' + vars: + manager_item: '{{ wazuh_managers_common | combine({"address": item}) }}' + loop: '{{ manager_addresses }}' + + - name: overview of cert configuration + debug: + var: odfe_endpoint_list + +- name: Generate certificates prior to converging + hosts: molecule_odfe_elasticsearch_centos7 + become: true + become_user: root + roles: + - role: ../../roles/opendistro/opendistro-elasticsearch + vars: + generate_certs: true + perform_installation: false + instances: '{{ odfe_endpoint_list }}' + pre_tasks: + - name: overview of cert configuration + debug: + var: odfe_endpoint_list + +- name: Converge + hosts: all + become: true + become_user: root + roles: + # 1. Elasticsearch + - role: ../../roles/opendistro/opendistro-elasticsearch + when: inventory_hostname in groups['elastic'] + # 2. Managers + - role: ../../roles/wazuh/ansible-wazuh-manager + when: inventory_hostname in groups['managers'] + - role: ../../roles/wazuh/ansible-filebeat-oss + when: inventory_hostname in groups['managers'] + # 3. Kibana + - role: ../../roles/opendistro/opendistro-kibana + when: inventory_hostname in groups['kibana'] + # 4. Agents: + - role: ../../roles/wazuh/ansible-wazuh-agent + vars: + wazuh_managers: '{{ wazuh_managers_list }}' + when: inventory_hostname in groups['agents'] \ No newline at end of file diff --git a/molecule/distributed-wazuh-odfe/group_vars/agents.yml b/molecule/distributed-wazuh-odfe/group_vars/agents.yml new file mode 100644 index 00000000..9fc66524 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/group_vars/agents.yml @@ -0,0 +1,25 @@ +--- + +wazuh_agent_config: + enrollment: + enabled: 'yes' + #manager_address: '' + #port: 1515 + agent_name: '{{ ansible_hostname }}' + #groups: '' + #agent_address: '' + #ssl_cipher: HIGH:!ADH:!EXP:!MD5:!RC4:!3DES:!CAMELLIA:@STRENGTH + #server_ca_path: '' + #agent_certificate_path: '' + #agent_key_path: '' + #authorization_pass_path : /var/ossec/etc/authd.pass + #auto_method: 'no' + #delay_after_enrollment: 20 + #use_source_ip: 'no' + +wazuh_agent_authd: + registration_address: '{{ manager_addresses[0] }}' + enable: true + port: 1515 + ssl_agent_ca: null + ssl_auto_negotiate: 'no' \ No newline at end of file diff --git a/molecule/distributed-wazuh-odfe/group_vars/all.yml b/molecule/distributed-wazuh-odfe/group_vars/all.yml new file mode 100644 index 00000000..998bbbb5 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/group_vars/all.yml @@ -0,0 +1,37 @@ +--- + +######################################################## +# Helper variables +private_ip: '{{ ansible_default_ipv4.address }}' + +managers_hostvars: "{{ groups['managers'] | map('extract', hostvars) | list }}" +elastic_hostvars: "{{ groups['elastic'] | map('extract', hostvars) | list }}" +kibana_hostvars: "{{ groups['kibana'] | map('extract', hostvars) | list }}" + +manager_addresses: "{{ managers_hostvars | map(attribute='private_ip') | list }}" +elastic_addresses: "{{ elastic_hostvars | map(attribute='private_ip') | list }}" +kibana_addresses: "{{ kibana_hostvars | map(attribute='private_ip') | list }}" + +######################################################## +# General ELK stack variables + +# Cluster Settings +#es_version: "7.9.1" +#es_major_version: "7.x" +#opendistro_version: 1.10.1 +filebeat_version: 7.9.1 + +# OpenDistro +kibana_opendistro_security: true + +opendistro_kibana_user: kibanaserver +opendistro_security_user: elastic + +opendistro_kibana_password: changeme +opendistro_security_password: admin +opendistro_admin_password: changeme + +# All nodes are called by IP name +elasticsearch_node_name: '{{ ansible_hostname }}' +kibana_node_name: '{{ ansible_hostname }}' +filebeat_node_name: '{{ ansible_hostname }}' \ No newline at end of file diff --git a/molecule/distributed-wazuh-odfe/group_vars/elastic.yml b/molecule/distributed-wazuh-odfe/group_vars/elastic.yml new file mode 100644 index 00000000..056f5184 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/group_vars/elastic.yml @@ -0,0 +1,16 @@ +--- + +single_node: false +elasticsearch_node_master: true +minimum_master_nodes: 1 + +elasticsearch_network_host: '{{ private_ip }}' + +elasticsearch_reachable_host: '{{ private_ip }}' +elasticsearch_http_port: 9200 + +elasticsearch_bootstrap_node: true +elasticsearch_cluster_nodes: '{{ elastic_addresses }}' +elasticsearch_discovery_nodes: '{{ elastic_addresses }}' + +opendistro_jvm_xms: 1024 diff --git a/molecule/distributed-wazuh-odfe/group_vars/kibana.yml b/molecule/distributed-wazuh-odfe/group_vars/kibana.yml new file mode 100644 index 00000000..5101d76a --- /dev/null +++ b/molecule/distributed-wazuh-odfe/group_vars/kibana.yml @@ -0,0 +1,17 @@ +--- + +kibana_server_name: '{{ ansible_hostname }}' +elasticsearch_network_host: "{{ elastic_addresses[0] }}" +#elasticsearch_http_port: 9200 + +elasticsearch_node_master: false +elasticsearch_node_ingest: false +elasticsearch_node_data: false + +wazuh_api_credentials: + - id: default + url: 'https://{{ manager_addresses[0] }}' + port: 55000 + #port: 1514 + username: wazuh + password: wazuh diff --git a/molecule/distributed-wazuh-odfe/group_vars/managers.yml b/molecule/distributed-wazuh-odfe/group_vars/managers.yml new file mode 100644 index 00000000..4f15afd5 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/group_vars/managers.yml @@ -0,0 +1,19 @@ +--- + +wazuh_manager_fqdn: '{{ ansible_hostname }}' +filebeat_output_elasticsearch_hosts: '{{ elastic_addresses }}' + +wazuh_manager_config: + connection: + - type: 'secure' + port: '1514' + protocol: 'tcp' + queue_size: 131072 + api: + https: 'yes' + cluster: + disable: 'no' + node_name: '{{ ansible_hostname }}' + node_type: "{{ 'master' if ansible_hostname == 'wazuh-mgr01' else 'worker' }}" + nodes: '{{ manager_addresses }}' + hidden: 'no' \ No newline at end of file diff --git a/molecule/distributed-wazuh-odfe/molecule.yml b/molecule/distributed-wazuh-odfe/molecule.yml new file mode 100644 index 00000000..46c08695 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/molecule.yml @@ -0,0 +1,162 @@ +--- +# Distributed scenario: clustered manager scenario + connected agents +# 2-core CPU +# 7 GB of RAM memory +# 14 GB of SSD disk space +# +# Source: https://docs.github.com/en/free-pro-team@latest/actions/reference/specifications-for-github-hosted-runners + +dependency: + name: galaxy +driver: + name: docker +lint: | + yamllint . + ansible-lint roles + flake8 molecule +platforms: + ################################################ + # Wazuh Managers + ################################################ + - name: molecule_odfe_manager_centos7 + hostname: wazuh-mgr01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: molecule_odfe_manager_debian9 + hostname: wazuh-mgr02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory_reservation: 512m + memory: 1024m + groups: + - managers + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Elastic Cluster + ################################################ + - name: molecule_odfe_elasticsearch_centos7 + hostname: wazuh-es01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 4096m + memory_reservation: 2048m + groups: + - elastic + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: molecule_odfe_elasticsearch_centos7_2 + hostname: wazuh-es02 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 4096m + memory_reservation: 2048m + groups: + - elastic + ulimits: + - nofile:262144:262144 + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Wazuh Agents + ################################################ + - name: molecule_odfe_agent_centos7 + hostname: wazuh-agent01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 1024m + memory_reservation: 512m + groups: + - agents + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + - name: molecule_odfe_agent_debian9 + hostname: wazuh-agent02 + image: geerlingguy/docker-debian9-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 1024m + memory_reservation: 512m + groups: + - agents + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + + ################################################ + # Kibana + ################################################ + + - name: molecule_odfe_kibana_centos7 + hostname: wazuh-kib01 + image: geerlingguy/docker-centos7-ansible + command: /sbin/init + pre_build_image: true + privileged: true + memory: 2048m + memory_reservation: 512m + groups: + - kibana + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + +provisioner: + name: ansible + ansible_args: + - -vv + inventory: + links: + group_vars: group_vars + playbooks: + create: create.yml + converge: converge.yml + #destroy: destroy.yml + config_options: + defaults: + hash_behaviour: merge + env: + ANSIBLE_ROLES_PATH: ./roles + lint: + name: ansible-lint + enabled: false +scenario: + name: distributed-wazuh-odfe + test_sequence: + - dependency + - syntax + - create + - prepare + - converge + #- idempotence + #- verify + - cleanup + - destroy +verifier: + name: testinfra \ No newline at end of file diff --git a/molecule/distributed-wazuh-odfe/tests/test_default.py b/molecule/distributed-wazuh-odfe/tests/test_default.py new file mode 100644 index 00000000..a6a86674 --- /dev/null +++ b/molecule/distributed-wazuh-odfe/tests/test_default.py @@ -0,0 +1,64 @@ +import os +import pytest +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def get_wazuh_version(): + """This return the version of Wazuh.""" + return "4.0.0" + + +def test_wazuh_packages_are_installed(host): + """Test the main packages are installed.""" + manager = host.package("wazuh-manager") + assert manager.is_installed + assert manager.version.startswith(get_wazuh_version()) + + +def test_wazuh_services_are_running(host): + """Test the services are enabled and running. + + When assert commands are commented, this means that the service command has + a wrong exit code: https://github.com/wazuh/wazuh-ansible/issues/107 + """ + # This currently doesn't work with out current Docker base images + # manager = host.service("wazuh-manager") + # api = host.service("wazuh-api") + # assert manager.is_running + # assert api.is_running + output = host.check_output( + 'ps aux | grep ossec | tr -s " " | cut -d" " -f11' + ) + assert 'ossec-authd' in output + assert 'wazuh-modulesd' in output + assert 'wazuh-db' in output + assert 'ossec-execd' in output + assert 'ossec-monitord' in output + assert 'ossec-remoted' in output + assert 'ossec-logcollector' in output + assert 'ossec-analysisd' in output + assert 'ossec-syscheckd' in output + + +@pytest.mark.parametrize("wazuh_file, wazuh_owner, wazuh_group, wazuh_mode", [ + ("/var/ossec/etc/sslmanager.cert", "root", "root", 0o640), + ("/var/ossec/etc/sslmanager.key", "root", "root", 0o640), + ("/var/ossec/etc/rules/local_rules.xml", "ossec", "ossec", 0o640), + ("/var/ossec/etc/lists/audit-keys", "ossec", "ossec", 0o660), +]) +def test_wazuh_files(host, wazuh_file, wazuh_owner, wazuh_group, wazuh_mode): + """Test Wazuh related files exist and have proper owners and mode.""" + wazuh_file_host = host.file(wazuh_file) + assert wazuh_file_host.user == wazuh_owner + assert wazuh_file_host.group == wazuh_group + assert wazuh_file_host.mode == wazuh_mode + + +def test_filebeat_is_installed(host): + """Test the elasticsearch package is installed.""" + filebeat = host.package("filebeat") + assert filebeat.is_installed + assert filebeat.version.startswith('7.9.1') diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..96daf99c --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1282 @@ +[[package]] +category = "main" +description = "Radically simple IT automation" +name = "ansible" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +version = "2.9.5" + +[[package]] +category = "dev" +description = "Checks playbooks for practices and behaviour that could potentially be improved" +name = "ansible-lint" +optional = false +python-versions = ">=3.6" +version = "4.3.7" + +[package.dependencies] +ansible = ">=2.8" +pyyaml = "*" +rich = "*" + +[[package.dependencies."ruamel.yaml"]] +python = "<3.7" +version = ">=0.15.34,<1" + +[[package.dependencies."ruamel.yaml"]] +python = ">=3.7" +version = ">=0.15.37,<1" + +[package.dependencies.typing-extensions] +python = "<3.8" +version = "*" + +[[package]] +category = "dev" +description = "Better dates & times for Python" +name = "arrow" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.17.0" + +[package.dependencies] +python-dateutil = ">=2.7.0" + +[[package]] +category = "dev" +description = "Atomic file writes." +marker = "sys_platform == \"win32\"" +name = "atomicwrites" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.0" + +[[package]] +category = "dev" +description = "Classes Without Boilerplate" +name = "attrs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.2.0" + +[package.extras] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] + +[[package]] +category = "dev" +description = "Modern password hashing for your software and your servers" +name = "bcrypt" +optional = false +python-versions = ">=3.6" +version = "3.2.0" + +[package.dependencies] +cffi = ">=1.1" +six = ">=1.4.1" + +[package.extras] +tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)"] +typecheck = ["mypy"] + +[[package]] +category = "dev" +description = "Ultra-lightweight pure Python package to check if a file is binary or text." +name = "binaryornot" +optional = false +python-versions = "*" +version = "0.4.4" + +[package.dependencies] +chardet = ">=3.0.2" + +[[package]] +category = "dev" +description = "Lightweight, extensible schema and data validation tool for Python dictionaries." +name = "cerberus" +optional = false +python-versions = ">=2.7" +version = "1.3.2" + +[package.dependencies] +setuptools = "*" + +[[package]] +category = "dev" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2020.6.20" + +[[package]] +category = "dev" +description = "Foreign Function Interface for Python calling C code." +name = "cffi" +optional = false +python-versions = "*" +version = "1.14.3" + +[package.dependencies] +pycparser = "*" + +[[package]] +category = "dev" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "dev" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" + +[[package]] +category = "dev" +description = "Fish, Bash, Zsh and PowerShell completion for Click" +name = "click-completion" +optional = false +python-versions = "*" +version = "0.5.2" + +[package.dependencies] +click = "*" +jinja2 = "*" +shellingham = "*" +six = "*" + +[[package]] +category = "dev" +description = "Colorization of help messages in Click" +name = "click-help-colors" +optional = false +python-versions = "*" +version = "0.8" + +[package.dependencies] +click = ">=7.0" + +[package.extras] +dev = ["pytest"] + +[[package]] +category = "dev" +description = "Cross-platform colored terminal text." +name = "colorama" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.4.4" + +[[package]] +category = "dev" +description = "Python parser for the CommonMark Markdown spec" +name = "commonmark" +optional = false +python-versions = "*" +version = "0.9.1" + +[package.extras] +test = ["flake8 (3.7.8)", "hypothesis (3.55.3)"] + +[[package]] +category = "dev" +description = "A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template." +name = "cookiecutter" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "1.7.2" + +[package.dependencies] +Jinja2 = "<3.0.0" +MarkupSafe = "<2.0.0" +binaryornot = ">=0.4.4" +click = ">=7.0" +jinja2-time = ">=0.2.0" +poyo = ">=0.5.0" +python-slugify = ">=4.0.0" +requests = ">=2.23.0" +six = ">=1.10" + +[[package]] +category = "dev" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +name = "cryptography" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +version = "3.2.1" + +[package.dependencies] +cffi = ">=1.8,<1.11.3 || >1.11.3" +six = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0,<3.1.0 || >3.1.0,<3.1.1 || >3.1.1)", "sphinx-rtd-theme"] +docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] + +[[package]] +category = "dev" +description = "A backport of the dataclasses module for Python 3.6" +marker = "python_version >= \"3.6\" and python_version < \"3.7\"" +name = "dataclasses" +optional = false +python-versions = ">=3.6, <3.7" +version = "0.7" + +[[package]] +category = "dev" +description = "Distro - an OS platform information API" +name = "distro" +optional = false +python-versions = "*" +version = "1.5.0" + +[[package]] +category = "dev" +description = "A Python library for the Docker Engine API." +name = "docker" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "4.3.1" + +[package.dependencies] +pywin32 = "227" +requests = ">=2.14.2,<2.18.0 || >2.18.0" +six = ">=1.4.0" +websocket-client = ">=0.32.0" + +[package.extras] +ssh = ["paramiko (>=2.4.2)"] +tls = ["pyOpenSSL (>=17.5.0)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] + +[[package]] +category = "dev" +description = "A python package that provides useful locks." +name = "fasteners" +optional = false +python-versions = "*" +version = "0.15" + +[package.dependencies] +monotonic = ">=0.1" +six = "*" + +[[package]] +category = "dev" +description = "the modular source code checker: pep8 pyflakes and co" +name = "flake8" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "3.8.4" + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.6.0a1,<2.7.0" +pyflakes = ">=2.2.0,<2.3.0" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + +[[package]] +category = "dev" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.10" + +[[package]] +category = "dev" +description = "Read metadata from Python packages" +marker = "python_version < \"3.8\"" +name = "importlib-metadata" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "2.0.0" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] + +[[package]] +category = "main" +description = "A very fast and expressive template engine." +name = "jinja2" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.11.2" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[package.extras] +i18n = ["Babel (>=0.8)"] + +[[package]] +category = "dev" +description = "Jinja2 Extension for Dates and Times" +name = "jinja2-time" +optional = false +python-versions = "*" +version = "0.2.0" + +[package.dependencies] +arrow = "*" +jinja2 = "*" + +[[package]] +category = "main" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.1" + +[[package]] +category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" +optional = false +python-versions = "*" +version = "0.6.1" + +[[package]] +category = "dev" +description = "Molecule aids in the development and testing of Ansible roles" +name = "molecule" +optional = false +python-versions = ">=3.6" +version = "3.0.8" + +[package.dependencies] +Jinja2 = ">=2.10.1" +PyYAML = ">=5.1,<6" +ansible = ">=2.8" +cerberus = ">=1.3.1" +click = ">=7.0" +click-completion = ">=0.5.1" +click-help-colors = ">=0.6" +colorama = ">=0.3.9" +cookiecutter = ">=1.6.0,<1.7.1 || >1.7.1" +paramiko = ">=2.5.0,<3" +pexpect = ">=4.6.0,<5" +pluggy = ">=0.7.1,<1.0" +python-gilt = ">=1.2.1,<2" +selinux = "*" +sh = ">=1.13.1,<1.14" +tabulate = ">=0.8.4" +tree-format = ">=0.1.2" +yamllint = ">=1.15.0,<2" + +[package.dependencies.docker] +optional = true +version = ">=2.0.0" + +[package.extras] +docker = ["docker (>=2.0.0)"] +docs = ["simplejson", "sphinx", "sphinx-ansible-theme (>=0.2.2)"] +lint = ["ansible-lint (>=4.2.0,<5)", "flake8 (>=3.6.0)", "pre-commit (>=1.21.0)", "yamllint (>=1.15.0)"] +test = ["ansi2html", "coverage (<5)", "mock (>=3.0.5,<4)", "packaging", "pytest-cov (>=2.7.1,<3)", "pytest-helpers-namespace (>=2019.1.8,<2020)", "pytest-html (>=1.21.0)", "pytest-mock (>=1.10.4,<2)", "pytest-verbose-parametrize (>=1.7.0,<2)", "pytest-plus", "pytest-xdist (>=1.29.0,<2)", "pytest (>=5.4.0,<5.5)", "testinfra (>=3.4.0)"] +windows = ["pywinrm"] + +[[package]] +category = "dev" +description = "An implementation of time.monotonic() for Python 2 & < 3.3" +name = "monotonic" +optional = false +python-versions = "*" +version = "1.5" + +[[package]] +category = "dev" +description = "More routines for operating on iterables, beyond itertools" +name = "more-itertools" +optional = false +python-versions = ">=3.5" +version = "8.6.0" + +[[package]] +category = "dev" +description = "Core utilities for Python packages" +name = "packaging" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "20.4" + +[package.dependencies] +pyparsing = ">=2.0.2" +six = "*" + +[[package]] +category = "dev" +description = "SSH2 protocol library" +name = "paramiko" +optional = false +python-versions = "*" +version = "2.7.2" + +[package.dependencies] +bcrypt = ">=3.1.3" +cryptography = ">=2.5" +pynacl = ">=1.0.1" + +[package.extras] +all = ["pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "bcrypt (>=3.1.3)", "invoke (>=1.3)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] +ed25519 = ["pynacl (>=1.0.1)", "bcrypt (>=3.1.3)"] +gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] +invoke = ["invoke (>=1.3)"] + +[[package]] +category = "dev" +description = "Utility library for gitignore style pattern matching of file paths." +name = "pathspec" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.8.0" + +[[package]] +category = "dev" +description = "Pexpect allows easy control of interactive console applications." +name = "pexpect" +optional = false +python-versions = "*" +version = "4.8.0" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.13.1" + +[package.dependencies] +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + +[package.extras] +dev = ["pre-commit", "tox"] + +[[package]] +category = "dev" +description = "A lightweight YAML Parser for Python. 🐓" +name = "poyo" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.5.0" + +[[package]] +category = "dev" +description = "Run a subprocess in a pseudo terminal" +name = "ptyprocess" +optional = false +python-versions = "*" +version = "0.6.0" + +[[package]] +category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.9.0" + +[[package]] +category = "dev" +description = "Python style guide checker" +name = "pycodestyle" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.6.0" + +[[package]] +category = "dev" +description = "C parser in Python" +name = "pycparser" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.20" + +[[package]] +category = "dev" +description = "passive checker of Python programs" +name = "pyflakes" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.2.0" + +[[package]] +category = "dev" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = ">=3.5" +version = "2.7.2" + +[[package]] +category = "dev" +description = "Python binding to the Networking and Cryptography (NaCl) library" +name = "pynacl" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.0" + +[package.dependencies] +cffi = ">=1.4.1" +six = "*" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)", "hypothesis (>=3.27.0)"] + +[[package]] +category = "dev" +description = "Python parsing module" +name = "pyparsing" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.4.7" + +[[package]] +category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" +optional = false +python-versions = ">=3.5" +version = "5.4.3" + +[package.dependencies] +atomicwrites = ">=1.0" +attrs = ">=17.4.0" +colorama = "*" +more-itertools = ">=4.0.0" +packaging = "*" +pluggy = ">=0.12,<1.0" +py = ">=1.5.0" +wcwidth = "*" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + +[package.extras] +checkqa-mypy = ["mypy (v0.761)"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +category = "dev" +description = "Extensions to the standard Python datetime module" +name = "python-dateutil" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +version = "2.8.1" + +[package.dependencies] +six = ">=1.5" + +[[package]] +category = "dev" +description = "gilt - A GIT layering tool." +name = "python-gilt" +optional = false +python-versions = ">=3.6" +version = "1.2.3" + +[package.dependencies] +PyYAML = "*" +click = "*" +colorama = "*" +fasteners = "*" +sh = "*" + +[package.extras] +test = ["black (19.10b0)", "flake8", "hacking", "pep517", "pytest", "pytest-cov", "pytest-helpers-namespace", "pytest-mock", "twine"] + +[[package]] +category = "dev" +description = "A Python Slugify application that handles Unicode" +name = "python-slugify" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "4.0.1" + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + +[[package]] +category = "dev" +description = "Python for Window Extensions" +marker = "sys_platform == \"win32\"" +name = "pywin32" +optional = false +python-versions = "*" +version = "227" + +[[package]] +category = "dev" +description = "YAML parser and emitter for Python" +name = "pyyaml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.3.1" + +[[package]] +category = "dev" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.24.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<4" +idna = ">=2.5,<3" +urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" + +[package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] + +[[package]] +category = "dev" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +name = "rich" +optional = false +python-versions = ">=3.6,<4.0" +version = "9.1.0" + +[package.dependencies] +colorama = ">=0.4.0,<0.5.0" +commonmark = ">=0.9.0,<0.10.0" +pygments = ">=2.6.0,<3.0.0" +typing-extensions = ">=3.7.4,<4.0.0" + +[package.dependencies.dataclasses] +python = ">=3.6,<3.7" +version = ">=0.7,<0.8" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] + +[[package]] +category = "dev" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +marker = "python_version < \"3.7\" or python_version >= \"3.7\"" +name = "ruamel.yaml" +optional = false +python-versions = "*" +version = "0.16.12" + +[package.dependencies] +[package.dependencies."ruamel.yaml.clib"] +python = "<3.9" +version = ">=0.1.2" + +[package.extras] +docs = ["ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +category = "dev" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +marker = "platform_python_implementation == \"CPython\" and python_version < \"3.7\" or platform_python_implementation == \"CPython\" and python_version < \"3.9\" and python_version >= \"3.7\"" +name = "ruamel.yaml.clib" +optional = false +python-versions = "*" +version = "0.2.2" + +[[package]] +category = "dev" +description = "shim selinux module" +name = "selinux" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "0.2.1" + +[package.dependencies] +distro = ">=1.3.0" +setuptools = ">=39.0" + +[[package]] +category = "dev" +description = "Python subprocess replacement" +name = "sh" +optional = false +python-versions = "*" +version = "1.13.1" + +[[package]] +category = "dev" +description = "Tool to Detect Surrounding Shell" +name = "shellingham" +optional = false +python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6" +version = "1.3.2" + +[[package]] +category = "dev" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.15.0" + +[[package]] +category = "dev" +description = "Pretty-print tabular data" +name = "tabulate" +optional = false +python-versions = "*" +version = "0.8.7" + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +category = "dev" +description = "Test infrastructures" +name = "testinfra" +optional = false +python-versions = ">=3.5" +version = "5.3.1" + +[package.dependencies] +pytest = "!=3.0.2" + +[package.extras] +ansible = ["ansible"] +paramiko = ["paramiko"] +salt = ["salt"] +winrm = ["pywinrm"] + +[[package]] +category = "dev" +description = "The most basic Text::Unidecode port" +name = "text-unidecode" +optional = false +python-versions = "*" +version = "1.3" + +[[package]] +category = "dev" +description = "" +name = "tree-format" +optional = false +python-versions = "*" +version = "0.1.2" + +[package.extras] +dev = ["pytest (>=2.7.1)", "testtools (>=1.8.0)"] + +[[package]] +category = "dev" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = false +python-versions = "*" +version = "3.7.4.3" + +[[package]] +category = "dev" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.25.11" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[[package]] +category = "dev" +description = "Measures the displayed width of unicode strings in a terminal" +name = "wcwidth" +optional = false +python-versions = "*" +version = "0.2.5" + +[[package]] +category = "dev" +description = "WebSocket client for Python. hybi13 is supported." +name = "websocket-client" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.57.0" + +[package.dependencies] +six = "*" + +[[package]] +category = "dev" +description = "A linter for YAML files." +name = "yamllint" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "1.25.0" + +[package.dependencies] +pathspec = ">=0.5.3" +pyyaml = "*" +setuptools = "*" + +[[package]] +category = "dev" +description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\"" +name = "zipp" +optional = false +python-versions = ">=3.6" +version = "3.4.0" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[metadata] +content-hash = "4114e22097faba4d352cd5aa591e462e7d681179fea8b2f46c819dede8e54aee" +lock-version = "1.0" +python-versions = "^3.6" + +[metadata.files] +ansible = [ + {file = "ansible-2.9.5.tar.gz", hash = "sha256:51ae50d33264eb644ecb79a0208a20569a1127ec3440e8de60eda3a2b3d9caa5"}, +] +ansible-lint = [ + {file = "ansible-lint-4.3.7.tar.gz", hash = "sha256:1012fc3f5c4c0c58eece515860f19c34c5088faa5be412eec6fae5b45bda9c4f"}, + {file = "ansible_lint-4.3.7-py2.py3-none-any.whl", hash = "sha256:300e841f690b556a08d44902d6414283dc101079b27909e3a892f1cf1d10d7ff"}, +] +arrow = [ + {file = "arrow-0.17.0-py2.py3-none-any.whl", hash = "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5"}, + {file = "arrow-0.17.0.tar.gz", hash = "sha256:ff08d10cda1d36c68657d6ad20d74fbea493d980f8b2d45344e00d6ed2bf6ed4"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, + {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, +] +bcrypt = [ + {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, + {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, + {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, + {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, + {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, +] +binaryornot = [ + {file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"}, + {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"}, +] +cerberus = [ + {file = "Cerberus-1.3.2.tar.gz", hash = "sha256:302e6694f206dd85cb63f13fd5025b31ab6d38c99c50c6d769f8fa0b0f299589"}, +] +certifi = [ + {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, + {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, +] +cffi = [ + {file = "cffi-1.14.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:485d029815771b9fe4fa7e1c304352fe57df6939afe835dfd0182c7c13d5e92e"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c"}, + {file = "cffi-1.14.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730"}, + {file = "cffi-1.14.3-cp27-cp27m-win32.whl", hash = "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d"}, + {file = "cffi-1.14.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b"}, + {file = "cffi-1.14.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171"}, + {file = "cffi-1.14.3-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:52bf29af05344c95136df71716bb60508bbd217691697b4307dcae681612db9f"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f"}, + {file = "cffi-1.14.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4"}, + {file = "cffi-1.14.3-cp35-cp35m-win32.whl", hash = "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d"}, + {file = "cffi-1.14.3-cp35-cp35m-win_amd64.whl", hash = "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d"}, + {file = "cffi-1.14.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c687778dda01832555e0af205375d649fa47afeaeeb50a201711f9a9573323b8"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808"}, + {file = "cffi-1.14.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537"}, + {file = "cffi-1.14.3-cp36-cp36m-win32.whl", hash = "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0"}, + {file = "cffi-1.14.3-cp36-cp36m-win_amd64.whl", hash = "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e"}, + {file = "cffi-1.14.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:03d3d238cc6c636a01cf55b9b2e1b6531a7f2f4103fabb5a744231582e68ecc7"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579"}, + {file = "cffi-1.14.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394"}, + {file = "cffi-1.14.3-cp37-cp37m-win32.whl", hash = "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc"}, + {file = "cffi-1.14.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869"}, + {file = "cffi-1.14.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c2a33558fdbee3df370399fe1712d72464ce39c66436270f3664c03f94971aff"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828"}, + {file = "cffi-1.14.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9"}, + {file = "cffi-1.14.3-cp38-cp38-win32.whl", hash = "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522"}, + {file = "cffi-1.14.3-cp38-cp38-win_amd64.whl", hash = "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15"}, + {file = "cffi-1.14.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d9a7dc7cf8b1101af2602fe238911bcc1ac36d239e0a577831f5dac993856e9"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d"}, + {file = "cffi-1.14.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c"}, + {file = "cffi-1.14.3-cp39-cp39-win32.whl", hash = "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b"}, + {file = "cffi-1.14.3-cp39-cp39-win_amd64.whl", hash = "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3"}, + {file = "cffi-1.14.3.tar.gz", hash = "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591"}, +] +chardet = [ + {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, + {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] +click-completion = [ + {file = "click-completion-0.5.2.tar.gz", hash = "sha256:5bf816b81367e638a190b6e91b50779007d14301b3f9f3145d68e3cade7bce86"}, +] +click-help-colors = [ + {file = "click-help-colors-0.8.tar.gz", hash = "sha256:119e5faf69cfc919c995c5962326ac8fd87f11e56a371af594e3dfd8458f4c6e"}, + {file = "click_help_colors-0.8-py3-none-any.whl", hash = "sha256:0d841a4058ec88c47f93ff6f32547a055f8e0a0273f6bd6cb3e08430f195131d"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +commonmark = [ + {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, + {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, +] +cookiecutter = [ + {file = "cookiecutter-1.7.2-py2.py3-none-any.whl", hash = "sha256:430eb882d028afb6102c084bab6cf41f6559a77ce9b18dc6802e3bc0cc5f4a30"}, + {file = "cookiecutter-1.7.2.tar.gz", hash = "sha256:efb6b2d4780feda8908a873e38f0e61778c23f6a2ea58215723bcceb5b515dac"}, +] +cryptography = [ + {file = "cryptography-3.2.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:6dc59630ecce8c1f558277ceb212c751d6730bd12c80ea96b4ac65637c4f55e7"}, + {file = "cryptography-3.2.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:75e8e6684cf0034f6bf2a97095cb95f81537b12b36a8fedf06e73050bb171c2d"}, + {file = "cryptography-3.2.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4e7268a0ca14536fecfdf2b00297d4e407da904718658c1ff1961c713f90fd33"}, + {file = "cryptography-3.2.1-cp27-cp27m-win32.whl", hash = "sha256:7117319b44ed1842c617d0a452383a5a052ec6aa726dfbaffa8b94c910444297"}, + {file = "cryptography-3.2.1-cp27-cp27m-win_amd64.whl", hash = "sha256:a733671100cd26d816eed39507e585c156e4498293a907029969234e5e634bc4"}, + {file = "cryptography-3.2.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:a75f306a16d9f9afebfbedc41c8c2351d8e61e818ba6b4c40815e2b5740bb6b8"}, + {file = "cryptography-3.2.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5849d59358547bf789ee7e0d7a9036b2d29e9a4ddf1ce5e06bb45634f995c53e"}, + {file = "cryptography-3.2.1-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:bd717aa029217b8ef94a7d21632a3bb5a4e7218a4513d2521c2a2fd63011e98b"}, + {file = "cryptography-3.2.1-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:efe15aca4f64f3a7ea0c09c87826490e50ed166ce67368a68f315ea0807a20df"}, + {file = "cryptography-3.2.1-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77"}, + {file = "cryptography-3.2.1-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:7b8d9d8d3a9bd240f453342981f765346c87ade811519f98664519696f8e6ab7"}, + {file = "cryptography-3.2.1-cp35-cp35m-win32.whl", hash = "sha256:d3545829ab42a66b84a9aaabf216a4dce7f16dbc76eb69be5c302ed6b8f4a29b"}, + {file = "cryptography-3.2.1-cp35-cp35m-win_amd64.whl", hash = "sha256:a4e27ed0b2504195f855b52052eadcc9795c59909c9d84314c5408687f933fc7"}, + {file = "cryptography-3.2.1-cp36-abi3-win32.whl", hash = "sha256:13b88a0bd044b4eae1ef40e265d006e34dbcde0c2f1e15eb9896501b2d8f6c6f"}, + {file = "cryptography-3.2.1-cp36-abi3-win_amd64.whl", hash = "sha256:07ca431b788249af92764e3be9a488aa1d39a0bc3be313d826bbec690417e538"}, + {file = "cryptography-3.2.1-cp36-cp36m-win32.whl", hash = "sha256:a035a10686532b0587d58a606004aa20ad895c60c4d029afa245802347fab57b"}, + {file = "cryptography-3.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:d26a2557d8f9122f9bf445fc7034242f4375bd4e95ecda007667540270965b13"}, + {file = "cryptography-3.2.1-cp37-cp37m-win32.whl", hash = "sha256:545a8550782dda68f8cdc75a6e3bf252017aa8f75f19f5a9ca940772fc0cb56e"}, + {file = "cryptography-3.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:55d0b896631412b6f0c7de56e12eb3e261ac347fbaa5d5e705291a9016e5f8cb"}, + {file = "cryptography-3.2.1-cp38-cp38-win32.whl", hash = "sha256:3cd75a683b15576cfc822c7c5742b3276e50b21a06672dc3a800a2d5da4ecd1b"}, + {file = "cryptography-3.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:d25cecbac20713a7c3bc544372d42d8eafa89799f492a43b79e1dfd650484851"}, + {file = "cryptography-3.2.1.tar.gz", hash = "sha256:d3d5e10be0cf2a12214ddee45c6bd203dab435e3d83b4560c03066eda600bfe3"}, +] +dataclasses = [ + {file = "dataclasses-0.7-py3-none-any.whl", hash = "sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836"}, + {file = "dataclasses-0.7.tar.gz", hash = "sha256:494a6dcae3b8bcf80848eea2ef64c0cc5cd307ffc263e17cdf42f3e5420808e6"}, +] +distro = [ + {file = "distro-1.5.0-py2.py3-none-any.whl", hash = "sha256:df74eed763e18d10d0da624258524ae80486432cd17392d9c3d96f5e83cd2799"}, + {file = "distro-1.5.0.tar.gz", hash = "sha256:0e58756ae38fbd8fc3020d54badb8eae17c5b9dcbed388b17bb55b8a5928df92"}, +] +docker = [ + {file = "docker-4.3.1-py2.py3-none-any.whl", hash = "sha256:13966471e8bc23b36bfb3a6fb4ab75043a5ef1dac86516274777576bed3b9828"}, + {file = "docker-4.3.1.tar.gz", hash = "sha256:bad94b8dd001a8a4af19ce4becc17f41b09f228173ffe6a4e0355389eef142f2"}, +] +fasteners = [ + {file = "fasteners-0.15-py2.py3-none-any.whl", hash = "sha256:007e4d2b2d4a10093f67e932e5166722d2eab83b77724156e92ad013c6226574"}, + {file = "fasteners-0.15.tar.gz", hash = "sha256:3a176da6b70df9bb88498e1a18a9e4a8579ed5b9141207762368a1017bf8f5ef"}, +] +flake8 = [ + {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, + {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, +] +idna = [ + {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, + {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, +] +importlib-metadata = [ + {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"}, + {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"}, +] +jinja2 = [ + {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, + {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, +] +jinja2-time = [ + {file = "jinja2-time-0.2.0.tar.gz", hash = "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40"}, + {file = "jinja2_time-0.2.0-py2.py3-none-any.whl", hash = "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa"}, +] +markupsafe = [ + {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, + {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +molecule = [ + {file = "molecule-3.0.8-py3-none-any.whl", hash = "sha256:6fb202099ff52bc427c6bd8f46f13b49b3d5812daa6880960a0fd0562e8a9be6"}, + {file = "molecule-3.0.8.tar.gz", hash = "sha256:42d0c661b52074b00a620466df367ddab9c3682875e6d685bfc93487ef0479cc"}, +] +monotonic = [ + {file = "monotonic-1.5-py2.py3-none-any.whl", hash = "sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"}, + {file = "monotonic-1.5.tar.gz", hash = "sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0"}, +] +more-itertools = [ + {file = "more-itertools-8.6.0.tar.gz", hash = "sha256:b3a9005928e5bed54076e6e549c792b306fddfe72b2d1d22dd63d42d5d3899cf"}, + {file = "more_itertools-8.6.0-py3-none-any.whl", hash = "sha256:8e1a2a43b2f2727425f2b5839587ae37093f19153dc26c0927d1048ff6557330"}, +] +packaging = [ + {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, + {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, +] +paramiko = [ + {file = "paramiko-2.7.2-py2.py3-none-any.whl", hash = "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898"}, + {file = "paramiko-2.7.2.tar.gz", hash = "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035"}, +] +pathspec = [ + {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, + {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, +] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +poyo = [ + {file = "poyo-0.5.0-py2.py3-none-any.whl", hash = "sha256:3e2ca8e33fdc3c411cd101ca395668395dd5dc7ac775b8e809e3def9f9fe041a"}, + {file = "poyo-0.5.0.tar.gz", hash = "sha256:e26956aa780c45f011ca9886f044590e2d8fd8b61db7b1c1cf4e0869f48ed4dd"}, +] +ptyprocess = [ + {file = "ptyprocess-0.6.0-py2.py3-none-any.whl", hash = "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"}, + {file = "ptyprocess-0.6.0.tar.gz", hash = "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0"}, +] +py = [ + {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, + {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, +] +pycodestyle = [ + {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, + {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, +] +pycparser = [ + {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, + {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, +] +pyflakes = [ + {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, + {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, +] +pygments = [ + {file = "Pygments-2.7.2-py3-none-any.whl", hash = "sha256:88a0bbcd659fcb9573703957c6b9cff9fab7295e6e76db54c9d00ae42df32773"}, + {file = "Pygments-2.7.2.tar.gz", hash = "sha256:381985fcc551eb9d37c52088a32914e00517e57f4a21609f48141ba08e193fa0"}, +] +pynacl = [ + {file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-win32.whl", hash = "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574"}, + {file = "PyNaCl-1.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80"}, + {file = "PyNaCl-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7"}, + {file = "PyNaCl-1.4.0-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122"}, + {file = "PyNaCl-1.4.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d"}, + {file = "PyNaCl-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4"}, + {file = "PyNaCl-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25"}, + {file = "PyNaCl-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4"}, + {file = "PyNaCl-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6"}, + {file = "PyNaCl-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f"}, + {file = "PyNaCl-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f"}, + {file = "PyNaCl-1.4.0-cp38-cp38-win32.whl", hash = "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96"}, + {file = "PyNaCl-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420"}, + {file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, + {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] +python-gilt = [ + {file = "python_gilt-1.2.3-py2.py3-none-any.whl", hash = "sha256:e220ea2e7e190ee06dbfa5fafe87967858b4ac0cf53f3072fa6ece4664a42082"}, +] +python-slugify = [ + {file = "python-slugify-4.0.1.tar.gz", hash = "sha256:69a517766e00c1268e5bbfc0d010a0a8508de0b18d30ad5a1ff357f8ae724270"}, +] +pywin32 = [ + {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, + {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, + {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, + {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, + {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, + {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, + {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, + {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, + {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, + {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, + {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, + {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, +] +pyyaml = [ + {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, + {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, + {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, + {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, + {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, +] +requests = [ + {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, + {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, +] +rich = [ + {file = "rich-9.1.0-py3-none-any.whl", hash = "sha256:5dd934a0f8953b59d9a5d8d58864012174f0b5ad2de687fd04f4df195f7f7066"}, + {file = "rich-9.1.0.tar.gz", hash = "sha256:05f1cf4dc191c483867b098d8572546de266440d61911d8270069023e325d14a"}, +] +"ruamel.yaml" = [ + {file = "ruamel.yaml-0.16.12-py2.py3-none-any.whl", hash = "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5"}, + {file = "ruamel.yaml-0.16.12.tar.gz", hash = "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e"}, +] +"ruamel.yaml.clib" = [ + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win32.whl", hash = "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win_amd64.whl", hash = "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"}, + {file = "ruamel.yaml.clib-0.2.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win32.whl", hash = "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f"}, + {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win32.whl", hash = "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2"}, + {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win32.whl", hash = "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6"}, + {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"}, + {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"}, + {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"}, +] +selinux = [ + {file = "selinux-0.2.1-py2.py3-none-any.whl", hash = "sha256:820adcf1b4451c9cc7759848797703263ba0eb6a4cad76d73548a9e0d57b7926"}, + {file = "selinux-0.2.1.tar.gz", hash = "sha256:d435f514e834e3fdc0941f6a29d086b80b2ea51b28112aee6254bd104ee42a74"}, +] +sh = [ + {file = "sh-1.13.1-py2.py3-none-any.whl", hash = "sha256:6f792e45b45d039b423081558904981e8ab49572b0c38009fcc65feaab06bcda"}, + {file = "sh-1.13.1.tar.gz", hash = "sha256:97a3d2205e3c6a842d87ebbc9ae93acae5a352b1bc4609b428d0fd5bb9e286a3"}, +] +shellingham = [ + {file = "shellingham-1.3.2-py2.py3-none-any.whl", hash = "sha256:7f6206ae169dc1a03af8a138681b3f962ae61cc93ade84d0585cca3aaf770044"}, + {file = "shellingham-1.3.2.tar.gz", hash = "sha256:576c1982bea0ba82fb46c36feb951319d7f42214a82634233f58b40d858a751e"}, +] +six = [ + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, +] +tabulate = [ + {file = "tabulate-0.8.7-py3-none-any.whl", hash = "sha256:ac64cb76d53b1231d364babcd72abbb16855adac7de6665122f97b593f1eb2ba"}, + {file = "tabulate-0.8.7.tar.gz", hash = "sha256:db2723a20d04bcda8522165c73eea7c300eda74e0ce852d9022e0159d7895007"}, +] +testinfra = [ + {file = "testinfra-5.3.1-py3-none-any.whl", hash = "sha256:9d3a01fb787253df76ac4ab46d18a84d4b01be877ed1b5812e590dcf480a627e"}, + {file = "testinfra-5.3.1.tar.gz", hash = "sha256:baf1d809ea2dc22c0cb5b9441bf4e17c1eb653e1ccc02cc63137d0ab467fa1de"}, +] +text-unidecode = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] +tree-format = [ + {file = "tree-format-0.1.2.tar.gz", hash = "sha256:a538523aa78ae7a4b10003b04f3e1b37708e0e089d99c9d3b9e1c71384c9a7f9"}, + {file = "tree_format-0.1.2-py2-none-any.whl", hash = "sha256:b5056228dbedde1fb81b79f71fb0c23c98e9d365230df9b29af76e8d8003de11"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, +] +urllib3 = [ + {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"}, + {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"}, +] +wcwidth = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] +websocket-client = [ + {file = "websocket_client-0.57.0-py2.py3-none-any.whl", hash = "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549"}, + {file = "websocket_client-0.57.0.tar.gz", hash = "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010"}, +] +yamllint = [ + {file = "yamllint-1.25.0-py2.py3-none-any.whl", hash = "sha256:c7be4d0d2584a1b561498fa9acb77ad22eb434a109725c7781373ae496d823b3"}, + {file = "yamllint-1.25.0.tar.gz", hash = "sha256:b1549cbe5b47b6ba67bdeea31720f5c51431a4d0c076c1557952d841f7223519"}, +] +zipp = [ + {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, + {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..aa98c6a0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,28 @@ +[tool.poetry] +name = "wazuh-ansible" +version = "4.0.0" +description = "" +authors = ["neonmei "] + +[tool.poetry.dependencies] +python = "^3.6" + +# Pin ansible version to that currently present on awx +ansible = "==2.9.5" +jinja2 = "^2.11.2" + +[tool.poetry.dev-dependencies] +pytest = "^5.2" +ansible-lint = "^4.3.5" +flake8 = "^3.8.4" +selinux = "^0.2.1" +yamllint = "^1.25.0" + +# minimum version is 3.0.3, because we need docker memory limitation +# https://github.com/ansible-community/molecule/pull/2615 +molecule = {extras = ["docker"], version = "==3.0.8"} +testinfra = "^5.3.1" + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api"