From e93f8f3907eccd5bcd3d88be6312f24bdf9ec05b Mon Sep 17 00:00:00 2001 From: Ryan Faircloth <35384120+rfaircloth-splunk@users.noreply.github.com> Date: Fri, 31 Jul 2020 19:53:54 -0400 Subject: [PATCH 01/10] [fix] Add commands for proper use of diag --upload feature (#404) * [fix] Add commands for proper use of diag --upload feature * Update install.sh * Update install.sh --- base/debian-10/install.sh | 2 ++ base/debian-9/install.sh | 2 ++ base/redhat-8/install.sh | 2 ++ 3 files changed, 6 insertions(+) diff --git a/base/debian-10/install.sh b/base/debian-10/install.sh index a2033e53..410aed75 100755 --- a/base/debian-10/install.sh +++ b/base/debian-10/install.sh @@ -43,6 +43,8 @@ tar -xf /usr/bin/scloud.tar.gz -C /usr/bin/ rm /usr/bin/scloud.tar.gz cd /bin +ln -s busybox clear +ln -s busybox find ln -s busybox killall ln -s busybox netstat ln -s busybox nslookup diff --git a/base/debian-9/install.sh b/base/debian-9/install.sh index 2f04be36..65bdaf88 100755 --- a/base/debian-9/install.sh +++ b/base/debian-9/install.sh @@ -43,6 +43,8 @@ tar -xf /usr/bin/scloud.tar.gz -C /usr/bin/ rm /usr/bin/scloud.tar.gz cd /bin +ln -s busybox clear +ln -s busybox find ln -s busybox diff ln -s busybox killall ln -s busybox netstat diff --git a/base/redhat-8/install.sh b/base/redhat-8/install.sh index 2bb08447..95b28064 100755 --- a/base/redhat-8/install.sh +++ b/base/redhat-8/install.sh @@ -50,6 +50,8 @@ tar -xf /usr/bin/scloud.tar.gz -C /usr/bin/ rm /usr/bin/scloud.tar.gz cd /bin +ln -s busybox clear || true +ln -s busybox find || true ln -s python2 python || true ln -s busybox diff || true ln -s busybox hostname || true From c641c9a08fae180b8a882bb2f2da645aef2fdef9 Mon Sep 17 00:00:00 2001 From: Nelson Wang Date: Wed, 5 Aug 2020 23:30:39 -0700 Subject: [PATCH 02/10] Fixing missing shc secret in scenario (#406) --- test_scenarios/1dep3sh2idx1dmc.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test_scenarios/1dep3sh2idx1dmc.yaml b/test_scenarios/1dep3sh2idx1dmc.yaml index 20c09e47..2f91bd3f 100644 --- a/test_scenarios/1dep3sh2idx1dmc.yaml +++ b/test_scenarios/1dep3sh2idx1dmc.yaml @@ -22,6 +22,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_deployer + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD @@ -45,6 +46,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_search_head_captain + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD @@ -68,6 +70,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_search_head + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD @@ -91,6 +94,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_search_head + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD @@ -114,6 +118,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_indexer + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD @@ -137,6 +142,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_indexer + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD @@ -160,6 +166,7 @@ services: - SPLUNK_SEARCH_HEAD_CAPTAIN_URL=sh1 - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_ROLE=splunk_monitor + - SPLUNK_SHC_PASS4SYMMKEY=mylittlepony - SPLUNK_LICENSE_URI - SPLUNK_PASSWORD - DEBUG=true From 612d24bce1e5655cdf742f00c5bd8c51c9d561e0 Mon Sep 17 00:00:00 2001 From: Cam Nelson Date: Fri, 7 Aug 2020 13:38:29 -0400 Subject: [PATCH 03/10] Rewrite tests to add parallelization (#402) * Initial commit * initial commit * added more tests * fix todo * added more tests * changed makefile to run new tests * added tests; removed some container names; working * remove unnecessary functions and container names * add env variables for tests to avoid timeout * fix broken test * add parallelism * fix failing tests * fix spelling error * adding another thread for tests * fix flaky test * add missing tests * seperate tests by size * rewrite circleci architecture * revert architecture changes * add rerun to help mitigate flaky tests * seperate tests into single and distributed * add missing tests * add removal of default.yml * Fixing non-terminating loop, more structured OOP * remove duplicate functions * remove check_for_default * remove tar conflicts * remove test_docker_splunk Co-authored-by: Nelson Wang Co-authored-by: cameronn Co-authored-by: TheCamNelson Co-authored-by: Nelson Wang --- .circleci/config.yml | 20 +- .gitignore | 1 - Makefile | 54 +- test_scenarios/1deployment1cm.yaml | 7 +- test_scenarios/1deployment1so.yaml | 5 +- test_scenarios/1deployment1uf.yaml | 5 +- test_scenarios/1hf_splunk_add_user.yaml | 1 - test_scenarios/1idx3sh1cm1dep.yaml | 19 +- test_scenarios/1sh1cm.yaml | 2 - test_scenarios/1sh1cm1dmc.yaml | 3 - test_scenarios/1sh2idx2hf1dmc.yaml | 6 - test_scenarios/1so1cm_connected.yaml | 2 - test_scenarios/1so1cm_unconnected.yaml | 2 - test_scenarios/1so1dmc.yaml | 2 - test_scenarios/1so_apps.yaml | 4 +- test_scenarios/1so_before_start_cmd.yaml | 1 - test_scenarios/1so_command_start.yaml | 23 - test_scenarios/1so_command_start_service.yaml | 23 - test_scenarios/1so_custombuild.yaml | 1 - test_scenarios/1so_enable_service.yaml | 1 - test_scenarios/1so_hec.yaml | 1 - test_scenarios/1so_java_openjdk11.yaml | 1 - test_scenarios/1so_java_openjdk8.yaml | 1 - test_scenarios/1so_java_oracle.yaml | 1 - test_scenarios/1so_namedvolumes.yaml | 1 - test_scenarios/1so_splunk_add_user.yaml | 1 - test_scenarios/1so_trial.yaml | 1 - test_scenarios/1uf1so.yaml | 2 - test_scenarios/1uf1so1dmc.yaml | 3 - test_scenarios/1uf_apps.yaml | 4 +- test_scenarios/1uf_before_start_cmd.yaml | 1 - test_scenarios/1uf_command_start.yaml | 22 - test_scenarios/1uf_command_start_service.yaml | 22 - test_scenarios/1uf_enable_service.yaml | 1 - test_scenarios/1uf_hec.yaml | 1 - test_scenarios/1uf_splunk_add_user.yaml | 1 - test_scenarios/1uf_splunk_cmd.yaml | 1 - test_scenarios/2idx2sh.yaml | 6 +- test_scenarios/2idx2sh1cm.yaml | 5 - test_scenarios/2idx2sh1cm_idx3.yaml | 1 - test_scenarios/2idx2sh1dmc.yaml | 7 +- test_scenarios/3idx1cm.yaml | 8 +- test_scenarios/3idx1cm1dmc.yaml | 5 - tests/executor.py | 422 ++ tests/requirements.txt | 4 +- tests/test_distributed_splunk_image.py | 1101 +++++ ..._splunk.py => test_single_splunk_image.py} | 4373 ++++++----------- 47 files changed, 3069 insertions(+), 3110 deletions(-) delete mode 100644 test_scenarios/1so_command_start.yaml delete mode 100644 test_scenarios/1so_command_start_service.yaml delete mode 100644 test_scenarios/1uf_command_start.yaml delete mode 100644 test_scenarios/1uf_command_start_service.yaml create mode 100644 tests/executor.py create mode 100644 tests/test_distributed_splunk_image.py rename tests/{test_docker_splunk.py => test_single_splunk_image.py} (56%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 22c704e9..a817e8c0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -61,8 +61,12 @@ jobs: name: Test if image size increase command: make test_debian10_image_size - run: - name: Run Debian 10 image tests - command: make run_tests_debian10 + name: Run small Debian 10 image tests + command: make run_small_tests_debian10 + no_output_timeout: 20m + - run: + name: Run large Debian 10 image tests + command: make run_large_tests_debian10 no_output_timeout: 20m - store_artifacts: path: test-results @@ -95,8 +99,12 @@ jobs: command: | make uf-redhat-8 - run: - name: Run Redhat 8 image tests - command: make run_tests_redhat8 + name: Run small Redhat 8 image tests + command: make run_small_tests_redhat8 + no_output_timeout: 20m + - run: + name: Run large Redhat 8 image tests + command: make run_large_tests_redhat8 no_output_timeout: 20m - store_artifacts: path: test-results @@ -144,6 +152,4 @@ workflows: - security-scanning - debian10-testing - container-validation - - redhat8-testing - - + - redhat8-testing \ No newline at end of file diff --git a/.gitignore b/.gitignore index ab4becd3..79a173d4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,4 @@ splunk-ansible *.xml *clair-scanner* .env -tests/fixtures/* venv diff --git a/Makefile b/Makefile index 9a2fde99..bc98abef 100644 --- a/Makefile +++ b/Makefile @@ -289,23 +289,35 @@ sample-compose-up: sample-compose-down sample-compose-down: docker-compose -f test_scenarios/${SPLUNK_COMPOSE} down --volumes --remove-orphans || true -test: clean ansible test_setup all run_tests_centos7 run_tests_redhat8 run_tests_debian9 +test: clean ansible test_setup all run_small_tests run_large_tests -test_centos7: clean ansible splunk-centos-7 uf-centos-7 test_setup run_tests_centos7 +run_small_tests: run_small_tests_centos7 run_small_tests_redhat8 run_small_tests_debian9 run_small_tests_debian10 -test_redhat8: clean ansible splunk-redhat-8 uf-redhat-8 test_setup run_tests_redhat8 +run_large_tests: run_large_tests_centos7 run_large_tests_redhat8 run_large_tests_debian9 run_large_tests_debian10 -test_debian9: clean ansible splunk-debian-9 uf-debian-9 test_setup run_tests_debian9 +test_centos7: clean ansible splunk-centos-7 uf-centos-7 test_setup run_small_tests_centos7 run_large_tests_centos7 -test_debian10: clean ansible splunk-debian-10 uf-debian-10 test_setup run_tests_debian10 +test_redhat8: clean ansible splunk-redhat-8 uf-redhat-8 test_setup run_small_tests_redhat8 run_large_tests_redhat8 -run_tests_centos7: - @echo 'Running the super awesome tests; CentOS 7' - pytest -sv tests/test_docker_splunk.py --platform centos-7 --junitxml test-results/centos7-result/testresults_centos7.xml +test_debian9: clean ansible splunk-debian-9 uf-debian-9 test_setup run_small_tests_debian9 run_large_tests_debian9 -run_tests_redhat8: - @echo 'Running the super awesome tests; RedHat 8' - pytest -sv tests/test_docker_splunk.py --platform redhat-8 --junitxml test-results/redhat8-result/testresults_redhat8.xml +test_debian10: clean ansible splunk-debian-10 uf-debian-10 test_setup run_small_tests_debian10 run_large_tests_debian10 + +run_small_tests_centos7: + @echo 'Running the super awesome small tests; CentOS 7' + pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform centos-7 --junitxml test-results/centos7-result/testresults_small_centos7.xml + +run_large_tests_centos7: + @echo 'Running the super awesome large tests; CentOS 7' + pytest -n 2 --reruns 1 -sv tests/test_distributed_splunk_image.py --platform centos-7 --junitxml test-results/centos7-result/testresults_large_centos7.xml + +run_small_tests_redhat8: + @echo 'Running the super awesome small tests; RedHat 8' + pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform redhat-8 --junitxml test-results/redhat8-result/testresults_small_redhat8.xml + +run_large_tests_redhat8: + @echo 'Running the super awesome large tests; RedHat 8' + pytest -n 2 --reruns 1 -sv tests/test_distributed_splunk_image.py --platform redhat-8 --junitxml test-results/redhat8-result/testresults_large_redhat8.xml test_setup: @echo 'Install test requirements' @@ -316,13 +328,21 @@ test_setup: mkdir test-results/debian10-result || true mkdir test-results/redhat8-result || true -run_tests_debian9: - @echo 'Running the super awesome tests; Debian 9' - pytest -sv tests/test_docker_splunk.py --platform debian-9 --junitxml test-results/debian9-result/testresults_debian9.xml +run_small_tests_debian9: + @echo 'Running the super awesome small tests; Debian 9' + pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform debian-9 --junitxml test-results/debian9-result/testresults_small_debian9.xml + +run_large_tests_debian9: + @echo 'Running the super awesome large tests; Debian 9' + pytest -n 2 --reruns 1 -sv tests/test_distributed_splunk_image.py --platform debian-9 --junitxml test-results/debian9-result/testresults_large_debian9.xml + +run_small_tests_debian10: + @echo 'Running the super awesome small tests; Debian 10' + pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform debian-10 --junitxml test-results/debian10-result/testresults_small_debian10.xml -run_tests_debian10: - @echo 'Running the super awesome tests; Debian 10' - pytest -sv tests/test_docker_splunk.py --platform debian-10 --junitxml test-results/debian10-result/testresults_debian10.xml +run_large_tests_debian10: + @echo 'Running the super awesome large tests; Debian 10' + pytest -n 2 --reruns 1 -sv tests/test_distributed_splunk_image.py --platform debian-10 --junitxml test-results/debian10-result/testresults_large_debian10.xml save_containers: @echo 'Saving the following containers:${CONTAINERS_TO_SAVE}' diff --git a/test_scenarios/1deployment1cm.yaml b/test_scenarios/1deployment1cm.yaml index d9017a19..a3417592 100644 --- a/test_scenarios/1deployment1cm.yaml +++ b/test_scenarios/1deployment1cm.yaml @@ -13,7 +13,6 @@ services: - appserver image: nwang92/nginx-mitm hostname: appserver - container_name: appserver ports: - 80 volumes: @@ -26,13 +25,13 @@ services: - depserver1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: depserver1 - container_name: depserver1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_deployment_server - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_APPS_URL - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8089 volumes: @@ -45,7 +44,6 @@ services: - cm1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_DEPLOYMENT_SERVER=depserver1 @@ -53,6 +51,7 @@ services: - SPLUNK_CLUSTER_MASTER_URL=cm1 - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 diff --git a/test_scenarios/1deployment1so.yaml b/test_scenarios/1deployment1so.yaml index eb9b813c..45501366 100644 --- a/test_scenarios/1deployment1so.yaml +++ b/test_scenarios/1deployment1so.yaml @@ -13,7 +13,6 @@ services: - appserver image: nwang92/nginx-mitm hostname: appserver - container_name: appserver ports: - 80 volumes: @@ -26,11 +25,10 @@ services: - depserver1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: depserver1 - container_name: depserver1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_deployment_server - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_APPS_URL - DEBUG=true - SPLUNK_PASSWORD ports: @@ -43,7 +41,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_DEPLOYMENT_SERVER=depserver1 diff --git a/test_scenarios/1deployment1uf.yaml b/test_scenarios/1deployment1uf.yaml index de19e876..6dc2e2b4 100644 --- a/test_scenarios/1deployment1uf.yaml +++ b/test_scenarios/1deployment1uf.yaml @@ -13,7 +13,6 @@ services: - appserver image: nwang92/nginx-mitm hostname: appserver - container_name: appserver ports: - 80 volumes: @@ -26,11 +25,10 @@ services: - depserver1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: depserver1 - container_name: depserver1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_deployment_server - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_APPS_URL - DEBUG=true - SPLUNK_PASSWORD ports: @@ -43,7 +41,6 @@ services: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} hostname: uf1 - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_DEPLOYMENT_SERVER=depserver1 diff --git a/test_scenarios/1hf_splunk_add_user.yaml b/test_scenarios/1hf_splunk_add_user.yaml index dfd61f0b..3467de11 100644 --- a/test_scenarios/1hf_splunk_add_user.yaml +++ b/test_scenarios/1hf_splunk_add_user.yaml @@ -12,7 +12,6 @@ services: aliases: - hf1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - container_name: hf1 environment: - SPLUNK_ROLE=splunk_heavy_forwarder - SPLUNK_START_ARGS=--accept-license diff --git a/test_scenarios/1idx3sh1cm1dep.yaml b/test_scenarios/1idx3sh1cm1dep.yaml index bd255df4..b5cdbf12 100644 --- a/test_scenarios/1idx3sh1cm1dep.yaml +++ b/test_scenarios/1idx3sh1cm1dep.yaml @@ -13,7 +13,6 @@ services: - appserver image: nwang92/nginx-mitm hostname: appserver - container_name: appserver ports: - 80 volumes: @@ -26,7 +25,6 @@ services: - dep1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: dep1 - container_name: dep1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1 @@ -38,7 +36,8 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_DEFAULTS_URL + - SPLUNK_APPS_URL ports: - 8000 - 8089 @@ -52,7 +51,6 @@ services: - sh1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1 @@ -64,6 +62,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 @@ -77,7 +76,6 @@ services: - sh2 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: sh2 - container_name: sh2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1 @@ -89,6 +87,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 @@ -102,7 +101,6 @@ services: - sh3 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: sh3 - container_name: sh3 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1 @@ -114,6 +112,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 @@ -127,7 +126,6 @@ services: - cm1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1 @@ -139,7 +137,8 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_DEFAULTS_URL + - SPLUNK_APPS_URL ports: - 8000 - 8089 @@ -153,7 +152,6 @@ services: - idx1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: idx1 - container_name: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1 @@ -162,10 +160,11 @@ services: - SPLUNK_DEPLOYER_URL=dep1 - SPLUNK_CLUSTER_MASTER_URL=cm1 - SPLUNK_ROLE=splunk_indexer - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_APPS_URL - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 diff --git a/test_scenarios/1sh1cm.yaml b/test_scenarios/1sh1cm.yaml index eecf5654..33a4c48d 100644 --- a/test_scenarios/1sh1cm.yaml +++ b/test_scenarios/1sh1cm.yaml @@ -13,7 +13,6 @@ services: - sh1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_CLUSTER_MASTER_URL=cm1 @@ -31,7 +30,6 @@ services: - cm1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_cluster_master diff --git a/test_scenarios/1sh1cm1dmc.yaml b/test_scenarios/1sh1cm1dmc.yaml index 25ee0ab9..68decef5 100644 --- a/test_scenarios/1sh1cm1dmc.yaml +++ b/test_scenarios/1sh1cm1dmc.yaml @@ -13,7 +13,6 @@ services: - sh1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_CLUSTER_MASTER_URL=cm1 @@ -31,7 +30,6 @@ services: - cm1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_cluster_master @@ -49,7 +47,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: dmc - container_name: dmc environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_CLUSTER_MASTER_URL=cm1 diff --git a/test_scenarios/1sh2idx2hf1dmc.yaml b/test_scenarios/1sh2idx2hf1dmc.yaml index 34c112ea..fb9309d1 100644 --- a/test_scenarios/1sh2idx2hf1dmc.yaml +++ b/test_scenarios/1sh2idx2hf1dmc.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_SEARCH_HEAD_URL=sh1 @@ -36,7 +35,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx1 - container_name: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_SEARCH_HEAD_URL=sh1 @@ -58,7 +56,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx2 - container_name: idx2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_SEARCH_HEAD_URL=sh1 @@ -80,7 +77,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: hf1 - container_name: hf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_SEARCH_HEAD_URL=sh1 @@ -102,7 +98,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: hf2 - container_name: hf2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_SEARCH_HEAD_URL=sh1 @@ -124,7 +119,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: dmc - container_name: dmc environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_SEARCH_HEAD_URL=sh1 diff --git a/test_scenarios/1so1cm_connected.yaml b/test_scenarios/1so1cm_connected.yaml index 8cca9788..fd89a30a 100644 --- a/test_scenarios/1so1cm_connected.yaml +++ b/test_scenarios/1so1cm_connected.yaml @@ -13,7 +13,6 @@ services: - cm1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_cluster_master @@ -30,7 +29,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_CLUSTER_MASTER_URL=cm1 diff --git a/test_scenarios/1so1cm_unconnected.yaml b/test_scenarios/1so1cm_unconnected.yaml index eae1f96c..ba4b80ba 100644 --- a/test_scenarios/1so1cm_unconnected.yaml +++ b/test_scenarios/1so1cm_unconnected.yaml @@ -13,7 +13,6 @@ services: - cm1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ROLE=splunk_cluster_master @@ -30,7 +29,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - DEBUG=true diff --git a/test_scenarios/1so1dmc.yaml b/test_scenarios/1so1dmc.yaml index fb697a05..289483dd 100644 --- a/test_scenarios/1so1dmc.yaml +++ b/test_scenarios/1so1dmc.yaml @@ -13,7 +13,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 @@ -31,7 +30,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: dmc - container_name: dmc environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 diff --git a/test_scenarios/1so_apps.yaml b/test_scenarios/1so_apps.yaml index 2555fb61..95c9fb7a 100644 --- a/test_scenarios/1so_apps.yaml +++ b/test_scenarios/1so_apps.yaml @@ -13,7 +13,6 @@ services: - appserver image: nwang92/nginx-mitm hostname: appserver - container_name: appserver ports: - 80 volumes: @@ -26,11 +25,10 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_APPS_URL - DEBUG=true ports: - 8000 diff --git a/test_scenarios/1so_before_start_cmd.yaml b/test_scenarios/1so_before_start_cmd.yaml index 77efc70f..17fce871 100644 --- a/test_scenarios/1so_before_start_cmd.yaml +++ b/test_scenarios/1so_before_start_cmd.yaml @@ -12,7 +12,6 @@ services: aliases: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_BEFORE_START_CMD=add user admin2 -password changemepls -role admin, add user admin3 -password changemepls -role admin diff --git a/test_scenarios/1so_command_start.yaml b/test_scenarios/1so_command_start.yaml deleted file mode 100644 index 022286d3..00000000 --- a/test_scenarios/1so_command_start.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3.6" - -networks: - splunknet: - driver: bridge - attachable: true - -services: - so1: - networks: - splunknet: - aliases: - - so1 - image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - command: start - container_name: so1 - environment: - - SPLUNK_START_ARGS=--accept-license - - SPLUNK_PASSWORD - - DEBUG=true - ports: - - 8000 - - 8089 diff --git a/test_scenarios/1so_command_start_service.yaml b/test_scenarios/1so_command_start_service.yaml deleted file mode 100644 index 55acaf72..00000000 --- a/test_scenarios/1so_command_start_service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3.6" - -networks: - splunknet: - driver: bridge - attachable: true - -services: - so1: - networks: - splunknet: - aliases: - - so1 - image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - command: start-service - container_name: so1 - environment: - - SPLUNK_START_ARGS=--accept-license - - SPLUNK_PASSWORD - - DEBUG=true - ports: - - 8000 - - 8089 diff --git a/test_scenarios/1so_custombuild.yaml b/test_scenarios/1so_custombuild.yaml index 2aaab6d9..a4fc183b 100644 --- a/test_scenarios/1so_custombuild.yaml +++ b/test_scenarios/1so_custombuild.yaml @@ -13,7 +13,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_BUILD_URL=https://download.splunk.com/products/splunk/releases/7.1.1/linux/splunk-7.1.1-8f0ead9ec3db-Linux-x86_64.tgz diff --git a/test_scenarios/1so_enable_service.yaml b/test_scenarios/1so_enable_service.yaml index 36a9a25e..8bc77f7f 100644 --- a/test_scenarios/1so_enable_service.yaml +++ b/test_scenarios/1so_enable_service.yaml @@ -12,7 +12,6 @@ services: aliases: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ENABLE_SERVICE=true diff --git a/test_scenarios/1so_hec.yaml b/test_scenarios/1so_hec.yaml index f8993450..57b27bc9 100644 --- a/test_scenarios/1so_hec.yaml +++ b/test_scenarios/1so_hec.yaml @@ -12,7 +12,6 @@ services: aliases: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1so_java_openjdk11.yaml b/test_scenarios/1so_java_openjdk11.yaml index ffed594d..866f4a65 100644 --- a/test_scenarios/1so_java_openjdk11.yaml +++ b/test_scenarios/1so_java_openjdk11.yaml @@ -9,7 +9,6 @@ services: so1: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1so_java_openjdk8.yaml b/test_scenarios/1so_java_openjdk8.yaml index ca642db0..4cb06358 100644 --- a/test_scenarios/1so_java_openjdk8.yaml +++ b/test_scenarios/1so_java_openjdk8.yaml @@ -9,7 +9,6 @@ services: so1: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1so_java_oracle.yaml b/test_scenarios/1so_java_oracle.yaml index ee553bfd..a339abda 100644 --- a/test_scenarios/1so_java_oracle.yaml +++ b/test_scenarios/1so_java_oracle.yaml @@ -9,7 +9,6 @@ services: so1: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1so_namedvolumes.yaml b/test_scenarios/1so_namedvolumes.yaml index 637b6dbf..024ec445 100644 --- a/test_scenarios/1so_namedvolumes.yaml +++ b/test_scenarios/1so_namedvolumes.yaml @@ -16,7 +16,6 @@ services: aliases: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1so_splunk_add_user.yaml b/test_scenarios/1so_splunk_add_user.yaml index 1011d5fb..473223ea 100644 --- a/test_scenarios/1so_splunk_add_user.yaml +++ b/test_scenarios/1so_splunk_add_user.yaml @@ -12,7 +12,6 @@ services: aliases: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ADD=user newman -password changemepls -role admin diff --git a/test_scenarios/1so_trial.yaml b/test_scenarios/1so_trial.yaml index 400e6c80..3a6236cd 100644 --- a/test_scenarios/1so_trial.yaml +++ b/test_scenarios/1so_trial.yaml @@ -9,7 +9,6 @@ services: so1: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1uf1so.yaml b/test_scenarios/1uf1so.yaml index 0f6eaef3..be2f8273 100644 --- a/test_scenarios/1uf1so.yaml +++ b/test_scenarios/1uf1so.yaml @@ -13,7 +13,6 @@ services: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} hostname: uf1 - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 @@ -30,7 +29,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 diff --git a/test_scenarios/1uf1so1dmc.yaml b/test_scenarios/1uf1so1dmc.yaml index 4e24f3ef..aef53d3d 100644 --- a/test_scenarios/1uf1so1dmc.yaml +++ b/test_scenarios/1uf1so1dmc.yaml @@ -13,7 +13,6 @@ services: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} hostname: uf1 - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 @@ -30,7 +29,6 @@ services: - so1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} hostname: so1 - container_name: so1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 @@ -48,7 +46,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: dmc - container_name: dmc environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_STANDALONE_URL=so1 diff --git a/test_scenarios/1uf_apps.yaml b/test_scenarios/1uf_apps.yaml index 23ef5add..1bd791f9 100644 --- a/test_scenarios/1uf_apps.yaml +++ b/test_scenarios/1uf_apps.yaml @@ -13,7 +13,6 @@ services: - appserver image: nwang92/nginx-mitm hostname: appserver - container_name: appserver ports: - 80 volumes: @@ -26,11 +25,10 @@ services: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} hostname: uf1 - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD - - SPLUNK_APPS_URL=http://appserver/splunk_app_example.tgz + - SPLUNK_APPS_URL - DEBUG=true ports: - 8089 diff --git a/test_scenarios/1uf_before_start_cmd.yaml b/test_scenarios/1uf_before_start_cmd.yaml index 1baf1593..b34fda34 100644 --- a/test_scenarios/1uf_before_start_cmd.yaml +++ b/test_scenarios/1uf_before_start_cmd.yaml @@ -12,7 +12,6 @@ services: aliases: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_BEFORE_START_CMD=add user normalplebe -password newpassword -role user diff --git a/test_scenarios/1uf_command_start.yaml b/test_scenarios/1uf_command_start.yaml deleted file mode 100644 index 529c8fc1..00000000 --- a/test_scenarios/1uf_command_start.yaml +++ /dev/null @@ -1,22 +0,0 @@ -version: "3.6" - -networks: - splunknet: - driver: bridge - attachable: true - -services: - uf1: - networks: - splunknet: - aliases: - - uf1 - image: ${UF_IMAGE:-splunk/universalforwarder:latest} - command: start - container_name: uf1 - environment: - - SPLUNK_START_ARGS=--accept-license - - SPLUNK_PASSWORD - - DEBUG=true - ports: - - 8089 diff --git a/test_scenarios/1uf_command_start_service.yaml b/test_scenarios/1uf_command_start_service.yaml deleted file mode 100644 index e4d14519..00000000 --- a/test_scenarios/1uf_command_start_service.yaml +++ /dev/null @@ -1,22 +0,0 @@ -version: "3.6" - -networks: - splunknet: - driver: bridge - attachable: true - -services: - uf1: - networks: - splunknet: - aliases: - - uf1 - image: ${UF_IMAGE:-splunk/universalforwarder:latest} - command: start-service - container_name: uf1 - environment: - - SPLUNK_START_ARGS=--accept-license - - SPLUNK_PASSWORD - - DEBUG=true - ports: - - 8089 diff --git a/test_scenarios/1uf_enable_service.yaml b/test_scenarios/1uf_enable_service.yaml index 2987c150..3a97435e 100644 --- a/test_scenarios/1uf_enable_service.yaml +++ b/test_scenarios/1uf_enable_service.yaml @@ -12,7 +12,6 @@ services: aliases: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ENABLE_SERVICE=true diff --git a/test_scenarios/1uf_hec.yaml b/test_scenarios/1uf_hec.yaml index 3e53c37e..d80f0b0e 100644 --- a/test_scenarios/1uf_hec.yaml +++ b/test_scenarios/1uf_hec.yaml @@ -13,7 +13,6 @@ services: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} hostname: uf1 - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_PASSWORD diff --git a/test_scenarios/1uf_splunk_add_user.yaml b/test_scenarios/1uf_splunk_add_user.yaml index 53269a16..21add4de 100644 --- a/test_scenarios/1uf_splunk_add_user.yaml +++ b/test_scenarios/1uf_splunk_add_user.yaml @@ -12,7 +12,6 @@ services: aliases: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_ADD=user elaine -password changemepls -role admin,user kramer -password changemepls -role admin diff --git a/test_scenarios/1uf_splunk_cmd.yaml b/test_scenarios/1uf_splunk_cmd.yaml index 5da60eaf..fd4562aa 100644 --- a/test_scenarios/1uf_splunk_cmd.yaml +++ b/test_scenarios/1uf_splunk_cmd.yaml @@ -12,7 +12,6 @@ services: aliases: - uf1 image: ${UF_IMAGE:-splunk/universalforwarder:latest} - container_name: uf1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_CMD=add user jerry -password changemepls -role admin,add user george -password changemepls -role admin diff --git a/test_scenarios/2idx2sh.yaml b/test_scenarios/2idx2sh.yaml index accb3b37..d42ed969 100644 --- a/test_scenarios/2idx2sh.yaml +++ b/test_scenarios/2idx2sh.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -35,7 +34,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh2 - container_name: sh2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -55,8 +53,7 @@ services: - idx1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start - hostname: idx1 - container_name: idx1 + hostname: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -77,7 +74,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx2 - container_name: idx2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 diff --git a/test_scenarios/2idx2sh1cm.yaml b/test_scenarios/2idx2sh1cm.yaml index b56fa983..6091d922 100644 --- a/test_scenarios/2idx2sh1cm.yaml +++ b/test_scenarios/2idx2sh1cm.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -36,7 +35,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh2 - container_name: sh2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -58,7 +56,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -80,7 +77,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx1 - container_name: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -102,7 +98,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx2 - container_name: idx2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 diff --git a/test_scenarios/2idx2sh1cm_idx3.yaml b/test_scenarios/2idx2sh1cm_idx3.yaml index 7c7025a6..48624cfa 100644 --- a/test_scenarios/2idx2sh1cm_idx3.yaml +++ b/test_scenarios/2idx2sh1cm_idx3.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx3 - container_name: idx3 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 diff --git a/test_scenarios/2idx2sh1dmc.yaml b/test_scenarios/2idx2sh1dmc.yaml index 79f12ba6..0b282b56 100644 --- a/test_scenarios/2idx2sh1dmc.yaml +++ b/test_scenarios/2idx2sh1dmc.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh1 - container_name: sh1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -35,7 +34,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: sh2 - container_name: sh2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -55,8 +53,7 @@ services: - idx1 image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start - hostname: idx1 - container_name: idx1 + hostname: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -77,7 +74,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx2 - container_name: idx2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 @@ -98,7 +94,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: dmc - container_name: dmc environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2 diff --git a/test_scenarios/3idx1cm.yaml b/test_scenarios/3idx1cm.yaml index 02560fe3..721c960f 100644 --- a/test_scenarios/3idx1cm.yaml +++ b/test_scenarios/3idx1cm.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -23,6 +22,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 @@ -37,7 +37,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx1 - container_name: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -46,6 +45,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 @@ -60,7 +60,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx2 - container_name: idx2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -69,6 +68,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 @@ -83,7 +83,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx3 - container_name: idx3 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -92,6 +91,7 @@ services: - SPLUNK_LICENSE_URI - DEBUG=true - SPLUNK_PASSWORD + - SPLUNK_DEFAULTS_URL ports: - 8000 - 8089 diff --git a/test_scenarios/3idx1cm1dmc.yaml b/test_scenarios/3idx1cm1dmc.yaml index 4e041351..dd9b5c7d 100644 --- a/test_scenarios/3idx1cm1dmc.yaml +++ b/test_scenarios/3idx1cm1dmc.yaml @@ -14,7 +14,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: cm1 - container_name: cm1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -37,7 +36,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx1 - container_name: idx1 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -60,7 +58,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx2 - container_name: idx2 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -83,7 +80,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: idx3 - container_name: idx3 environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 @@ -106,7 +102,6 @@ services: image: ${SPLUNK_IMAGE:-splunk/splunk:latest} command: start hostname: dmc - container_name: dmc environment: - SPLUNK_START_ARGS=--accept-license - SPLUNK_INDEXER_URL=idx1,idx2,idx3 diff --git a/tests/executor.py b/tests/executor.py new file mode 100644 index 00000000..1d511eb6 --- /dev/null +++ b/tests/executor.py @@ -0,0 +1,422 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import pytest +import time +import os +import sys +import requests +import logging +import docker +import json +import urllib +import yaml +import shlex +import subprocess +import logging.handlers +from shutil import copy +from random import choice +from string import ascii_lowercase +# Code to suppress insecure https warnings +import urllib3 +from urllib3.exceptions import InsecureRequestWarning, SubjectAltNameWarning +urllib3.disable_warnings(InsecureRequestWarning) +urllib3.disable_warnings(SubjectAltNameWarning) + + +# Define variables +FILE_DIR = os.path.dirname(os.path.normpath(os.path.join(__file__))) +REPO_DIR = os.path.join(FILE_DIR, "..") +# Setup logging +LOGGER = logging.getLogger("docker-splunk") +LOGGER.setLevel(logging.INFO) +file_handler = logging.handlers.RotatingFileHandler(os.path.join(FILE_DIR, "docker_splunk_test_python{}.log".format(sys.version_info[0])), maxBytes=25000000) +formatter = logging.Formatter('%(asctime)s %(levelname)s [%(name)s] [%(process)d] %(message)s') +file_handler.setFormatter(formatter) +LOGGER.addHandler(file_handler) +# Define Docker client settings +os.environ['COMPOSE_HTTP_TIMEOUT'] = "500" +os.environ['DOCKER_CLIENT_TIMEOUT'] = "500" + + +class Executor(object): + """ + Parent executor class that handles concurrent test execution workflows and shared methods + to validate the Docker images for Splunk Enterprise/Universal Forwarder + """ + + logger = LOGGER + RETRY_COUNT = 3 + RETRY_DELAY = 6 # in seconds + + FIXTURES_DIR = os.path.join(FILE_DIR, "fixtures") + EXAMPLE_APP = os.path.join(FIXTURES_DIR, "splunk_app_example") + EXAMPLE_APP_TGZ = os.path.join(FIXTURES_DIR, "splunk_app_example.tgz") + SCENARIOS_DIR = os.path.join(FILE_DIR, "..", "test_scenarios") + DEFAULTS_DIR = os.path.join(SCENARIOS_DIR, "defaults") + + @classmethod + def setup_class(cls, platform): + cls.client = docker.APIClient() + # Define images by name to be validated + cls.BASE_IMAGE_NAME = "base-{}".format(platform) + cls.SPLUNK_IMAGE_NAME = "splunk-{}".format(platform) + cls.UF_IMAGE_NAME = "uf-{}".format(platform) + # Define new, random password for each executor + cls.password = Executor.generate_random_string() + cls.compose_file_name = None + cls.project_name = None + cls.DIR = None + cls.container_id = None + # Wrap into custom env variable for subprocess overrides + cls.env = { + "SPLUNK_PASSWORD": cls.password, + "SPLUNK_IMAGE": cls.SPLUNK_IMAGE_NAME, + "UF_IMAGE": cls.UF_IMAGE_NAME + } + + @classmethod + def teardown_class(cls): + pass + + @staticmethod + def generate_random_string(): + return ''.join(choice(ascii_lowercase) for b in range(10)) + + @classmethod + def _run_cmd(cls, cmd, cwd=REPO_DIR): + if isinstance(cmd, list): + sh = command + elif isinstance(command, str): + sh = shlex.split(command) + cls.logger.info("CALL: {}".format(sh)) + proc = subprocess.Popen(sh, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) + lines = [] + err_lines = [] + for line in iter(proc.stdout.readline, ''): + lines.append(line) + for line in iter(proc.stderr.readline, ''): + err_lines.append(line) + proc.stdout.close() + proc.stderr.close() + proc.wait() + out = "".join(lines) + self.logger.info("STDOUT: {}".format(out)) + err = "".join(err_lines) + self.logger.info("STDERR: {}".format(err)) + self.logger.info("RC: {}".format(proc.returncode)) + return out, err, proc.returncode + + def handle_request_retry(self, method, url, kwargs): + for n in range(Executor.RETRY_COUNT): + try: + self.logger.info("Attempt #{}: running {} against {} with kwargs {}".format(n+1, method, url, kwargs)) + resp = requests.request(method, url, **kwargs) + resp.raise_for_status() + return resp + except Exception as e: + self.logger.error("Attempt #{} error: {}".format(n+1, str(e))) + if n < Executor.RETRY_COUNT-1: + time.sleep(Executor.RETRY_DELAY) + continue + raise e + + def get_container_logs(self, container_id): + stream = self.client.logs(container_id, stream=True) + output = "" + for char in stream: + if "Ansible playbook complete" in char: + break + output += char + return output + + def cleanup_files(self, files): + try: + for file in files: + os.remove(file) + except OSError as e: + pass + except Exception as e: + raise e + + def _clean_docker_env(self): + # Remove anything spun up by docker-compose + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + for container in containers: + self.client.remove_container(container["Id"], v=True, force=True) + try: + self.client.prune_networks({"until": "15s"}) + self.client.prune_volumes() + except: + pass + + def wait_for_containers(self, count, label=None, name=None, timeout=500): + ''' + NOTE: This helper method can only be used for `compose up` scenarios where self.project_name is defined + ''' + start = time.time() + end = start + # Wait + while end-start < timeout: + filters = {} + if name: + filters["name"] = name + if label: + filters["label"] = label + containers = self.client.containers(filters=filters) + self.logger.info("Found {} containers, expected {}: {}".format(len(containers), count, [x["Names"][0] for x in containers])) + if len(containers) != count: + return False + healthy_count = 0 + for container in containers: + # The healthcheck on our Splunk image is not reliable - resorting to checking logs + if container.get("Labels", {}).get("maintainer") == "support@splunk.com": + output = self.client.logs(container["Id"], tail=10) + if "unable to" in output or "denied" in output or "splunkd.pid file is unreadable" in output: + self.logger.error("Container {} did not start properly, last log line: {}".format(container["Names"][0], output)) + elif "Ansible playbook complete" in output: + self.logger.info("Container {} is ready".format(container["Names"][0])) + healthy_count += 1 + else: + self.logger.info("Container {} is ready".format(container["Names"][0])) + healthy_count += 1 + if healthy_count == count: + self.logger.info("All containers ready to proceed") + break + time.sleep(5) + end = time.time() + return True + + def handle_request_retry(self, method, url, kwargs): + RETRIES = 10 + IMPLICIT_WAIT = 6 + for n in range(RETRIES): + try: + self.logger.info("Attempt #{}: running {} against {} with kwargs {}".format(n+1, method, url, kwargs)) + resp = requests.request(method, url, **kwargs) + resp.raise_for_status() + return (resp.status_code, resp.content) + except Exception as e: + self.logger.error("Attempt #{} error: {}".format(n+1, str(e))) + if n < RETRIES-1: + time.sleep(IMPLICIT_WAIT) + continue + raise e + + def check_splunkd(self, username, password, name=None, scheme="https"): + ''' + NOTE: This helper method can only be used for `compose up` scenarios where self.project_name is defined + ''' + filters = {} + if name: + filters["name"] = name + if self.project_name: + filters["label"] = "com.docker.compose.project={}".format(self.project_name) + containers = self.client.containers(filters=filters) + for container in containers: + # We can't check splunkd on non-Splunk containers + if "maintainer" not in container["Labels"] or container["Labels"]["maintainer"] != "support@splunk.com": + continue + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + url = "{}://localhost:{}/services/server/info".format(scheme, splunkd_port) + kwargs = {"auth": (username, password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + return True + + def _run_splunk_query(self, container_id, query, username="admin", password="password"): + splunkd_port = self.client.port(container_id, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/search/jobs?output_mode=json".format(splunkd_port) + kwargs = { + "auth": (username, password), + "data": "search={}".format(urllib.quote_plus(query)), + "verify": False + } + resp = requests.post(url, **kwargs) + assert resp.status_code == 201 + sid = json.loads(resp.content)["sid"] + assert sid + self.logger.info("Search job {} created against on {}".format(sid, container_id)) + # Wait for search to finish + job_status = None + url = "https://localhost:{}/services/search/jobs/{}?output_mode=json".format(splunkd_port, sid) + kwargs = { + "auth": (username, password), + "verify": False + } + for _ in range(10): + job_status = requests.get(url, **kwargs) + done = json.loads(job_status.content)["entry"][0]["content"]["isDone"] + self.logger.info("Search job {} done status is {}".format(sid, done)) + if done: + break + time.sleep(3) + assert job_status and job_status.status_code == 200 + # Get job metadata + job_metadata = json.loads(job_status.content) + # Check search results + url = "https://localhost:{}/services/search/jobs/{}/results?output_mode=json".format(splunkd_port, sid) + job_results = requests.get(url, **kwargs) + assert job_results.status_code == 200 + job_results = json.loads(job_results.content) + return job_metadata, job_results + + def compose_up(self, defaults_url=None, apps_url=None): + container_count = self.get_number_of_containers(os.path.join(self.SCENARIOS_DIR, self.compose_file_name)) + command = "docker-compose -p {} -f test_scenarios/{} up -d".format(self.project_name, self.compose_file_name) + out, err, rc = self._run_command(command, defaults_url, apps_url) + return container_count, rc + + def extract_json(self, container_name): + retries = 15 + for i in range(retries): + exec_command = self.client.exec_create(container_name, "cat /opt/container_artifact/ansible_inventory.json") + json_data = self.client.exec_start(exec_command) + if "No such file or directory" in json_data: + time.sleep(5) + else: + break + try: + data = json.loads(json_data) + return data + except Exception as e: + self.logger.error(e) + return None + + def get_number_of_containers(self, filename): + yml = {} + with open(filename, "r") as f: + yml = yaml.load(f, Loader=yaml.Loader) + return len(yml["services"]) + + def search_internal_distinct_hosts(self, container_id, username="admin", password="password"): + query = "search index=_internal earliest=-1m | stats dc(host) as distinct_hosts" + meta, results = self._run_splunk_query(container_id, query, username, password) + search_providers = meta["entry"][0]["content"]["searchProviders"] + distinct_hosts = int(results["results"][0]["distinct_hosts"]) + return search_providers, distinct_hosts + + def _run_command(self, command, defaults_url=None, apps_url=None): + if isinstance(command, list): + sh = command + elif isinstance(command, str): + sh = shlex.split(command) + self.logger.info("CALL: %s" % sh) + env = os.environ.copy() + env["SPLUNK_PASSWORD"] = self.password + env["SPLUNK_IMAGE"] = self.SPLUNK_IMAGE_NAME + env["UF_IMAGE"] = self.UF_IMAGE_NAME + if defaults_url: + env["SPLUNK_DEFAULTS_URL"] = defaults_url + if apps_url: + env["SPLUNK_APPS_URL"] = apps_url + proc = subprocess.Popen(sh, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + lines = [] + err_lines = [] + for line in iter(proc.stdout.readline, ''): + lines.append(line) + for line in iter(proc.stderr.readline, ''): + err_lines.append(line) + proc.stdout.close() + proc.stderr.close() + proc.wait() + out = "".join(lines) + self.logger.info("STDOUT: %s" % out) + err = "".join(err_lines) + self.logger.info("STDERR: %s" % err) + self.logger.info("RC: %s" % proc.returncode) + return out, err, proc.returncode + + def check_common_keys(self, log_output, role): + try: + assert log_output["all"]["vars"]["ansible_ssh_user"] == "splunk" + assert log_output["all"]["vars"]["ansible_pre_tasks"] == None + assert log_output["all"]["vars"]["ansible_post_tasks"] == None + assert log_output["all"]["vars"]["retry_num"] == 60 + assert log_output["all"]["vars"]["retry_delay"] == 6 + assert log_output["all"]["vars"]["wait_for_splunk_retry_num"] == 60 + assert log_output["all"]["vars"]["shc_sync_retry_num"] == 60 + assert log_output["all"]["vars"]["splunk"]["group"] == "splunk" + assert log_output["all"]["vars"]["splunk"]["license_download_dest"] == "/tmp/splunk.lic" + assert log_output["all"]["vars"]["splunk"]["opt"] == "/opt" + assert log_output["all"]["vars"]["splunk"]["user"] == "splunk" + + if role == "uf": + assert log_output["all"]["vars"]["splunk"]["exec"] == "/opt/splunkforwarder/bin/splunk" + assert log_output["all"]["vars"]["splunk"]["home"] == "/opt/splunkforwarder" + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_universal_forwarder" + else: + assert log_output["all"]["vars"]["splunk"]["exec"] == "/opt/splunk/bin/splunk" + assert log_output["all"]["vars"]["splunk"]["home"] == "/opt/splunk" + if role == "so": + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_standalone" + elif role == "deployment_server": + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_deployment_server" + elif role == "idx": + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_indexer" + elif role == "sh": + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_search_head" + elif role == "hf": + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_heavy_forwarder" + elif role == "cm": + assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_cluster_master" + except KeyError as e: + self.logger.error("{} key not found".format(e)) + assert False + + def check_ansible(self, output): + assert "ansible-playbook" in output + assert "config file = /opt/ansible/ansible.cfg" in output + + def check_dmc(self, containers, num_peers, num_idx, num_sh, num_cm, num_lm): + for container in containers: + container_name = container["Names"][0].strip("/") + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "dmc": + # check 1: curl -k https://localhost:8089/servicesNS/nobody/splunk_monitoring_console/configs/conf-splunk_monitoring_console_assets/settings?output_mode=json -u admin:helloworld + status, content = self.handle_request_retry("GET", "https://localhost:{}/servicesNS/nobody/splunk_monitoring_console/configs/conf-splunk_monitoring_console_assets/settings?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert output["entry"][0]["content"]["disabled"] == False + # check 2: curl -k https://localhost:8089/servicesNS/nobody/system/apps/local/splunk_monitoring_console?output_mode=json -u admin:helloworld + status, content = self.handle_request_retry("GET", "https://localhost:{}/servicesNS/nobody/system/apps/local/splunk_monitoring_console?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert output["entry"][0]["content"]["disabled"] == False + # check 3: curl -k https://localhost:8089/services/search/distributed/peers?output_mode=json -u admin:helloworld + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/peers?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert num_peers == len(output["entry"]) + for peer in output["entry"]: + assert peer["content"]["status"] == "Up" + self.check_dmc_groups(splunkd_port, num_idx, num_sh, num_cm, num_lm) + + def check_dmc_groups(self, splunkd_port, num_idx, num_sh, num_cm, num_lm): + # check dmc_group_indexer + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_indexer?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert len(output["entry"][0]["content"]["member"]) == num_idx + # check dmc_group_cluster_master + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_cluster_master?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert len(output["entry"][0]["content"]["member"]) == num_cm + # check dmc_group_license_master + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_license_master?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert len(output["entry"][0]["content"]["member"]) == num_lm + # check dmc_group_search_head + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_search_head?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert len(output["entry"][0]["content"]["member"]) == num_sh \ No newline at end of file diff --git a/tests/requirements.txt b/tests/requirements.txt index 1c2d838b..2595ef7e 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -4,4 +4,6 @@ docker PyYAML docker-compose pyasn1 -junit-xml \ No newline at end of file +junit-xml +pytest-xdist +pytest-rerunfailures \ No newline at end of file diff --git a/tests/test_distributed_splunk_image.py b/tests/test_distributed_splunk_image.py new file mode 100644 index 00000000..39768bfb --- /dev/null +++ b/tests/test_distributed_splunk_image.py @@ -0,0 +1,1101 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import pytest +import time +import re +import os +import tarfile +import requests +import tarfile +import docker +import json +import urllib +import yaml +import subprocess +from shutil import copy, copytree, rmtree +from executor import Executor +from docker.types import Mount +# Code to suppress insecure https warnings +import urllib3 +from urllib3.exceptions import InsecureRequestWarning, SubjectAltNameWarning +urllib3.disable_warnings(InsecureRequestWarning) +urllib3.disable_warnings(SubjectAltNameWarning) + +global PLATFORM +PLATFORM = "debian-9" +OLD_SPLUNK_VERSION = "7.3.4" + +def pytest_generate_tests(metafunc): + # This is called for every test. Only get/set command line arguments + # if the argument is specified in the list of test "fixturenames". + option_value = metafunc.config.option.platform + global PLATFORM + PLATFORM = option_value + +class TestDockerSplunk(Executor): + + @classmethod + def setup_class(cls): + super(TestDockerSplunk, cls).setup_class(PLATFORM) + + def setup_method(self, method): + # Make sure all running containers are removed + self._clean_docker_env() + self.compose_file_name = None + self.project_name = None + self.DIR = None + + def teardown_method(self, method): + if self.compose_file_name and self.project_name: + if self.DIR: + command = "docker-compose -p {} -f {} down --volumes --remove-orphans".format(self.project_name, os.path.join(self.DIR, self.compose_file_name)) + else: + command = "docker-compose -p {} -f test_scenarios/{} down --volumes --remove-orphans".format(self.project_name, self.compose_file_name) + out, err, rc = self._run_command(command) + self._clean_docker_env() + if self.DIR: + try: + rmtree(self.DIR) + except OSError: + pass + self.compose_file_name, self.project_name, self.DIR = None, None, None + + def test_compose_3idx1cm_custom_repl_factor(self): + self.project_name = self.generate_random_string() + # Generate default.yml + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Change repl factor & search factor + output = re.sub(r' replication_factor: 3', r''' replication_factor: 2''', output) + output = re.sub(r' search_factor: 3', r''' search_factor: 1''', output) + # Write the default.yml to a file + with open(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name)), "w") as f: + f.write(output) + # Standup deployment + try: + self.compose_file_name = "3idx1cm.yaml" + container_count, rc = self.compose_up(defaults_url="/tmp/defaults/{}.yml".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) + # Get container logs + container_mapping = {"cm1": "cm", "idx1": "idx", "idx2": "idx", "idx3": "idx"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2", "idx3"] + assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] + except KeyError as e: + self.logger.error(e) + raise e + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed, and shcluster is setup properly + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 4 + for container in containers: + container_name = container["Names"][0].strip("/").split("_")[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "cm1": + # Check the replication factor & search factor + url = "https://localhost:{}/services/cluster/config/config?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + assert json.loads(content)["entry"][0]["content"]["replication_factor"] == 2 + assert json.loads(content)["entry"][0]["content"]["search_factor"] == 1 + except Exception as e: + self.logger.error(e) + raise e + finally: + try: + os.remove(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name))) + except OSError as e: + pass + + def test_compose_1idx3sh1cm1dep(self): + self.project_name = self.generate_random_string() + # Generate default.yml -- for SHC, we need a common default.yml otherwise things won't work + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Write the default.yml to a file + with open(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name)), "w") as f: + f.write(output) + # Tar the app before spinning up the scenario + with tarfile.open(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name)), "w:gz") as tar: + tar.add(self.EXAMPLE_APP, arcname=os.path.basename(self.EXAMPLE_APP)) + # Standup deployment + try: + self.compose_file_name = "1idx3sh1cm1dep.yaml" + container_count, rc = self.compose_up(defaults_url="/tmp/defaults/{}.yml".format(self.project_name), apps_url="http://appserver/{}.tgz".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) + # Get container logs + container_mapping = {"sh1": "sh", "sh2": "sh", "sh3": "sh", "cm1": "cm", "idx1": "idx", "dep1": "dep"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_indexer"]["hosts"] == ["idx1"] + assert inventory_json["splunk_search_head_captain"]["hosts"] == ["sh1"] + assert inventory_json["splunk_search_head"]["hosts"] == ["sh2", "sh3"] + assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] + assert inventory_json["splunk_deployer"]["hosts"] == ["dep1"] + except KeyError as e: + self.logger.error(e) + raise e + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed, and shcluster is setup properly + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 7 + for container in containers: + # Skip the nginx container + if "nginx" in container["Image"]: + continue + container_name = container["Names"][0].strip("/").split("_")[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name in {"sh1", "sh2", "sh3", "idx1"}: + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" + # Make sure preferred captain is set + if container_name == "sh1": + url = "https://localhost:{}/servicesNS/nobody/system/configs/conf-server/shclustering?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert json.loads(content)["entry"][0]["content"]["preferred_captain"] == "1" + # Search results won't return the correct results immediately :( + time.sleep(30) + RETRIES = 10 + IMPLICIT_WAIT = 6 + for n in range(RETRIES): + try: + self.logger.info("Attempt #{}: checking internal search host count".format(n+1)) + search_providers, distinct_hosts = self.search_internal_distinct_hosts("{}_sh1_1".format(self.project_name), password=self.password) + assert len(search_providers) == 2 + assert "idx1" in search_providers and "sh1" in search_providers + assert distinct_hosts == 6 + break + except Exception as e: + self.logger.error("Attempt #{} error: {}".format(n+1, str(e))) + if n < RETRIES-1: + time.sleep(IMPLICIT_WAIT) + continue + raise e + except Exception as e: + self.logger.error(e) + raise e + finally: + try: + os.remove(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name))) + os.remove(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name))) + except OSError as e: + pass + + def test_compose_1uf1so(self): + # Standup deployment + self.compose_file_name = "1uf1so.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"so1": "so", "uf1": "uf"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_standalone"]["hosts"] == ["so1"] + except KeyError as e: + self.logger.error(e) + raise e + # Search results won't return the correct results immediately :( + time.sleep(30) + search_providers, distinct_hosts = self.search_internal_distinct_hosts("{}_so1_1".format(self.project_name), password=self.password) + assert len(search_providers) == 1 + assert search_providers[0] == "so1" + assert distinct_hosts == 2 + + def test_compose_3idx1cm_default_repl_factor(self): + self.project_name = self.generate_random_string() + # Generate default.yml + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Write the default.yml to a file + with open(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name)), "w") as f: + f.write(output) + # Standup deployment + try: + self.compose_file_name = "3idx1cm.yaml" + container_count, rc = self.compose_up(defaults_url="/tmp/defaults/{}.yml".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) + # Get container logs + container_mapping = {"cm1": "cm", "idx1": "idx", "idx2": "idx", "idx3": "idx"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2", "idx3"] + assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] + except KeyError as e: + self.logger.error(e) + raise e + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed, and shcluster is setup properly + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 4 + for container in containers: + container_name = container["Names"][0].strip("/").split("_")[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "cm1": + # Check the replication factor & search factor + url = "https://localhost:{}/services/cluster/config/config?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + assert json.loads(content)["entry"][0]["content"]["replication_factor"] == 3 + assert json.loads(content)["entry"][0]["content"]["search_factor"] == 3 + except Exception as e: + self.logger.error(e) + raise e + finally: + try: + os.remove(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name))) + except OSError as e: + pass + + def test_compose_1so1cm_connected(self): + # Standup deployment + self.compose_file_name = "1so1cm_connected.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"so1": "so", "cm1": "cm"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check connections + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + for container in containers: + container_name = container["Names"][0].strip("/").split('_')[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "cm1": + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert len(output["entry"]) == 2 + for sh in output["entry"]: + assert sh["content"]["label"] in ["cm1", "so1"] + assert sh["content"]["status"] == "Connected" + + def test_compose_1so1cm_unconnected(self): + # Standup deployment + self.compose_file_name = "1so1cm_unconnected.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"so1": "so", "cm1": "cm"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check connections + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + for container in containers: + container_name = container["Names"][0].strip("/").split('_')[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "cm1": + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + assert len(output["entry"]) == 1 + assert output["entry"][0]["content"]["label"] == "cm1" + assert output["entry"][0]["content"]["status"] == "Connected" + + def test_adhoc_1cm_idxc_pass4symmkey(self): + # Create the container + cid = None + try: + self.project_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=self.project_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_ROLE": "splunk_cluster_master", + "SPLUNK_INDEXER_URL": "idx1", + "SPLUNK_IDXC_PASS4SYMMKEY": "keepsummerbeingliketotallystokedaboutlikethegeneralvibeandstuff", + "SPLUNK_IDXC_LABEL": "keepsummersafe", + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=self.project_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Check if the cluster label and pass4SymmKey line up + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "cluster_label = keepsummersafe" in std_out + pass4SymmKey = re.search(r'\[clustering\].*?pass4SymmKey = (.*?)\n', std_out, flags=re.MULTILINE|re.DOTALL).group(1).strip() + exec_command = self.client.exec_create(cid, "/opt/splunk/bin/splunk show-decrypted --value '{}'".format(pass4SymmKey), user="splunk") + std_out = self.client.exec_start(exec_command) + assert "keepsummerbeingliketotallystokedaboutlikethegeneralvibeandstuff" in std_out + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_compose_1cm_smartstore(self): + # Generate default.yml + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Add a custom conf file + output = re.sub(r' smartstore: null', r''' smartstore: + index: + - indexName: default + remoteName: remote_vol + scheme: s3 + remoteLocation: smartstore-test + s3: + access_key: abcd + secret_key: 1234 + endpoint: https://s3-region.amazonaws.com''', output) + # Write the default.yml to a file + with open(os.path.join(self.DIR, "default.yml"), "w") as f: + f.write(output) + # Create the container and mount the default.yml + cid = None + try: + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], + volumes=["/tmp/defaults/default.yml"], name=self.project_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_ROLE": "splunk_cluster_master", + "SPLUNK_INDEXER_URL": "idx1" + }, + host_config=self.client.create_host_config(binds=[self.DIR + "/default.yml:/tmp/defaults/default.yml"], + port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=self.project_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/master-apps/_cluster/local/indexes.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert 'remotePath = volume:remote_vol/$_index_name' in std_out + assert 'repFactor = auto' in std_out + assert '[volume:remote_vol]' in std_out + assert 'storageType = remote' in std_out + assert 'path = s3://smartstore-test' in std_out + assert 'remote.s3.access_key = abcd' in std_out + assert 'remote.s3.secret_key = 1234' in std_out + assert 'remote.s3.endpoint = https://s3-region.amazonaws.com' in std_out + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + try: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: + pass + + def test_compose_1sh1cm(self): + # Standup deployment + self.compose_file_name = "1sh1cm.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"sh1": "sh", "cm1": "cm"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check connections + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + for container in containers: + container_name = container["Names"][0].strip("/").split('_')[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "cm1": + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + # There's only 1 "standalone" search head connected and 1 cluster master + assert len(output["entry"]) == 2 + for sh in output["entry"]: + assert sh["content"]["label"] == "sh1" or sh["content"]["label"] == "cm1" + assert sh["content"]["status"] == "Connected" + + def test_compose_1sh1cm1dmc(self): + # Standup deployment + self.compose_file_name = "1sh1cm1dmc.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + self.check_dmc(containers, 2, 0, 2, 1, 3) + + def test_compose_1sh2idx2hf1dmc(self): + # Standup deployment + self.compose_file_name = "1sh2idx2hf1dmc.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + self.check_dmc(containers, 3, 2, 2, 0, 4) + + def test_compose_3idx1cm1dmc(self): + # Standup deployment + self.compose_file_name = "3idx1cm1dmc.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + self.check_dmc(containers, 4, 3, 2, 1, 5) + + def test_compose_1uf1so1dmc(self): + # Standup deployment + self.compose_file_name = "1uf1so1dmc.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + self.check_dmc(containers, 1, 1, 1, 0, 2) + + def test_compose_1so1dmc(self): + # Standup deployment + self.compose_file_name = "1so1dmc.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + self.check_dmc(containers, 1, 1, 1, 0, 2) + + def test_compose_2idx2sh1dmc(self): + # Standup deployment + self.compose_file_name = "2idx2sh1dmc.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + self.check_dmc(containers, 4, 2, 3, 0, 5) + + def test_compose_2idx2sh(self): + # Standup deployment + self.compose_file_name = "2idx2sh.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"sh1": "sh", "sh2": "sh", "idx1": "idx", "idx2": "idx"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2"] + assert inventory_json["splunk_search_head"]["hosts"] == ["sh1", "sh2"] + except KeyError as e: + self.logger.error(e) + raise e + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check connections + idx_list = ["idx1", "idx2"] + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + for container in containers: + c_name = container["Labels"]["com.docker.compose.service"] + if "sh1" in c_name or "sh2" in c_name: + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + url = "https://localhost:{}/services/search/distributed/peers?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + output = json.loads(content) + peers = [x["content"]["peerName"] for x in output["entry"]] + assert len(peers) == 2 and set(peers) == set(idx_list) + # Search results won't return the correct results immediately :( + time.sleep(30) + search_providers, distinct_hosts = self.search_internal_distinct_hosts("{}_sh1_1".format(self.project_name), password=self.password) + assert len(search_providers) == 3 + assert "idx1" in search_providers and "idx2" in search_providers and "sh1" in search_providers + assert distinct_hosts == 4 + + def test_compose_2idx2sh1cm(self): + # Standup deployment + self.compose_file_name = "2idx2sh1cm.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"sh1": "sh", "sh2": "sh", "idx1": "idx", "idx2": "idx", "cm1": "cm"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] + assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2"] + assert inventory_json["splunk_search_head"]["hosts"] == ["sh1", "sh2"] + except KeyError as e: + self.logger.error(e) + raise e + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check connections + idx_list = ["idx1", "idx2"] + sh_list = ["sh1", "sh2", "cm1"] + + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + for container in containers: + container_name = container["Names"][0].strip("/").split('_')[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "cm1": + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + for sh in output["entry"]: + if sh["content"]["label"] in sh_list and sh["content"]["status"] == "Connected": + sh_list.remove(sh["content"]["label"]) + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/peers?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + for idx in output["entry"]: + if idx["content"]["label"] in idx_list and idx["content"]["status"] == "Up": + idx_list.remove(idx["content"]["label"]) + assert len(idx_list) == 0 and len(sh_list) == 0 + # Add one more indexer + self.compose_file_name = "2idx2sh1cm_idx3.yaml" + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, name="idx3") + + retries = 10 + for n in range(retries): + status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/peers?output_mode=json".format(splunkd_port), + {"auth": ("admin", self.password), "verify": False}) + assert status == 200 + output = json.loads(content) + for idx in output["entry"]: + if idx["content"]["label"] == "idx3" and idx["content"]["status"] == "Up": + break + else: + time.sleep(10) + if n < retries-1: + continue + assert False + + def test_compose_1deployment1cm(self): + self.project_name = self.generate_random_string() + # Tar the app before spinning up the scenario + with tarfile.open(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name)), "w:gz") as tar: + tar.add(self.EXAMPLE_APP, arcname=os.path.basename(self.EXAMPLE_APP)) + # Generate default.yml + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Add a custom conf file + output = re.sub(r' group: splunk', r''' group: splunk + conf: + - key: user-prefs + value: + directory: /opt/splunk/etc/users/admin/user-prefs/local + content: + general: + default_namespace: appboilerplate + search_syntax_highlighting: dark + search_assistant: + "serverClass:secrets:app:test": {}''', output) + # Write the default.yml to a file + with open(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name)), "w") as f: + f.write(output) + # Standup deployment + try: + self.compose_file_name = "1deployment1cm.yaml" + container_count, rc = self.compose_up(defaults_url="/tmp/defaults/{}.yml".format(self.project_name), apps_url="http://appserver/{}.tgz".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"cm1": "cm", "depserver1": "deployment_server"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed and certain subdirectories are excluded + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 3 + for container in containers: + # Skip the nginx container + if "nginx" in container["Image"]: + continue + container_name = container["Names"][0].strip("/").split("_")[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "depserver1": + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + resp = requests.get(url, auth=("admin", self.password), verify=False) + # Deployment server should *not* install the app + assert resp.status_code == 404 + # Check that the app exists in etc/apps + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "state = disabled" in std_out + # Check that the app exists in etc/deployment-apps + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/deployment-apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/deployment-apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "# Autogenerated file " == std_out + if container_name == "cm1": + # Check if the created file exists + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/users/admin/user-prefs/local/user-prefs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "[serverClass:secrets:app:test]" in std_out + assert "[general]" in std_out + assert "default_namespace = appboilerplate" in std_out + assert "search_syntax_highlighting = dark" in std_out + assert "search_assistant" in std_out + RETRIES = 5 + for i in range(RETRIES): + try: + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "# Autogenerated file" in std_out + assert "state = enabled" in std_out + except Exception as e: + self.logger.error(e) + if i < RETRIES-1: + time.sleep(30) + continue + raise e + except Exception as e: + self.logger.error(e) + raise e + finally: + try: + os.remove(os.path.join(self.SCENARIOS_DIR, "defaults", "{}.yml".format(self.project_name))) + os.remove(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name))) + except OSError as e: + pass + + def test_compose_1deployment1so(self): + self.project_name = self.generate_random_string() + # Tar the app before spinning up the scenario + with tarfile.open(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name)), "w:gz") as tar: + tar.add(self.EXAMPLE_APP, arcname=os.path.basename(self.EXAMPLE_APP)) + # Standup deployment + try: + self.compose_file_name = "1deployment1so.yaml" + container_count, rc = self.compose_up(apps_url="http://appserver/{}.tgz".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"{}_so1_1".format(self.project_name): "so", "{}_depserver1_1".format(self.project_name): "deployment_server"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs(container) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json(container) + self.check_common_keys(inventory_json, container_mapping[container]) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed and certain subdirectories are excluded + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 3 + for container in containers: + # Skip the nginx container + if "nginx" in container["Image"]: + continue + container_name = container["Names"][0].strip("/").split('_')[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "depserver1": + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + resp = requests.get(url, auth=("admin", self.password), verify=False) + # Deployment server should *not* install the app + assert resp.status_code == 404 + # Check that the app exists in etc/apps + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "state = disabled" in std_out + # Check that the app exists in etc/deployment-apps + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/deployment-apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/deployment-apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "# Autogenerated file " == std_out + if container_name == "so1": + RETRIES = 5 + for i in range(RETRIES): + try: + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "# Autogenerated file" in std_out + assert "state = enabled" in std_out + except Exception as e: + self.logger.error(e) + if i < RETRIES-1: + time.sleep(30) + continue + raise e + except Exception as e: + self.logger.error(e) + raise e + finally: + try: + os.remove(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name))) + except OSError: + pass + + def test_compose_1deployment1uf(self): + self.project_name = self.generate_random_string() + # Tar the app before spinning up the scenario + with tarfile.open(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name)), "w:gz") as tar: + tar.add(self.EXAMPLE_APP, arcname=os.path.basename(self.EXAMPLE_APP)) + # Standup deployment + try: + self.compose_file_name = "1deployment1uf.yaml" + container_count, rc = self.compose_up(apps_url="http://appserver/{}.tgz".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Get container logs + container_mapping = {"{}_uf1_1".format(self.project_name): "uf", "{}_depserver1_1".format(self.project_name): "deployment_server"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs(container) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json(container) + self.check_common_keys(inventory_json, container_mapping[container]) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed, and shcluster is setup properly + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 3 + for container in containers: + # Skip the nginx container + if "nginx" in container["Image"]: + continue + container_name = container["Names"][0].strip("/") + container_name = container_name.split('_')[1] + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + if container_name == "depserver1": + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + resp = requests.get(url, auth=("admin", self.password), verify=False) + # Deployment server should *not* install the app + assert resp.status_code == 404 + # Check that the app exists in etc/apps + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "state = disabled" in std_out + # Check that the app exists in etc/deployment-apps + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/deployment-apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/deployment-apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "# Autogenerated file " == std_out + if container_name == "uf1": + RETRIES = 5 + for i in range(RETRIES): + try: + # Check the app and version + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" + exec_command = self.client.exec_create(container["Id"], "ls /opt/splunkforwarder/etc/apps/splunk_app_example/local/", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "savedsearches.conf" in std_out + assert "app.conf" in std_out + exec_command = self.client.exec_create(container["Id"], "cat /opt/splunkforwarder/etc/apps/splunk_app_example/local/app.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "# Autogenerated file" in std_out + assert "state = enabled" in std_out + except Exception as e: + self.logger.error(e) + if i < RETRIES-1: + time.sleep(30) + continue + raise e + except Exception as e: + self.logger.error(e) + raise e + finally: + try: + os.remove(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name))) + except OSError: + pass + + def test_compose_3idx1cm_splunktcp_ssl(self): + self.project_name = self.generate_random_string() + # Generate default.yml + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates + passphrase = "carolebaskindidit" + cmds = [ + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DEFAULTS_DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DEFAULTS_DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DEFAULTS_DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DEFAULTS_DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DEFAULTS_DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DEFAULTS_DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DEFAULTS_DIR) + ] + for cmd in cmds: + execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) + # Update s2s ssl settings + output = re.sub(r''' s2s:.*?ssl: false''', r''' s2s: + ca: /tmp/defaults/ca.pem + cert: /tmp/defaults/cert.pem + enable: true + password: {} + port: 9997 + ssl: true'''.format(passphrase), output, flags=re.DOTALL) + # Write the default.yml to a file + with open(os.path.join(self.DEFAULTS_DIR, "{}.yml".format(self.project_name)), "w") as f: + f.write(output) + # Standup deployment + try: + self.compose_file_name = "3idx1cm.yaml" + container_count, rc = self.compose_up(defaults_url="/tmp/defaults/{}.yml".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) + # Get container logs + container_mapping = {"cm1": "cm", "idx1": "idx", "idx2": "idx", "idx3": "idx"} + for container in container_mapping: + # Check ansible version & configs + ansible_logs = self.get_container_logs("{}_{}_1".format(self.project_name, container)) + self.check_ansible(ansible_logs) + # Check values in log output + inventory_json = self.extract_json("{}_{}_1".format(self.project_name, container)) + self.check_common_keys(inventory_json, container_mapping[container]) + try: + assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2", "idx3"] + assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] + except KeyError as e: + self.logger.error(e) + raise e + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Make sure apps are installed, and shcluster is setup properly + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 4 + for container in containers: + container_name = container["Names"][0].strip("/").split("_")[1] + cid = container["Id"] + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/inputs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "[splunktcp-ssl:9997]" in std_out + assert "disabled = 0" in std_out + assert "[SSL]" in std_out + assert "serverCert = /tmp/defaults/cert.pem" in std_out + assert "[sslConfig]" not in std_out + assert "rootCA = /tmp/defaults/ca.pem" in std_out + if container_name == "cm1": + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/outputs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "clientCert = /tmp/defaults/cert.pem" in std_out + assert "sslPassword" in std_out + assert "useClientSSLCompression = true" in std_out + # Check that data is being forwarded properly + time.sleep(30) + search_providers, distinct_hosts = self.search_internal_distinct_hosts("{}_cm1_1".format(self.project_name), password=self.password) + assert len(search_providers) == 4 + assert "idx1" in search_providers + assert "idx2" in search_providers + assert "idx3" in search_providers + assert distinct_hosts == 4 + except Exception as e: + self.logger.error(e) + raise e + finally: + files = [ + os.path.join(self.DEFAULTS_DIR, "ca.key"), + os.path.join(self.DEFAULTS_DIR, "ca.csr"), + os.path.join(self.DEFAULTS_DIR, "ca.pem"), + os.path.join(self.DEFAULTS_DIR, "server.key"), + os.path.join(self.DEFAULTS_DIR, "server.csr"), + os.path.join(self.DEFAULTS_DIR, "server.pem"), + os.path.join(self.DEFAULTS_DIR, "cert.pem"), + os.path.join(self.DEFAULTS_DIR, "{}.yml".format(self.project_name)) + ] + self.cleanup_files(files) \ No newline at end of file diff --git a/tests/test_docker_splunk.py b/tests/test_single_splunk_image.py similarity index 56% rename from tests/test_docker_splunk.py rename to tests/test_single_splunk_image.py index e699a3a3..8dfd30a7 100644 --- a/tests/test_docker_splunk.py +++ b/tests/test_single_splunk_image.py @@ -1,397 +1,66 @@ #!/usr/bin/env python # encoding: utf-8 -import os -import re -import time import pytest -import shlex -import yaml +import time +import re +import os +import tarfile import docker -from docker.types import Mount +import json import urllib -import requests +import yaml import subprocess -import tarfile -import logging -import logging.handlers -import json -import sys -from random import choice -from string import ascii_lowercase +from shutil import copy, copytree, rmtree +from executor import Executor +from docker.types import Mount # Code to suppress insecure https warnings import urllib3 -from urllib3.exceptions import InsecureRequestWarning +from urllib3.exceptions import InsecureRequestWarning, SubjectAltNameWarning urllib3.disable_warnings(InsecureRequestWarning) +urllib3.disable_warnings(SubjectAltNameWarning) -FILE_DIR = os.path.dirname(os.path.realpath(__file__)) -FIXTURES_DIR = os.path.join(FILE_DIR, "fixtures") -REPO_DIR = os.path.join(FILE_DIR, "..") -SCENARIOS_DIR = os.path.join(FILE_DIR, "..", "test_scenarios") -DEFAULTS_DIR = os.path.join(SCENARIOS_DIR, "defaults") -EXAMPLE_APP = os.path.join(FIXTURES_DIR, "splunk_app_example") -EXAMPLE_APP_TGZ = os.path.join(FIXTURES_DIR, "splunk_app_example.tgz") -# Setup logging -LOGGER = logging.getLogger("image_test") -LOGGER.setLevel(logging.INFO) -file_handler = logging.handlers.RotatingFileHandler(os.path.join(FILE_DIR, "functional_image_test.log"), maxBytes=25000000) -formatter = logging.Formatter('%(asctime)s %(levelname)s [%(name)s] [%(process)d] %(message)s') -file_handler.setFormatter(formatter) -LOGGER.addHandler(file_handler) - - -global platform -platform = "debian-9" +global PLATFORM +PLATFORM = "debian-9" OLD_SPLUNK_VERSION = "7.3.4" - -def generate_random_string(): - return ''.join(choice(ascii_lowercase) for b in range(20)) - def pytest_generate_tests(metafunc): # This is called for every test. Only get/set command line arguments # if the argument is specified in the list of test "fixturenames". option_value = metafunc.config.option.platform - global platform - platform = option_value + global PLATFORM + PLATFORM = option_value -@pytest.mark.large -class TestDockerSplunk(object): - """ - Test suite to validate the Splunk/UF Docker image - """ - - logger = LOGGER - +class TestDockerSplunk(Executor): @classmethod def setup_class(cls): - cls.client = docker.APIClient() - # Docker variables - global platform - cls.BASE_IMAGE_NAME = "base-{}".format(platform) - cls.SPLUNK_IMAGE_NAME = "splunk-{}".format(platform) - cls.UF_IMAGE_NAME = "uf-{}".format(platform) - # Setup password - cls.password = generate_random_string() - with open(os.path.join(REPO_DIR, ".env"), "w") as f: - f.write("SPLUNK_PASSWORD={}\n".format(cls.password)) - f.write("SPLUNK_IMAGE={}\n".format(cls.SPLUNK_IMAGE_NAME)) - f.write("UF_IMAGE={}\n".format(cls.UF_IMAGE_NAME)) - - @classmethod - def teardown_class(cls): - try: - os.remove(os.path.join(REPO_DIR, ".env")) - except OSError as e: - pass - except Exception as e: - raise e + super(TestDockerSplunk, cls).setup_class(PLATFORM) def setup_method(self, method): # Make sure all running containers are removed self._clean_docker_env() self.compose_file_name = None self.project_name = None + self.DIR = None def teardown_method(self, method): if self.compose_file_name and self.project_name: - command = "docker-compose -p {} -f test_scenarios/{} down --volumes --remove-orphans".format(self.project_name, self.compose_file_name) + if self.DIR: + command = "docker-compose -p {} -f {} down --volumes --remove-orphans".format(self.project_name, os.path.join(self.DIR, self.compose_file_name)) + else: + command = "docker-compose -p {} -f test_scenarios/{} down --volumes --remove-orphans".format(self.project_name, self.compose_file_name) out, err, rc = self._run_command(command) - self.compose_file_name, self.project_name = None, None - self._clean_docker_env() - - def cleanup_files(self, files): - try: - for file in files: - os.remove(file) - except OSError as e: - pass - except Exception as e: - raise e - - def _clean_docker_env(self): - # Remove anything spun up by docker-compose - containers = self.client.containers(filters={"label": "com.docker.compose.version"}) - for container in containers: - self.client.remove_container(container["Id"], v=True, force=True) - self.client.prune_networks() - self.client.prune_volumes() - - def _run_command(self, command, cwd=REPO_DIR): - if isinstance(command, list): - sh = command - elif isinstance(command, str): - sh = shlex.split(command) - self.logger.info("CALL: %s" % sh) - proc = subprocess.Popen(sh, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) - lines = [] - err_lines = [] - for line in iter(proc.stdout.readline, ''): - lines.append(line) - for line in iter(proc.stderr.readline, ''): - err_lines.append(line) - proc.stdout.close() - proc.stderr.close() - proc.wait() - out = "".join(lines) - self.logger.info("STDOUT: %s" % out) - err = "".join(err_lines) - self.logger.info("STDERR: %s" % err) - self.logger.info("RC: %s" % proc.returncode) - return out, err, proc.returncode - - def compose_up(self): - container_count = self.get_number_of_containers(os.path.join(SCENARIOS_DIR, self.compose_file_name)) - command = "docker-compose -p {} -f test_scenarios/{} up -d".format(self.project_name, self.compose_file_name) - out, err, rc = self._run_command(command) - return container_count, rc - - def get_number_of_containers(self, filename): - yml = {} - with open(filename, "r") as f: - yml = yaml.load(f, Loader=yaml.Loader) - return len(yml["services"]) - - def wait_for_containers(self, count, label=None, name=None, timeout=300): - ''' - NOTE: This helper method can only be used for `compose up` scenarios where self.project_name is defined - ''' - start = time.time() - end = start - # Wait - while end-start < timeout: - filters = {} - if name: - filters["name"] = name - if label: - filters["label"] = label - containers = self.client.containers(filters=filters) - self.logger.info("Found {} containers, expected {}: {}".format(len(containers), count, [x["Names"][0] for x in containers])) - if len(containers) != count: - return False - healthy_count = 0 - for container in containers: - # The healthcheck on our Splunk image is not reliable - resorting to checking logs - if container.get("Labels", {}).get("maintainer") == "support@splunk.com": - output = self.client.logs(container["Id"], tail=10) - if "unable to" in output or "denied" in output or "splunkd.pid file is unreadable" in output: - self.logger.error("Container {} did not start properly, last log line: {}".format(container["Names"][0], output)) - elif "Ansible playbook complete" in output: - self.logger.info("Container {} is ready".format(container["Names"][0])) - healthy_count += 1 - else: - self.logger.info("Container {} is ready".format(container["Names"][0])) - healthy_count += 1 - if healthy_count == count: - self.logger.info("All containers ready to proceed") - break - time.sleep(5) - end = time.time() - return True - - def handle_request_retry(self, method, url, kwargs): - RETRIES = 10 - IMPLICIT_WAIT = 6 - for n in range(RETRIES): + self._clean_docker_env() + if self.DIR: try: - self.logger.info("Attempt #{}: running {} against {} with kwargs {}".format(n+1, method, url, kwargs)) - resp = requests.request(method, url, **kwargs) - resp.raise_for_status() - return (resp.status_code, resp.content) - except Exception as e: - self.logger.error("Attempt #{} error: {}".format(n+1, str(e))) - if n < RETRIES-1: - time.sleep(IMPLICIT_WAIT) - continue - raise e - - def check_splunkd(self, username, password, name=None, scheme="https"): - ''' - NOTE: This helper method can only be used for `compose up` scenarios where self.project_name is defined - ''' - filters = {} - if name: - filters["name"] = name - if self.project_name: - filters["label"] = "com.docker.compose.project={}".format(self.project_name) - containers = self.client.containers(filters=filters) - for container in containers: - # We can't check splunkd on non-Splunk containers - if "maintainer" not in container["Labels"] or container["Labels"]["maintainer"] != "support@splunk.com": - continue - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - url = "{}://localhost:{}/services/server/info".format(scheme, splunkd_port) - kwargs = {"auth": (username, password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - return True - - def check_dmc(self, containers, num_peers, num_idx, num_sh, num_cm, num_lm): - for container in containers: - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name == "dmc": - # check 1: curl -k https://localhost:8089/servicesNS/nobody/splunk_monitoring_console/configs/conf-splunk_monitoring_console_assets/settings?output_mode=json -u admin:helloworld - status, content = self.handle_request_retry("GET", "https://localhost:{}/servicesNS/nobody/splunk_monitoring_console/configs/conf-splunk_monitoring_console_assets/settings?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert output["entry"][0]["content"]["disabled"] == False - # check 2: curl -k https://localhost:8089/servicesNS/nobody/system/apps/local/splunk_monitoring_console?output_mode=json -u admin:helloworld - status, content = self.handle_request_retry("GET", "https://localhost:{}/servicesNS/nobody/system/apps/local/splunk_monitoring_console?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert output["entry"][0]["content"]["disabled"] == False - # check 3: curl -k https://localhost:8089/services/search/distributed/peers?output_mode=json -u admin:helloworld - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/peers?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert num_peers == len(output["entry"]) - for peer in output["entry"]: - assert peer["content"]["status"] == "Up" - self.check_dmc_groups(splunkd_port, num_idx, num_sh, num_cm, num_lm) - - def check_dmc_groups(self, splunkd_port, num_idx, num_sh, num_cm, num_lm): - # check dmc_group_indexer - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_indexer?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert len(output["entry"][0]["content"]["member"]) == num_idx - # check dmc_group_cluster_master - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_cluster_master?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert len(output["entry"][0]["content"]["member"]) == num_cm - # check dmc_group_license_master - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_license_master?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert len(output["entry"][0]["content"]["member"]) == num_lm - # check dmc_group_search_head - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/search/distributed/groups/dmc_group_search_head?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert len(output["entry"][0]["content"]["member"]) == num_sh - - def get_container_logs(self, container_id): - stream = self.client.logs(container_id, stream=True) - output = "" - for char in stream: - if "Ansible playbook complete" in char: - break - output += char - return output - - def extract_json(self, container_name): - retries = 15 - for i in range(retries): - exec_command = self.client.exec_create(container_name, "cat /opt/container_artifact/ansible_inventory.json") - json_data = self.client.exec_start(exec_command) - if "No such file or directory" in json_data: - time.sleep(5) - else: - break - try: - data = json.loads(json_data) - return data - except Exception as e: - self.logger.error(e) - return None - - def _run_splunk_query(self, container_id, query, username="admin", password="password"): - splunkd_port = self.client.port(container_id, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/search/jobs?output_mode=json".format(splunkd_port) - kwargs = { - "auth": (username, password), - "data": "search={}".format(urllib.quote_plus(query)), - "verify": False - } - resp = requests.post(url, **kwargs) - assert resp.status_code == 201 - sid = json.loads(resp.content)["sid"] - assert sid - self.logger.info("Search job {} created against on {}".format(sid, container_id)) - # Wait for search to finish - job_status = None - url = "https://localhost:{}/services/search/jobs/{}?output_mode=json".format(splunkd_port, sid) - kwargs = { - "auth": (username, password), - "verify": False - } - for _ in range(10): - job_status = requests.get(url, **kwargs) - done = json.loads(job_status.content)["entry"][0]["content"]["isDone"] - self.logger.info("Search job {} done status is {}".format(sid, done)) - if done: - break - time.sleep(3) - assert job_status and job_status.status_code == 200 - # Get job metadata - job_metadata = json.loads(job_status.content) - # Check search results - url = "https://localhost:{}/services/search/jobs/{}/results?output_mode=json".format(splunkd_port, sid) - job_results = requests.get(url, **kwargs) - assert job_results.status_code == 200 - job_results = json.loads(job_results.content) - return job_metadata, job_results - - def search_internal_distinct_hosts(self, container_id, username="admin", password="password"): - query = "search index=_internal earliest=-1m | stats dc(host) as distinct_hosts" - meta, results = self._run_splunk_query(container_id, query, username, password) - search_providers = meta["entry"][0]["content"]["searchProviders"] - distinct_hosts = int(results["results"][0]["distinct_hosts"]) - return search_providers, distinct_hosts - - def check_common_keys(self, log_output, role): - try: - assert log_output["all"]["vars"]["ansible_ssh_user"] == "splunk" - assert log_output["all"]["vars"]["ansible_pre_tasks"] == None - assert log_output["all"]["vars"]["ansible_post_tasks"] == None - assert log_output["all"]["vars"]["retry_num"] == 60 - assert log_output["all"]["vars"]["retry_delay"] == 6 - assert log_output["all"]["vars"]["wait_for_splunk_retry_num"] == 60 - assert log_output["all"]["vars"]["shc_sync_retry_num"] == 60 - assert log_output["all"]["vars"]["splunk"]["group"] == "splunk" - assert log_output["all"]["vars"]["splunk"]["license_download_dest"] == "/tmp/splunk.lic" - assert log_output["all"]["vars"]["splunk"]["opt"] == "/opt" - assert log_output["all"]["vars"]["splunk"]["user"] == "splunk" - - if role == "uf": - assert log_output["all"]["vars"]["splunk"]["exec"] == "/opt/splunkforwarder/bin/splunk" - assert log_output["all"]["vars"]["splunk"]["home"] == "/opt/splunkforwarder" - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_universal_forwarder" - else: - assert log_output["all"]["vars"]["splunk"]["exec"] == "/opt/splunk/bin/splunk" - assert log_output["all"]["vars"]["splunk"]["home"] == "/opt/splunk" - if role == "so": - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_standalone" - elif role == "deployment_server": - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_deployment_server" - elif role == "idx": - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_indexer" - elif role == "sh": - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_search_head" - elif role == "hf": - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_heavy_forwarder" - elif role == "cm": - assert log_output["all"]["vars"]["splunk"]["role"] == "splunk_cluster_master" - except KeyError as e: - self.logger.error("{} key not found".format(e)) - assert False + rmtree(self.DIR) + except OSError: + pass + self.compose_file_name, self.project_name, self.DIR = None, None, None - def check_ansible(self, output): - assert "ansible-playbook" in output - assert "config file = /opt/ansible/ansible.cfg" in output - def test_splunk_entrypoint_help(self): # Run container cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="help") @@ -401,60 +70,6 @@ def test_splunk_entrypoint_help(self): assert "SPLUNK_HOME - home directory where Splunk gets installed (default: /opt/splunk)" in output assert "Examples:" in output - def test_splunk_entrypoint_create_defaults(self): - # Run container - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - assert "home: /opt/splunk" in output - assert "password: " in output - assert "secret: " in output - - def test_splunk_entrypoint_start_no_password(self): - # Run container - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", - environment={"SPLUNK_START_ARGS": "nothing"}) - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - assert "WARNING: No password ENV var." in output - - def test_splunk_entrypoint_start_no_accept_license(self): - # Run container - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", - environment={"SPLUNK_PASSWORD": "something", "SPLUNK_START_ARGS": "nothing"}) - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - assert "License not accepted, please ensure the environment variable SPLUNK_START_ARGS contains the '--accept-license' flag" in output - - def test_splunk_entrypoint_no_provision(self): - cid = None - try: - # Run container - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="no-provision") - cid = cid.get("Id") - self.client.start(cid) - # Wait a bit - time.sleep(5) - # If the container is still running, we should be able to exec inside - # Check that the git SHA exists in /opt/ansible - exec_command = self.client.exec_create(cid, "cat /opt/ansible/version.txt") - std_out = self.client.exec_start(exec_command) - assert len(std_out.strip()) == 40 - # Check that the wrapper-example directory does not exist - exec_command = self.client.exec_create(cid, "ls /opt/ansible/") - std_out = self.client.exec_start(exec_command) - assert "wrapper-example" not in std_out - assert "docs" not in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - def test_splunk_scloud(self): cid = None try: @@ -478,69 +93,40 @@ def test_splunk_scloud(self): finally: if cid: self.client.remove_container(cid, v=True, force=True) - - def test_splunk_uid_gid(self): - cid = None - try: - # Run container - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="no-provision") - cid = cid.get("Id") - self.client.start(cid) - # Wait a bit - time.sleep(5) - # If the container is still running, we should be able to exec inside - # Check that the uid/gid is correct - exec_command = self.client.exec_create(cid, "id", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "uid=41812" in std_out - assert "gid=41812" in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_uf_entrypoint_help(self): - # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="help") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - assert "SPLUNK_CMD - 'any splunk command' - execute any splunk commands separated by commas" in output - def test_uf_entrypoint_create_defaults(self): + def test_splunk_entrypoint_create_defaults(self): # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) assert "home: /opt/splunk" in output assert "password: " in output + assert "secret: " in output - def test_uf_entrypoint_start_no_password(self): + def test_splunk_entrypoint_start_no_password(self): # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", environment={"SPLUNK_START_ARGS": "nothing"}) self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) assert "WARNING: No password ENV var." in output - - def test_uf_entrypoint_start_no_accept_license(self): + + def test_splunk_entrypoint_start_no_accept_license(self): # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", environment={"SPLUNK_PASSWORD": "something", "SPLUNK_START_ARGS": "nothing"}) self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) assert "License not accepted, please ensure the environment variable SPLUNK_START_ARGS contains the '--accept-license' flag" in output - def test_uf_entrypoint_no_provision(self): + def test_splunk_entrypoint_no_provision(self): cid = None try: # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="no-provision") + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="no-provision") cid = cid.get("Id") self.client.start(cid) # Wait a bit @@ -558,45 +144,20 @@ def test_uf_entrypoint_no_provision(self): except Exception as e: self.logger.error(e) raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) + if cid: + self.client.remove_container(cid, v=True, force=True) - def test_uf_scloud(self): - cid = None - try: - # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="no-provision") - cid = cid.get("Id") - self.client.start(cid) - # Wait a bit - time.sleep(5) - # If the container is still running, we should be able to exec inside - # Check that the version returns successfully for multiple users - exec_command = self.client.exec_create(cid, "scloud version", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "scloud version " in std_out - exec_command = self.client.exec_create(cid, "scloud version", user="ansible") - std_out = self.client.exec_start(exec_command) - assert "scloud version " in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_uf_uid_gid(self): + def test_splunk_uid_gid(self): cid = None try: # Run container - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="no-provision") + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="no-provision") cid = cid.get("Id") self.client.start(cid) # Wait a bit time.sleep(5) # If the container is still running, we should be able to exec inside - # Check that the uid/gid is correct + # Check that the git SHA exists in /opt/ansible exec_command = self.client.exec_create(cid, "id", user="splunk") std_out = self.client.exec_start(exec_command) assert "uid=41812" in std_out @@ -604,77 +165,124 @@ def test_uf_uid_gid(self): except Exception as e: self.logger.error(e) raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_compose_1so_trial(self): + # Standup deployment + self.compose_file_name = "1so_trial.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + + def test_compose_1so_custombuild(self): + # Standup deployment + self.compose_file_name = "1so_custombuild.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + + def test_compose_1so_namedvolumes(self): + # TODO: We can do a lot better in this test - ex. check that data is persisted after restarts + # Standup deployment + self.compose_file_name = "1so_namedvolumes.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + + def test_compose_1so_before_start_cmd(self): + # Check that SPLUNK_BEFORE_START_CMD works for splunk image + # Standup deployment + self.compose_file_name = "1so_before_start_cmd.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check Splunkd using the new users + assert self.check_splunkd("admin2", "changemepls") + assert self.check_splunkd("admin3", "changemepls") + def test_compose_1so_splunk_add(self): + # Check that SPLUNK_ADD works for splunk image (role=standalone) + # Standup deployment + self.compose_file_name = "1so_splunk_add_user.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check Splunkd using the new users + assert self.check_splunkd("newman", "changemepls") + def test_adhoc_1so_using_default_yml(self): + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) # Generate default.yml cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" # Change the admin user output = re.sub(r' admin_user: admin', r' admin_user: chewbacca', output) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + os.mkdir(self.DIR) + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", ports=[8089], volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("chewbacca", password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) - except OSError: - pass - - def test_adhoc_1uf_using_default_yml(self): - # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Change the admin user - output = re.sub(r' admin_user: admin', r' admin_user: hansolo', output) - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", ports=[8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], + host_config=self.client.create_host_config(binds=[os.path.join(self.FIXTURES_DIR, splunk_container_name) + ":/tmp/defaults/"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -684,7 +292,7 @@ def test_adhoc_1uf_using_default_yml(self): # Check splunkd splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("hansolo", password), "verify": False} + kwargs = {"auth": ("chewbacca", p), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 except Exception as e: @@ -694,40 +302,24 @@ def test_adhoc_1uf_using_default_yml(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(os.path.join(self.DIR, "default.yml")) + os.rmdir(self.DIR) except OSError: pass - def test_adhoc_1so_custom_conf(self): - # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Add a custom conf file - output = re.sub(r' group: splunk', r''' group: splunk - conf: - user-prefs: - directory: /opt/splunk/etc/users/admin/user-prefs/local - content: - general: - default_namespace: appboilerplate - search_syntax_highlighting: dark''', output) - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml + def test_adhoc_1so_splunk_launch_conf(self): + # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", ports=[8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",)}) + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_LAUNCH_CONF": "OPTIMISTIC_ABOUT_FILE_LOCKING=1,HELLO=WORLD" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -736,56 +328,35 @@ def test_adhoc_1so_custom_conf(self): # Check splunkd splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} + kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/users/admin/user-prefs/local/user-prefs.conf", user="splunk") + # Check splunk-launch.conf + exec_command = self.client.exec_create(cid, r'cat /opt/splunk/etc/splunk-launch.conf', user="splunk") std_out = self.client.exec_start(exec_command) - assert "[general]" in std_out - assert "default_namespace = appboilerplate" in std_out - assert "search_syntax_highlighting = dark" in std_out + assert "OPTIMISTIC_ABOUT_FILE_LOCKING=1" in std_out + assert "HELLO=WORLD" in std_out except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) - except OSError: - pass - - def test_adhoc_1uf_custom_conf(self): - # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Add a custom conf file - output = re.sub(r' group: splunk', r''' group: splunk - conf: - user-prefs: - directory: /opt/splunkforwarder/etc/users/admin/user-prefs/local - content: - general: - default_namespace: appboilerplate - search_syntax_highlighting: dark''', output) - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml + + def test_adhoc_1so_change_tailed_files(self): + # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", ports=[8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",)}) + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], + name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_TAIL_FILE": "/opt/splunk/var/log/splunk/web_access.log /opt/splunk/var/log/splunk/first_install.log" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -794,40 +365,35 @@ def test_adhoc_1uf_custom_conf(self): # Check splunkd splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} + kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/users/admin/user-prefs/local/user-prefs.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "[general]" in std_out - assert "default_namespace = appboilerplate" in std_out - assert "search_syntax_highlighting = dark" in std_out + # Check the tailed logs + logs = self.client.logs(cid, tail=20) + assert "==> /opt/splunk/var/log/splunk/first_install.log <==" in logs + assert "==> /opt/splunk/var/log/splunk/web_access.log <==" in logs except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) - except OSError: - pass - def test_adhoc_1so_preplaybook(self): + def test_adhoc_1so_password_from_file(self): # Create a splunk container cid = None + # From fixtures/pwfile + filePW = "changeme123" try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], - volumes=["/playbooks/play.yml"], name=splunk_container_name, + volumes=["/var/secrets/pwfile"], name=splunk_container_name, environment={ "DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_ANSIBLE_PRE_TASKS": "file:///playbooks/play.yml" + "SPLUNK_PASSWORD": "/var/secrets/pwfile" }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/touch_dummy_file.yml:/playbooks/play.yml"], + host_config=self.client.create_host_config(binds=[self.FIXTURES_DIR + "/pwfile:/var/secrets/pwfile"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -837,41 +403,30 @@ def test_adhoc_1so_preplaybook(self): # Check splunkd splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} + kwargs = {"auth": ("admin", filePW), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /tmp/i-am", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "batman" in std_out - # Check file owner - exec_command = self.client.exec_create(cid, r'stat -c \'%U\' /tmp/i-am') - std_out = self.client.exec_start(exec_command) - assert "splunk" in std_out except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) - except OSError: - pass - def test_adhoc_1so_splunk_launch_conf(self): + def test_adhoc_1so_reflexive_forwarding(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() + # When adding SPLUNK_STANDALONE_URL to the standalone, we shouldn't have any situation where it starts forwarding/disables indexing cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ + environment={ "DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": self.password, - "SPLUNK_LAUNCH_CONF": "OPTIMISTIC_ABOUT_FILE_LOCKING=1,HELLO=WORLD" + "SPLUNK_STANDALONE_URL": splunk_container_name }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -883,11 +438,10 @@ def test_adhoc_1so_splunk_launch_conf(self): kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check splunk-launch.conf - exec_command = self.client.exec_create(cid, r'cat /opt/splunk/etc/splunk-launch.conf', user="splunk") + # Check the decrypted pass4SymmKey + exec_command = self.client.exec_create(cid, "ls /opt/splunk/etc/system/local/", user="splunk") std_out = self.client.exec_start(exec_command) - assert "OPTIMISTIC_ABOUT_FILE_LOCKING=1" in std_out - assert "HELLO=WORLD" in std_out + assert "outputs.conf" not in std_out except Exception as e: self.logger.error(e) raise e @@ -895,20 +449,19 @@ def test_adhoc_1so_splunk_launch_conf(self): if cid: self.client.remove_container(cid, v=True, force=True) - def test_adhoc_1so_change_tailed_files(self): + def test_adhoc_1so_splunk_pass4symmkey(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], - name=splunk_container_name, - environment={ + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, + environment={ "DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": self.password, - "SPLUNK_TAIL_FILE": "/opt/splunk/var/log/splunk/web_access.log /opt/splunk/var/log/splunk/first_install.log" + "SPLUNK_PASS4SYMMKEY": "wubbalubbadubdub" }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -920,10 +473,13 @@ def test_adhoc_1so_change_tailed_files(self): kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check the tailed logs - logs = self.client.logs(cid, tail=20) - assert "==> /opt/splunk/var/log/splunk/first_install.log <==" in logs - assert "==> /opt/splunk/var/log/splunk/web_access.log <==" in logs + # Check the decrypted pass4SymmKey + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + pass4SymmKey = re.search(r'\[general\].*?pass4SymmKey = (.*?)\n', std_out, flags=re.MULTILINE|re.DOTALL).group(1).strip() + exec_command = self.client.exec_create(cid, "/opt/splunk/bin/splunk show-decrypted --value '{}'".format(pass4SymmKey), user="splunk") + std_out = self.client.exec_start(exec_command) + assert "wubbalubbadubdub" in std_out except Exception as e: self.logger.error(e) raise e @@ -931,20 +487,19 @@ def test_adhoc_1so_change_tailed_files(self): if cid: self.client.remove_container(cid, v=True, force=True) - def test_adhoc_1uf_change_tailed_files(self): + def test_adhoc_1so_splunk_secret_env(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], - name=splunk_container_name, - environment={ + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, + environment={ "DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": self.password, - "SPLUNK_TAIL_FILE": "/opt/splunkforwarder/var/log/splunk/splunkd_stderr.log /opt/splunkforwarder/var/log/splunk/first_install.log" + "SPLUNK_SECRET": "wubbalubbadubdub" }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -956,10 +511,10 @@ def test_adhoc_1uf_change_tailed_files(self): kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check the tailed logs - logs = self.client.logs(cid, tail=20) - assert "==> /opt/splunkforwarder/var/log/splunk/first_install.log <==" in logs - assert "==> /opt/splunkforwarder/var/log/splunk/splunkd_stderr.log <==" in logs + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/auth/splunk.secret", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "wubbalubbadubdub" in std_out except Exception as e: self.logger.error(e) raise e @@ -967,261 +522,43 @@ def test_adhoc_1uf_change_tailed_files(self): if cid: self.client.remove_container(cid, v=True, force=True) - def test_adhoc_1so_password_from_file(self): - # Create a splunk container - cid = None - # From fixtures/pwfile - filePW = "changeme123" + def test_compose_1so_hec(self): + # Standup deployment + self.compose_file_name = "1so_hec.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], - volumes=["/var/secrets/pwfile"], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": "/var/secrets/pwfile" - }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/pwfile:/var/secrets/pwfile"], - port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", filePW), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1uf_password_from_file(self): - # Create a splunk container - cid = None - # From fixtures/pwfile - filePW = "changeme123" - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], - volumes=["/var/secrets/pwfile"], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": "/var/secrets/pwfile" - }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/pwfile:/var/secrets/pwfile"], - port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", filePW), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1so_reflexive_forwarding(self): - # Create a splunk container - cid = None - try: - splunk_container_name = generate_random_string() - # When adding SPLUNK_STANDALONE_URL to the standalone, we shouldn't have any situation where it starts forwarding/disables indexing - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_STANDALONE_URL": splunk_container_name - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Check the decrypted pass4SymmKey - exec_command = self.client.exec_create(cid, "ls /opt/splunk/etc/system/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "outputs.conf" not in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1so_splunk_pass4symmkey(self): - # Create a splunk container - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_PASS4SYMMKEY": "wubbalubbadubdub" - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Check the decrypted pass4SymmKey - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - pass4SymmKey = re.search(r'\[general\].*?pass4SymmKey = (.*?)\n', std_out, flags=re.MULTILINE|re.DOTALL).group(1).strip() - exec_command = self.client.exec_create(cid, "/opt/splunk/bin/splunk show-decrypted --value '{}'".format(pass4SymmKey), user="splunk") - std_out = self.client.exec_start(exec_command) - assert "wubbalubbadubdub" in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1so_splunk_secret_env(self): - # Create a splunk container - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_SECRET": "wubbalubbadubdub" - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/auth/splunk.secret", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "wubbalubbadubdub" in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1uf_splunk_pass4symmkey(self): - # Create a splunk container - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_PASS4SYMMKEY": "wubbalubbadubdub" - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Check the decrypted pass4SymmKey - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - pass4SymmKey = re.search(r'\[general\].*?pass4SymmKey = (.*?)\n', std_out, flags=re.MULTILINE|re.DOTALL).group(1).strip() - exec_command = self.client.exec_create(cid, "/opt/splunkforwarder/bin/splunk show-decrypted --value '{}'".format(pass4SymmKey), user="splunk") - std_out = self.client.exec_start(exec_command) - assert "wubbalubbadubdub" in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1uf_splunk_secret_env(self): - # Create a uf container - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_SECRET": "wubbalubbadubdub" - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/auth/splunk.secret", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "wubbalubbadubdub" in std_out - except Exception as e: + # token "abcd1234" is hard-coded within the 1so_hec.yaml compose + assert log_json["all"]["vars"]["splunk"]["hec"]["token"] == "abcd1234" + except KeyError as e: self.logger.error(e) raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check HEC works - note the token "abcd1234" is hard-coded within the 1so_hec.yaml compose + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 1 + so1 = containers[0] + splunk_hec_port = self.client.port(so1["Id"], 8088)[0]["HostPort"] + url = "https://localhost:{}/services/collector/event".format(splunk_hec_port) + kwargs = {"json": {"event": "hello world"}, "verify": False, "headers": {"Authorization": "Splunk abcd1234"}} + status, content = self.handle_request_retry("POST", url, kwargs) + assert status == 200 def test_adhoc_1so_preplaybook_with_sudo(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], volumes=["/playbooks/play.yml"], name=splunk_container_name, environment={ @@ -1230,7 +567,7 @@ def test_adhoc_1so_preplaybook_with_sudo(self): "SPLUNK_PASSWORD": self.password, "SPLUNK_ANSIBLE_PRE_TASKS": "file:///playbooks/play.yml" }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/sudo_touch_dummy_file.yml:/playbooks/play.yml"], + host_config=self.client.create_host_config(binds=[self.FIXTURES_DIR + "/sudo_touch_dummy_file.yml:/playbooks/play.yml"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -1262,7 +599,7 @@ def test_adhoc_1so_postplaybook(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], volumes=["/playbooks/play.yml"], name=splunk_container_name, environment={ @@ -1271,7 +608,7 @@ def test_adhoc_1so_postplaybook(self): "SPLUNK_PASSWORD": self.password, "SPLUNK_ANSIBLE_POST_TASKS": "file:///playbooks/play.yml" }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/touch_dummy_file.yml:/playbooks/play.yml"], + host_config=self.client.create_host_config(binds=[self.FIXTURES_DIR + "/touch_dummy_file.yml:/playbooks/play.yml"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -1303,7 +640,7 @@ def test_adhoc_1so_postplaybook_with_sudo(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], volumes=["/playbooks/play.yml"], name=splunk_container_name, environment={ @@ -1312,7 +649,7 @@ def test_adhoc_1so_postplaybook_with_sudo(self): "SPLUNK_PASSWORD": self.password, "SPLUNK_ANSIBLE_POST_TASKS": "file:///playbooks/play.yml" }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/sudo_touch_dummy_file.yml:/playbooks/play.yml"], + host_config=self.client.create_host_config(binds=[self.FIXTURES_DIR + "/sudo_touch_dummy_file.yml:/playbooks/play.yml"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -1339,32 +676,37 @@ def test_adhoc_1so_postplaybook_with_sudo(self): finally: if cid: self.client.remove_container(cid, v=True, force=True) - + def test_adhoc_1so_apps_location_in_default_yml(self): - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + DIR_EXAMPLE_APP = os.path.join(self.DIR, "splunk_app_example") + copytree(self.EXAMPLE_APP, DIR_EXAMPLE_APP) + self.EXAMPLE_APP_TGZ = os.path.join(self.DIR, "splunk_app_example.tgz") + with tarfile.open(self.EXAMPLE_APP_TGZ, "w:gz") as tar: + tar.add(DIR_EXAMPLE_APP, arcname=os.path.basename(DIR_EXAMPLE_APP)) # Generate default.yml cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" # Change repl factor & search factor output = re.sub(r' user: splunk', r' user: splunk\n apps_location: /tmp/defaults/splunk_app_example.tgz', output) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + # os.mkdir(self.DIR) + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: # Spin up this container, but also bind-mount the app in the fixtures directory - splunk_container_name = generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start-service", ports=[8089], volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -1374,13 +716,13 @@ def test_adhoc_1so_apps_location_in_default_yml(self): # Check splunkd splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} + kwargs = {"auth": ("admin", p), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 # Check the app endpoint splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} + kwargs = {"auth": ("admin", p), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 # Let's go further and check app version @@ -1393,33 +735,36 @@ def test_adhoc_1so_apps_location_in_default_yml(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(EXAMPLE_APP_TGZ) - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(self.EXAMPLE_APP_TGZ) + os.remove(os.path.join(self.DIR, "default.yml")) except OSError: pass def test_adhoc_1so_bind_mount_apps(self): # Generate default.yml + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + DIR_EXAMPLE_APP = os.path.join(self.DIR, "splunk_app_example") + copytree(self.EXAMPLE_APP, DIR_EXAMPLE_APP) cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: # Spin up this container, but also bind-mount the app in the fixtures directory - splunk_container_name = generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start-service", ports=[8089], volumes=["/tmp/defaults/", "/opt/splunk/etc/apps/splunk_app_example/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/", - EXAMPLE_APP + ":/opt/splunk/etc/apps/splunk_app_example/"], + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/", + DIR_EXAMPLE_APP + ":/opt/splunk/etc/apps/splunk_app_example/"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -1429,13 +774,13 @@ def test_adhoc_1so_bind_mount_apps(self): # Check splunkd splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} + kwargs = {"auth": ("admin", p), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 # Check the app endpoint splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} + kwargs = {"auth": ("admin", p), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 # Let's go further and check app version @@ -1448,57 +793,7 @@ def test_adhoc_1so_bind_mount_apps(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) - except OSError: - pass - - def test_adhoc_1uf_bind_mount_apps(self): - # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml - cid = None - try: - # Spin up this container, but also bind-mount the app in the fixtures directory - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start-service", ports=[8089], - volumes=["/tmp/defaults/", "/opt/splunkforwarder/etc/apps/splunk_app_example/"], name=splunk_container_name, - environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/", - EXAMPLE_APP + ":/opt/splunkforwarder/etc/apps/splunk_app_example/"], - port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - assert self.check_splunkd("admin", password) - # Check the app endpoint - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Let's go further and check app version - output = json.loads(content) - assert output["entry"][0]["content"]["version"] == "0.0.1" - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(os.path.join(self.DIR, "default.yml")) except OSError: pass @@ -1506,7 +801,7 @@ def test_adhoc_1so_run_as_root(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, user="root", environment={ "DEBUG": "true", @@ -1538,43 +833,7 @@ def test_adhoc_1so_run_as_root(self): finally: if cid: self.client.remove_container(cid, v=True, force=True) - - def test_adhoc_1uf_run_as_root(self): - # Create a uf container - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, user="root", - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_USER": "root", - "SPLUNK_GROUP": "root" - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Check that root owns the splunkd process - exec_command = self.client.exec_create(cid, "ps -u root", user="root") - std_out = self.client.exec_start(exec_command) - assert "entrypoint.sh" in std_out - assert "splunkd" in std_out - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) + def test_adhoc_1so_hec_idempotence(self): """ @@ -1583,7 +842,8 @@ def test_adhoc_1so_hec_idempotence(self): # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() + splunk_container_name = self.generate_random_string() + self.project_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8088, 9999], name=splunk_container_name, environment={ @@ -1727,66 +987,33 @@ def test_adhoc_1so_hec_idempotence(self): if cid: self.client.remove_container(cid, v=True, force=True) - def test_adhoc_1so_hec_custom_cert(self): - # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates - passphrase = "glootie" - cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=FIXTURES_DIR), - "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=FIXTURES_DIR) - ] - for cmd in cmds: - execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) - # Update s2s ssl settings - output = re.sub(r''' hec:.*? token: .*?\n''', r''' hec: - enable: True - port: 8088 - ssl: True - token: doyouwannadevelopanapp - cert: /tmp/defaults/cert.pem - password: {}\n'''.format(passphrase), output, flags=re.DOTALL) - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml + def test_adhoc_1so_hec_ssl_disabled(self): + # Create the container cid = None try: - splunk_container_name = generate_random_string() - password = "helloworld" - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8088, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) + splunk_container_name = self.generate_random_string() + self.project_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8088], + name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_HEC_TOKEN": "get-schwifty", + "SPLUNK_HEC_SSL": "False", + "SPLUNK_PASSWORD": self.password + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "[http://splunk_hec_token]" in std_out - assert "serverCert = /tmp/defaults/cert.pem" in std_out - assert "sslPassword = " in std_out - # Check HEC using the custom certs + assert self.check_splunkd("admin", self.password) + # Check HEC hec_port = self.client.port(cid, 8088)[0]["HostPort"] - url = "https://localhost:{}/services/collector/event".format(hec_port) - kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk doyouwannadevelopanapp"}, "verify": "{}/cacert.pem".format(FIXTURES_DIR)} + url = "http://localhost:{}/services/collector/event".format(hec_port) + kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk get-schwifty"}} status, content = self.handle_request_retry("POST", url, kwargs) assert status == 200 except Exception as e: @@ -1795,127 +1022,56 @@ def test_adhoc_1so_hec_custom_cert(self): finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [ - os.path.join(FIXTURES_DIR, "ca.key"), - os.path.join(FIXTURES_DIR, "ca.csr"), - os.path.join(FIXTURES_DIR, "ca.pem"), - os.path.join(FIXTURES_DIR, "cacert.pem"), - os.path.join(FIXTURES_DIR, "server.key"), - os.path.join(FIXTURES_DIR, "server.csr"), - os.path.join(FIXTURES_DIR, "server.pem"), - os.path.join(FIXTURES_DIR, "cert.pem"), - os.path.join(FIXTURES_DIR, "default.yml") - ] - self.cleanup_files(files) - def test_adhoc_1uf_hec_custom_cert(self): + def test_adhoc_1so_splunkd_no_ssl(self): # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.project_name = self.generate_random_string() + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) - # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates - passphrase = "glootie" - cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=FIXTURES_DIR), - "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=FIXTURES_DIR) - ] - for cmd in cmds: - execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) - # Update s2s ssl settings - output = re.sub(r''' hec:.*? token: .*?\n''', r''' hec: - enable: True - port: 8088 - ssl: True - token: doyouwannadevelopanapp - cert: /tmp/defaults/cert.pem - password: {}\n'''.format(passphrase), output, flags=re.DOTALL) + # Get the password + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" + # Update server ssl settings + output = re.sub(r'''^ ssl:.*?password: null''', r''' ssl: + ca: null + cert: null + enable: false + password: null''', output, flags=re.MULTILINE|re.DOTALL) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() - password = "helloworld" - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8088, 8089], + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) + "SPLUNK_CERT_PREFIX": "http", + "SPLUNK_PASSWORD": p}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) + assert self.check_splunkd("admin", p, scheme="http") # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") std_out = self.client.exec_start(exec_command) - assert "[http://splunk_hec_token]" in std_out - assert "serverCert = /tmp/defaults/cert.pem" in std_out - assert "sslPassword = " in std_out - # Check HEC using the custom certs - hec_port = self.client.port(cid, 8088)[0]["HostPort"] - url = "https://localhost:{}/services/collector/event".format(hec_port) - kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk doyouwannadevelopanapp"}, "verify": "{}/cacert.pem".format(FIXTURES_DIR)} - status, content = self.handle_request_retry("POST", url, kwargs) - assert status == 200 - except Exception as e: - self.logger.error(e) - raise e - finally: - if cid: - self.client.remove_container(cid, v=True, force=True) - files = [ - os.path.join(FIXTURES_DIR, "ca.key"), - os.path.join(FIXTURES_DIR, "ca.csr"), - os.path.join(FIXTURES_DIR, "ca.pem"), - os.path.join(FIXTURES_DIR, "cacert.pem"), - os.path.join(FIXTURES_DIR, "server.key"), - os.path.join(FIXTURES_DIR, "server.csr"), - os.path.join(FIXTURES_DIR, "server.pem"), - os.path.join(FIXTURES_DIR, "cert.pem"), - os.path.join(FIXTURES_DIR, "default.yml") - ] - self.cleanup_files(files) - - def test_adhoc_1so_hec_ssl_disabled(self): - # Create the container - cid = None - try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8088], - name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_HEC_TOKEN": "get-schwifty", - "SPLUNK_HEC_SSL": "False", - "SPLUNK_PASSWORD": self.password - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) - ) - cid = cid.get("Id") - self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - assert self.check_splunkd("admin", self.password) - # Check HEC - hec_port = self.client.port(cid, 8088)[0]["HostPort"] - url = "http://localhost:{}/services/collector/event".format(hec_port) - kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk get-schwifty"}} - status, content = self.handle_request_retry("POST", url, kwargs) + assert "enableSplunkdSSL = false" in std_out + # Check splunkd using the custom certs + mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "http://localhost:{}/services/server/info".format(mgmt_port) + kwargs = {"auth": ("admin", p)} + status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 except Exception as e: self.logger.error(e) @@ -1924,25 +1080,33 @@ def test_adhoc_1so_hec_ssl_disabled(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(os.path.join(self.DIR, "default.yml")) except OSError: pass - - def test_adhoc_1uf_hec_ssl_disabled(self): + + def test_adhoc_1so_web_ssl(self): # Create the container + splunk_container_name = self.generate_random_string() + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + os.mkdir(self.DIR) cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089, 8088], - name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_HEC_TOKEN": "get-schwifty", - "SPLUNK_HEC_SSL": "false", - "SPLUNK_PASSWORD": self.password - }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) + # Commands to generate self-signed certificates for SplunkWeb here: https://docs.splunk.com/Documentation/Splunk/latest/Security/Self-signcertificatesforSplunkWeb + cmd = "openssl req -x509 -newkey rsa:4096 -passout pass:abcd1234 -keyout {path}/key.pem -out {path}/cert.pem -days 365 -subj /CN=localhost".format(path=self.DIR) + generate_certs = subprocess.check_output(cmd.split()) + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], + volumes=["/tmp/defaults/"], name=splunk_container_name, + environment={"DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_HTTP_ENABLESSL": "true", + "SPLUNK_HTTP_ENABLESSL_CERT": "/tmp/defaults/cert.pem", + "SPLUNK_HTTP_ENABLESSL_PRIVKEY": "/tmp/defaults/key.pem", + "SPLUNK_HTTP_ENABLESSL_PRIVKEY_PASSWORD": "abcd1234" + }, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -1950,11 +1114,11 @@ def test_adhoc_1uf_hec_ssl_disabled(self): assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd assert self.check_splunkd("admin", self.password) - # Check HEC - hec_port = self.client.port(cid, 8088)[0]["HostPort"] - url = "http://localhost:{}/services/collector/event".format(hec_port) - kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk get-schwifty"}} - status, content = self.handle_request_retry("POST", url, kwargs) + # Check splunkweb + web_port = self.client.port(cid, 8000)[0]["HostPort"] + url = "https://localhost:{}/".format(web_port) + kwargs = {"verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 except Exception as e: self.logger.error(e) @@ -1963,87 +1127,225 @@ def test_adhoc_1uf_hec_ssl_disabled(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(os.path.join(self.DIR, "key.pem")) + os.remove(os.path.join(self.DIR, "cert.pem")) except OSError: pass - - def test_adhoc_1so_splunktcp_ssl(self): + + def test_compose_1so_java_oracle(self): + # Standup deployment + self.compose_file_name = "1so_java_oracle.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + try: + assert log_json["all"]["vars"]["java_version"] == "oracle:8" + except KeyError as e: + self.logger.error(e) + raise e + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check if java is installed + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "java -version") + std_out = self.client.exec_start(exec_command) + assert "java version \"1.8.0" in std_out + # Restart the container and make sure java is still installed + self.client.restart("{}_so1_1".format(self.project_name)) + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + assert self.check_splunkd("admin", self.password) + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "java -version") + std_out = self.client.exec_start(exec_command) + assert "java version \"1.8.0" in std_out + + + def test_compose_1so_java_openjdk8(self): + # Standup deployment + self.compose_file_name = "1so_java_openjdk8.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + try: + assert log_json["all"]["vars"]["java_version"] == "openjdk:8" + except KeyError as e: + self.logger.error(e) + raise e + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check if java is installed + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "java -version") + std_out = self.client.exec_start(exec_command) + assert "openjdk version \"1.8.0" in std_out + # Restart the container and make sure java is still installed + self.client.restart("{}_so1_1".format(self.project_name)) + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + assert self.check_splunkd("admin", self.password) + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "java -version") + std_out = self.client.exec_start(exec_command) + assert "openjdk version \"1.8.0" in std_out + + + def test_compose_1so_java_openjdk11(self): + # Standup deployment + self.compose_file_name = "1so_java_openjdk11.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + try: + assert log_json["all"]["vars"]["java_version"] == "openjdk:11" + except KeyError as e: + self.logger.error(e) + raise e + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check if java is installed + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "java -version") + std_out = self.client.exec_start(exec_command) + assert "openjdk version \"11.0.2" in std_out + # Restart the container and make sure java is still installed + self.client.restart("{}_so1_1".format(self.project_name)) + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + assert self.check_splunkd("admin", self.password) + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "java -version") + std_out = self.client.exec_start(exec_command) + assert "openjdk version \"11.0.2" in std_out + + def test_compose_1so_enable_service(self): + # Standup deployment + self.compose_file_name = "1so_enable_service.yaml" + self.project_name = self.generate_random_string() + container_count, rc = self.compose_up() + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + try: + # enable_service is set in the compose file + assert log_json["all"]["vars"]["splunk"]["enable_service"] == "true" + except KeyError as e: + self.logger.error(e) + raise e + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check Splunkd on all the containers + assert self.check_splunkd("admin", self.password) + # Check if service is registered + if 'debian' in PLATFORM: + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "sudo service splunk status") + std_out = self.client.exec_start(exec_command) + assert "splunkd is running" in std_out + else: + exec_command = self.client.exec_create("{}_so1_1".format(self.project_name), "stat /etc/init.d/splunk") + std_out = self.client.exec_start(exec_command) + assert "/etc/init.d/splunk" in std_out + + def test_adhoc_1so_hec_custom_cert(self): # Generate default.yml + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates - passphrase = "abcd1234" + passphrase = "glootie" cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=FIXTURES_DIR) + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DIR), + "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=self.DIR) ] for cmd in cmds: execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) # Update s2s ssl settings - output = re.sub(r''' s2s:.*?ssl: false''', r''' s2s: - ca: /tmp/defaults/ca.pem + output = re.sub(r''' hec:.*? token: .*?\n''', r''' hec: + enable: True + port: 8088 + ssl: True + token: doyouwannadevelopanapp cert: /tmp/defaults/cert.pem - enable: true - password: {} - port: 9997 - ssl: true'''.format(passphrase), output, flags=re.DOTALL) + password: {}\n'''.format(passphrase), output, flags=re.DOTALL) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, + password = "helloworld" + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8088, 8089], + volumes=["/tmp/defaults/"], name=self.project_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) + assert self.wait_for_containers(1, name=self.project_name) # Check splunkd assert self.check_splunkd("admin", password) # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/inputs.conf", user="splunk") + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) - assert "[splunktcp-ssl:9997]" in std_out + assert "[http://splunk_hec_token]" in std_out assert "serverCert = /tmp/defaults/cert.pem" in std_out + assert "sslPassword = " in std_out + # Check HEC using the custom certs + hec_port = self.client.port(cid, 8088)[0]["HostPort"] + url = "https://localhost:{}/services/collector/event".format(hec_port) + kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk doyouwannadevelopanapp"}, "verify": "{}/cacert.pem".format(self.DIR)} + status, content = self.handle_request_retry("POST", url, kwargs) + assert status == 200 except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [ - os.path.join(FIXTURES_DIR, "ca.key"), - os.path.join(FIXTURES_DIR, "ca.csr"), - os.path.join(FIXTURES_DIR, "ca.pem"), - os.path.join(FIXTURES_DIR, "server.key"), - os.path.join(FIXTURES_DIR, "server.csr"), - os.path.join(FIXTURES_DIR, "server.pem"), - os.path.join(FIXTURES_DIR, "cert.pem"), - os.path.join(FIXTURES_DIR, "default.yml") - ] - self.cleanup_files(files) + try: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: + pass - def test_adhoc_1uf_splunktcp_ssl(self): + def test_adhoc_1so_splunktcp_ssl(self): # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) @@ -2053,13 +1355,13 @@ def test_adhoc_1uf_splunktcp_ssl(self): # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates passphrase = "abcd1234" cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=FIXTURES_DIR) + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DIR) ] for cmd in cmds: execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) @@ -2072,28 +1374,27 @@ def test_adhoc_1uf_splunktcp_ssl(self): port: 9997 ssl: true'''.format(passphrase), output, flags=re.DOTALL) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], + volumes=["/tmp/defaults/"], name=self.project_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) + assert self.wait_for_containers(1, name=self.project_name) # Check splunkd assert self.check_splunkd("admin", password) # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/inputs.conf", user="splunk") + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) assert "[splunktcp-ssl:9997]" in std_out assert "serverCert = /tmp/defaults/cert.pem" in std_out @@ -2103,21 +1404,16 @@ def test_adhoc_1uf_splunktcp_ssl(self): finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [ - os.path.join(FIXTURES_DIR, "ca.key"), - os.path.join(FIXTURES_DIR, "ca.csr"), - os.path.join(FIXTURES_DIR, "ca.pem"), - os.path.join(FIXTURES_DIR, "server.key"), - os.path.join(FIXTURES_DIR, "server.csr"), - os.path.join(FIXTURES_DIR, "server.pem"), - os.path.join(FIXTURES_DIR, "cert.pem"), - os.path.join(FIXTURES_DIR, "cacert.pem"), - os.path.join(FIXTURES_DIR, "default.yml") - ] - self.cleanup_files(files) + try: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: + pass def test_adhoc_1so_splunkd_custom_ssl(self): # Generate default.yml + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) @@ -2128,14 +1424,14 @@ def test_adhoc_1so_splunkd_custom_ssl(self): # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates passphrase = "heyallyoucoolcatsandkittens" cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=FIXTURES_DIR), - "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=FIXTURES_DIR) + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DIR), + "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=self.DIR) ] for cmd in cmds: execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) @@ -2146,24 +1442,23 @@ def test_adhoc_1so_splunkd_custom_ssl(self): enable: true password: {}'''.format(passphrase), output, flags=re.MULTILINE|re.DOTALL) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, + volumes=["/tmp/defaults/"], name=self.project_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) + assert self.wait_for_containers(1, name=self.project_name) # Check splunkd assert self.check_splunkd("admin", password) # Check if the created file exists @@ -2174,7 +1469,7 @@ def test_adhoc_1so_splunkd_custom_ssl(self): # Check splunkd using the custom certs mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/services/server/info".format(mgmt_port) - kwargs = {"auth": ("admin", password), "verify": "{}/cacert.pem".format(FIXTURES_DIR)} + kwargs = {"auth": ("admin", password), "verify": "{}/cacert.pem".format(self.DIR)} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 except Exception as e: @@ -2183,61 +1478,51 @@ def test_adhoc_1so_splunkd_custom_ssl(self): finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [ - os.path.join(FIXTURES_DIR, "ca.key"), - os.path.join(FIXTURES_DIR, "ca.csr"), - os.path.join(FIXTURES_DIR, "ca.pem"), - os.path.join(FIXTURES_DIR, "server.key"), - os.path.join(FIXTURES_DIR, "server.csr"), - os.path.join(FIXTURES_DIR, "server.pem"), - os.path.join(FIXTURES_DIR, "cert.pem"), - os.path.join(FIXTURES_DIR, "cacert.pem"), - os.path.join(FIXTURES_DIR, "default.yml") - ] - self.cleanup_files(files) - - def test_adhoc_1uf_splunkd_custom_ssl(self): - # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates - passphrase = "heyallyoucoolcatsandkittens" - cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=FIXTURES_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=FIXTURES_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=FIXTURES_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=FIXTURES_DIR), - "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=FIXTURES_DIR) - ] - for cmd in cmds: - execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) - # Update server ssl settings - output = re.sub(r'''^ ssl:.*?password: null''', r''' ssl: - ca: /tmp/defaults/ca.pem - cert: /tmp/defaults/cert.pem - enable: true - password: {}'''.format(passphrase), output, flags=re.MULTILINE|re.DOTALL) - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml - cid = None + try: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: + pass + + def test_adhoc_1so_upgrade(self): + # Pull the old image + for line in self.client.pull("splunk/splunk:{}".format(OLD_SPLUNK_VERSION), stream=True, decode=True): + continue + # Create the "splunk-old" container try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], + cid = None + splunk_container_name = self.generate_random_string() + user, password = "admin", self.generate_random_string() + cid = self.client.create_container("splunk/splunk:{}".format(OLD_SPLUNK_VERSION), tty=True, ports=[8089, 8088], hostname="splunk", + name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_HEC_TOKEN": "qwerty", "SPLUNK_PASSWORD": password, "SPLUNK_START_ARGS": "--accept-license"}, + host_config=self.client.create_host_config(mounts=[Mount("/opt/splunk/etc", "opt-splunk-etc"), Mount("/opt/splunk/var", "opt-splunk-var")], + port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name), "name": splunk_container_name}) + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Add some data via HEC + splunk_hec_port = self.client.port(cid, 8088)[0]["HostPort"] + url = "https://localhost:{}/services/collector/event".format(splunk_hec_port) + kwargs = {"json": {"event": "world never says hello back"}, "verify": False, "headers": {"Authorization": "Splunk qwerty"}} + status, content = self.handle_request_retry("POST", url, kwargs) + assert status == 200 + # Sleep to let the data index + time.sleep(3) + # Remove the "splunk-old" container + self.client.remove_container(cid, v=False, force=True) + # Create the "splunk-new" container re-using volumes + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8000], hostname="splunk", + name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_HEC_TOKEN": "qwerty", "SPLUNK_PASSWORD": password, "SPLUNK_START_ARGS": "--accept-license"}, + host_config=self.client.create_host_config(mounts=[Mount("/opt/splunk/etc", "opt-splunk-etc"), Mount("/opt/splunk/var", "opt-splunk-var")], port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -2245,245 +1530,365 @@ def test_adhoc_1uf_splunkd_custom_ssl(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "sslRootCAPath = /tmp/defaults/ca.pem" in std_out - assert "serverCert = /tmp/defaults/cert.pem" in std_out - # Check splunkd using the custom certs - mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(mgmt_port) - kwargs = {"auth": ("admin", password), "verify": "{}/cacert.pem".format(FIXTURES_DIR)} + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name), "name": splunk_container_name}) + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 + # Run a search + time.sleep(3) + query = "search index=main earliest=-10m" + meta, results = self._run_splunk_query(cid, query, user, password) + results = results["results"] + assert len(results) == 1 + assert results[0]["_raw"] == "world never says hello back" except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [ - os.path.join(FIXTURES_DIR, "ca.key"), - os.path.join(FIXTURES_DIR, "ca.csr"), - os.path.join(FIXTURES_DIR, "ca.pem"), - os.path.join(FIXTURES_DIR, "server.key"), - os.path.join(FIXTURES_DIR, "server.csr"), - os.path.join(FIXTURES_DIR, "server.pem"), - os.path.join(FIXTURES_DIR, "cert.pem"), - os.path.join(FIXTURES_DIR, "default.yml") - ] - self.cleanup_files(files) - def test_adhoc_1so_splunkd_no_ssl(self): - # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Update server ssl settings - output = re.sub(r'''^ ssl:.*?password: null''', r''' ssl: - ca: null - cert: null - enable: false - password: null''', output, flags=re.MULTILINE|re.DOTALL) - # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: - f.write(output) - # Create the container and mount the default.yml + def test_adhoc_1so_preplaybook(self): + # Create a splunk container cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], + volumes=["/playbooks/play.yml"], name=splunk_container_name, + environment={ + "DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_CERT_PREFIX": "http", - "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) + "SPLUNK_PASSWORD": self.password, + "SPLUNK_ANSIBLE_PRE_TASKS": "file:///playbooks/play.yml" + }, + host_config=self.client.create_host_config(binds=[self.FIXTURES_DIR + "/touch_dummy_file.yml:/playbooks/play.yml"], + port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password, scheme="http") - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "enableSplunkdSSL = false" in std_out - # Check splunkd using the custom certs - mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "http://localhost:{}/services/server/info".format(mgmt_port) - kwargs = {"auth": ("admin", password)} + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /tmp/i-am", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "batman" in std_out + # Check file owner + exec_command = self.client.exec_create(cid, r'stat -c \'%U\' /tmp/i-am') + std_out = self.client.exec_start(exec_command) + assert "splunk" in std_out except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [os.path.join(FIXTURES_DIR, "default.yml")] - self.cleanup_files(files) - def test_adhoc_1uf_splunkd_no_ssl(self): + def test_compose_1so_apps(self): + self.project_name = self.generate_random_string() + # Tar the app before spinning up the scenario + with tarfile.open(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name)), "w:gz") as tar: + tar.add(self.EXAMPLE_APP, arcname=os.path.basename(self.EXAMPLE_APP)) + # Standup deployment + self.compose_file_name = "1so_apps.yaml" + container_count, rc = self.compose_up(apps_url="http://appserver/{}.tgz".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_so1_1".format(self.project_name)) + self.check_common_keys(log_json, "so") + try: + assert log_json["all"]["vars"]["splunk"]["apps_location"][0] == "http://appserver/{}.tgz".format(self.project_name) + assert log_json["all"]["vars"]["splunk"]["app_paths"]["default"] == "/opt/splunk/etc/apps" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["deployment"] == "/opt/splunk/etc/deployment-apps" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["httpinput"] == "/opt/splunk/etc/apps/splunk_httpinput" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["idxc"] == "/opt/splunk/etc/master-apps" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["shc"] == "/opt/splunk/etc/shcluster/apps" + except KeyError as e: + self.logger.error(e) + raise e + # Check container logs + output = self.get_container_logs("{}_so1_1".format(self.project_name)) + self.check_ansible(output) + # Check to make sure the app got installed + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 2 + for container in containers: + # Skip the nginx container + if "nginx" in container["Image"]: + continue + # Check the app endpoint + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Let's go further and check app version + output = json.loads(content) + assert output["entry"][0]["content"]["version"] == "0.0.1" + try: + os.remove(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name))) + except OSError: + pass + + def test_adhoc_1so_custom_conf(self): + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + os.mkdir(self.DIR) # Generate default.yml - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) # Get the password password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() assert password and password != "null" - # Update server ssl settings - output = re.sub(r'''^ ssl:.*?password: null''', r''' ssl: - ca: null - cert: null - enable: false - password: null''', output, flags=re.MULTILINE|re.DOTALL) + # Add a custom conf file + output = re.sub(r' group: splunk', r''' group: splunk + conf: + user-prefs: + directory: /opt/splunk/etc/users/admin/user-prefs/local + content: + general: + default_namespace: appboilerplate + search_syntax_highlighting: dark''', output) # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_CERT_PREFIX": "http", - "SPLUNK_PASSWORD": password}, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="start", ports=[8089], + volumes=["/tmp/defaults/"], name=splunk_container_name, + environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password, scheme="http") - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "enableSplunkdSSL = false" in std_out - # Check splunkd using the custom certs - mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "http://localhost:{}/services/server/info".format(mgmt_port) - kwargs = {"auth": ("admin", password)} + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/users/admin/user-prefs/local/user-prefs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "[general]" in std_out + assert "default_namespace = appboilerplate" in std_out + assert "search_syntax_highlighting = dark" in std_out except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - files = [os.path.join(FIXTURES_DIR, "default.yml")] - self.cleanup_files(files) + try: + os.remove(os.path.join(self.DIR, "default.yml")) + rmtree(self.DIR) + except OSError: + pass - def test_adhoc_1so_web_ssl(self): - # Generate a password - password = generate_random_string() - # Create the container + def test_compose_1uf_apps(self): + self.project_name = self.generate_random_string() + # Tar the app before spinning up the scenario + with tarfile.open(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name)), "w:gz") as tar: + tar.add(self.EXAMPLE_APP, arcname=os.path.basename(self.EXAMPLE_APP)) + # Standup deployment + self.compose_file_name = "1uf_apps.yaml" + container_count, rc = self.compose_up(apps_url="http://appserver/{}.tgz".format(self.project_name)) + assert rc == 0 + # Wait for containers to come up + assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) + # Check ansible inventory json + log_json = self.extract_json("{}_uf1_1".format(self.project_name)) + self.check_common_keys(log_json, "uf") + try: + assert log_json["all"]["vars"]["splunk"]["apps_location"][0] == "http://appserver/{}.tgz".format(self.project_name) + assert log_json["all"]["vars"]["splunk"]["app_paths"]["default"] == "/opt/splunkforwarder/etc/apps" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["deployment"] == "/opt/splunkforwarder/etc/deployment-apps" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["httpinput"] == "/opt/splunkforwarder/etc/apps/splunk_httpinput" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["idxc"] == "/opt/splunkforwarder/etc/master-apps" + assert log_json["all"]["vars"]["splunk"]["app_paths"]["shc"] == "/opt/splunkforwarder/etc/shcluster/apps" + except KeyError as e: + self.logger.error(e) + raise e + # Check container logs + output = self.get_container_logs("{}_uf1_1".format(self.project_name)) + self.check_ansible(output) + # Check to make sure the app got installed + containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) + assert len(containers) == 2 + for container in containers: + # Skip the nginx container + if "nginx" in container["Image"]: + continue + # Check the app endpoint + splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Let's go further and check app version + output = json.loads(content) + assert output["entry"][0]["content"]["version"] == "0.0.1" + try: + os.remove(os.path.join(self.FIXTURES_DIR, "{}.tgz".format(self.project_name))) + except OSError: + pass + + def test_uf_entrypoint_help(self): + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="help") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + assert "SPLUNK_CMD - 'any splunk command' - execute any splunk commands separated by commas" in output + + def test_uf_entrypoint_create_defaults(self): + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + assert "home: /opt/splunk" in output + assert "password: " in output + + def test_uf_entrypoint_start_no_password(self): + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", + environment={"SPLUNK_START_ARGS": "nothing"}) + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + assert "WARNING: No password ENV var." in output + + def test_uf_entrypoint_start_no_accept_license(self): + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", + environment={"SPLUNK_PASSWORD": "something", "SPLUNK_START_ARGS": "nothing"}) + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + assert "License not accepted, please ensure the environment variable SPLUNK_START_ARGS contains the '--accept-license' flag" in output + + def test_uf_entrypoint_no_provision(self): cid = None try: - splunk_container_name = generate_random_string() - # Commands to generate self-signed certificates for SplunkWeb here: https://docs.splunk.com/Documentation/Splunk/latest/Security/Self-signcertificatesforSplunkWeb - cmd = "openssl req -x509 -newkey rsa:4096 -passout pass:abcd1234 -keyout {path}/key.pem -out {path}/cert.pem -days 365 -subj /CN=localhost".format(path=FIXTURES_DIR) - generate_certs = subprocess.check_output(cmd.split()) - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=splunk_container_name, - environment={"DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": password, - "SPLUNK_HTTP_ENABLESSL": "true", - "SPLUNK_HTTP_ENABLESSL_CERT": "/tmp/defaults/cert.pem", - "SPLUNK_HTTP_ENABLESSL_PRIVKEY": "/tmp/defaults/key.pem", - "SPLUNK_HTTP_ENABLESSL_PRIVKEY_PASSWORD": "abcd1234" - }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + ":/tmp/defaults/"], - port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) - ) + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="no-provision") cid = cid.get("Id") self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - assert self.check_splunkd("admin", password) - # Check splunkweb - web_port = self.client.port(cid, 8000)[0]["HostPort"] - url = "https://localhost:{}/".format(web_port) - kwargs = {"verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 + # Wait a bit + time.sleep(5) + # If the container is still running, we should be able to exec inside + # Check that the git SHA exists in /opt/ansible + exec_command = self.client.exec_create(cid, "cat /opt/ansible/version.txt") + std_out = self.client.exec_start(exec_command) + assert len(std_out.strip()) == 40 + # Check that the wrapper-example directory does not exist + exec_command = self.client.exec_create(cid, "ls /opt/ansible/") + std_out = self.client.exec_start(exec_command) + assert "wrapper-example" not in std_out + assert "docs" not in std_out except Exception as e: self.logger.error(e) raise e finally: if cid: self.client.remove_container(cid, v=True, force=True) - try: - os.remove(os.path.join(FIXTURES_DIR, "key.pem")) - os.remove(os.path.join(FIXTURES_DIR, "cert.pem")) - except OSError: - pass - def test_adhoc_1so_upgrade(self): - # Pull the old image - for line in self.client.pull("splunk/splunk:{}".format(OLD_SPLUNK_VERSION), stream=True, decode=True): - continue - # Create the "splunk-old" container + def test_uf_uid_gid(self): + cid = None try: - cid = None - splunk_container_name = generate_random_string() - user, password = "admin", generate_random_string() - cid = self.client.create_container("splunk/splunk:{}".format(OLD_SPLUNK_VERSION), tty=True, ports=[8089, 8088], hostname="splunk", - name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_HEC_TOKEN": "qwerty", "SPLUNK_PASSWORD": password, "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(mounts=[Mount("/opt/splunk/etc", "opt-splunk-etc"), Mount("/opt/splunk/var", "opt-splunk-var")], - port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) - ) + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="no-provision") cid = cid.get("Id") self.client.start(cid) - # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) - # Check splunkd - assert self.check_splunkd(user, password) - # Add some data via HEC - splunk_hec_port = self.client.port(cid, 8088)[0]["HostPort"] - url = "https://localhost:{}/services/collector/event".format(splunk_hec_port) - kwargs = {"json": {"event": "world never says hello back"}, "verify": False, "headers": {"Authorization": "Splunk qwerty"}} - status, content = self.handle_request_retry("POST", url, kwargs) - assert status == 200 - # Sleep to let the data index - time.sleep(3) - # Remove the "splunk-old" container - self.client.remove_container(cid, v=False, force=True) - # Create the "splunk-new" container re-using volumes - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8000], hostname="splunk", - name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_HEC_TOKEN": "qwerty", "SPLUNK_PASSWORD": password, "SPLUNK_START_ARGS": "--accept-license"}, - host_config=self.client.create_host_config(mounts=[Mount("/opt/splunk/etc", "opt-splunk-etc"), Mount("/opt/splunk/var", "opt-splunk-var")], + # Wait a bit + time.sleep(5) + # If the container is still running, we should be able to exec inside + # Check that the git SHA exists in /opt/ansible + exec_command = self.client.exec_create(cid, "id", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "uid=41812" in std_out + assert "gid=41812" in std_out + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_adhoc_1uf_splunktcp_ssl(self): + # Generate default.yml + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates + passphrase = "abcd1234" + cmds = [ + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DIR) + ] + for cmd in cmds: + execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) + # Update s2s ssl settings + output = re.sub(r''' s2s:.*?ssl: false''', r''' s2s: + ca: /tmp/defaults/ca.pem + cert: /tmp/defaults/cert.pem + enable: true + password: {} + port: 9997 + ssl: true'''.format(passphrase), output, flags=re.DOTALL) + # Write the default.yml to a file + with open(os.path.join(self.DIR, "default.yml"), "w") as f: + f.write(output) + # Create the container and mount the default.yml + cid = None + try: + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], + volumes=["/tmp/defaults/"], name=self.project_name, + environment={"DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": password}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=splunk_container_name) + assert self.wait_for_containers(1, name=self.project_name) # Check splunkd - assert self.check_splunkd(user, password) - # Run a search - time.sleep(3) - query = "search index=main earliest=-10m" - meta, results = self._run_splunk_query(cid, query, user, password) - results = results["results"] - assert len(results) == 1 - assert results[0]["_raw"] == "world never says hello back" + assert self.check_splunkd("admin", password) + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/inputs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "[splunktcp-ssl:9997]" in std_out + assert "serverCert = /tmp/defaults/cert.pem" in std_out except Exception as e: self.logger.error(e) raise e @@ -2491,447 +1896,284 @@ def test_adhoc_1so_upgrade(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(os.path.join(self.DIR, "default.yml")) except OSError: pass - def test_compose_1so_trial(self): - # Standup deployment - self.compose_file_name = "1so_trial.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - def test_compose_1so_custombuild(self): - # Standup deployment - self.compose_file_name = "1so_custombuild.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - def test_compose_1so_namedvolumes(self): - # TODO: We can do a lot better in this test - ex. check that data is persisted after restarts - # Standup deployment - self.compose_file_name = "1so_namedvolumes.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - def test_compose_1deployment1cm(self): - # Tar the app before spinning up the scenario - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) - + def test_adhoc_1uf_splunkd_custom_ssl(self): # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) - # Add a custom conf file - output = re.sub(r' group: splunk', r''' group: splunk - conf: - - key: user-prefs - value: - directory: /opt/splunk/etc/users/admin/user-prefs/local - content: - general: - default_namespace: appboilerplate - search_syntax_highlighting: dark - search_assistant: - "serverClass:secrets:app:test": {}''', output) + # Get the password + password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert password and password != "null" + # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates + passphrase = "heyallyoucoolcatsandkittens" + cmds = [ + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DIR), + "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=self.DIR) + ] + for cmd in cmds: + execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) + # Update server ssl settings + output = re.sub(r'''^ ssl:.*?password: null''', r''' ssl: + ca: /tmp/defaults/ca.pem + cert: /tmp/defaults/cert.pem + enable: true + password: {}'''.format(passphrase), output, flags=re.MULTILINE|re.DOTALL) # Write the default.yml to a file - with open(os.path.join(SCENARIOS_DIR, "defaults", "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) - # Standup deployment - try: - self.compose_file_name = "1deployment1cm.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"cm1": "cm", "depserver1": "deployment_server"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed and certain subdirectories are excluded - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 3 - for container in containers: - # Skip the nginx container - if "nginx" in container["Image"]: - continue - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name == "depserver1": - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - resp = requests.get(url, auth=("admin", self.password), verify=False) - # Deployment server should *not* install the app - assert resp.status_code == 404 - # Check that the app exists in etc/apps - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "state = disabled" in std_out - # Check that the app exists in etc/deployment-apps - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/deployment-apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/deployment-apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "# Autogenerated file " == std_out - if container_name == "cm1": - # Check if the created file exists - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/users/admin/user-prefs/local/user-prefs.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "[serverClass:secrets:app:test]" in std_out - assert "[general]" in std_out - assert "default_namespace = appboilerplate" in std_out - assert "search_syntax_highlighting = dark" in std_out - assert "search_assistant" in std_out - RETRIES = 5 - for i in range(RETRIES): - try: - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "# Autogenerated file" in std_out - assert "state = enabled" in std_out - except Exception as e: - self.logger.error(e) - if i < RETRIES-1: - time.sleep(30) - continue - raise e - except Exception as e: - self.logger.error(e) - raise e - finally: - try: - os.remove(EXAMPLE_APP_TGZ) - except OSError as e: - pass - - def test_compose_1deployment1so(self): - # Tar the app before spinning up the scenario - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) - # Standup deployment + # Create the container and mount the default.yml + cid = None try: - self.compose_file_name = "1deployment1so.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"so1": "so", "depserver1": "deployment_server"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed and certain subdirectories are excluded - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 3 - for container in containers: - # Skip the nginx container - if "nginx" in container["Image"]: - continue - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name == "depserver1": - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - resp = requests.get(url, auth=("admin", self.password), verify=False) - # Deployment server should *not* install the app - assert resp.status_code == 404 - # Check that the app exists in etc/apps - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "state = disabled" in std_out - # Check that the app exists in etc/deployment-apps - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/deployment-apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/deployment-apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "# Autogenerated file " == std_out - if container_name == "so1": - RETRIES = 5 - for i in range(RETRIES): - try: - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "# Autogenerated file" in std_out - assert "state = enabled" in std_out - except Exception as e: - self.logger.error(e) - if i < RETRIES-1: - time.sleep(30) - continue - raise e + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], + volumes=["/tmp/defaults/"], name=self.project_name, + environment={"DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": password}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=self.project_name) + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "sslRootCAPath = /tmp/defaults/ca.pem" in std_out + assert "serverCert = /tmp/defaults/cert.pem" in std_out + # Check splunkd using the custom certs + mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(mgmt_port) + kwargs = {"auth": ("admin", password), "verify": "{}/cacert.pem".format(self.DIR)} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 except Exception as e: self.logger.error(e) raise e finally: + if cid: + self.client.remove_container(cid, v=True, force=True) try: - os.remove(EXAMPLE_APP_TGZ) - except OSError as e: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: pass - def test_compose_1deployment1uf(self): - # Tar the app before spinning up the scenario - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) - # Standup deployment + def test_adhoc_1uf_hec_custom_cert(self): + # Generate default.yml + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates + passphrase = "glootie" + cmds = [ + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=self.DIR), + "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=self.DIR), + "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=self.DIR), + "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=self.DIR), + "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=self.DIR), + "cat {path}/server.pem {path}/ca.pem > {path}/cacert.pem".format(path=self.DIR) + ] + for cmd in cmds: + execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) + # Update s2s ssl settings + output = re.sub(r''' hec:.*? token: .*?\n''', r''' hec: + enable: True + port: 8088 + ssl: True + token: doyouwannadevelopanapp + cert: /tmp/defaults/cert.pem + password: {}\n'''.format(passphrase), output, flags=re.DOTALL) + # Write the default.yml to a file + with open(os.path.join(self.DIR, "default.yml"), "w") as f: + f.write(output) + # Create the container and mount the default.yml + cid = None try: - self.compose_file_name = "1deployment1uf.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"uf1": "uf", "depserver1": "deployment_server"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed, and shcluster is setup properly - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 3 - for container in containers: - # Skip the nginx container - if "nginx" in container["Image"]: - continue - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name == "depserver1": - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - resp = requests.get(url, auth=("admin", self.password), verify=False) - # Deployment server should *not* install the app - assert resp.status_code == 404 - # Check that the app exists in etc/apps - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "state = disabled" in std_out - # Check that the app exists in etc/deployment-apps - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunk/etc/deployment-apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunk/etc/deployment-apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "# Autogenerated file " == std_out - if container_name == "uf1": - RETRIES = 5 - for i in range(RETRIES): - try: - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" - exec_command = self.client.exec_create(container["Id"], "ls /opt/splunkforwarder/etc/apps/splunk_app_example/local/", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "savedsearches.conf" in std_out - assert "app.conf" in std_out - exec_command = self.client.exec_create(container["Id"], "cat /opt/splunkforwarder/etc/apps/splunk_app_example/local/app.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "# Autogenerated file" in std_out - assert "state = enabled" in std_out - except Exception as e: - self.logger.error(e) - if i < RETRIES-1: - time.sleep(30) - continue - raise e + password = "helloworld" + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8088, 8089], + volumes=["/tmp/defaults/"], name=self.project_name, + environment={"DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": password}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=self.project_name) + # Check splunkd + assert self.check_splunkd("admin", password) + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "[http://splunk_hec_token]" in std_out + assert "serverCert = /tmp/defaults/cert.pem" in std_out + assert "sslPassword = " in std_out + # Check HEC using the custom certs + hec_port = self.client.port(cid, 8088)[0]["HostPort"] + url = "https://localhost:{}/services/collector/event".format(hec_port) + kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk doyouwannadevelopanapp"}, "verify": "{}/cacert.pem".format(self.DIR)} + status, content = self.handle_request_retry("POST", url, kwargs) + assert status == 200 except Exception as e: self.logger.error(e) raise e finally: + if cid: + self.client.remove_container(cid, v=True, force=True) try: - os.remove(EXAMPLE_APP_TGZ) - except OSError as e: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: pass - def test_compose_1so_before_start_cmd(self): - # Check that SPLUNK_BEFORE_START_CMD works for splunk image + def test_compose_1uf_enable_service(self): # Standup deployment - self.compose_file_name = "1so_before_start_cmd.yaml" - self.project_name = generate_random_string() + self.compose_file_name = "1uf_enable_service.yaml" + self.project_name = self.generate_random_string() container_count, rc = self.compose_up() assert rc == 0 # Wait for containers to come up assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") + log_json = self.extract_json("{}_uf1_1".format(self.project_name)) + self.check_common_keys(log_json, "uf") + try: + # enable_service is set in the compose file + assert log_json["all"]["vars"]["splunk"]["enable_service"] == "true" + except KeyError as e: + self.logger.error(e) + raise e # Check container logs - output = self.get_container_logs("so1") + output = self.get_container_logs("{}_uf1_1".format(self.project_name)) self.check_ansible(output) # Check Splunkd on all the containers assert self.check_splunkd("admin", self.password) - # Check Splunkd using the new users - assert self.check_splunkd("admin2", "changemepls") - assert self.check_splunkd("admin3", "changemepls") - + # Check if service is registered + if 'debian' in PLATFORM: + exec_command = self.client.exec_create("{}_uf1_1".format(self.project_name), "sudo service splunk status") + std_out = self.client.exec_start(exec_command) + assert "splunkd is running" in std_out + else: + exec_command = self.client.exec_create("{}_uf1_1".format(self.project_name), "stat /etc/init.d/splunk") + std_out = self.client.exec_start(exec_command) + assert "/etc/init.d/splunk" in std_out + + def test_adhoc_1uf_splunkd_no_ssl(self): + # Generate default.yml + self.project_name = self.generate_random_string() + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + os.mkdir(self.DIR) + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" + # Update server ssl settings + output = re.sub(r'''^ ssl:.*?password: null''', r''' ssl: + ca: null + cert: null + enable: false + password: null''', output, flags=re.MULTILINE|re.DOTALL) + # Write the default.yml to a file + with open(os.path.join(self.DIR, "default.yml"), "w") as f: + f.write(output) + # Create the container and mount the default.yml + cid = None + try: + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], + volumes=["/tmp/defaults/"], name=splunk_container_name, + environment={"DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_CERT_PREFIX": "http", + "SPLUNK_PASSWORD": p}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",), 8000: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + assert self.check_splunkd("admin", p, scheme="http") + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "enableSplunkdSSL = false" in std_out + # Check splunkd using the custom certs + mgmt_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "http://localhost:{}/services/server/info".format(mgmt_port) + kwargs = {"auth": ("admin", p)} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + try: + os.remove(os.path.join(self.DIR, "default.yml")) + except OSError: + pass + def test_compose_1uf_before_start_cmd(self): # Check that SPLUNK_BEFORE_START_CMD works for splunkforwarder image # Standup deployment self.compose_file_name = "1uf_before_start_cmd.yaml" - self.project_name = generate_random_string() + self.project_name = self.generate_random_string() container_count, rc = self.compose_up() assert rc == 0 # Wait for containers to come up assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) # Check ansible inventory json - log_json = self.extract_json("uf1") + log_json = self.extract_json("{}_uf1_1".format(self.project_name)) self.check_common_keys(log_json, "uf") # Check container logs - output = self.get_container_logs("uf1") + output = self.get_container_logs("{}_uf1_1".format(self.project_name)) self.check_ansible(output) # Check Splunkd on all the containers assert self.check_splunkd("admin", self.password) # Check Splunkd using the new users assert self.check_splunkd("normalplebe", "newpassword") - - def test_compose_1so_splunk_add(self): - # Check that SPLUNK_ADD works for splunk image (role=standalone) - # Standup deployment - self.compose_file_name = "1so_splunk_add_user.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check Splunkd using the new users - assert self.check_splunkd("newman", "changemepls") - - def test_compose_1hf_splunk_add(self): - # Check that SPLUNK_ADD works for splunk image (role=heavy forwarder) - # Standup deployment - self.compose_file_name = "1hf_splunk_add_user.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("hf1") - self.check_common_keys(log_json, "hf") - # Check container logs - output = self.get_container_logs("hf1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check Splunkd using the new users - assert self.check_splunkd("jerry", "seinfeld") - + def test_compose_1uf_splunk_add(self): # Check that SPLUNK_ADD works for splunkforwarder image # Standup deployment self.compose_file_name = "1uf_splunk_add_user.yaml" - self.project_name = generate_random_string() + self.project_name = self.generate_random_string() container_count, rc = self.compose_up() assert rc == 0 # Wait for containers to come up assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) # Check ansible inventory json - log_json = self.extract_json("uf1") + log_json = self.extract_json("{}_uf1_1".format(self.project_name)) self.check_common_keys(log_json, "uf") # Check container logs - output = self.get_container_logs("uf1") + output = self.get_container_logs("{}_uf1_1".format(self.project_name)) self.check_ansible(output) # Check Splunkd on all the containers assert self.check_splunkd("admin", self.password) @@ -2943,16 +2185,16 @@ def test_compose_1uf_splunk_cmd(self): # Check that SPLUNK_ADD works for splunkforwarder image # Standup deployment self.compose_file_name = "1uf_splunk_cmd.yaml" - self.project_name = generate_random_string() + self.project_name = self.generate_random_string() container_count, rc = self.compose_up() assert rc == 0 # Wait for containers to come up assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) # Check ansible inventory json - log_json = self.extract_json("uf1") + log_json = self.extract_json("{}_uf1_1".format(self.project_name)) self.check_common_keys(log_json, "uf") # Check container logs - output = self.get_container_logs("uf1") + output = self.get_container_logs("{}_uf1_1".format(self.project_name)) self.check_ansible(output) # Check Splunkd on all the containers assert self.check_splunkd("admin", self.password) @@ -2960,228 +2202,179 @@ def test_compose_1uf_splunk_cmd(self): assert self.check_splunkd("jerry", "changemepls") assert self.check_splunkd("george", "changemepls") - @pytest.mark.skip(reason="The validation captured here is absorbed by test_adhoc_1so_using_default_yml") - def test_compose_1so_command_start(self): - # Standup deployment - self.compose_file_name = "1so_command_start.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - @pytest.mark.skip(reason="The validation captured here is absorbed by test_adhoc_1uf_using_default_yml") - def test_compose_1uf_command_start(self): + def test_adhoc_1uf_using_default_yml(self): + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + # Generate default.yml + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") + self.client.start(cid.get("Id")) + output = self.get_container_logs(cid.get("Id")) + self.client.remove_container(cid.get("Id"), v=True, force=True) + # Get the password + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" + # Change the admin user + output = re.sub(r' admin_user: admin', r' admin_user: hansolo', output) + # Write the default.yml to a file + os.mkdir(self.DIR) + with open(os.path.join(self.DIR, "default.yml"), "w") as f: + f.write(output) + # Create the container and mount the default.yml + cid = None + try: + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", ports=[8089], + volumes=["/tmp/defaults/"], name=splunk_container_name, + environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("hansolo", p), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + try: + os.remove(os.path.join(self.DIR, "default.yml")) + os.rmdir(self.DIR) + except OSError: + pass + + def test_adhoc_1uf_hec_ssl_disabled(self): + # Create the container + cid = None + try: + splunk_container_name = self.generate_random_string() + self.project_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089, 8088], + name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_HEC_TOKEN": "get-schwifty", + "SPLUNK_HEC_SSL": "false", + "SPLUNK_PASSWORD": self.password + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",), 8088: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + assert self.check_splunkd("admin", self.password) + # Check HEC + hec_port = self.client.port(cid, 8088)[0]["HostPort"] + url = "http://localhost:{}/services/collector/event".format(hec_port) + kwargs = {"json": {"event": "hello world"}, "headers": {"Authorization": "Splunk get-schwifty"}} + status, content = self.handle_request_retry("POST", url, kwargs) + assert status == 200 + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_adhoc_1uf_change_tailed_files(self): + # Create a splunk container + cid = None + try: + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], + name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_TAIL_FILE": "/opt/splunkforwarder/var/log/splunk/splunkd_stderr.log /opt/splunkforwarder/var/log/splunk/first_install.log" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Check the tailed logs + logs = self.client.logs(cid, tail=20) + assert "==> /opt/splunkforwarder/var/log/splunk/first_install.log <==" in logs + assert "==> /opt/splunkforwarder/var/log/splunk/splunkd_stderr.log <==" in logs + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_adhoc_1uf_password_from_file(self): + # Create a splunk container + cid = None + # From fixtures/pwfile + filePW = "changeme123" + try: + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], + volumes=["/var/secrets/pwfile"], name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": "/var/secrets/pwfile" + }, + host_config=self.client.create_host_config(binds=[self.FIXTURES_DIR + "/pwfile:/var/secrets/pwfile"], + port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", filePW), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_compose_1uf_hec(self): # Standup deployment - self.compose_file_name = "1uf_command_start.yaml" - self.project_name = generate_random_string() + self.compose_file_name = "1uf_hec.yaml" + self.project_name = self.generate_random_string() container_count, rc = self.compose_up() assert rc == 0 # Wait for containers to come up assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) # Check ansible inventory json - log_json = self.extract_json("uf1") + log_json = self.extract_json("{}_uf1_1".format(self.project_name)) self.check_common_keys(log_json, "uf") + try: + # token "abcd1234" is hard-coded within the 1so_hec.yaml compose + assert log_json["all"]["vars"]["splunk"]["hec"]["token"] == "abcd1234" + except KeyError as e: + self.logger.error(e) + raise e # Check container logs - output = self.get_container_logs("uf1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - @pytest.mark.skip(reason="The validation captured here is absorbed by test_adhoc_1so_bind_mount_apps") - def test_compose_1so_command_start_service(self): - # Standup deployment - self.compose_file_name = "1so_command_start_service.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - @pytest.mark.skip(reason="The validation captured here is absorbed by test_adhoc_1uf_bind_mount_apps") - def test_compose_1uf_command_start_service(self): - # Standup deployment - self.compose_file_name = "1uf_command_start_service.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("uf1") - self.check_common_keys(log_json, "uf") - # Check container logs - output = self.get_container_logs("uf1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - - def test_compose_1so_java_oracle(self): - # Standup deployment - self.compose_file_name = "1so_java_oracle.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - try: - assert log_json["all"]["vars"]["java_version"] == "oracle:8" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check if java is installed - exec_command = self.client.exec_create("so1", "java -version") - std_out = self.client.exec_start(exec_command) - assert "java version \"1.8.0" in std_out - # Restart the container and make sure java is still installed - self.client.restart("so1") - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - assert self.check_splunkd("admin", self.password) - exec_command = self.client.exec_create("so1", "java -version") - std_out = self.client.exec_start(exec_command) - assert "java version \"1.8.0" in std_out - - def test_compose_1so_java_openjdk8(self): - # Standup deployment - self.compose_file_name = "1so_java_openjdk8.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - try: - assert log_json["all"]["vars"]["java_version"] == "openjdk:8" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check if java is installed - exec_command = self.client.exec_create("so1", "java -version") - std_out = self.client.exec_start(exec_command) - assert "openjdk version \"1.8.0" in std_out - # Restart the container and make sure java is still installed - self.client.restart("so1") - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - assert self.check_splunkd("admin", self.password) - exec_command = self.client.exec_create("so1", "java -version") - std_out = self.client.exec_start(exec_command) - assert "openjdk version \"1.8.0" in std_out - - def test_compose_1so_java_openjdk11(self): - # Standup deployment - self.compose_file_name = "1so_java_openjdk11.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - try: - assert log_json["all"]["vars"]["java_version"] == "openjdk:11" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check if java is installed - exec_command = self.client.exec_create("so1", "java -version") - std_out = self.client.exec_start(exec_command) - assert "openjdk version \"11.0.2" in std_out - # Restart the container and make sure java is still installed - self.client.restart("so1") - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - assert self.check_splunkd("admin", self.password) - exec_command = self.client.exec_create("so1", "java -version") - std_out = self.client.exec_start(exec_command) - assert "openjdk version \"11.0.2" in std_out - - def test_compose_1so_hec(self): - # Standup deployment - self.compose_file_name = "1so_hec.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - try: - # token "abcd1234" is hard-coded within the 1so_hec.yaml compose - assert log_json["all"]["vars"]["splunk"]["hec"]["token"] == "abcd1234" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check HEC works - note the token "abcd1234" is hard-coded within the 1so_hec.yaml compose - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 1 - so1 = containers[0] - splunk_hec_port = self.client.port(so1["Id"], 8088)[0]["HostPort"] - url = "https://localhost:{}/services/collector/event".format(splunk_hec_port) - kwargs = {"json": {"event": "hello world"}, "verify": False, "headers": {"Authorization": "Splunk abcd1234"}} - status, content = self.handle_request_retry("POST", url, kwargs) - assert status == 200 - - def test_compose_1uf_hec(self): - # Standup deployment - self.compose_file_name = "1uf_hec.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("uf1") - self.check_common_keys(log_json, "uf") - try: - # token "abcd1234" is hard-coded within the 1so_hec.yaml compose - assert log_json["all"]["vars"]["splunk"]["hec"]["token"] == "abcd1234" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("uf1") + output = self.get_container_logs("{}_uf1_1".format(self.project_name)) self.check_ansible(output) # Check Splunkd on all the containers assert self.check_splunkd("admin", self.password) @@ -3195,497 +2388,57 @@ def test_compose_1uf_hec(self): status, content = self.handle_request_retry("POST", url, kwargs) assert status == 200 - def test_compose_1so_enable_service(self): - # Standup deployment - self.compose_file_name = "1so_enable_service.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - try: - # enable_service is set in the compose file - assert log_json["all"]["vars"]["splunk"]["enable_service"] == "true" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check if service is registered - if 'debian' in platform: - exec_command = self.client.exec_create("so1", "sudo service splunk status") - std_out = self.client.exec_start(exec_command) - assert "splunkd is running" in std_out - else: - exec_command = self.client.exec_create("so1", "stat /etc/init.d/splunk") - std_out = self.client.exec_start(exec_command) - assert "/etc/init.d/splunk" in std_out - - def test_compose_1uf_enable_service(self): - # Standup deployment - self.compose_file_name = "1uf_enable_service.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("uf1") - self.check_common_keys(log_json, "uf") - try: - # enable_service is set in the compose file - assert log_json["all"]["vars"]["splunk"]["enable_service"] == "true" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("uf1") - self.check_ansible(output) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check if service is registered - if 'debian' in platform: - exec_command = self.client.exec_create("uf1", "sudo service splunk status") - std_out = self.client.exec_start(exec_command) - assert "splunkd is running" in std_out - else: - exec_command = self.client.exec_create("uf1", "stat /etc/init.d/splunk") - std_out = self.client.exec_start(exec_command) - assert "/etc/init.d/splunk" in std_out - - def test_compose_1so_apps(self): - # Tar the app before spinning up the scenario - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) - # Standup deployment - self.compose_file_name = "1so_apps.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("so1") - self.check_common_keys(log_json, "so") - try: - assert log_json["all"]["vars"]["splunk"]["apps_location"][0] == "http://appserver/splunk_app_example.tgz" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["default"] == "/opt/splunk/etc/apps" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["deployment"] == "/opt/splunk/etc/deployment-apps" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["httpinput"] == "/opt/splunk/etc/apps/splunk_httpinput" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["idxc"] == "/opt/splunk/etc/master-apps" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["shc"] == "/opt/splunk/etc/shcluster/apps" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("so1") - self.check_ansible(output) - # Check to make sure the app got installed - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 2 - for container in containers: - # Skip the nginx container - if "nginx" in container["Image"]: - continue - # Check the app endpoint - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Let's go further and check app version - output = json.loads(content) - assert output["entry"][0]["content"]["version"] == "0.0.1" - try: - os.remove(EXAMPLE_APP_TGZ) - except OSError as e: - pass - - def test_compose_1uf_apps(self): - # Tar the app before spinning up the scenario - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) - # Standup deployment - self.compose_file_name = "1uf_apps.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Check ansible inventory json - log_json = self.extract_json("uf1") - self.check_common_keys(log_json, "uf") - try: - assert log_json["all"]["vars"]["splunk"]["apps_location"][0] == "http://appserver/splunk_app_example.tgz" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["default"] == "/opt/splunkforwarder/etc/apps" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["deployment"] == "/opt/splunkforwarder/etc/deployment-apps" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["httpinput"] == "/opt/splunkforwarder/etc/apps/splunk_httpinput" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["idxc"] == "/opt/splunkforwarder/etc/master-apps" - assert log_json["all"]["vars"]["splunk"]["app_paths"]["shc"] == "/opt/splunkforwarder/etc/shcluster/apps" - except KeyError as e: - self.logger.error(e) - raise e - # Check container logs - output = self.get_container_logs("uf1") - self.check_ansible(output) - # Check to make sure the app got installed - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 2 - for container in containers: - # Skip the nginx container - if "nginx" in container["Image"]: - continue - # Check the app endpoint - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - # Let's go further and check app version - output = json.loads(content) - assert output["entry"][0]["content"]["version"] == "0.0.1" - try: - os.remove(EXAMPLE_APP_TGZ) - except OSError as e: - pass - - def test_compose_1uf1so(self): - # Standup deployment - self.compose_file_name = "1uf1so.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"so1": "so", "uf1": "uf"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_standalone"]["hosts"] == ["so1"] - except KeyError as e: - self.logger.error(e) - raise e - # Search results won't return the correct results immediately :( - time.sleep(30) - search_providers, distinct_hosts = self.search_internal_distinct_hosts("so1", password=self.password) - assert len(search_providers) == 1 - assert search_providers[0] == "so1" - assert distinct_hosts == 2 - - def test_compose_3idx1cm_splunktcp_ssl(self): - # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Commands to generate self-signed certificates for Splunk here: https://docs.splunk.com/Documentation/Splunk/latest/Security/ConfigureSplunkforwardingtousesignedcertificates - passphrase = "carolebaskindidit" - cmds = [ - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/ca.key 2048".format(pw=passphrase, path=DEFAULTS_DIR), - "openssl req -new -key {path}/ca.key -passin pass:{pw} -out {path}/ca.csr -subj /CN=localhost".format(pw=passphrase, path=DEFAULTS_DIR), - "openssl x509 -req -in {path}/ca.csr -sha512 -passin pass:{pw} -signkey {path}/ca.key -CAcreateserial -out {path}/ca.pem -days 3".format(pw=passphrase, path=DEFAULTS_DIR), - "openssl genrsa -aes256 -passout pass:{pw} -out {path}/server.key 2048".format(pw=passphrase, path=DEFAULTS_DIR), - "openssl req -new -passin pass:{pw} -key {path}/server.key -out {path}/server.csr -subj /CN=localhost".format(pw=passphrase, path=DEFAULTS_DIR), - "openssl x509 -req -passin pass:{pw} -in {path}/server.csr -SHA256 -CA {path}/ca.pem -CAkey {path}/ca.key -CAcreateserial -out {path}/server.pem -days 3".format(pw=passphrase, path=DEFAULTS_DIR), - "cat {path}/server.pem {path}/server.key {path}/ca.pem > {path}/cert.pem".format(path=DEFAULTS_DIR) - ] - for cmd in cmds: - execute_cmd = subprocess.check_output(["/bin/sh", "-c", cmd]) - # Update s2s ssl settings - output = re.sub(r''' s2s:.*?ssl: false''', r''' s2s: - ca: /tmp/defaults/ca.pem - cert: /tmp/defaults/cert.pem - enable: true - password: {} - port: 9997 - ssl: true'''.format(passphrase), output, flags=re.DOTALL) - # Write the default.yml to a file - with open(os.path.join(DEFAULTS_DIR, "default.yml"), "w") as f: - f.write(output) - # Standup deployment - try: - self.compose_file_name = "3idx1cm.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) - # Get container logs - container_mapping = {"cm1": "cm", "idx1": "idx", "idx2": "idx", "idx3": "idx"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2", "idx3"] - assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] - except KeyError as e: - self.logger.error(e) - raise e - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed, and shcluster is setup properly - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 4 - for container in containers: - container_name = container["Names"][0].strip("/") - cid = container["Id"] - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/inputs.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "[splunktcp-ssl:9997]" in std_out - assert "disabled = 0" in std_out - assert "[SSL]" in std_out - assert "serverCert = /tmp/defaults/cert.pem" in std_out - assert "[sslConfig]" not in std_out - assert "rootCA = /tmp/defaults/ca.pem" in std_out - if container_name == "cm1": - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/outputs.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "clientCert = /tmp/defaults/cert.pem" in std_out - assert "sslPassword" in std_out - assert "useClientSSLCompression = true" in std_out - # Check that data is being forwarded properly - time.sleep(30) - search_providers, distinct_hosts = self.search_internal_distinct_hosts("cm1", password=self.password) - assert len(search_providers) == 4 - assert "idx1" in search_providers - assert "idx2" in search_providers - assert "idx3" in search_providers - assert distinct_hosts == 4 - except Exception as e: - self.logger.error(e) - raise e - finally: - files = [ - os.path.join(DEFAULTS_DIR, "ca.key"), - os.path.join(DEFAULTS_DIR, "ca.csr"), - os.path.join(DEFAULTS_DIR, "ca.pem"), - os.path.join(DEFAULTS_DIR, "server.key"), - os.path.join(DEFAULTS_DIR, "server.csr"), - os.path.join(DEFAULTS_DIR, "server.pem"), - os.path.join(DEFAULTS_DIR, "cert.pem"), - os.path.join(DEFAULTS_DIR, "default.yml") - ] - self.cleanup_files(files) - - def test_compose_3idx1cm_default_repl_factor(self): - # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Write the default.yml to a file - with open(os.path.join(SCENARIOS_DIR, "defaults", "default.yml"), "w") as f: - f.write(output) - # Standup deployment - try: - self.compose_file_name = "3idx1cm.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) - # Get container logs - container_mapping = {"cm1": "cm", "idx1": "idx", "idx2": "idx", "idx3": "idx"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2", "idx3"] - assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] - except KeyError as e: - self.logger.error(e) - raise e - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed, and shcluster is setup properly - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 4 - for container in containers: - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name == "cm1": - # Check the replication factor & search factor - url = "https://localhost:{}/services/cluster/config/config?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - assert json.loads(content)["entry"][0]["content"]["replication_factor"] == 3 - assert json.loads(content)["entry"][0]["content"]["search_factor"] == 3 - except Exception as e: - self.logger.error(e) - raise e - finally: - try: - os.remove(os.path.join(SCENARIOS_DIR, "defaults", "default.yml")) - except OSError as e: - pass - - def test_compose_3idx1cm_custom_repl_factor(self): - # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") - self.client.start(cid.get("Id")) - output = self.get_container_logs(cid.get("Id")) - self.client.remove_container(cid.get("Id"), v=True, force=True) - # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Change repl factor & search factor - output = re.sub(r' replication_factor: 3', r''' replication_factor: 2''', output) - output = re.sub(r' search_factor: 3', r''' search_factor: 1''', output) - # Write the default.yml to a file - with open(os.path.join(SCENARIOS_DIR, "defaults", "default.yml"), "w") as f: - f.write(output) - # Standup deployment + def test_adhoc_1uf_splunk_pass4symmkey(self): + # Create a splunk container + cid = None try: - self.compose_file_name = "3idx1cm.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) - # Get container logs - container_mapping = {"cm1": "cm", "idx1": "idx", "idx2": "idx", "idx3": "idx"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2", "idx3"] - assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] - except KeyError as e: - self.logger.error(e) - raise e - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed, and shcluster is setup properly - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 4 - for container in containers: - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name == "cm1": - # Check the replication factor & search factor - url = "https://localhost:{}/services/cluster/config/config?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - assert json.loads(content)["entry"][0]["content"]["replication_factor"] == 2 - assert json.loads(content)["entry"][0]["content"]["search_factor"] == 1 + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_PASS4SYMMKEY": "wubbalubbadubdub" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Check the decrypted pass4SymmKey + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + pass4SymmKey = re.search(r'\[general\].*?pass4SymmKey = (.*?)\n', std_out, flags=re.MULTILINE|re.DOTALL).group(1).strip() + exec_command = self.client.exec_create(cid, "/opt/splunkforwarder/bin/splunk show-decrypted --value '{}'".format(pass4SymmKey), user="splunk") + std_out = self.client.exec_start(exec_command) + assert "wubbalubbadubdub" in std_out except Exception as e: self.logger.error(e) raise e finally: - try: - os.remove(os.path.join(SCENARIOS_DIR, "defaults", "default.yml")) - except OSError as e: - pass - - def test_compose_1so1cm_connected(self): - # Standup deployment - self.compose_file_name = "1so1cm_connected.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"so1": "so", "cm1": "cm"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check connections - containers = self.client.containers(filters={"label": "com.docker.compose.service={}".format("cm1")}) - splunkd_port = self.client.port(containers[0]["Id"], 8089)[0]["HostPort"] - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert len(output["entry"]) == 2 - for sh in output["entry"]: - assert sh["content"]["label"] in ["cm1", "so1"] - assert sh["content"]["status"] == "Connected" - - def test_compose_1so1cm_unconnected(self): - # Standup deployment - self.compose_file_name = "1so1cm_unconnected.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"so1": "so", "cm1": "cm"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check connections - containers = self.client.containers(filters={"label": "com.docker.compose.service={}".format("cm1")}) - splunkd_port = self.client.port(containers[0]["Id"], 8089)[0]["HostPort"] - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - assert len(output["entry"]) == 1 - assert output["entry"][0]["content"]["label"] == "cm1" - assert output["entry"][0]["content"]["status"] == "Connected" + if cid: + self.client.remove_container(cid, v=True, force=True) - def test_adhoc_1cm_idxc_pass4symmkey(self): - # Create the container + def test_adhoc_1uf_splunk_secret_env(self): + # Create a uf container cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, - environment={ + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, + environment={ "DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": self.password, - "SPLUNK_ROLE": "splunk_cluster_master", - "SPLUNK_INDEXER_URL": "idx1", - "SPLUNK_IDXC_PASS4SYMMKEY": "keepsummerbeingliketotallystokedaboutlikethegeneralvibeandstuff", - "SPLUNK_IDXC_LABEL": "keepsummersafe", + "SPLUNK_SECRET": "wubbalubbadubdub" }, - host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") self.client.start(cid) @@ -3697,14 +2450,10 @@ def test_adhoc_1cm_idxc_pass4symmkey(self): kwargs = {"auth": ("admin", self.password), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check if the cluster label and pass4SymmKey line up - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert "cluster_label = keepsummersafe" in std_out - pass4SymmKey = re.search(r'\[clustering\].*?pass4SymmKey = (.*?)\n', std_out, flags=re.MULTILINE|re.DOTALL).group(1).strip() - exec_command = self.client.exec_create(cid, "/opt/splunk/bin/splunk show-decrypted --value '{}'".format(pass4SymmKey), user="splunk") + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/auth/splunk.secret", user="splunk") std_out = self.client.exec_start(exec_command) - assert "keepsummerbeingliketotallystokedaboutlikethegeneralvibeandstuff" in std_out + assert "wubbalubbadubdub" in std_out except Exception as e: self.logger.error(e) raise e @@ -3712,43 +2461,33 @@ def test_adhoc_1cm_idxc_pass4symmkey(self): if cid: self.client.remove_container(cid, v=True, force=True) - def test_compose_1cm_smartstore(self): + def test_adhoc_1uf_bind_mount_apps(self): # Generate default.yml - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + splunk_container_name = self.generate_random_string() + self.project_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + DIR_EXAMPLE_APP = os.path.join(self.DIR, "splunk_app_example") + copytree(self.EXAMPLE_APP, DIR_EXAMPLE_APP) + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) # Get the password - password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() - assert password and password != "null" - # Add a custom conf file - output = re.sub(r' smartstore: null', r''' smartstore: - index: - - indexName: default - remoteName: remote_vol - scheme: s3 - remoteLocation: smartstore-test - s3: - access_key: abcd - secret_key: 1234 - endpoint: https://s3-region.amazonaws.com''', output) + p = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() + assert p and p != "null" # Write the default.yml to a file - with open(os.path.join(FIXTURES_DIR, "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) # Create the container and mount the default.yml cid = None try: - splunk_container_name = generate_random_string() - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], - volumes=["/tmp/defaults/default.yml"], name=splunk_container_name, - environment={ - "DEBUG": "true", - "SPLUNK_START_ARGS": "--accept-license", - "SPLUNK_PASSWORD": self.password, - "SPLUNK_ROLE": "splunk_cluster_master", - "SPLUNK_INDEXER_URL": "idx1" - }, - host_config=self.client.create_host_config(binds=[FIXTURES_DIR + "/default.yml:/tmp/defaults/default.yml"], + # Spin up this container, but also bind-mount the app in the fixtures directory + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start-service", ports=[8089], + volumes=["/tmp/defaults/", "/opt/splunkforwarder/etc/apps/splunk_app_example/"], name=splunk_container_name, + environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/", + DIR_EXAMPLE_APP + ":/opt/splunkforwarder/etc/apps/splunk_app_example/"], port_bindings={8089: ("0.0.0.0",)}) ) cid = cid.get("Id") @@ -3756,22 +2495,16 @@ def test_compose_1cm_smartstore(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd + assert self.check_splunkd("admin", p) + # Check the app endpoint splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] - url = "https://localhost:{}/services/server/info".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} + url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) + kwargs = {"auth": ("admin", p), "verify": False} status, content = self.handle_request_retry("GET", url, kwargs) assert status == 200 - # Check if the created file exists - exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/master-apps/_cluster/local/indexes.conf", user="splunk") - std_out = self.client.exec_start(exec_command) - assert 'remotePath = volume:remote_vol/$_index_name' in std_out - assert 'repFactor = auto' in std_out - assert '[volume:remote_vol]' in std_out - assert 'storageType = remote' in std_out - assert 'path = s3://smartstore-test' in std_out - assert 'remote.s3.access_key = abcd' in std_out - assert 'remote.s3.secret_key = 1234' in std_out - assert 'remote.s3.endpoint = https://s3-region.amazonaws.com' in std_out + # Let's go further and check app version + output = json.loads(content) + assert output["entry"][0]["content"]["version"] == "0.0.1" except Exception as e: self.logger.error(e) raise e @@ -3779,312 +2512,148 @@ def test_compose_1cm_smartstore(self): if cid: self.client.remove_container(cid, v=True, force=True) try: - os.remove(os.path.join(FIXTURES_DIR, "default.yml")) + os.remove(os.path.join(self.DIR, "default.yml")) except OSError: pass - def test_compose_1sh1cm(self): - # Standup deployment - self.compose_file_name = "1sh1cm.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"sh1": "sh", "cm1": "cm"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check connections - containers = self.client.containers(filters={"label": "com.docker.compose.service={}".format("cm1")}) - splunkd_port = self.client.port(containers[0]["Id"], 8089)[0]["HostPort"] - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - # There's only 1 "standalone" search head connected and 1 cluster master - assert len(output["entry"]) == 2 - for sh in output["entry"]: - assert sh["content"]["label"] == "sh1" or sh["content"]["label"] == "cm1" - assert sh["content"]["status"] == "Connected" - - def test_compose_1sh1cm1dmc(self): - # Standup deployment - self.compose_file_name = "1sh1cm1dmc.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - self.check_dmc(containers, 2, 0, 2, 1, 3) - - def test_compose_1sh2idx2hf1dmc(self): - # Standup deployment - self.compose_file_name = "1sh2idx2hf1dmc.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - self.check_dmc(containers, 3, 2, 2, 0, 4) - - def test_compose_3idx1cm1dmc(self): - # Standup deployment - self.compose_file_name = "3idx1cm1dmc.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - self.check_dmc(containers, 4, 3, 2, 1, 5) - - def test_compose_1uf1so1dmc(self): - # Standup deployment - self.compose_file_name = "1uf1so1dmc.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - self.check_dmc(containers, 1, 1, 1, 0, 2) - - def test_compose_1so1dmc(self): - # Standup deployment - self.compose_file_name = "1so1dmc.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - self.check_dmc(containers, 1, 1, 1, 0, 2) - - def test_compose_2idx2sh(self): - # Standup deployment - self.compose_file_name = "2idx2sh.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"sh1": "sh", "sh2": "sh", "idx1": "idx", "idx2": "idx"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2"] - assert inventory_json["splunk_search_head"]["hosts"] == ["sh1", "sh2"] - except KeyError as e: - self.logger.error(e) - raise e - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Check connections - idx_list = ["idx1", "idx2"] - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - for container in containers: - c_name = container["Labels"]["com.docker.compose.service"] - if c_name == "sh1" or c_name == "sh2": - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - url = "https://localhost:{}/services/search/distributed/peers?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - output = json.loads(content) - peers = [x["content"]["peerName"] for x in output["entry"]] - assert len(peers) == 2 and set(peers) == set(idx_list) - # Search results won't return the correct results immediately :( - time.sleep(30) - search_providers, distinct_hosts = self.search_internal_distinct_hosts("sh1", password=self.password) - assert len(search_providers) == 3 - assert "idx1" in search_providers and "idx2" in search_providers and "sh1" in search_providers - assert distinct_hosts == 4 - - def test_compose_2idx2sh1dmc(self): - # Standup deployment - self.compose_file_name = "2idx2sh1dmc.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - self.check_dmc(containers, 4, 2, 3, 0, 5) + def test_uf_scloud(self): + cid = None + try: + # Run container + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="no-provision") + cid = cid.get("Id") + self.client.start(cid) + # Wait a bit + time.sleep(5) + # If the container is still running, we should be able to exec inside + # Check that the version returns successfully for multiple users + exec_command = self.client.exec_create(cid, "scloud version", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "scloud version " in std_out + exec_command = self.client.exec_create(cid, "scloud version", user="ansible") + std_out = self.client.exec_start(exec_command) + assert "scloud version " in std_out + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) - def test_compose_1idx3sh1cm1dep(self): - # Generate default.yml -- for SHC, we need a common default.yml otherwise things won't work - cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") + def test_adhoc_1uf_custom_conf(self): + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) + os.mkdir(self.DIR) + # Generate default.yml + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) output = self.get_container_logs(cid.get("Id")) self.client.remove_container(cid.get("Id"), v=True, force=True) # Get the password password = re.search(r"^ password: (.*?)\n", output, flags=re.MULTILINE|re.DOTALL).group(1).strip() assert password and password != "null" + # Add a custom conf file + output = re.sub(r' group: splunk', r''' group: splunk + conf: + user-prefs: + directory: /opt/splunkforwarder/etc/users/admin/user-prefs/local + content: + general: + default_namespace: appboilerplate + search_syntax_highlighting: dark''', output) # Write the default.yml to a file - with open(os.path.join(SCENARIOS_DIR, "defaults", "default.yml"), "w") as f: + with open(os.path.join(self.DIR, "default.yml"), "w") as f: f.write(output) - # Tar the app before spinning up the scenario - with tarfile.open(EXAMPLE_APP_TGZ, "w:gz") as tar: - tar.add(EXAMPLE_APP, arcname=os.path.basename(EXAMPLE_APP)) - # Standup deployment + # Create the container and mount the default.yml + cid = None try: - self.compose_file_name = "1idx3sh1cm1dep.yaml" - self.project_name = generate_random_string() - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name), timeout=600) - # Get container logs - container_mapping = {"sh1": "sh", "sh2": "sh", "sh3": "sh", "cm1": "cm", "idx1": "idx", "dep1": "dep"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_indexer"]["hosts"] == ["idx1"] - assert inventory_json["splunk_search_head_captain"]["hosts"] == ["sh1"] - assert inventory_json["splunk_search_head"]["hosts"] == ["sh2", "sh3"] - assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] - assert inventory_json["splunk_deployer"]["hosts"] == ["dep1"] - except KeyError as e: - self.logger.error(e) - raise e - # Check Splunkd on all the containers - assert self.check_splunkd("admin", self.password) - # Make sure apps are installed, and shcluster is setup properly - containers = self.client.containers(filters={"label": "com.docker.compose.project={}".format(self.project_name)}) - assert len(containers) == 7 - for container in containers: - # Skip the nginx container - if "nginx" in container["Image"]: - continue - container_name = container["Names"][0].strip("/") - splunkd_port = self.client.port(container["Id"], 8089)[0]["HostPort"] - if container_name in {"sh1", "sh2", "sh3", "idx1"}: - # Check the app and version - url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert status == 200 - assert json.loads(content)["entry"][0]["content"]["version"] == "0.0.1" - # Make sure preferred captain is set - if container_name == "sh1": - url = "https://localhost:{}/servicesNS/nobody/system/configs/conf-server/shclustering?output_mode=json".format(splunkd_port) - kwargs = {"auth": ("admin", self.password), "verify": False} - status, content = self.handle_request_retry("GET", url, kwargs) - assert json.loads(content)["entry"][0]["content"]["preferred_captain"] == "1" - # Search results won't return the correct results immediately :( - time.sleep(30) - RETRIES = 10 - IMPLICIT_WAIT = 6 - for n in range(RETRIES): - try: - self.logger.info("Attempt #{}: checking internal search host count".format(n+1)) - search_providers, distinct_hosts = self.search_internal_distinct_hosts("sh1", password=self.password) - assert len(search_providers) == 2 - assert "idx1" in search_providers and "sh1" in search_providers - assert distinct_hosts == 6 - break - except Exception as e: - self.logger.error("Attempt #{} error: {}".format(n+1, str(e))) - if n < RETRIES-1: - time.sleep(IMPLICIT_WAIT) - continue - raise e + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="start", ports=[8089], + volumes=["/tmp/defaults/"], name=splunk_container_name, + environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license"}, + host_config=self.client.create_host_config(binds=[self.DIR + ":/tmp/defaults/"], + port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Check if the created file exists + exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/users/admin/user-prefs/local/user-prefs.conf", user="splunk") + std_out = self.client.exec_start(exec_command) + assert "[general]" in std_out + assert "default_namespace = appboilerplate" in std_out + assert "search_syntax_highlighting = dark" in std_out except Exception as e: self.logger.error(e) raise e finally: + if cid: + self.client.remove_container(cid, v=True, force=True) try: - os.remove(EXAMPLE_APP_TGZ) - os.remove(os.path.join(SCENARIOS_DIR, "defaults", "default.yml")) - except OSError as e: + os.remove(os.path.join(self.DIR, "default.yml")) + rmtree(self.DIR) + except OSError: pass - def test_compose_2idx2sh1cm(self): + def test_adhoc_1uf_run_as_root(self): + # Create a uf container + cid = None + try: + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], name=splunk_container_name, user="root", + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_PASSWORD": self.password, + "SPLUNK_USER": "root", + "SPLUNK_GROUP": "root" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Poll for the container to be ready + assert self.wait_for_containers(1, name=splunk_container_name) + # Check splunkd + splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] + url = "https://localhost:{}/services/server/info".format(splunkd_port) + kwargs = {"auth": ("admin", self.password), "verify": False} + status, content = self.handle_request_retry("GET", url, kwargs) + assert status == 200 + # Check that root owns the splunkd process + exec_command = self.client.exec_create(cid, "ps -u root", user="root") + std_out = self.client.exec_start(exec_command) + assert "entrypoint.sh" in std_out + assert "splunkd" in std_out + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_compose_1hf_splunk_add(self): + # Check that SPLUNK_ADD works for splunk image (role=heavy forwarder) # Standup deployment - self.compose_file_name = "2idx2sh1cm.yaml" - self.project_name = generate_random_string() + self.compose_file_name = "1hf_splunk_add_user.yaml" + self.project_name = self.generate_random_string() container_count, rc = self.compose_up() assert rc == 0 # Wait for containers to come up assert self.wait_for_containers(container_count, label="com.docker.compose.project={}".format(self.project_name)) - # Get container logs - container_mapping = {"sh1": "sh", "sh2": "sh", "idx1": "idx", "idx2": "idx", "cm1": "cm"} - for container in container_mapping: - # Check ansible version & configs - ansible_logs = self.get_container_logs(container) - self.check_ansible(ansible_logs) - # Check values in log output - inventory_json = self.extract_json(container) - self.check_common_keys(inventory_json, container_mapping[container]) - try: - assert inventory_json["splunk_cluster_master"]["hosts"] == ["cm1"] - assert inventory_json["splunk_indexer"]["hosts"] == ["idx1", "idx2"] - assert inventory_json["splunk_search_head"]["hosts"] == ["sh1", "sh2"] - except KeyError as e: - self.logger.error(e) - raise e + # Check ansible inventory json + log_json = self.extract_json("{}_hf1_1".format(self.project_name)) + self.check_common_keys(log_json, "hf") + # Check container logs + output = self.get_container_logs("{}_hf1_1".format(self.project_name)) + self.check_ansible(output) # Check Splunkd on all the containers assert self.check_splunkd("admin", self.password) - # Check connections - idx_list = ["idx1", "idx2"] - sh_list = ["sh1", "sh2", "cm1"] - - containers = self.client.containers(filters={"label": "com.docker.compose.service={}".format("cm1")}) - splunkd_port = self.client.port(containers[0]["Id"], 8089)[0]["HostPort"] - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/searchheads?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - for sh in output["entry"]: - if sh["content"]["label"] in sh_list and sh["content"]["status"] == "Connected": - sh_list.remove(sh["content"]["label"]) - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/peers?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - for idx in output["entry"]: - if idx["content"]["label"] in idx_list and idx["content"]["status"] == "Up": - idx_list.remove(idx["content"]["label"]) - assert len(idx_list) == 0 and len(sh_list) == 0 - # Add one more indexer - self.compose_file_name = "2idx2sh1cm_idx3.yaml" - container_count, rc = self.compose_up() - assert rc == 0 - # Wait for containers to come up - assert self.wait_for_containers(container_count, name="idx3") - - retries = 10 - for n in range(retries): - status, content = self.handle_request_retry("GET", "https://localhost:{}/services/cluster/master/peers?output_mode=json".format(splunkd_port), - {"auth": ("admin", self.password), "verify": False}) - assert status == 200 - output = json.loads(content) - for idx in output["entry"]: - if idx["content"]["label"] == "idx3" and idx["content"]["status"] == "Up": - break - else: - time.sleep(10) - if n < retries-1: - continue - assert False + # Check Splunkd using the new users + assert self.check_splunkd("jerry", "seinfeld") \ No newline at end of file From ff3edb4f1676f9b94df57465fd8cc2adac183da0 Mon Sep 17 00:00:00 2001 From: Henri Cook Date: Sat, 15 Aug 2020 17:51:50 +0100 Subject: [PATCH 04/10] Add Slack registration instructions to Readme (#409) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16d4724e..18a4edb0 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Use the [GitHub issue tracker](https://github.com/splunk/docker-splunk/issues) t If you have additional questions or need more support, you can: * Post a question to [Splunk Answers](http://answers.splunk.com) -* Join the [#docker](https://splunk-usergroups.slack.com/messages/C1RH09ERM/) room in the [Splunk Slack channel](http://splunk-usergroups.slack.com) +* Join the [#docker](https://splunk-usergroups.slack.com/messages/C1RH09ERM/) room in the [Splunk Slack channel](http://splunk-usergroups.slack.com). If you're a new Splunk customer you can register for Slack [here](http://splk.it/slack) * If you are a Splunk Enterprise customer with a valid support entitlement contract and have a Splunk-related question, you can also open a support case on the https://www.splunk.com/ support portal See the official [support guidelines](docs/SUPPORT.md) for more detailed information. From 7e45aae5a8316adca7cbb713caa12f62de899edd Mon Sep 17 00:00:00 2001 From: Alisha Mayor Date: Mon, 17 Aug 2020 14:34:24 -0700 Subject: [PATCH 05/10] Updating changelog for Release/7.3.7 (#411) Skipping failed tests on this docs update --- docs/CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5f8f3396..0e65e17e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,7 @@ * [8.0.2](#802) * [8.0.1](#801) * [8.0.0](#800) +* [7.3.7](#737) * [7.3.6](#736) * [7.3.5](#735) * [7.3.4.2](#7342) @@ -188,6 +189,17 @@ --- +## 7.3.7 + +#### What's New? +* New Splunk Enterprise maintenance patch. For details, see [Fixed issues for 7.3.7](https://docs.splunk.com/Documentation/Splunk/7.3.7/ReleaseNotes/Fixedissues) +* Bundling in changes to be consistent with the release of [8.0.5](#805) + +#### Changes +* See [8.0.5](#805) changes + +--- + ## 7.3.6 #### What's New? From ab38cb7cbfd6cfaa465fc853814af1825b29c73d Mon Sep 17 00:00:00 2001 From: Nelson Wang Date: Thu, 20 Aug 2020 21:18:48 -0700 Subject: [PATCH 06/10] Test/declarative password (#413) * Adding tests for declarative passwords * Fixing test issues * Changing resource class * change number of parallel processes for small test * save logger output into /test-results * output docker container logs in logs * fix docker container logging * add ansible mode 0666 * Updating timeout vals * change back wait_for_containers Co-authored-by: TheCamNelson --- .circleci/config.yml | 6 +- Makefile | 8 +- tests/executor.py | 2 +- tests/fixtures/sudo_touch_dummy_file.yml | 1 + tests/test_single_splunk_image.py | 200 +++++++++++++++++------ 5 files changed, 164 insertions(+), 53 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a817e8c0..7ae8fedc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,6 +35,7 @@ jobs: debian10-testing: machine: image: circleci/classic:latest + resource_class: xlarge steps: - checkout - run: @@ -67,7 +68,7 @@ jobs: - run: name: Run large Debian 10 image tests command: make run_large_tests_debian10 - no_output_timeout: 20m + no_output_timeout: 1h - store_artifacts: path: test-results destination: test-results @@ -76,6 +77,7 @@ jobs: redhat8-testing: machine: image: circleci/classic:latest + resource_class: xlarge steps: - checkout - run: @@ -105,7 +107,7 @@ jobs: - run: name: Run large Redhat 8 image tests command: make run_large_tests_redhat8 - no_output_timeout: 20m + no_output_timeout: 1h - store_artifacts: path: test-results destination: test-results diff --git a/Makefile b/Makefile index bc98abef..65899a3d 100644 --- a/Makefile +++ b/Makefile @@ -305,7 +305,7 @@ test_debian10: clean ansible splunk-debian-10 uf-debian-10 test_setup run_small_ run_small_tests_centos7: @echo 'Running the super awesome small tests; CentOS 7' - pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform centos-7 --junitxml test-results/centos7-result/testresults_small_centos7.xml + pytest -n 2 --reruns 1 -sv tests/test_single_splunk_image.py --platform centos-7 --junitxml test-results/centos7-result/testresults_small_centos7.xml run_large_tests_centos7: @echo 'Running the super awesome large tests; CentOS 7' @@ -313,7 +313,7 @@ run_large_tests_centos7: run_small_tests_redhat8: @echo 'Running the super awesome small tests; RedHat 8' - pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform redhat-8 --junitxml test-results/redhat8-result/testresults_small_redhat8.xml + pytest -n 2 --reruns 1 -sv tests/test_single_splunk_image.py --platform redhat-8 --junitxml test-results/redhat8-result/testresults_small_redhat8.xml run_large_tests_redhat8: @echo 'Running the super awesome large tests; RedHat 8' @@ -330,7 +330,7 @@ test_setup: run_small_tests_debian9: @echo 'Running the super awesome small tests; Debian 9' - pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform debian-9 --junitxml test-results/debian9-result/testresults_small_debian9.xml + pytest -n 2 --reruns 1 -sv tests/test_single_splunk_image.py --platform debian-9 --junitxml test-results/debian9-result/testresults_small_debian9.xml run_large_tests_debian9: @echo 'Running the super awesome large tests; Debian 9' @@ -338,7 +338,7 @@ run_large_tests_debian9: run_small_tests_debian10: @echo 'Running the super awesome small tests; Debian 10' - pytest -n 3 --reruns 1 -sv tests/test_single_splunk_image.py --platform debian-10 --junitxml test-results/debian10-result/testresults_small_debian10.xml + pytest -n 2 --reruns 1 -sv tests/test_single_splunk_image.py --platform debian-10 --junitxml test-results/debian10-result/testresults_small_debian10.xml run_large_tests_debian10: @echo 'Running the super awesome large tests; Debian 10' diff --git a/tests/executor.py b/tests/executor.py index 1d511eb6..1b8fd1cd 100644 --- a/tests/executor.py +++ b/tests/executor.py @@ -30,7 +30,7 @@ # Setup logging LOGGER = logging.getLogger("docker-splunk") LOGGER.setLevel(logging.INFO) -file_handler = logging.handlers.RotatingFileHandler(os.path.join(FILE_DIR, "docker_splunk_test_python{}.log".format(sys.version_info[0])), maxBytes=25000000) +file_handler = logging.handlers.RotatingFileHandler(os.path.join(FILE_DIR, "..", "test-results", "docker_splunk_test_python{}.log".format(sys.version_info[0])), maxBytes=25000000) formatter = logging.Formatter('%(asctime)s %(levelname)s [%(name)s] [%(process)d] %(message)s') file_handler.setFormatter(formatter) LOGGER.addHandler(file_handler) diff --git a/tests/fixtures/sudo_touch_dummy_file.yml b/tests/fixtures/sudo_touch_dummy_file.yml index d2eba3e9..9e4964ba 100644 --- a/tests/fixtures/sudo_touch_dummy_file.yml +++ b/tests/fixtures/sudo_touch_dummy_file.yml @@ -5,5 +5,6 @@ dest: /tmp/i-am owner: root group: root + mode: 0666 become: yes become_user: root diff --git a/tests/test_single_splunk_image.py b/tests/test_single_splunk_image.py index 8dfd30a7..200c8482 100644 --- a/tests/test_single_splunk_image.py +++ b/tests/test_single_splunk_image.py @@ -835,6 +835,118 @@ def test_adhoc_1so_run_as_root(self): self.client.remove_container(cid, v=True, force=True) + def test_adhoc_1so_declarative_password(self): + """ + This test is intended to check how the container gets provisioned with declarative passwords + """ + # Create a splunk container + cid = None + try: + # Start the container using no-provision, otherwise we can't mutate the password + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089], + name=splunk_container_name, + command="no-provision", + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_DECLARATIVE_ADMIN_PASSWORD": "true" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Create a new /tmp/defaults/default.yml to change desired HEC settings + exec_command = self.client.exec_create(cid, "mkdir -p /tmp/defaults", user="splunk") + self.client.exec_start(exec_command) + exec_command = self.client.exec_create(cid, "touch /tmp/defaults/default.yml", user="splunk") + self.client.exec_start(exec_command) + exec_command = self.client.exec_create(cid, '''bash -c 'cat > /tmp/defaults/default.yml << EOL +splunk: + password: thisisarealpassword123 +EOL' +''', user="splunk") + self.client.exec_start(exec_command) + # Execute ansible + exec_command = self.client.exec_create(cid, "/sbin/entrypoint.sh start-and-exit") + std_out = self.client.exec_start(exec_command) + # Check splunk with the initial password + assert self.check_splunkd("admin", "thisisarealpassword123", name=splunk_container_name) + # Mutate the password so that ansible changes it on the next run + exec_command = self.client.exec_create(cid, '''bash -c 'cat > /tmp/defaults/default.yml << EOL +splunk: + password: thisisadifferentpw456 +EOL' +''', user="splunk") + self.client.exec_start(exec_command) + # Execute ansible again + exec_command = self.client.exec_create(cid, "/sbin/entrypoint.sh start-and-exit") + stdout = self.client.exec_start(exec_command) + # Check splunk with the initial password + assert self.check_splunkd("admin", "thisisadifferentpw456", name=splunk_container_name) + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + + def test_adhoc_1uf_declarative_password(self): + """ + This test is intended to check how the container gets provisioned with declarative passwords + """ + # Create a splunk container + cid = None + try: + # Start the container using no-provision, otherwise we can't mutate the password + splunk_container_name = self.generate_random_string() + cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089], + name=splunk_container_name, + command="no-provision", + environment={ + "DEBUG": "true", + "SPLUNK_START_ARGS": "--accept-license", + "SPLUNK_DECLARATIVE_ADMIN_PASSWORD": "true" + }, + host_config=self.client.create_host_config(port_bindings={8089: ("0.0.0.0",)}) + ) + cid = cid.get("Id") + self.client.start(cid) + # Create a new /tmp/defaults/default.yml to change desired HEC settings + exec_command = self.client.exec_create(cid, "mkdir -p /tmp/defaults", user="splunk") + self.client.exec_start(exec_command) + exec_command = self.client.exec_create(cid, "touch /tmp/defaults/default.yml", user="splunk") + self.client.exec_start(exec_command) + exec_command = self.client.exec_create(cid, '''bash -c 'cat > /tmp/defaults/default.yml << EOL +splunk: + password: thisisarealpassword123 +EOL' +''', user="splunk") + self.client.exec_start(exec_command) + # Execute ansible + exec_command = self.client.exec_create(cid, "/sbin/entrypoint.sh start-and-exit") + std_out = self.client.exec_start(exec_command) + # Check splunk with the initial password + assert self.check_splunkd("admin", "thisisarealpassword123", name=splunk_container_name) + # Mutate the password so that ansible changes it on the next run + exec_command = self.client.exec_create(cid, '''bash -c 'cat > /tmp/defaults/default.yml << EOL +splunk: + password: thisisadifferentpw456 +EOL' +''', user="splunk") + self.client.exec_start(exec_command) + # Execute ansible again + exec_command = self.client.exec_create(cid, "/sbin/entrypoint.sh start-and-exit") + stdout = self.client.exec_start(exec_command) + # Check splunk with the initial password + assert self.check_splunkd("admin", "thisisadifferentpw456", name=splunk_container_name) + except Exception as e: + self.logger.error(e) + raise e + finally: + if cid: + self.client.remove_container(cid, v=True, force=True) + def test_adhoc_1so_hec_idempotence(self): """ This test is intended to check how the container gets provisioned with changing splunk.hec.* parameters @@ -843,7 +955,6 @@ def test_adhoc_1so_hec_idempotence(self): cid = None try: splunk_container_name = self.generate_random_string() - self.project_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8088, 9999], name=splunk_container_name, environment={ @@ -858,7 +969,7 @@ def test_adhoc_1so_hec_idempotence(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check that HEC endpoint is up - by default, the image will enable HEC exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -871,6 +982,8 @@ def test_adhoc_1so_hec_idempotence(self): # Create a new /tmp/defaults/default.yml to change desired HEC settings exec_command = self.client.exec_create(cid, "mkdir -p /tmp/defaults", user="splunk") self.client.exec_start(exec_command) + exec_command = self.client.exec_create(cid, "touch /tmp/defaults/default.yml", user="splunk") + self.client.exec_start(exec_command) exec_command = self.client.exec_create(cid, '''bash -c 'cat > /tmp/defaults/default.yml << EOL splunk: hec: @@ -883,7 +996,7 @@ def test_adhoc_1so_hec_idempotence(self): # Restart the container - it should pick up the new HEC settings in /tmp/defaults/default.yml self.client.restart(splunk_container_name) assert self.wait_for_containers(1, name=splunk_container_name) - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check the new HEC settings exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -916,7 +1029,7 @@ def test_adhoc_1so_hec_idempotence(self): # Restart the container - it should pick up the new HEC settings in /tmp/defaults/default.yml self.client.restart(splunk_container_name) assert self.wait_for_containers(1, name=splunk_container_name) - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check the new HEC settings exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -947,7 +1060,7 @@ def test_adhoc_1so_hec_idempotence(self): # Restart the container - it should pick up the new HEC settings in /tmp/defaults/default.yml self.client.restart(splunk_container_name) assert self.wait_for_containers(1, name=splunk_container_name) - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check the new HEC settings exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -971,7 +1084,7 @@ def test_adhoc_1so_hec_idempotence(self): # Restart the container - it should pick up the new HEC settings in /tmp/defaults/default.yml self.client.restart(splunk_container_name) assert self.wait_for_containers(1, name=splunk_container_name) - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check the new HEC settings exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -992,7 +1105,6 @@ def test_adhoc_1so_hec_ssl_disabled(self): cid = None try: splunk_container_name = self.generate_random_string() - self.project_name = self.generate_random_string() cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8089, 8088], name=splunk_container_name, environment={ @@ -1009,7 +1121,7 @@ def test_adhoc_1so_hec_ssl_disabled(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check HEC hec_port = self.client.port(cid, 8088)[0]["HostPort"] url = "http://localhost:{}/services/collector/event".format(hec_port) @@ -1025,7 +1137,6 @@ def test_adhoc_1so_hec_ssl_disabled(self): def test_adhoc_1so_splunkd_no_ssl(self): # Generate default.yml - self.project_name = self.generate_random_string() splunk_container_name = self.generate_random_string() self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) @@ -1062,7 +1173,7 @@ def test_adhoc_1so_splunkd_no_ssl(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", p, scheme="http") + assert self.check_splunkd("admin", p, name=splunk_container_name, scheme="http") # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -1087,7 +1198,6 @@ def test_adhoc_1so_splunkd_no_ssl(self): def test_adhoc_1so_web_ssl(self): # Create the container splunk_container_name = self.generate_random_string() - self.project_name = self.generate_random_string() self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = None @@ -1113,7 +1223,7 @@ def test_adhoc_1so_web_ssl(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check splunkweb web_port = self.client.port(cid, 8000)[0]["HostPort"] url = "https://localhost:{}/".format(web_port) @@ -1267,8 +1377,8 @@ def test_compose_1so_enable_service(self): def test_adhoc_1so_hec_custom_cert(self): # Generate default.yml - self.project_name = self.generate_random_string() - self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) @@ -1304,7 +1414,7 @@ def test_adhoc_1so_hec_custom_cert(self): try: password = "helloworld" cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8088, 8089], - volumes=["/tmp/defaults/"], name=self.project_name, + volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, @@ -1314,9 +1424,9 @@ def test_adhoc_1so_hec_custom_cert(self): cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=self.project_name) + assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) + assert self.check_splunkd("admin", password, name=splunk_container_name) # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -1342,8 +1452,8 @@ def test_adhoc_1so_hec_custom_cert(self): def test_adhoc_1so_splunktcp_ssl(self): # Generate default.yml - self.project_name = self.generate_random_string() - self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) @@ -1380,7 +1490,7 @@ def test_adhoc_1so_splunktcp_ssl(self): cid = None try: cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=self.project_name, + volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, @@ -1390,9 +1500,9 @@ def test_adhoc_1so_splunktcp_ssl(self): cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=self.project_name) + assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) + assert self.check_splunkd("admin", password, name=splunk_container_name) # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -1411,8 +1521,8 @@ def test_adhoc_1so_splunktcp_ssl(self): def test_adhoc_1so_splunkd_custom_ssl(self): # Generate default.yml - self.project_name = self.generate_random_string() - self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) @@ -1448,7 +1558,7 @@ def test_adhoc_1so_splunkd_custom_ssl(self): cid = None try: cid = self.client.create_container(self.SPLUNK_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=self.project_name, + volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, @@ -1458,9 +1568,9 @@ def test_adhoc_1so_splunkd_custom_ssl(self): cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=self.project_name) + assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) + assert self.check_splunkd("admin", password, name=splunk_container_name) # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunk/etc/system/local/server.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -1833,8 +1943,8 @@ def test_uf_uid_gid(self): def test_adhoc_1uf_splunktcp_ssl(self): # Generate default.yml - self.project_name = self.generate_random_string() - self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) @@ -1871,7 +1981,7 @@ def test_adhoc_1uf_splunktcp_ssl(self): cid = None try: cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=self.project_name, + volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, @@ -1881,9 +1991,9 @@ def test_adhoc_1uf_splunktcp_ssl(self): cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=self.project_name) + assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) + assert self.check_splunkd("admin", password, name=splunk_container_name) # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -1902,8 +2012,8 @@ def test_adhoc_1uf_splunktcp_ssl(self): def test_adhoc_1uf_splunkd_custom_ssl(self): # Generate default.yml - self.project_name = self.generate_random_string() - self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) @@ -1939,7 +2049,7 @@ def test_adhoc_1uf_splunkd_custom_ssl(self): cid = None try: cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8000, 8089], - volumes=["/tmp/defaults/"], name=self.project_name, + volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, @@ -1949,7 +2059,7 @@ def test_adhoc_1uf_splunkd_custom_ssl(self): cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=self.project_name) + assert self.wait_for_containers(1, name=splunk_container_name) # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -1974,8 +2084,8 @@ def test_adhoc_1uf_splunkd_custom_ssl(self): def test_adhoc_1uf_hec_custom_cert(self): # Generate default.yml - self.project_name = self.generate_random_string() - self.DIR = os.path.join(self.FIXTURES_DIR, self.project_name) + splunk_container_name = self.generate_random_string() + self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, command="create-defaults") self.client.start(cid.get("Id")) @@ -2011,7 +2121,7 @@ def test_adhoc_1uf_hec_custom_cert(self): try: password = "helloworld" cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8088, 8089], - volumes=["/tmp/defaults/"], name=self.project_name, + volumes=["/tmp/defaults/"], name=splunk_container_name, environment={"DEBUG": "true", "SPLUNK_START_ARGS": "--accept-license", "SPLUNK_PASSWORD": password}, @@ -2021,9 +2131,9 @@ def test_adhoc_1uf_hec_custom_cert(self): cid = cid.get("Id") self.client.start(cid) # Poll for the container to be ready - assert self.wait_for_containers(1, name=self.project_name) + assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", password) + assert self.check_splunkd("admin", password, name=splunk_container_name) # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/apps/splunk_httpinput/local/inputs.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -2081,7 +2191,6 @@ def test_compose_1uf_enable_service(self): def test_adhoc_1uf_splunkd_no_ssl(self): # Generate default.yml - self.project_name = self.generate_random_string() splunk_container_name = self.generate_random_string() self.DIR = os.path.join(self.FIXTURES_DIR, splunk_container_name) os.mkdir(self.DIR) @@ -2118,7 +2227,7 @@ def test_adhoc_1uf_splunkd_no_ssl(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", p, scheme="http") + assert self.check_splunkd("admin", p, name=splunk_container_name, scheme="http") # Check if the created file exists exec_command = self.client.exec_create(cid, "cat /opt/splunkforwarder/etc/system/local/server.conf", user="splunk") std_out = self.client.exec_start(exec_command) @@ -2255,7 +2364,6 @@ def test_adhoc_1uf_hec_ssl_disabled(self): cid = None try: splunk_container_name = self.generate_random_string() - self.project_name = self.generate_random_string() cid = self.client.create_container(self.UF_IMAGE_NAME, tty=True, ports=[8089, 8088], name=splunk_container_name, environment={ @@ -2272,7 +2380,7 @@ def test_adhoc_1uf_hec_ssl_disabled(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", self.password) + assert self.check_splunkd("admin", self.password, name=splunk_container_name) # Check HEC hec_port = self.client.port(cid, 8088)[0]["HostPort"] url = "http://localhost:{}/services/collector/event".format(hec_port) @@ -2495,7 +2603,7 @@ def test_adhoc_1uf_bind_mount_apps(self): # Poll for the container to be ready assert self.wait_for_containers(1, name=splunk_container_name) # Check splunkd - assert self.check_splunkd("admin", p) + assert self.check_splunkd("admin", p, name=splunk_container_name) # Check the app endpoint splunkd_port = self.client.port(cid, 8089)[0]["HostPort"] url = "https://localhost:{}/servicesNS/nobody/splunk_app_example/configs/conf-app/launcher?output_mode=json".format(splunkd_port) From bb6e278ed6ddebb5f2eaac48eee92d45b91521a9 Mon Sep 17 00:00:00 2001 From: Nelson Wang Date: Tue, 25 Aug 2020 17:23:18 -0700 Subject: [PATCH 07/10] Changing etc backup directory so its not tied to SPLUNK_HOME (#410) * Changing etc backup directory so its not tied to SPLUNK_HOME * Applying fix for uf as well --- splunk/common-files/updateetc.sh | 10 ++++++---- uf/common-files/Dockerfile | 2 +- uf/common-files/updateetc.sh | 31 +++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) create mode 100755 uf/common-files/updateetc.sh diff --git a/splunk/common-files/updateetc.sh b/splunk/common-files/updateetc.sh index 7e2212b9..5af27a64 100755 --- a/splunk/common-files/updateetc.sh +++ b/splunk/common-files/updateetc.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2018 Splunk +# Copyright 2018-2020 Splunk # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,8 +15,10 @@ # limitations under the License. # -if [[ -f "${SPLUNK_HOME}-etc/splunk.version" ]]; then - IMAGE_VERSION_SHA=`cat ${SPLUNK_HOME}-etc/splunk.version | sha512sum` +SPLUNK_ETC_BAK="${SPLUNK_ETC_BAK:-/opt/splunk-etc}" + +if [[ -f "${SPLUNK_ETC_BAK}/splunk.version" ]]; then + IMAGE_VERSION_SHA=`cat ${SPLUNK_ETC_BAK}/splunk.version | sha512sum` if [[ -f "${SPLUNK_HOME}/etc/splunk.version" ]]; then ETC_VERSION_SHA=`cat ${SPLUNK_HOME}/etc/splunk.version | sha512sum` @@ -24,6 +26,6 @@ if [[ -f "${SPLUNK_HOME}-etc/splunk.version" ]]; then if [[ "x${IMAGE_VERSION_SHA}" != "x${ETC_VERSION_SHA}" ]]; then echo Updating ${SPLUNK_HOME}/etc - (cd ${SPLUNK_HOME}-etc; tar cf - *) | (cd ${SPLUNK_HOME}/etc; tar xf -) + (cd ${SPLUNK_ETC_BAK}; tar cf - *) | (cd ${SPLUNK_HOME}/etc; tar xf -) fi fi diff --git a/uf/common-files/Dockerfile b/uf/common-files/Dockerfile index efa1e76a..3cb0cda5 100644 --- a/uf/common-files/Dockerfile +++ b/uf/common-files/Dockerfile @@ -47,7 +47,7 @@ ENV SPLUNK_HOME=/opt/splunkforwarder \ SPLUNK_USER=splunk # Simple script used to populate/upgrade splunk/etc directory -COPY [ "splunk/common-files/updateetc.sh", "/sbin/"] +COPY [ "uf/common-files/updateetc.sh", "/sbin/"] # Setup users and groups RUN groupadd -r -g ${GID} ${SPLUNK_GROUP} \ diff --git a/uf/common-files/updateetc.sh b/uf/common-files/updateetc.sh new file mode 100755 index 00000000..5bfc4381 --- /dev/null +++ b/uf/common-files/updateetc.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright 2018-2020 Splunk + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +SPLUNK_ETC_BAK="${SPLUNK_ETC_BAK:-/opt/splunkforwarder-etc}" + +if [[ -f "${SPLUNK_ETC_BAK}/splunk.version" ]]; then + IMAGE_VERSION_SHA=`cat ${SPLUNK_ETC_BAK}/splunk.version | sha512sum` + + if [[ -f "${SPLUNK_HOME}/etc/splunk.version" ]]; then + ETC_VERSION_SHA=`cat ${SPLUNK_HOME}/etc/splunk.version | sha512sum` + fi + + if [[ "x${IMAGE_VERSION_SHA}" != "x${ETC_VERSION_SHA}" ]]; then + echo Updating ${SPLUNK_HOME}/etc + (cd ${SPLUNK_ETC_BAK}; tar cf - *) | (cd ${SPLUNK_HOME}/etc; tar xf -) + fi +fi From 2abeda8592f1bc530bee37f532990fdf1533839d Mon Sep 17 00:00:00 2001 From: hendolim Date: Fri, 28 Aug 2020 14:00:03 -0700 Subject: [PATCH 08/10] dont remvoe systemd (#415) --- base/redhat-8/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/redhat-8/install.sh b/base/redhat-8/install.sh index 95b28064..ebfd0b46 100755 --- a/base/redhat-8/install.sh +++ b/base/redhat-8/install.sh @@ -35,7 +35,7 @@ chmod +x /bin/busybox microdnf -y --nodocs update gnutls kernel-headers microdnf -y --nodocs install python2-pip python2-devel redhat-rpm-config gcc libffi-devel openssl-devel pip2 --no-cache-dir install requests ansible jmespath -microdnf -y remove gcc openssl-devel redhat-rpm-config python2-devel device-mapper-libs device-mapper trousers systemd systemd-pam \ +microdnf -y remove gcc openssl-devel redhat-rpm-config python2-devel device-mapper-libs device-mapper trousers \ dwz dbus dbus-common dbus-daemon dbus-tools dbus-libs go-srpm-macros iptables-libs annobin cryptsetup-libs \ ocaml-srpm-macros openblas-srpm-macros qt5-srpm-macros perl-srpm-macros rust-srpm-macros ghc-srpm-macros \ efi-srpm-macros python-srpm-macros python-rpm-macros python3-rpm-macros python2-rpm-macros python3-rpm-generators \ From fb53361753f18e71e09524ade201a14d25fc8e0e Mon Sep 17 00:00:00 2001 From: David Wang Date: Thu, 3 Sep 2020 17:16:01 -0400 Subject: [PATCH 09/10] add splunk password env var to examples (#416) --- splunk/common-files/entrypoint.sh | 7 ++++--- uf/common-files/entrypoint.sh | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/splunk/common-files/entrypoint.sh b/splunk/common-files/entrypoint.sh index 55b0b509..a8cedff5 100755 --- a/splunk/common-files/entrypoint.sh +++ b/splunk/common-files/entrypoint.sh @@ -124,6 +124,7 @@ Environment Variables: * SPLUNK_GROUP - group under which to run Splunk (default: splunk) * SPLUNK_HOME - home directory where Splunk gets installed (default: /opt/splunk) * SPLUNK_START_ARGS - arguments to pass into the Splunk start command; you must include '--accept-license' to start Splunk (default: none) + * SPLUNK_PASSWORD - password to log into this Splunk instance, you must include a password (default: none) * SPLUNK_ROLE - the role of this Splunk instance (default: splunk_standalone) Acceptable values: - splunk_standalone @@ -140,9 +141,9 @@ Environment Variables: * SPLUNK_APPS_URL - comma-separated list of URLs to Splunk apps which will be downloaded and installed Examples: - * docker run -it -p 8000:8000 splunk/splunk start - * docker run -it -e SPLUNK_START_ARGS=--accept-license -p 8000:8000 -p 8089:8089 splunk/splunk start - * docker run -it -e SPLUNK_START_ARGS=--accept-license -e SPLUNK_LICENSE_URI=http://example.com/splunk.lic -p 8000:8000 splunk/splunk start + * docker run -it -e SPLUNK_PASSWORD=helloworld -p 8000:8000 splunk/splunk start + * docker run -it -e SPLUNK_START_ARGS=--accept-license -e SPLUNK_PASSWORD=helloworld -p 8000:8000 -p 8089:8089 splunk/splunk start + * docker run -it -e SPLUNK_START_ARGS=--accept-license -e SPLUNK_LICENSE_URI=http://example.com/splunk.lic -e SPLUNK_PASSWORD=helloworld -p 8000:8000 splunk/splunk start * docker run -it -e SPLUNK_START_ARGS=--accept-license -e SPLUNK_INDEXER_URL=idx1,idx2 -e SPLUNK_SEARCH_HEAD_URL=sh1,sh2 -e SPLUNK_ROLE=splunk_search_head --hostname sh1 --network splunknet --network-alias sh1 -e SPLUNK_PASSWORD=helloworld -e SPLUNK_LICENSE_URI=http://example.com/splunk.lic splunk/splunk start EOF diff --git a/uf/common-files/entrypoint.sh b/uf/common-files/entrypoint.sh index c21c5de4..e80ef26b 100755 --- a/uf/common-files/entrypoint.sh +++ b/uf/common-files/entrypoint.sh @@ -118,6 +118,7 @@ Environment Variables: * SPLUNK_GROUP - group under which to run Splunk (default: splunk) * SPLUNK_HOME - home directory where Splunk gets installed (default: /opt/splunk) * SPLUNK_START_ARGS - arguments to pass into the Splunk start command; you must include '--accept-license' to start Splunk (default: none) + * SPLUNK_PASSWORD - password to log into this Splunk instance, you must include a password (default: none) * SPLUNK_STANDALONE_URL, SPLUNK_INDEXER_URL, ... - comma-separated list of resolvable aliases to properly bring-up a distributed environment. This is optional for the UF, but necessary if you want to forward logs to another containerized Splunk instance * SPLUNK_BUILD_URL - URL to a Splunk Universal Forwarder build which will be installed (instead of the image's default build) From 405a421a89c2f3982cc9690e7a538c06494a478a Mon Sep 17 00:00:00 2001 From: Alisha Mayor Date: Thu, 3 Sep 2020 14:16:50 -0700 Subject: [PATCH 10/10] Update changelog for Release/8.0.6 and 8.0.5.1 (#417) --- Makefile | 4 ++-- docs/CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 65899a3d..3dadb9fb 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ SPLUNK_ANSIBLE_BRANCH ?= develop SPLUNK_COMPOSE ?= cluster_absolute_unit.yaml # Set Splunk version/build parameters here to define downstream URLs and file names SPLUNK_PRODUCT := splunk -SPLUNK_VERSION := 8.0.5 -SPLUNK_BUILD := a1a6394cc5ae +SPLUNK_VERSION := 8.0.6 +SPLUNK_BUILD := 152fb4b2bb96 ifeq ($(shell arch), s390x) SPLUNK_ARCH = s390x else diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0e65e17e..f513fd04 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,8 @@ ## Navigation +* [8.0.6](#806) +* [8.0.5.1](#8051) * [8.0.5](#805) * [8.0.4.1](#8041) * [8.0.4](#804) @@ -35,6 +37,35 @@ --- +## 8.0.6 + +#### What's New? +* Releasing new images to support Splunk Enterprise maintenance patch. + +#### docker-splunk changes: +* Bumping Splunk version. For details, see [Fixed issues for 8.0.6](https://docs.splunk.com/Documentation/Splunk/8.0.6/ReleaseNotes/Fixedissues) +* Test rewrite for parallelization +* Decouples `etc` backup directory from `SPLUNK_HOME` +* Added tests and documentation for new features + +#### splunk-ansible changes: +* Support for declarative admin password, enabling password updates and rotations. `splunk.password` will always be the password for the admin user and changes to `splunk.password` will drive password reconciliation. +* Added flag to disable pop-ups and new user tour +* Fixed default variable propagation order + +--- + +## 8.0.5.1 + +#### What's New? +* New Splunk Enterprise maintenance patch. For details, see [Fixed issues for 8.0.5.1](https://docs.splunk.com/Documentation/Splunk/8.0.5/ReleaseNotes/Fixedissues) +* Bundling in changes to be consistent with the release of [8.0.6](#806) + +#### Changes +* See [8.0.6](#806) changes + +--- + ## 8.0.5 #### What's New?