diff --git a/README.md b/README.md new file mode 100644 index 0000000..388fd81 --- /dev/null +++ b/README.md @@ -0,0 +1,512 @@ +# `whoami` +The main purpose of this repo is to provide a meaningful example for [a pull request against molecule.](https://github.com/ansible/molecule/pull/1646) +This is an example ansible role to set up an active-active keepalived cluster, which monitors nginx on two hosts. +There's a molecule scenario in the generic_laodbalancer repo, which will setup the cluster and run a side-effect playbook afterwards, to kill nginx on one host. +The verifier, [which is goss](https://github.com/aelsabbahy/goss), will check if the IP moved to the second host. + +## Installation/Usage +Checkout the repo, install requirements, cd into the roles/generic_loadbalancer directory, install optional requirements if you want to use mitogen, and run +`molecule test` + +##### Converge +This is the setup after converge. Active-active nginx cluster with keepalived managing the IPs. +``` +| nginx - glb-001 | <-- keepalived active/active --> | nginx - glb-002 | +| vip: 10.10.10.10 | <-- keepalived active/active --> | vip: 10.10.10.10 | +``` +##### Side-Effect +Our side-effect playbook now kills nginx on the first host. We are expecting the keepalived to move over the IP to the second host. + +``` +| nginx - glb-001 -> dead | <-- keepalived active/active --> | nginx - glb-002 | +| vip: move ip to glb-002 | <-- keepalived active/active --> | ip: 10.10.10.10, 10.10.10.11 | +``` + +##### example output +Here's what a test run looks like. +``` +--> Validating schema /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/molecule.yml. +Validation completed successfully. +--> Test matrix + +└── default + ├── lint + ├── destroy + ├── dependency + ├── syntax + ├── create + ├── prepare + ├── converge + ├── idempotence + ├── side_effect + ├── verify + └── destroy + +--> Scenario: 'default' +--> Action: 'lint' +--> Executing Yamllint on files found in /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/... +Lint completed successfully. +--> Executing Yamllint on files found in /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/tests/... +Lint completed successfully. +--> Executing Ansible Lint on /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/playbook.yml... +Lint completed successfully. +--> Scenario: 'default' +--> Action: 'destroy' + + PLAY [Destroy] ***************************************************************** + + TASK [Destroy molecule instance(s)] ******************************************** + Wednesday 16 January 2019 10:42:23 +0100 (0:00:00.107) 0:00:00.107 ***** + changed: [localhost] => (item=None) + changed: [localhost] => (item=None) + changed: [localhost] + + TASK [Wait for instance(s) deletion to complete] ******************************* + Wednesday 16 January 2019 10:42:26 +0100 (0:00:02.527) 0:00:02.634 ***** + ok: [localhost] => (item=None) + ok: [localhost] => (item=None) + ok: [localhost] + + TASK [Delete docker network(s)] ************************************************ + Wednesday 16 January 2019 10:42:26 +0100 (0:00:00.596) 0:00:03.231 ***** + skipping: [localhost] + + PLAY RECAP ********************************************************************* + localhost : ok=2 changed=1 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:42:27 +0100 (0:00:00.104) 0:00:03.336 ***** + =============================================================================== + Destroy molecule instance(s) -------------------------------------------- 2.53s + Wait for instance(s) deletion to complete ------------------------------- 0.60s + Delete docker network(s) ------------------------------------------------ 0.10s + +--> Scenario: 'default' +--> Action: 'dependency' +Skipping, missing the requirements file. +--> Scenario: 'default' +--> Action: 'syntax' + + playbook: /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/playbook.yml + +--> Scenario: 'default' +--> Action: 'create' + + PLAY [Create] ****************************************************************** + + TASK [Log into a Docker registry] ********************************************** + Wednesday 16 January 2019 10:42:29 +0100 (0:00:00.104) 0:00:00.104 ***** + skipping: [localhost] => (item=None) + skipping: [localhost] => (item=None) + skipping: [localhost] + + TASK [Create Dockerfiles from image names] ************************************* + Wednesday 16 January 2019 10:42:29 +0100 (0:00:00.190) 0:00:00.295 ***** + changed: [localhost] => (item=None) + ok: [localhost] => (item=None) + changed: [localhost] + + TASK [Discover local Docker images] ******************************************** + Wednesday 16 January 2019 10:42:31 +0100 (0:00:01.330) 0:00:01.626 ***** + ok: [localhost] => (item=None) + ok: [localhost] => (item=None) + ok: [localhost] + + TASK [Build an Ansible compatible image] *************************************** + Wednesday 16 January 2019 10:42:32 +0100 (0:00:01.069) 0:00:02.695 ***** + changed: [localhost] => (item=None) + changed: [localhost] => (item=None) + changed: [localhost] + + TASK [Create docker network(s)] ************************************************ + Wednesday 16 January 2019 10:42:42 +0100 (0:00:10.204) 0:00:12.900 ***** + skipping: [localhost] + + TASK [Create molecule instance(s)] ********************************************* + Wednesday 16 January 2019 10:42:42 +0100 (0:00:00.109) 0:00:13.010 ***** + changed: [localhost] => (item=None) + changed: [localhost] => (item=None) + changed: [localhost] + + TASK [Wait for instance(s) creation to complete] ******************************* + Wednesday 16 January 2019 10:42:45 +0100 (0:00:02.728) 0:00:15.738 ***** + changed: [localhost] => (item=None) + changed: [localhost] => (item=None) + changed: [localhost] + + PLAY RECAP ********************************************************************* + localhost : ok=5 changed=4 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:42:47 +0100 (0:00:02.043) 0:00:17.782 ***** + =============================================================================== + Build an Ansible compatible image -------------------------------------- 10.20s + Create molecule instance(s) --------------------------------------------- 2.74s + Wait for instance(s) creation to complete ------------------------------- 2.04s + Create Dockerfiles from image names ------------------------------------- 1.33s + Discover local Docker images -------------------------------------------- 1.07s + Log into a Docker registry ---------------------------------------------- 0.19s + Create docker network(s) ------------------------------------------------ 0.11s + +--> Scenario: 'default' +--> Action: 'prepare' + + PLAY [Prepare] ***************************************************************** + + TASK [install dependencies] **************************************************** + Wednesday 16 January 2019 10:42:52 +0100 (0:00:00.320) 0:00:00.320 ***** + changed: [glb-002.example.com] => (item=[u'iproute', u'sysvinit-tools', u'epel-release']) + changed: [glb-001.example.com] => (item=[u'iproute', u'sysvinit-tools', u'epel-release']) + + TASK [create facts dir] ******************************************************** + Wednesday 16 January 2019 10:43:00 +0100 (0:00:08.084) 0:00:08.404 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + TASK [set fact] **************************************************************** + Wednesday 16 January 2019 10:43:01 +0100 (0:00:00.929) 0:00:09.334 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + PLAY RECAP ********************************************************************* + glb-001.example.com : ok=3 changed=3 unreachable=0 failed=0 + glb-002.example.com : ok=3 changed=3 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:43:03 +0100 (0:00:01.412) 0:00:10.746 ***** + =============================================================================== + install dependencies ---------------------------------------------------- 8.08s + set fact ---------------------------------------------------------------- 1.41s + create facts dir -------------------------------------------------------- 0.93s + +--> Scenario: 'default' +--> Action: 'converge' + + PLAY [Converge] **************************************************************** + + TASK [Gathering Facts] ********************************************************* + Wednesday 16 January 2019 10:43:04 +0100 (0:00:00.108) 0:00:00.109 ***** + ok: [glb-001.example.com] + ok: [glb-002.example.com] + + TASK [nginx : enable ipv4 non local bind] ************************************** + Wednesday 16 January 2019 10:43:08 +0100 (0:00:03.726) 0:00:03.835 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + TASK [nginx : install nginx and rngd] ****************************************** + Wednesday 16 January 2019 10:43:09 +0100 (0:00:01.341) 0:00:05.176 ***** + changed: [glb-001.example.com] => (item=[u'nginx', u'rng-tools']) + changed: [glb-002.example.com] => (item=[u'nginx', u'rng-tools']) + + TASK [nginx : check if nginx is compiled with dynamic or static stream module] *** + Wednesday 16 January 2019 10:43:46 +0100 (0:00:36.633) 0:00:41.810 ***** + ok: [glb-002.example.com] + ok: [glb-001.example.com] + + TASK [nginx : install mod-stream] ********************************************** + Wednesday 16 January 2019 10:43:47 +0100 (0:00:01.221) 0:00:43.032 ***** + ok: [glb-001.example.com] => (item=[u'nginx-mod-stream']) + ok: [glb-002.example.com] => (item=[u'nginx-mod-stream']) + + TASK [nginx : create default nginx.conf] *************************************** + Wednesday 16 January 2019 10:43:48 +0100 (0:00:01.120) 0:00:44.153 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + TASK [nginx : Create systemd service override directory] *********************** + Wednesday 16 January 2019 10:43:49 +0100 (0:00:01.530) 0:00:45.683 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + TASK [nginx : Copy systemd overrides] ****************************************** + Wednesday 16 January 2019 10:43:50 +0100 (0:00:00.898) 0:00:46.581 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + TASK [nginx : create empty dummy default.conf] ********************************* + Wednesday 16 January 2019 10:43:52 +0100 (0:00:01.371) 0:00:47.953 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + RUNNING HANDLER [nginx : enable nginx] ***************************************** + Wednesday 16 January 2019 10:43:53 +0100 (0:00:01.366) 0:00:49.319 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + RUNNING HANDLER [nginx : reload nginx] ***************************************** + Wednesday 16 January 2019 10:43:55 +0100 (0:00:01.658) 0:00:50.977 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + RUNNING HANDLER [nginx : restart nginx] **************************************** + Wednesday 16 January 2019 10:43:56 +0100 (0:00:01.348) 0:00:52.326 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + RUNNING HANDLER [nginx : enable rngd] ****************************************** + Wednesday 16 January 2019 10:43:57 +0100 (0:00:01.427) 0:00:53.753 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + RUNNING HANDLER [nginx : reload systemd] *************************************** + Wednesday 16 January 2019 10:43:59 +0100 (0:00:01.957) 0:00:55.711 ***** + ok: [glb-001.example.com] + ok: [glb-002.example.com] + + TASK [generic_loadbalancer : gather facts from all servers in cluster] ********* + Wednesday 16 January 2019 10:44:03 +0100 (0:00:03.558) 0:00:59.270 ***** + ok: [glb-001.example.com -> glb-001.example.com] => (item=glb-001.example.com) + ok: [glb-002.example.com -> glb-001.example.com] => (item=glb-001.example.com) + ok: [glb-001.example.com -> glb-002.example.com] => (item=glb-002.example.com) + ok: [glb-002.example.com -> glb-002.example.com] => (item=glb-002.example.com) + + TASK [generic_loadbalancer : include_tasks] ************************************ + Wednesday 16 January 2019 10:44:18 +0100 (0:00:14.570) 0:01:13.840 ***** + included: /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/tasks/keepalived.yml for glb-001.example.com, glb-002.example.com + + TASK [generic_loadbalancer : install keepalived] ******************************* + Wednesday 16 January 2019 10:44:18 +0100 (0:00:00.182) 0:01:14.022 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + TASK [generic_loadbalancer : create keepalived config] ************************* + Wednesday 16 January 2019 10:44:27 +0100 (0:00:09.464) 0:01:23.487 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + TASK [generic_loadbalancer : enable and start keepalived] ********************** + Wednesday 16 January 2019 10:44:29 +0100 (0:00:02.020) 0:01:25.508 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + TASK [generic_loadbalancer : include_tasks] ************************************ + Wednesday 16 January 2019 10:44:31 +0100 (0:00:02.003) 0:01:27.512 ***** + included: /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/tasks/nginx/main.yml for glb-001.example.com, glb-002.example.com + + TASK [generic_loadbalancer : nginx | create fallback vhost] ******************** + Wednesday 16 January 2019 10:44:32 +0100 (0:00:00.244) 0:01:27.756 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + RUNNING HANDLER [nginx : reload nginx] ***************************************** + Wednesday 16 January 2019 10:44:33 +0100 (0:00:01.317) 0:01:29.073 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + RUNNING HANDLER [generic_loadbalancer : restart keepalived] ******************** + Wednesday 16 January 2019 10:44:35 +0100 (0:00:01.938) 0:01:31.011 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + PLAY RECAP ********************************************************************* + glb-001.example.com : ok=23 changed=16 unreachable=0 failed=0 + glb-002.example.com : ok=23 changed=16 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:44:38 +0100 (0:00:02.829) 0:01:33.841 ***** + =============================================================================== + nginx : install nginx and rngd ----------------------------------------- 36.63s + generic_loadbalancer : gather facts from all servers in cluster -------- 14.57s + generic_loadbalancer : install keepalived ------------------------------- 9.46s + Gathering Facts --------------------------------------------------------- 3.73s + nginx : reload systemd -------------------------------------------------- 3.56s + generic_loadbalancer : restart keepalived ------------------------------- 2.83s + generic_loadbalancer : create keepalived config ------------------------- 2.02s + generic_loadbalancer : enable and start keepalived ---------------------- 2.00s + nginx : enable rngd ----------------------------------------------------- 1.96s + nginx : reload nginx ---------------------------------------------------- 1.94s + nginx : enable nginx ---------------------------------------------------- 1.66s + nginx : create default nginx.conf --------------------------------------- 1.53s + nginx : restart nginx --------------------------------------------------- 1.43s + nginx : Copy systemd overrides ------------------------------------------ 1.37s + nginx : create empty dummy default.conf --------------------------------- 1.37s + nginx : enable ipv4 non local bind -------------------------------------- 1.34s + generic_loadbalancer : nginx | create fallback vhost -------------------- 1.32s + nginx : check if nginx is compiled with dynamic or static stream module --- 1.22s + nginx : install mod-stream ---------------------------------------------- 1.12s + nginx : Create systemd service override directory ----------------------- 0.90s + +--> Scenario: 'default' +--> Action: 'idempotence' +Idempotence completed successfully. +--> Scenario: 'default' +--> Action: 'side_effect' + + PLAY [kill nginx on glb-001] *************************************************** + + TASK [stop nginx] ************************************************************** + Wednesday 16 January 2019 10:45:19 +0100 (0:00:00.107) 0:00:00.107 ***** + changed: [glb-001.example.com] + + TASK [wait for keepalived to move IP] ****************************************** + Wednesday 16 January 2019 10:45:21 +0100 (0:00:01.950) 0:00:02.058 ***** + changed: [glb-001.example.com] + + PLAY RECAP ********************************************************************* + glb-001.example.com : ok=2 changed=2 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:45:27 +0100 (0:00:05.889) 0:00:07.947 ***** + =============================================================================== + wait for keepalived to move IP ------------------------------------------ 5.89s + stop nginx -------------------------------------------------------------- 1.95s + +--> Scenario: 'default' +--> Action: 'verify' +--> Executing Goss tests found in /home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/tests/... + + PLAY [Verify] ****************************************************************** + + TASK [Gathering Facts] ********************************************************* + Wednesday 16 January 2019 10:45:28 +0100 (0:00:00.106) 0:00:00.106 ***** + ok: [glb-001.example.com] + ok: [glb-002.example.com] + + TASK [Download and install Goss] *********************************************** + Wednesday 16 January 2019 10:45:31 +0100 (0:00:03.504) 0:00:03.611 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + TASK [Create Molecule directory for test files] ******************************** + Wednesday 16 January 2019 10:45:41 +0100 (0:00:09.593) 0:00:13.204 ***** + changed: [glb-002.example.com] + changed: [glb-001.example.com] + + TASK [Find Goss tests on localhost] ******************************************** + Wednesday 16 January 2019 10:45:42 +0100 (0:00:01.193) 0:00:14.398 ***** + changed: [glb-001.example.com -> localhost] + changed: [glb-002.example.com -> localhost] + + TASK [debug] ******************************************************************* + Wednesday 16 January 2019 10:45:43 +0100 (0:00:00.480) 0:00:14.879 ***** + skipping: [glb-001.example.com] + skipping: [glb-002.example.com] + + TASK [Copy Goss tests to remote] *********************************************** + Wednesday 16 January 2019 10:45:43 +0100 (0:00:00.286) 0:00:15.165 ***** + changed: [glb-002.example.com] => (item=/home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/tests/test_default.yml) + changed: [glb-001.example.com] => (item=/home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/tests/test_default.yml) + changed: [glb-002.example.com] => (item=/home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-002.example.com.yml) + changed: [glb-001.example.com] => (item=/home/nvarz/git/molecule-pr-example/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-001.example.com.yml) + + TASK [Register test files] ***************************************************** + Wednesday 16 January 2019 10:45:46 +0100 (0:00:03.392) 0:00:18.558 ***** + changed: [glb-001.example.com] + changed: [glb-002.example.com] + + TASK [Execute Goss tests] ****************************************************** + Wednesday 16 January 2019 10:45:48 +0100 (0:00:01.198) 0:00:19.757 ***** + changed: [glb-001.example.com] => (item=/tmp/molecule/goss/test_default.yml) + changed: [glb-002.example.com] => (item=/tmp/molecule/goss/test_default.yml) + changed: [glb-002.example.com] => (item=/tmp/molecule/goss/test_host_glb-002.example.com.yml) + changed: [glb-001.example.com] => (item=/tmp/molecule/goss/test_host_glb-001.example.com.yml) + + TASK [Display details about the Goss results] ********************************** + Wednesday 16 January 2019 10:45:50 +0100 (0:00:02.095) 0:00:21.853 ***** + ok: [glb-001.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:48.962033', '_ansible_no_log': False, u'stdout': u'Group: nginx: exists: matches expectation: [true]\nUser: nginx: exists: matches expectation: [true]\nUser: nginx: home: matches expectation: ["/var/lib/nginx"]\nUser: nginx: groups: matches expectation: [["nginx"]]\nUser: nginx: shell: matches expectation: ["/sbin/nologin"]\nPackage: keepalived: installed: matches expectation: [true]\nPackage: nginx: installed: matches expectation: [true]\n\n\nTotal Duration: 0.032s\nCount: 7, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_default.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_default.yml', u'delta': u'0:00:00.307828', '_ansible_item_label': u'/tmp/molecule/goss/test_default.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_default.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Group: nginx: exists: matches expectation: [true]', u'User: nginx: exists: matches expectation: [true]', u'User: nginx: home: matches expectation: ["/var/lib/nginx"]', u'User: nginx: groups: matches expectation: [["nginx"]]', u'User: nginx: shell: matches expectation: ["/sbin/nologin"]', u'Package: keepalived: installed: matches expectation: [true]', u'Package: nginx: installed: matches expectation: [true]', u'', u'', u'Total Duration: 0.032s', u'Count: 7, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:48.654205', '_ansible_ignore_errors': True, 'failed': False}) => { + "msg": [ + "Group: nginx: exists: matches expectation: [true]", + "User: nginx: exists: matches expectation: [true]", + "User: nginx: home: matches expectation: [\"/var/lib/nginx\"]", + "User: nginx: groups: matches expectation: [[\"nginx\"]]", + "User: nginx: shell: matches expectation: [\"/sbin/nologin\"]", + "Package: keepalived: installed: matches expectation: [true]", + "Package: nginx: installed: matches expectation: [true]", + "", + "", + "Total Duration: 0.032s", + "Count: 7, Failed: 0, Skipped: 0" + ] + } + ok: [glb-002.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:48.987570', '_ansible_no_log': False, u'stdout': u'Group: nginx: exists: matches expectation: [true]\nUser: nginx: exists: matches expectation: [true]\nUser: nginx: home: matches expectation: ["/var/lib/nginx"]\nUser: nginx: groups: matches expectation: [["nginx"]]\nUser: nginx: shell: matches expectation: ["/sbin/nologin"]\nPackage: nginx: installed: matches expectation: [true]\nPackage: keepalived: installed: matches expectation: [true]\n\n\nTotal Duration: 0.041s\nCount: 7, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_default.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_default.yml', u'delta': u'0:00:00.314446', '_ansible_item_label': u'/tmp/molecule/goss/test_default.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_default.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Group: nginx: exists: matches expectation: [true]', u'User: nginx: exists: matches expectation: [true]', u'User: nginx: home: matches expectation: ["/var/lib/nginx"]', u'User: nginx: groups: matches expectation: [["nginx"]]', u'User: nginx: shell: matches expectation: ["/sbin/nologin"]', u'Package: nginx: installed: matches expectation: [true]', u'Package: keepalived: installed: matches expectation: [true]', u'', u'', u'Total Duration: 0.041s', u'Count: 7, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:48.673124', '_ansible_ignore_errors': True, 'failed': False}) => { + "msg": [ + "Group: nginx: exists: matches expectation: [true]", + "User: nginx: exists: matches expectation: [true]", + "User: nginx: home: matches expectation: [\"/var/lib/nginx\"]", + "User: nginx: groups: matches expectation: [[\"nginx\"]]", + "User: nginx: shell: matches expectation: [\"/sbin/nologin\"]", + "Package: nginx: installed: matches expectation: [true]", + "Package: keepalived: installed: matches expectation: [true]", + "", + "", + "Total Duration: 0.041s", + "Count: 7, Failed: 0, Skipped: 0" + ] + } + ok: [glb-001.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:49.944775', '_ansible_no_log': False, u'stdout': u'Port: tcp:80: listening: matches expectation: [false]\nService: nginx: enabled: matches expectation: [true]\nService: nginx: running: matches expectation: [false]\n\n\nTotal Duration: 0.012s\nCount: 3, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_host_glb-001.example.com.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_host_glb-001.example.com.yml', u'delta': u'0:00:00.285448', '_ansible_item_label': u'/tmp/molecule/goss/test_host_glb-001.example.com.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_host_glb-001.example.com.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Port: tcp:80: listening: matches expectation: [false]', u'Service: nginx: enabled: matches expectation: [true]', u'Service: nginx: running: matches expectation: [false]', u'', u'', u'Total Duration: 0.012s', u'Count: 3, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:49.659327', '_ansible_ignore_errors': True, 'failed': False}) => { + "msg": [ + "Port: tcp:80: listening: matches expectation: [false]", + "Service: nginx: enabled: matches expectation: [true]", + "Service: nginx: running: matches expectation: [false]", + "", + "", + "Total Duration: 0.012s", + "Count: 3, Failed: 0, Skipped: 0" + ] + } + ok: [glb-002.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:49.944755', '_ansible_no_log': False, u'stdout': u'Port: tcp:80: listening: matches expectation: [true]\nPort: tcp:80: ip: matches expectation: [["0.0.0.0"]]\nService: nginx: enabled: matches expectation: [true]\nService: nginx: running: matches expectation: [true]\n\n\nTotal Duration: 0.006s\nCount: 4, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_host_glb-002.example.com.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_host_glb-002.example.com.yml', u'delta': u'0:00:00.275222', '_ansible_item_label': u'/tmp/molecule/goss/test_host_glb-002.example.com.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_host_glb-002.example.com.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Port: tcp:80: listening: matches expectation: [true]', u'Port: tcp:80: ip: matches expectation: [["0.0.0.0"]]', u'Service: nginx: enabled: matches expectation: [true]', u'Service: nginx: running: matches expectation: [true]', u'', u'', u'Total Duration: 0.006s', u'Count: 4, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:49.669533', '_ansible_ignore_errors': True, 'failed': False}) => { + "msg": [ + "Port: tcp:80: listening: matches expectation: [true]", + "Port: tcp:80: ip: matches expectation: [[\"0.0.0.0\"]]", + "Service: nginx: enabled: matches expectation: [true]", + "Service: nginx: running: matches expectation: [true]", + "", + "", + "Total Duration: 0.006s", + "Count: 4, Failed: 0, Skipped: 0" + ] + } + + TASK [Fail when tests fail] **************************************************** + Wednesday 16 January 2019 10:45:50 +0100 (0:00:00.528) 0:00:22.382 ***** + skipping: [glb-001.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:48.962033', '_ansible_no_log': False, u'stdout': u'Group: nginx: exists: matches expectation: [true]\nUser: nginx: exists: matches expectation: [true]\nUser: nginx: home: matches expectation: ["/var/lib/nginx"]\nUser: nginx: groups: matches expectation: [["nginx"]]\nUser: nginx: shell: matches expectation: ["/sbin/nologin"]\nPackage: keepalived: installed: matches expectation: [true]\nPackage: nginx: installed: matches expectation: [true]\n\n\nTotal Duration: 0.032s\nCount: 7, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_default.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_default.yml', u'delta': u'0:00:00.307828', '_ansible_item_label': u'/tmp/molecule/goss/test_default.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_default.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Group: nginx: exists: matches expectation: [true]', u'User: nginx: exists: matches expectation: [true]', u'User: nginx: home: matches expectation: ["/var/lib/nginx"]', u'User: nginx: groups: matches expectation: [["nginx"]]', u'User: nginx: shell: matches expectation: ["/sbin/nologin"]', u'Package: keepalived: installed: matches expectation: [true]', u'Package: nginx: installed: matches expectation: [true]', u'', u'', u'Total Duration: 0.032s', u'Count: 7, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:48.654205', '_ansible_ignore_errors': True, 'failed': False}) + skipping: [glb-001.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:49.944775', '_ansible_no_log': False, u'stdout': u'Port: tcp:80: listening: matches expectation: [false]\nService: nginx: enabled: matches expectation: [true]\nService: nginx: running: matches expectation: [false]\n\n\nTotal Duration: 0.012s\nCount: 3, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_host_glb-001.example.com.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_host_glb-001.example.com.yml', u'delta': u'0:00:00.285448', '_ansible_item_label': u'/tmp/molecule/goss/test_host_glb-001.example.com.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_host_glb-001.example.com.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Port: tcp:80: listening: matches expectation: [false]', u'Service: nginx: enabled: matches expectation: [true]', u'Service: nginx: running: matches expectation: [false]', u'', u'', u'Total Duration: 0.012s', u'Count: 3, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:49.659327', '_ansible_ignore_errors': True, 'failed': False}) + skipping: [glb-002.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:48.987570', '_ansible_no_log': False, u'stdout': u'Group: nginx: exists: matches expectation: [true]\nUser: nginx: exists: matches expectation: [true]\nUser: nginx: home: matches expectation: ["/var/lib/nginx"]\nUser: nginx: groups: matches expectation: [["nginx"]]\nUser: nginx: shell: matches expectation: ["/sbin/nologin"]\nPackage: nginx: installed: matches expectation: [true]\nPackage: keepalived: installed: matches expectation: [true]\n\n\nTotal Duration: 0.041s\nCount: 7, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_default.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_default.yml', u'delta': u'0:00:00.314446', '_ansible_item_label': u'/tmp/molecule/goss/test_default.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_default.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Group: nginx: exists: matches expectation: [true]', u'User: nginx: exists: matches expectation: [true]', u'User: nginx: home: matches expectation: ["/var/lib/nginx"]', u'User: nginx: groups: matches expectation: [["nginx"]]', u'User: nginx: shell: matches expectation: ["/sbin/nologin"]', u'Package: nginx: installed: matches expectation: [true]', u'Package: keepalived: installed: matches expectation: [true]', u'', u'', u'Total Duration: 0.041s', u'Count: 7, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:48.673124', '_ansible_ignore_errors': True, 'failed': False}) + skipping: [glb-002.example.com] => (item={'_ansible_parsed': True, 'stderr_lines': [], '_ansible_item_result': True, u'end': u'2019-01-16 09:45:49.944755', '_ansible_no_log': False, u'stdout': u'Port: tcp:80: listening: matches expectation: [true]\nPort: tcp:80: ip: matches expectation: [["0.0.0.0"]]\nService: nginx: enabled: matches expectation: [true]\nService: nginx: running: matches expectation: [true]\n\n\nTotal Duration: 0.006s\nCount: 4, Failed: 0, Skipped: 0', u'cmd': [u'/usr/local/bin/goss', u'-g', u'/tmp/molecule/goss/test_host_glb-002.example.com.yml', u'validate', u'--format', u'documentation'], u'rc': 0, 'item': u'/tmp/molecule/goss/test_host_glb-002.example.com.yml', u'delta': u'0:00:00.275222', '_ansible_item_label': u'/tmp/molecule/goss/test_host_glb-002.example.com.yml', u'stderr': u'', u'changed': True, u'invocation': {u'module_args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params': u'/usr/local/bin/goss -g /tmp/molecule/goss/test_host_glb-002.example.com.yml validate --format documentation', u'removes': None, u'creates': None, u'chdir': None, u'stdin': None}}, 'stdout_lines': [u'Port: tcp:80: listening: matches expectation: [true]', u'Port: tcp:80: ip: matches expectation: [["0.0.0.0"]]', u'Service: nginx: enabled: matches expectation: [true]', u'Service: nginx: running: matches expectation: [true]', u'', u'', u'Total Duration: 0.006s', u'Count: 4, Failed: 0, Skipped: 0'], u'start': u'2019-01-16 09:45:49.669533', '_ansible_ignore_errors': True, 'failed': False}) + + PLAY RECAP ********************************************************************* + glb-001.example.com : ok=8 changed=6 unreachable=0 failed=0 + glb-002.example.com : ok=8 changed=6 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:45:50 +0100 (0:00:00.241) 0:00:22.623 ***** + =============================================================================== + Download and install Goss ----------------------------------------------- 9.59s + Gathering Facts --------------------------------------------------------- 3.51s + Copy Goss tests to remote ----------------------------------------------- 3.39s + Execute Goss tests ------------------------------------------------------ 2.10s + Register test files ----------------------------------------------------- 1.20s + Create Molecule directory for test files -------------------------------- 1.19s + Display details about the Goss results ---------------------------------- 0.53s + Find Goss tests on localhost -------------------------------------------- 0.48s + debug ------------------------------------------------------------------- 0.29s + Fail when tests fail ---------------------------------------------------- 0.24s + +Verifier completed successfully. +--> Scenario: 'default' +--> Action: 'destroy' + + PLAY [Destroy] ***************************************************************** + + TASK [Destroy molecule instance(s)] ******************************************** + Wednesday 16 January 2019 10:45:52 +0100 (0:00:00.156) 0:00:00.156 ***** + changed: [localhost] => (item=None) + changed: [localhost] => (item=None) + changed: [localhost] + + TASK [Wait for instance(s) deletion to complete] ******************************* + Wednesday 16 January 2019 10:45:55 +0100 (0:00:02.686) 0:00:02.843 ***** + changed: [localhost] => (item=None) + changed: [localhost] => (item=None) + changed: [localhost] + + TASK [Delete docker network(s)] ************************************************ + Wednesday 16 January 2019 10:45:56 +0100 (0:00:00.970) 0:00:03.813 ***** + skipping: [localhost] + + PLAY RECAP ********************************************************************* + localhost : ok=2 changed=2 unreachable=0 failed=0 + + Wednesday 16 January 2019 10:45:56 +0100 (0:00:00.111) 0:00:03.925 ***** + =============================================================================== + Destroy molecule instance(s) -------------------------------------------- 2.69s + Wait for instance(s) deletion to complete ------------------------------- 0.97s + Delete docker network(s) ------------------------------------------------ 0.11s + +``` + diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..fc9a037 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,33 @@ +[defaults] +strategy_plugins = plugins/mitogen/ansible_mitogen/plugins/strategy +stdout_callback=debug +stderr_callback=debug +library = /opt/ansible/modules/library +remote_tmp = $HOME/.ansible/tmp +pattern = * +forks = 15 +poll_interval = 15 +become_user = root +transport = smart +remote_port = 22 +gathering = implicit +roles_path = roles +host_key_checking = False +timeout = 10 +jinja2_extensions = jinja2.ext.do +ansible_managed = Ansible managed +display_skipped_hosts = False +deprecation_warnings = True +action_plugins = /usr/share/ansible_plugins/action_plugins +connection_plugins = /usr/share/ansible_plugins/connection_plugins +lookup_plugins = /usr/share/ansible_plugins/lookup_plugins +vars_plugins = /usr/share/ansible_plugins/vars_plugins +filter_plugins = ./filter_plugins/filter +callback_whitelist = profile_tasks +nocows = 1 +retry_files_enabled = False +[ssh_connection] +control_path = %(directory)s/ssh-%%h +scp_if_ssh = True +[inventory] +unparsed_is_failed = True diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e998661 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +molecule == 2.19 +docker +redis diff --git a/roles/.yamllint b/roles/.yamllint new file mode 100644 index 0000000..82e6e56 --- /dev/null +++ b/roles/.yamllint @@ -0,0 +1,22 @@ +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-before: 0 + max-spaces-after: 1 + line-length: disable + truthy: disable + comments: + require-starting-space: true + comments-indentation: disable + hyphens: + max-spaces-after: 1 + indentation: + indent-sequences: consistent + new-line-at-end-of-file: enable diff --git a/roles/generic_loadbalancer/.yamllint b/roles/generic_loadbalancer/.yamllint new file mode 100644 index 0000000..ea90a39 --- /dev/null +++ b/roles/generic_loadbalancer/.yamllint @@ -0,0 +1,23 @@ +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-before: 0 + max-spaces-after: 1 + line-length: disable + truthy: disable + comments: + require-starting-space: true + comments-indentation: disable + hyphens: + max-spaces-after: 1 + indentation: + indent-sequences: consistent + new-line-at-end-of-file: enable + diff --git a/roles/generic_loadbalancer/defaults/main.yml b/roles/generic_loadbalancer/defaults/main.yml new file mode 100644 index 0000000..feed05b --- /dev/null +++ b/roles/generic_loadbalancer/defaults/main.yml @@ -0,0 +1,6 @@ +--- +# defaults file for generic_loadbalancer +generic_loadbalancer: + vip: + - 10.10.10.10 + - 10.10.10.11 diff --git a/roles/generic_loadbalancer/handlers/main.yml b/roles/generic_loadbalancer/handlers/main.yml new file mode 100644 index 0000000..4cc7eb0 --- /dev/null +++ b/roles/generic_loadbalancer/handlers/main.yml @@ -0,0 +1,7 @@ +--- +# handlers file for generic_loadbalancer + +- name: restart keepalived + systemd: + name: keepalived + state: restarted diff --git a/roles/generic_loadbalancer/meta/main.yml b/roles/generic_loadbalancer/meta/main.yml new file mode 100644 index 0000000..e3d1763 --- /dev/null +++ b/roles/generic_loadbalancer/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: nginx } diff --git a/roles/generic_loadbalancer/molecule/default/Dockerfile.j2 b/roles/generic_loadbalancer/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..03ef761 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/Dockerfile.j2 @@ -0,0 +1,9 @@ +FROM {{ item.image }} + +RUN /bin/sh -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash; fi' +RUN /bin/sh -c 'if [ -x "$(command -v yum)" ]; then touch /var/lib/rpm/* && 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; fi' +RUN /bin/sh -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash; fi' +RUN /bin/sh -c 'if [ -x "$(command -v apk)" ]; then apk update && apk add python sudo bash; fi' +RUN /bin/sh -c 'if [ -x "$(command -v pacman)" ]; then pacman --sync --noconfirm --refresh python2 bash; fi' +RUN /bin/sh -c 'if [ -x "$(command -v dnf)" ]; then dnf makecache fast; dnf --assumeyes install python python-devel python2-dnf bash; fi' +RUN /bin/sh -c 'if [ -x "$(command -v emerge)" ]; then emerge --ask n =dev-lang/python-2\* gentoolkit; fi' diff --git a/roles/generic_loadbalancer/molecule/default/INSTALL.rst b/roles/generic_loadbalancer/molecule/default/INSTALL.rst new file mode 100644 index 0000000..09e8735 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/INSTALL.rst @@ -0,0 +1,46 @@ +******* +Install +******* + +This set of playbooks have specific dependencies on Ansible due to the modules +being used. + +Requirements +============ + +* Ansible 2.2 +* Docker Engine +* docker-py + +Install OS dependencies on CentOS 7 + +.. code-block:: bash + + $ sudo yum install -y epel-release + $ sudo yum install -y gcc python-pip python-devel openssl-devel + # If installing Molecule from source. + $ sudo yum install libffi-devel git + +Install OS dependencies on Ubuntu 16.x + +.. code-block:: bash + + $ sudo apt-get update + $ sudo apt-get install -y python-pip libssl-dev docker-engine + # If installing Molecule from source. + $ sudo apt-get install -y libffi-dev git + +Install OS dependencies on Mac OS + +.. code-block:: bash + + $ brew install python + $ brew install git + +Install using pip: + +.. code-block:: bash + + $ sudo pip install ansible + $ sudo pip install docker-py + $ sudo pip install molecule --pre diff --git a/roles/generic_loadbalancer/molecule/default/create.yml b/roles/generic_loadbalancer/molecule/default/create.yml new file mode 100644 index 0000000..c8dea38 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/create.yml @@ -0,0 +1,93 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not (lookup('env', 'MOLECULE_DEBUG') | bool or molecule_yml.provisioner.log|default(false) | bool) }}" + tasks: + - name: Log into a Docker registry + docker_login: + username: "{{ item.registry.credentials.username }}" + password: "{{ item.registry.credentials.password }}" + email: "{{ item.registry.credentials.email | default(omit) }}" + registry: "{{ item.registry.url }}" + docker_host: "{{ item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}" + with_items: "{{ molecule_yml.platforms }}" + when: + - item.registry is defined + - item.registry.credentials is defined + - item.registry.credentials.username is defined + + - name: Create Dockerfiles from image names + template: + src: "{{ molecule_scenario_directory }}/Dockerfile.j2" + dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.image | regex_replace('[^a-zA-Z0-9_]', '_') }}" + with_items: "{{ molecule_yml.platforms }}" + when: not item.pre_build_image | default(false) + register: platforms + + - name: Discover local Docker images + docker_image_facts: + name: "molecule_local/{{ item.item.name }}" + docker_host: "{{ item.item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}" + with_items: "{{ platforms.results }}" + when: not item.pre_build_image | default(false) + register: docker_images + + - name: Build an Ansible compatible image + docker_image: + path: "{{ molecule_ephemeral_directory }}" + name: "molecule_local/{{ item.item.image }}" + docker_host: "{{ item.item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}" + dockerfile: "{{ item.item.dockerfile | default(item.invocation.module_args.dest) }}" + force: "{{ item.item.force | default(true) }}" + pull: "{{ item.item.pull | default(omit) }}" + with_items: "{{ platforms.results }}" + when: + - platforms.changed or docker_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0 + - not item.item.pre_build_image | default(false) + + - name: Create docker network(s) + docker_network: + name: "{{ item }}" + docker_host: "{{ item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}" + state: present + with_items: "{{ molecule_yml.platforms | molecule_get_docker_networks }}" + + - name: Create molecule instance(s) + docker_container: + name: "{{ item.name }}" + docker_host: "{{ item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}" + hostname: "{{ item.hostname | default(item.name) }}" + image: "{{ item.pre_build_image | default(false) | ternary('', 'molecule_local/') }}{{ item.image }}" + state: started + recreate: false + log_driver: json-file + command: "{{ item.command | default('bash -c \"while true; do sleep 10000; done\"') }}" + privileged: "{{ item.privileged | default(omit) }}" + security_opts: "{{ item.security_opts | default(omit) }}" + volumes: "{{ item.volumes | default(omit) }}" + tmpfs: "{{ item.tmpfs | default(omit) }}" + capabilities: "{{ item.capabilities | default(omit) }}" + sysctls: "{{ item.sysctls| default(omit) }}" + exposed_ports: "{{ item.exposed_ports | default(omit) }}" + published_ports: "{{ item.published_ports | default(omit) }}" + ulimits: "{{ item.ulimits | default(omit) }}" + networks: "{{ item.networks | default(omit) }}" + network_mode: "{{ item.network_mode | default(omit) }}" + dns_servers: "{{ item.dns_servers | default(omit) }}" + env: "{{ item.env | default(omit) }}" + restart_policy: "{{ item.restart_policy | default(omit) }}" + restart_retries: "{{ item.restart_retries | default(omit) }}" + register: server + with_items: "{{ molecule_yml.platforms }}" + async: 7200 + poll: 0 + + - name: Wait for instance(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: docker_jobs + until: docker_jobs.finished + retries: 300 + with_items: "{{ server.results }}" diff --git a/roles/generic_loadbalancer/molecule/default/molecule.yml b/roles/generic_loadbalancer/molecule/default/molecule.yml new file mode 100644 index 0000000..c9731ba --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/molecule.yml @@ -0,0 +1,56 @@ +--- +dependency: + name: gilt +driver: + name: docker +lint: + name: yamllint + options: + config-file: ../.yamllint +platforms: + - name: glb-001.example.com + image: centos:latest + command: /sbin/init + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + capabilities: + - SYS_ADMIN + - NET_ADMIN + - NET_BIND_SERVICE + sysctls: + net.ipv4.ip_nonlocal_bind: 1 + groups: + - generic_loadbalancer + - name: glb-002.example.com + image: centos:latest + command: /sbin/init + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + capabilities: + - SYS_ADMIN + - NET_ADMIN + - NET_BIND_SERVICE + sysctls: + net.ipv4.ip_nonlocal_bind: 1 + groups: + - generic_loadbalancer +provisioner: + name: ansible + config_options: + defaults: + jinja2_extensions: jinja2.ext.do + callback_whitelist: profile_tasks + lint: + name: ansible-lint + playbooks: + side_effect: side_effect.yml +scenario: + name: default +verifier: + name: goss + lint: + name: yamllint + options: + config-file: ../.yamllint diff --git a/roles/generic_loadbalancer/molecule/default/playbook.yml b/roles/generic_loadbalancer/molecule/default/playbook.yml new file mode 100644 index 0000000..9dd2a7c --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: generic_loadbalancer + roles: + - role: generic_loadbalancer diff --git a/roles/generic_loadbalancer/molecule/default/prepare.yml b/roles/generic_loadbalancer/molecule/default/prepare.yml new file mode 100644 index 0000000..9a09da5 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/prepare.yml @@ -0,0 +1,25 @@ +--- +- name: Prepare + hosts: generic_loadbalancer + gather_facts: False + tasks: + - name: install dependencies + yum: + name: "{{ item }}" + state: present + with_items: + - iproute + - sysvinit-tools + - epel-release + + - name: create facts dir + file: + path: /etc/ansible/facts.d + state: directory + + - name: set fact + copy: + content: | + [run] + true = 1 + dest: /etc/ansible/facts.d/molecule.fact diff --git a/roles/generic_loadbalancer/molecule/default/side_effect.yml b/roles/generic_loadbalancer/molecule/default/side_effect.yml new file mode 100644 index 0000000..c085ce1 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/side_effect.yml @@ -0,0 +1,13 @@ +--- +- name: kill nginx on glb-001 + gather_facts: false + hosts: + - glb-001.example.com + become: true + tasks: + - name: stop nginx + service: + name: nginx + state: stopped + - name: wait for keepalived to move IP + shell: sleep 5 diff --git a/roles/generic_loadbalancer/molecule/default/tests/test_default.yml b/roles/generic_loadbalancer/molecule/default/tests/test_default.yml new file mode 100644 index 0000000..da105fb --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/tests/test_default.yml @@ -0,0 +1,16 @@ +--- +package: + nginx: + installed: true + keepalived: + installed: true +user: + nginx: + exists: true + groups: + - nginx + home: /var/lib/nginx + shell: /sbin/nologin +group: + nginx: + exists: true diff --git a/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-001.example.com.yml b/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-001.example.com.yml new file mode 100644 index 0000000..9fb9066 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-001.example.com.yml @@ -0,0 +1,12 @@ +--- +service: + nginx: + enabled: true + running: false +port: + tcp:80: + listening: false + +eth0: + exists: true + addrs: [] diff --git a/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-002.example.com.yml b/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-002.example.com.yml new file mode 100644 index 0000000..4eda2b7 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/tests/test_host_glb-002.example.com.yml @@ -0,0 +1,15 @@ +--- +service: + nginx: + enabled: true + running: true +port: + tcp:80: + listening: true + ip: + - 0.0.0.0 +eth0: + exists: true + addrs: + - 10.10.10.11/32 + - 10.10.10.10/32 diff --git a/roles/generic_loadbalancer/molecule/default/verify.yml b/roles/generic_loadbalancer/molecule/default/verify.yml new file mode 100644 index 0000000..df350d7 --- /dev/null +++ b/roles/generic_loadbalancer/molecule/default/verify.yml @@ -0,0 +1,61 @@ +--- +- name: Verify + hosts: generic_loadbalancer + become: true + vars: + goss_version: v0.3.6 + goss_arch: amd64 + goss_bin: /usr/local/bin/goss + goss_sha256sum: 53dd1156ab66f2c4275fd847372e6329d895cfb2f0bcbec5f86c1c4df7236dde. + goss_test_directory: /tmp/molecule/goss + goss_format: documentation + tasks: + - name: Download and install Goss + get_url: + url: "https://github.com/aelsabbahy/goss/releases/download/{{ goss_version }}/goss-linux-{{ goss_arch }}" + dest: "{{ goss_bin }}" + sha256sum: "{{ goss_sha256sum }}" + mode: 0755 + + - name: Create Molecule directory for test files + file: + path: "{{ goss_test_directory }}" + state: directory + + - name: Find Goss tests on localhost + shell: "find {{ lookup('env', 'MOLECULE_VERIFIER_TEST_DIRECTORY') }} \\( -name 'test_*.yml' -and -not -name 'test_host_*.yml' \\) -or -name 'test_host_{{ ansible_hostname }}*.yml'" + delegate_to: localhost + register: test_files + + - name: debug + debug: + msg: "{{ test_files.stdout_lines }}" + verbosity: 3 + + - name: Copy Goss tests to remote + copy: + src: "{{ item }}" + dest: "{{ goss_test_directory }}/{{ item | basename }}" + with_items: + - "{{ test_files.stdout_lines }}" + + - name: Register test files + shell: "ls {{ goss_test_directory }}/test_*.yml" + register: test_files + + - name: Execute Goss tests + command: "{{ goss_bin }} -g {{ item }} validate --format {{ goss_format }}" + register: test_results + with_items: "{{ test_files.stdout_lines }}" + ignore_errors: true + + - name: Display details about the Goss results + debug: + msg: "{{ item.stdout_lines }}" + with_items: "{{ test_results.results }}" + + - name: Fail when tests fail + fail: + msg: "Goss failed to validate" + when: item.rc != 0 + with_items: "{{ test_results.results }}" diff --git a/roles/generic_loadbalancer/requirements.txt b/roles/generic_loadbalancer/requirements.txt new file mode 100644 index 0000000..6dae112 --- /dev/null +++ b/roles/generic_loadbalancer/requirements.txt @@ -0,0 +1,3 @@ +ansible >=2.5,<2.6 +git+https://github.com/dw/mitogen.git@v0.2.2 + diff --git a/roles/generic_loadbalancer/tasks/keepalived.yml b/roles/generic_loadbalancer/tasks/keepalived.yml new file mode 100644 index 0000000..9bdb586 --- /dev/null +++ b/roles/generic_loadbalancer/tasks/keepalived.yml @@ -0,0 +1,17 @@ +--- +- name: install keepalived + yum: + name: keepalived + state: present + +- name: create keepalived config + template: + src: keepalived.conf.j2 + dest: /etc/keepalived/keepalived.conf + notify: restart keepalived + +- name: enable and start keepalived + systemd: + name: keepalived + state: started + enabled: yes diff --git a/roles/generic_loadbalancer/tasks/main.yml b/roles/generic_loadbalancer/tasks/main.yml new file mode 100644 index 0000000..74baec4 --- /dev/null +++ b/roles/generic_loadbalancer/tasks/main.yml @@ -0,0 +1,10 @@ +--- +# tasks file for generic_loadbalancer +- name: gather facts from all servers in cluster + setup: + delegate_to: "{{item}}" + delegate_facts: True + loop: "{{groups['generic_loadbalancer']}}" + +- include_tasks: keepalived.yml +- include_tasks: nginx/main.yml diff --git a/roles/generic_loadbalancer/tasks/nginx/main.yml b/roles/generic_loadbalancer/tasks/nginx/main.yml new file mode 100644 index 0000000..0a8393e --- /dev/null +++ b/roles/generic_loadbalancer/tasks/nginx/main.yml @@ -0,0 +1,10 @@ +--- + +- name: nginx | create fallback vhost + template: + src: fallback.conf.j2 + dest: /etc/nginx/conf.d/fallback.conf + owner: nginx + group: nginx + notify: + - reload nginx diff --git a/roles/generic_loadbalancer/templates/.gitkeep b/roles/generic_loadbalancer/templates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/roles/generic_loadbalancer/templates/fallback.conf.j2 b/roles/generic_loadbalancer/templates/fallback.conf.j2 new file mode 100644 index 0000000..4ce018a --- /dev/null +++ b/roles/generic_loadbalancer/templates/fallback.conf.j2 @@ -0,0 +1,8 @@ +server { + listen 80; + server_name _; + + location / { + return 502 "$http_host has no upstreams available"; + } +} diff --git a/roles/generic_loadbalancer/templates/keepalived.conf.j2 b/roles/generic_loadbalancer/templates/keepalived.conf.j2 new file mode 100644 index 0000000..8b95589 --- /dev/null +++ b/roles/generic_loadbalancer/templates/keepalived.conf.j2 @@ -0,0 +1,74 @@ +global_defs { +} + +vrrp_script chk_nginx { + script "pidof nginx" + interval 2 +} + +vrrp_instance VI_1 { + interface {{ ansible_default_ipv4.interface | default('eth0') }} + state BACKUP +{% if ( ansible_fqdn | regex_replace('^[^\\.]+([1-9]+)\\..*','\\1') | int % 2) == 1 %} + priority 101 +{% else %} + priority 100 +{%endif%} + + virtual_router_id 220 + unicast_src_ip {{ ansible_default_ipv4.address }} + unicast_peer { +{% for h in groups.generic_loadbalancer | difference([inventory_hostname]) %} + {{ hostvars[h]['ansible_default_ipv4']['address'] }} +{%endfor%} + } + + authentication { + auth_type PASS + auth_pass {{ ansible_domain | checksum | default('keepalived_auth_pass') }} + } + + track_script { + chk_nginx + } + + virtual_ipaddress { + {{ generic_loadbalancer.vip.0 }} + } + +} + +{% if generic_loadbalancer.vip.1 is defined %} +vrrp_instance VI_2 { + interface {{ ansible_default_ipv4.interface | default('eth0') }} + state BACKUP +{% if ( ansible_fqdn | regex_replace('^[^\\.]+([1-9]+)\\..*','\\1') | int % 2) == 1 %} + priority 100 +{% else %} + priority 101 +{%endif%} + + virtual_router_id 221 + unicast_src_ip {{ ansible_default_ipv4.address }} + unicast_peer { +{% for h in groups.generic_loadbalancer | difference([inventory_hostname]) %} + {{ hostvars[h]['ansible_default_ipv4']['address'] }} +{%endfor%} + } + + authentication { + auth_type PASS + auth_pass {{ ansible_domain | checksum | default('keepalived_auth_pass') }} + } + + track_script { + chk_nginx + } + + virtual_ipaddress { + {{ generic_loadbalancer.vip.1 }} + } + +} + +{% endif %} diff --git a/roles/generic_loadbalancer/vars/main.yml b/roles/generic_loadbalancer/vars/main.yml new file mode 100644 index 0000000..20bb9cb --- /dev/null +++ b/roles/generic_loadbalancer/vars/main.yml @@ -0,0 +1,21 @@ +--- +# vars file for kubernetes loadbalancer + +# access-key +cattle_access_key: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 37646237333666313930636338663564396234633162386164636130386666383062396163373162 + 6130383836396432636133633236636530666338636665340a633262336363653430373863323332 + 32323035313931386634336338363261616466306636373636613136343335616665396665326638 + 3738393938663932650a316431343031323038393066303639386466396130643833313237306636 + 3463 +# secret-key +cattle_secret_key: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 34623362363363653033646364316466623039316162396163306163353863626633396536386661 + 6464383134313834663334653435656532636138626466310a383031326432326636643039613536 + 65333631326266373639666366336633326634663631326461623334316437303832313465356261 + 3133613664303230620a363237353539373130363361343963666461646234313737613730646530 + 61306633623062616636333661326333373030626239346335306434313838623162393636363666 + 38346166656661356236656530326135646630356363383034346161663166393366613939393236 + 663865373935303135376233343834323136 diff --git a/roles/nginx/.yamllint b/roles/nginx/.yamllint new file mode 100644 index 0000000..3a2255e --- /dev/null +++ b/roles/nginx/.yamllint @@ -0,0 +1,13 @@ +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + line-length: disable + # NOTE(retr0h): Templates no longer fail this lint rule. + # Uncomment if running old Molecule templates. + # truthy: disable diff --git a/roles/nginx/README.md b/roles/nginx/README.md new file mode 100644 index 0000000..f28e3d1 --- /dev/null +++ b/roles/nginx/README.md @@ -0,0 +1,35 @@ +Role Name +========= + +Install epel-release and nginx from package. + +Requirements +------------ + +nginx.yml +- epel-release +- nginx + +Role Variables +-------------- + +handlers/main.yml +- nginx restart and validate nginx config +tasks/main.yml +- Installation epel-release and nginx package + +Dependencies +------------ + +First epel-release is needed then nginx can be install. + +Example Playbook +---------------- + +playbook: nginx.yml + +License +------- + +Author Information +----------------- diff --git a/roles/nginx/defaults/main.yml b/roles/nginx/defaults/main.yml new file mode 100644 index 0000000..7467044 --- /dev/null +++ b/roles/nginx/defaults/main.yml @@ -0,0 +1,3 @@ +--- +nginx_limit_no_files: 132000 +dns_primary_ip: "{{ ansible_dns['nameservers'][0] }}" diff --git a/roles/nginx/handlers/main.yml b/roles/nginx/handlers/main.yml new file mode 100644 index 0000000..480b7cf --- /dev/null +++ b/roles/nginx/handlers/main.yml @@ -0,0 +1,31 @@ +--- +# handlers file for nginx + +- name: enable nginx + systemd: + name: nginx + enabled: true + +- name: reload nginx + systemd: + name: nginx + state: reloaded + +- name: restart nginx + systemd: + name: nginx + state: restarted + +- name: validate nginx configuration + command: nginx -t -c /etc/nginx/nginx.conf + changed_when: false + +- name: enable rngd + systemd: + name: rngd + enabled: true + state: started + +- name: reload systemd + systemd: + daemon_reload: true diff --git a/roles/nginx/molecule/default/.molecule/Dockerfile_centos_7 b/roles/nginx/molecule/default/.molecule/Dockerfile_centos_7 new file mode 100644 index 0000000..77f9636 --- /dev/null +++ b/roles/nginx/molecule/default/.molecule/Dockerfile_centos_7 @@ -0,0 +1,9 @@ +# Molecule managed + +FROM centos:7 + +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; fi diff --git a/roles/nginx/molecule/default/.molecule/ansible.cfg b/roles/nginx/molecule/default/.molecule/ansible.cfg new file mode 100644 index 0000000..761e8ce --- /dev/null +++ b/roles/nginx/molecule/default/.molecule/ansible.cfg @@ -0,0 +1,10 @@ +# Molecule managed + +[ssh_connection] +control_path = %(directory)s/%%h-%%p-%%r +scp_if_ssh = True +[defaults] +host_key_checking = False +ansible_managed = Ansible managed: Do NOT edit this file manually! +retry_files_enabled = False +nocows = 1 diff --git a/roles/nginx/molecule/default/.molecule/ansible_inventory.yml b/roles/nginx/molecule/default/.molecule/ansible_inventory.yml new file mode 100644 index 0000000..607aeed --- /dev/null +++ b/roles/nginx/molecule/default/.molecule/ansible_inventory.yml @@ -0,0 +1,11 @@ +# Molecule managed + +--- +all: + hosts: + instance: &id001 + ansible_connection: docker +ungrouped: + hosts: + instance: *id001 + vars: {} diff --git a/roles/nginx/molecule/default/.molecule/state.yml b/roles/nginx/molecule/default/.molecule/state.yml new file mode 100644 index 0000000..2c257c0 --- /dev/null +++ b/roles/nginx/molecule/default/.molecule/state.yml @@ -0,0 +1,7 @@ +# Molecule managed + +--- +converged: false +created: false +driver: docker +prepared: null diff --git a/roles/nginx/molecule/default/Dockerfile.j2 b/roles/nginx/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..f93c13a --- /dev/null +++ b/roles/nginx/molecule/default/Dockerfile.j2 @@ -0,0 +1,13 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry }}/{{ 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; fi diff --git a/roles/nginx/molecule/default/INSTALL.rst b/roles/nginx/molecule/default/INSTALL.rst new file mode 100644 index 0000000..e26493b --- /dev/null +++ b/roles/nginx/molecule/default/INSTALL.rst @@ -0,0 +1,16 @@ +******* +Install +******* + +Requirements +============ + +* Docker Engine +* docker-py + +Install +======= + +.. code-block:: bash + + $ sudo pip install docker-py diff --git a/roles/nginx/molecule/default/molecule.yml b/roles/nginx/molecule/default/molecule.yml new file mode 100644 index 0000000..80f505c --- /dev/null +++ b/roles/nginx/molecule/default/molecule.yml @@ -0,0 +1,41 @@ +--- +dependency: + name: gilt +driver: + name: docker +lint: + name: yamllint + options: + config-file: ../.yamllint +platforms: + - name: instance + # systemd needs a privileged container atm. + privileged: true + image: centos:7 + command: /sbin/init + env: + container: docker + security_opts: + - apparmor=unconfined + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + capabilities: + - SYS_ADMIN + - SYSLOG +provisioner: + name: ansible + config_options: + defaults: + jinja2_extensions: jinja2.ext.do + options: + vault-id: ~/.ssh/vault_pass.txt + lint: + name: ansible-lint +scenario: + name: default +verifier: + name: testinfra + lint: + name: flake8 + options: + config: ../.flake8 diff --git a/roles/nginx/molecule/default/playbook.yml b/roles/nginx/molecule/default/playbook.yml new file mode 100644 index 0000000..a0eb8e2 --- /dev/null +++ b/roles/nginx/molecule/default/playbook.yml @@ -0,0 +1,5 @@ +--- +- name: Converge + hosts: all + roles: + - role: nginx diff --git a/roles/nginx/molecule/default/prepare.yml b/roles/nginx/molecule/default/prepare.yml new file mode 100644 index 0000000..b575937 --- /dev/null +++ b/roles/nginx/molecule/default/prepare.yml @@ -0,0 +1,14 @@ +--- +- name: Prepare + hosts: all + gather_facts: false + tasks: + - name: Install requirements + yum: + name: "{{ item }}" + state: installed + with_items: + - systemd + - systemd-libs + - initscripts + - epel-release diff --git a/roles/nginx/molecule/default/tests/test_default.py b/roles/nginx/molecule/default/tests/test_default.py new file mode 100644 index 0000000..83a519c --- /dev/null +++ b/roles/nginx/molecule/default/tests/test_default.py @@ -0,0 +1,29 @@ +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 test_hosts_file(host): + f = host.file('/etc/hosts') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' + + +@pytest.mark.parametrize('file, content, mode, owner, group', [ + ('/etc/systemd/system/nginx.service.d/override.conf', + '', 0o0644, 'root', 'root') +]) +def test_files_created(host, file, mode, owner, group, content): + afile = host.file(file) + assert afile.exists + assert afile.mode == mode + assert afile.user == owner + assert afile.group == group + if content != '': + assert afile.contains(content) diff --git a/roles/nginx/molecule/default/verify.yml b/roles/nginx/molecule/default/verify.yml new file mode 100644 index 0000000..c1b0f39 --- /dev/null +++ b/roles/nginx/molecule/default/verify.yml @@ -0,0 +1,61 @@ +--- +- name: Verify + hosts: all + become: true + vars: + goss_version: v0.3.6 + goss_arch: amd64 + goss_bin: /usr/local/bin/goss + goss_sha256sum: 53dd1156ab66f2c4275fd847372e6329d895cfb2f0bcbec5f86c1c4df7236dde. + goss_test_directory: /tmp/molecule/goss + goss_format: documentation + tasks: + - name: Download and install Goss + get_url: + url: "https://github.com/aelsabbahy/goss/releases/download/{{ goss_version }}/goss-linux-{{ goss_arch }}" + dest: "{{ goss_bin }}" + sha256sum: "{{ goss_sha256sum }}" + mode: 0755 + + - name: Create Molecule directory for test files + file: + path: "{{ goss_test_directory }}" + state: directory + + - name: Find Goss tests on localhost + shell: "find {{ lookup('env', 'MOLECULE_VERIFIER_TEST_DIRECTORY') }} \\( -name 'test_*.yml' -and -not -name 'test_host_*.yml' \\) -or -name 'test_host_{{ ansible_hostname }}*.yml'" + delegate_to: localhost + register: test_files + + - name: debug + debug: + msg: "{{ test_files.stdout_lines }}" + verbosity: 3 + + - name: Copy Goss tests to remote + copy: + src: "{{ item }}" + dest: "{{ goss_test_directory }}/{{ item | basename }}" + with_items: + - "{{ test_files.stdout_lines }}" + + - name: Register test files + shell: "ls {{ goss_test_directory }}/test_*.yml" + register: test_files + + - name: Execute Goss tests + command: "{{ goss_bin }} -g {{ item }} validate --format {{ goss_format }}" + register: test_results + with_items: "{{ test_files.stdout_lines }}" + ignore_errors: true + + - name: Display details about the Goss results + debug: + msg: "{{ item.stdout_lines }}" + with_items: "{{ test_results.results }}" + + - name: Fail when tests fail + fail: + msg: "Goss failed to validate" + when: item.rc != 0 + with_items: "{{ test_results.results }}" diff --git a/roles/nginx/nginx.yml b/roles/nginx/nginx.yml new file mode 100644 index 0000000..e3ad4cd --- /dev/null +++ b/roles/nginx/nginx.yml @@ -0,0 +1,6 @@ +--- +- name: Setup nginx + hosts: all + become: true + roles: + - nginx diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml new file mode 100644 index 0000000..81cee4f --- /dev/null +++ b/roles/nginx/tasks/main.yml @@ -0,0 +1,77 @@ +--- +# tasks file for nginx + +## enable epel + +# - name: setup epel +# yum: +# name: "{{ item }}" +# state: installed +# with_items: +# - epel-release + +- name: enable ipv4 non local bind + sysctl: + name: net.ipv4.ip_nonlocal_bind + value: 1 + sysctl_set: yes + +- name: install nginx and rngd + yum: + name: "{{ item }}" + state: installed + with_items: + - nginx + - rng-tools + notify: + - enable nginx + - restart nginx + - enable rngd + +- name: check if nginx is compiled with dynamic or static stream module + shell: /sbin/nginx -V 2>&1 | grep -q ' --with-stream ' + register: static_stream + changed_when: false + failed_when: false + check_mode: no + +- name: install mod-stream + yum: + name: "{{ item }}" + state: installed + with_items: + - nginx-mod-stream + when: + - static_stream.rc != 0 + +- name: create default nginx.conf + template: + src: nginx.conf.j2 + dest: /etc/nginx/nginx.conf + notify: + - reload nginx + +- name: Create systemd service override directory + file: + path: /etc/systemd/system/nginx.service.d + state: directory + +- name: Copy systemd overrides + template: + src: systemd_override.conf.j2 + dest: /etc/systemd/system/nginx.service.d/override.conf + notify: + - reload systemd + +# avoid overriding of default.conf by package updates +- name: create empty dummy default.conf + copy: + content: '# do not remove this file' + dest: /etc/nginx/conf.d/default.conf + owner: nginx + group: nginx + mode: 0644 + notify: + - reload nginx + +- meta: flush_handlers diff --git a/roles/nginx/templates/nginx.conf.j2 b/roles/nginx/templates/nginx.conf.j2 new file mode 100644 index 0000000..44aaf95 --- /dev/null +++ b/roles/nginx/templates/nginx.conf.j2 @@ -0,0 +1,85 @@ +{% if static_stream.rc != 0 %} +load_module /usr/lib64/nginx/modules/ngx_stream_module.so; +{% endif %} + +user nginx; +worker_processes auto; + +####### CUSTOM +# Has to be smaller or equal to LimitNOFILE, see /etc/systemd/system/nginx.service.d/override.conf +worker_rlimit_nofile {{ nginx_limit_no_files }}; +####### + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 16000; + use epoll; +} + + +http { +## Custom + underscores_in_headers on; + client_body_buffer_size 10M; + client_max_body_size 10M; + # needs thorough testing + # # allow the server to close connection on non responding client, this will free up memory + reset_timedout_connection on; + # hide server information + server_tokens off; + # set resolver config + resolver {{ dns_primary_ip }} valid=1200s ipv6=off; + resolver_timeout 600s; + types_hash_max_size 4096; + server_names_hash_bucket_size 4096; + proxy_headers_hash_bucket_size 512; +###### + ssl_session_cache shared:SSL:40m; + ssl_session_timeout 10m; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + + + log_format upstreamlog '$remote_addr - $remote_user [$time_local] "$request" ' + '$status "$http_referer" ' + '"$upstream_addr"'; + + log_format default_log_format '[$time_local] $status $request $request_time $remote_addr ' + '"$upstream_addr" "$connection_requests" $body_bytes_sent ' + '"$http_referer" "$http_user_agent" "$http_x_forwarded_for"'; + + log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" ' + '"$host" sn="$server_name" ' + 'rt=$request_time ' + 'ua="$upstream_addr" us="$upstream_status" ' + 'ut="$upstream_response_time" ul="$upstream_response_length" ' + 'cs=$upstream_cache_status' ; + + access_log /var/log/nginx/access.log main_ext; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 20; + + gzip on; + gzip_types text/plain text/xml text/css text/javascript application/javascript application/x-javascript image/svg+xml; + + include /etc/nginx/conf.d/*.conf; + +} + +stream { + include /etc/nginx/conf.d/*.stream; +} diff --git a/roles/nginx/templates/systemd_override.conf.j2 b/roles/nginx/templates/systemd_override.conf.j2 new file mode 100644 index 0000000..7121b5b --- /dev/null +++ b/roles/nginx/templates/systemd_override.conf.j2 @@ -0,0 +1,2 @@ +[Service] +LimitNOFILE={{ nginx_limit_no_files }}