From ab2644dd8025707201f76df8d7c4e5f86c0a95b1 Mon Sep 17 00:00:00 2001 From: Ram Mohan Rao Chukka <1331672+chukka@users.noreply.github.com> Date: Mon, 3 May 2021 21:11:56 +0530 Subject: [PATCH] [ansible] JFrog Platform 7.18.5 release (#106) * [ansible] JFrog Platform 7.18.5 release --- Ansible/CHANGELOG.md | 21 - Ansible/README.md | 124 --- Ansible/ansible_collections/.ansible-lint | 8 - Ansible/ansible_collections/.yamllint | 12 - .../jfrog/installers/README.md | 89 -- .../installers/jfrog-installers-1.1.1.tar.gz | Bin 31024 -> 0 bytes .../installers/jfrog-installers-1.1.2.tar.gz | Bin 31828 -> 0 bytes .../installers/roles/artifactory/README.md | 49 -- .../roles/artifactory/defaults/main.yml | 56 -- .../roles/artifactory/handlers/main.yml | 10 - .../roles/artifactory/tasks/install.yml | 228 ------ .../artifactory/tasks/legacy_migration.yml | 34 - .../roles/artifactory/tasks/main.yml | 44 - .../roles/artifactory/tasks/upgrade.yml | 94 --- .../templates/artifactory.cluster.license.j2 | 31 - .../templates/installer-info.json.j2 | 12 - .../roles/artifactory/templates/join.key.j2 | 1 - .../roles/artifactory/templates/master.key.j2 | 1 - .../artifactory/templates/system.yaml.j2 | 44 - .../roles/artifactory_nginx/.travis.yml | 29 - .../roles/artifactory_nginx/defaults/main.yml | 2 - .../roles/artifactory_nginx/handlers/main.yml | 2 - .../roles/artifactory_nginx/tasks/main.yml | 53 -- .../roles/artifactory_nginx_ssl/.travis.yml | 29 - .../artifactory_nginx_ssl/defaults/main.yml | 2 - .../artifactory_nginx_ssl/handlers/main.yml | 2 - .../installers/roles/postgres/.travis.yml | 30 - .../jfrog/installers/roles/postgres/README.md | 25 - .../roles/postgres/handlers/main.yml | 4 - .../installers/roles/postgres/tasks/main.yml | 105 --- .../installers/roles/postgres/vars/Debian.yml | 12 - .../installers/roles/postgres/vars/RedHat.yml | 11 - .../roles/postgres/vars/RedHat_pg-9.6.yml | 4 - .../roles/postgres/vars/RedHat_pg-default.yml | 4 - .../jfrog/installers/roles/xray/.travis.yml | 29 - .../jfrog/installers/roles/xray/README.md | 36 - .../installers/roles/xray/defaults/main.yml | 29 - .../installers/roles/xray/handlers/main.yml | 2 - .../installers/roles/xray/tasks/Debian.yml | 42 - .../installers/roles/xray/tasks/RedHat.yml | 26 - .../installers/roles/xray/tasks/install.yml | 111 --- .../installers/roles/xray/tasks/upgrade.yml | 54 -- .../xray/templates/installer-info.json.j2 | 11 - .../roles/xray/templates/join.key.j2 | 1 - .../roles/xray/templates/master.key.j2 | 1 - .../roles/xray/templates/system.yaml.j2 | 36 - .../jfrog/platform/README.md | 112 +++ .../jfrog/platform/ansible.cfg | 6 + .../jfrog/platform/artifactory.yml | 4 + .../jfrog/platform/distribution.yml | 4 + .../jfrog/{installers => platform}/galaxy.yml | 20 +- .../group_vars/all/package_version.yml | 8 + .../jfrog/platform/group_vars/all/vars.yml | 74 ++ .../jfrog/platform/hosts.ini | 23 + .../platform/jfrog-platform-7.18.5.tar.gz | Bin 0 -> 55136 bytes .../jfrog/platform/missionControl.yml | 4 + .../jfrog/platform/platform.yml | 16 + .../plugins/README.md | 0 .../jfrog/platform/plugins/callback/README.md | 31 + .../jfrog/platform/postgres.yml | 4 + .../platform/roles/artifactory/README.md | 28 + .../roles/artifactory/defaults/main.yml | 57 ++ .../roles/artifactory/handlers/main.yml | 7 + .../roles/artifactory/meta/main.yml | 2 +- .../roles/artifactory/tasks/install.yml | 161 ++++ .../platform/roles/artifactory/tasks/main.yml | 6 + .../roles/artifactory/tasks/upgrade.yml | 105 +++ .../templates/artifactory.cluster.license.j2 | 3 + .../artifactory/templates/artifactory.lic.j2 | 3 + .../artifactory/templates/binarystore.xml.j2 | 2 +- .../templates/installer-info.json.j2 | 9 + .../artifactory/templates/system.yaml.j2 | 17 + .../roles/artifactory_nginx/README.md | 2 +- .../roles/artifactory_nginx/defaults/main.yml | 7 + .../roles/artifactory_nginx/files/nginx.conf | 0 .../roles/artifactory_nginx/handlers/main.yml | 8 + .../roles/artifactory_nginx/meta/main.yml | 2 +- .../roles/artifactory_nginx/tasks/Debian.yml | 2 +- .../roles/artifactory_nginx/tasks/RedHat.yml | 4 +- .../roles/artifactory_nginx/tasks/main.yml | 35 + .../templates/artifactory.conf.j2 | 2 +- .../roles/artifactory_nginx/vars/main.yml | 0 .../roles/artifactory_nginx_ssl/README.md | 9 - .../artifactory_nginx_ssl/defaults/main.yml | 7 + .../artifactory_nginx_ssl/handlers/main.yml | 8 + .../roles/artifactory_nginx_ssl/meta/main.yml | 2 +- .../artifactory_nginx_ssl/tasks/main.yml | 31 +- .../templates/artifactory.conf.j2 | 2 +- .../templates/certificate.key.j2 | 0 .../templates/certificate.pem.j2 | 0 .../roles/artifactory_nginx_ssl/vars/main.yml | 0 .../platform/roles/distribution/README.md | 26 + .../roles/distribution/defaults/main.yml | 43 + .../roles/distribution/handlers/main.yml | 7 + .../platform/roles/distribution/meta/main.yml | 16 + .../roles/distribution/tasks/expect.yml | 44 + .../roles/distribution/tasks/install.yml | 155 ++++ .../roles/distribution/tasks/main.yml | 6 + .../roles/distribution/tasks/upgrade.yml | 111 +++ .../templates/installer-info.json.j2 | 9 + .../distribution/templates/redis.conf.j2 | 15 + .../distribution/templates/system.yaml.j2 | 20 + .../platform/roles/distribution/vars/main.yml | 2 + .../distribution/vars/script/archive.yml | 42 + .../platform/roles/missionControl/README.md | 26 + .../roles/missionControl/defaults/main.yml | 58 ++ .../files/searchguard/localhost.key | 28 + .../files/searchguard/localhost.pem | 51 ++ .../files/searchguard/root-ca.pem | 23 + .../files/searchguard/sg_roles.yml | 7 + .../files/searchguard/sg_roles_mapping.yml | 48 ++ .../files/searchguard/sgadmin.key | 28 + .../files/searchguard/sgadmin.pem | 50 ++ .../roles/missionControl/handlers/main.yml | 7 + .../roles/missionControl/meta/main.yml | 16 + .../roles/missionControl/tasks/expect.yml | 44 + .../roles/missionControl/tasks/install.yml | 150 ++++ .../roles/missionControl/tasks/main.yml | 6 + .../tasks/setup-elasticsearch.yml | 179 ++++ .../tasks/setup-searchguard.yml | 100 +++ .../tasks/upgrade-elasticsearch.yml | 113 +++ .../tasks/upgrade-searchguard.yml | 100 +++ .../roles/missionControl/tasks/upgrade.yml | 96 +++ .../templates/elasticsearch.yml.j2 | 21 + .../templates/ha/master.elasticsearch.yml.j2 | 14 + .../templates/ha/master.system.yaml.j2 | 21 + .../templates/ha/slave.elasticsearch.yml.j2 | 11 + .../templates/ha/slave.system.yaml.j2 | 22 + .../templates/installer-info.json.j2 | 9 + .../missionControl/templates/system.yaml.j2 | 35 + .../roles/missionControl/vars/main.yml | 1 + .../missionControl/vars/script/archive.yml | 58 ++ .../jfrog/platform/roles/postgres/README.md | 23 + .../roles/postgres/defaults/main.yml | 30 +- .../platform/roles/postgres/handlers/main.yml | 6 + .../roles/postgres/meta/main.yml | 2 +- .../roles/postgres/tasks/Debian.yml | 26 +- .../roles/postgres/tasks/RedHat.yml | 43 +- .../platform/roles/postgres/tasks/main.yml | 118 +++ .../roles/postgres/templates/pg_hba.conf.j2 | 9 +- .../roles/postgres/templates/postgres.sh.j2 | 4 + .../postgres/templates/postgresql.conf.j2 | 125 ++- .../platform/roles/postgres/vars/Debian.yml | 6 + .../platform/roles/postgres/vars/RedHat.yml | 6 + .../jfrog/platform/roles/xray/README.md | 26 + .../platform/roles/xray/defaults/main.yml | 77 ++ .../platform/roles/xray/handlers/main.yml | 7 + .../roles/xray/meta/main.yml | 2 +- .../platform/roles/xray/tasks/expect.yml | 44 + .../platform/roles/xray/tasks/install.yml | 165 ++++ .../roles/xray/tasks/main.yml | 0 .../xray/tasks/rabbitmq/check/archive.yml | 63 ++ .../xray/tasks/rabbitmq/setup/Debian.yml | 102 +++ .../xray/tasks/rabbitmq/setup/RedHat.yml | 59 ++ .../xray/tasks/rabbitmq/status/archive.yml | 12 + .../xray/tasks/rabbitmq/upgrade/Debian.yml | 20 + .../xray/tasks/rabbitmq/upgrade/RedHat.yml | 32 + .../platform/roles/xray/tasks/upgrade.yml | 112 +++ .../xray/templates/installer-info.json.j2 | 9 + .../roles/xray/templates/rabbitmq.conf.j2 | 9 + .../roles/xray/templates/system.yaml.j2 | 24 + .../roles/xray/vars/main.yml | 0 .../roles/xray/vars/script/archive.yml | 54 ++ .../jfrog/platform/xray.yml | 4 + Ansible/examples/host_vars/rt-ha/hosts.yml | 52 -- .../examples/host_vars/rt-xray-ha/hosts.yml | 57 -- Ansible/examples/host_vars/rt-xray/hosts.yml | 45 - Ansible/examples/host_vars/rt/hosts.yml | 25 - Ansible/examples/host_vars/ssl/hosts.yml | 40 - Ansible/examples/host_vars/xray/hosts.yml | 18 - Ansible/examples/inventory/platform/hosts.ini | 15 + Ansible/examples/inventory/rt-xray/hosts.ini | 9 + Ansible/examples/inventory/rt/hosts.ini | 6 + Ansible/examples/inventory/xray/hosts.ini | 6 + Ansible/examples/playbook-platform.yml | 30 + Ansible/examples/playbook-rt-ha.yml | 13 - Ansible/examples/playbook-rt-xray.yml | 12 +- Ansible/examples/playbook-rt.yml | 8 +- Ansible/examples/playbook-ssl.yml | 13 - Ansible/examples/playbook-xray.yml | 12 +- Ansible/infra/aws/lb-rt-xray-ha-centos78.json | 769 ------------------ Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json | 769 ------------------ Ansible/infra/azure/lb-rt-xray-ha.json | 679 ---------------- Ansible/pipelines.yaml | 58 -- Ansible/test/aws/playbook-ha-install.yaml | 151 ---- Ansible/test/aws/playbook-ha-upgrade.yaml | 172 ---- Ansible/test/aws/runAwsInstall.sh | 12 - Ansible/test/aws/runAwsUpgrade.sh | 14 - Ansible/test/azure/playbook-ha-install.yaml | 165 ---- Ansible/test/azure/runAzure.sh | 3 - .../6.5/executionHistory/executionHistory.bin | Bin 138306 -> 0 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 0 bytes .../.gradle/6.5/fileChanges/last-build.bin | Bin 1 -> 0 bytes .../.gradle/6.5/fileContent/fileContent.lock | Bin 17 -> 0 bytes .../.gradle/6.5/fileHashes/fileHashes.bin | Bin 23647 -> 0 bytes .../.gradle/6.5/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes Ansible/test/tests/.gradle/6.5/gc.properties | 0 .../buildOutputCleanup.lock | Bin 17 -> 0 bytes .../buildOutputCleanup/cache.properties | 2 - .../buildOutputCleanup/outputFiles.bin | Bin 18947 -> 0 bytes .../tests/.gradle/checksums/checksums.lock | Bin 17 -> 0 bytes .../test/tests/.gradle/vcs-1/gc.properties | 0 Ansible/test/tests/README.md | 19 - Ansible/test/tests/build.gradle | 63 -- .../tests/gradle/wrapper/gradle-wrapper.jar | Bin 55190 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - Ansible/test/tests/gradlew | 172 ---- Ansible/test/tests/gradlew.bat | 84 -- Ansible/test/tests/settings.gradle | 2 - .../test/groovy/steps/RepositorySteps.groovy | 139 ---- Ansible/test/tests/src/test/groovy/testng.xml | 10 - .../test/groovy/tests/HealthCheckTest.groovy | 57 -- .../groovy/utils/ConfigurationUtil.groovy | 19 - .../tests/src/test/groovy/utils/DSL.groovy | 81 -- .../groovy/utils/EnvironmentConfig.groovy | 10 - .../groovy/utils/ProcessOutputStream.groovy | 32 - .../tests/src/test/groovy/utils/Shell.groovy | 17 - .../test/groovy/utils/WorkSpaceManager.groovy | 32 - .../src/test/resources/enableRabbitMQ.json | 11 - .../tests/src/test/resources/integration.json | 9 - .../resources/repositories/CreateDefault.yaml | 554 ------------- .../resources/repositories/CreateJCR.yaml | 119 --- .../test/resources/repositories/artifact.zip | Bin 519 -> 0 bytes .../tests/src/test/resources/testenv.yaml | 6 - .../tests/src/test/resources/testenv_tpl.yaml | 6 - ansible.cfg | 10 - 226 files changed, 3815 insertions(+), 6212 deletions(-) delete mode 100644 Ansible/CHANGELOG.md delete mode 100644 Ansible/README.md delete mode 100644 Ansible/ansible_collections/.ansible-lint delete mode 100644 Ansible/ansible_collections/.yamllint delete mode 100644 Ansible/ansible_collections/jfrog/installers/README.md delete mode 100644 Ansible/ansible_collections/jfrog/installers/jfrog-installers-1.1.1.tar.gz delete mode 100644 Ansible/ansible_collections/jfrog/installers/jfrog-installers-1.1.2.tar.gz delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/README.md delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/defaults/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/handlers/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/install.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/legacy_migration.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/upgrade.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/artifactory.cluster.license.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/installer-info.json.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/join.key.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/master.key.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/system.yaml.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/.travis.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/defaults/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/handlers/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/.travis.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/defaults/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/handlers/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/.travis.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/README.md delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/handlers/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/Debian.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-9.6.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-default.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/.travis.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/README.md delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/defaults/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/handlers/main.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/Debian.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/RedHat.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/install.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/upgrade.yml delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/templates/installer-info.json.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/templates/join.key.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/templates/master.key.j2 delete mode 100644 Ansible/ansible_collections/jfrog/installers/roles/xray/templates/system.yaml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/README.md create mode 100644 Ansible/ansible_collections/jfrog/platform/ansible.cfg create mode 100644 Ansible/ansible_collections/jfrog/platform/artifactory.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/distribution.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/galaxy.yml (80%) create mode 100644 Ansible/ansible_collections/jfrog/platform/group_vars/all/package_version.yml create mode 100755 Ansible/ansible_collections/jfrog/platform/group_vars/all/vars.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/hosts.ini create mode 100644 Ansible/ansible_collections/jfrog/platform/jfrog-platform-7.18.5.tar.gz create mode 100644 Ansible/ansible_collections/jfrog/platform/missionControl.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/platform.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/plugins/README.md (100%) create mode 100644 Ansible/ansible_collections/jfrog/platform/plugins/callback/README.md create mode 100644 Ansible/ansible_collections/jfrog/platform/postgres.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/README.md create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/defaults/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/handlers/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory/meta/main.yml (88%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/install.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/upgrade.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.cluster.license.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.lic.j2 rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory/templates/binarystore.xml.j2 (91%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/installer-info.json.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/system.yaml.j2 rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/README.md (65%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/defaults/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/files/nginx.conf (100%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/handlers/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/meta/main.yml (87%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/tasks/Debian.yml (100%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/tasks/RedHat.yml (63%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/templates/artifactory.conf.j2 (95%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx/vars/main.yml (100%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/README.md (72%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/defaults/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/handlers/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/meta/main.yml (84%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/tasks/main.yml (66%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 (96%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/templates/certificate.key.j2 (100%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/templates/certificate.pem.j2 (100%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/artifactory_nginx_ssl/vars/main.yml (100%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/README.md create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/defaults/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/handlers/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/meta/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/expect.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/install.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/upgrade.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/installer-info.json.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/redis.conf.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/system.yaml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/script/archive.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/README.md create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/defaults/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.key create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.pem create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/root-ca.pem create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles_mapping.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.key create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.pem create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/handlers/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/meta/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/expect.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/install.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-elasticsearch.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-searchguard.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-elasticsearch.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-searchguard.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/elasticsearch.yml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.elasticsearch.yml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.system.yaml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.elasticsearch.yml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.system.yaml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/installer-info.json.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/system.yaml.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/script/archive.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/postgres/README.md rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/postgres/defaults/main.yml (82%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/postgres/handlers/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/postgres/meta/main.yml (86%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/postgres/tasks/Debian.yml (59%) rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/postgres/tasks/RedHat.yml (65%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/postgres/templates/pg_hba.conf.j2 (76%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgres.sh.j2 rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/postgres/templates/postgresql.conf.j2 (87%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/Debian.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/RedHat.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/README.md create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/defaults/main.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/handlers/main.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/xray/meta/main.yml (86%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/expect.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/install.yml rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/xray/tasks/main.yml (100%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/check/archive.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/Debian.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/RedHat.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/status/archive.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/Debian.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/RedHat.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/upgrade.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/templates/installer-info.json.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/templates/rabbitmq.conf.j2 create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/templates/system.yaml.j2 rename Ansible/ansible_collections/jfrog/{installers => platform}/roles/xray/vars/main.yml (100%) create mode 100644 Ansible/ansible_collections/jfrog/platform/roles/xray/vars/script/archive.yml create mode 100644 Ansible/ansible_collections/jfrog/platform/xray.yml delete mode 100644 Ansible/examples/host_vars/rt-ha/hosts.yml delete mode 100644 Ansible/examples/host_vars/rt-xray-ha/hosts.yml delete mode 100644 Ansible/examples/host_vars/rt-xray/hosts.yml delete mode 100644 Ansible/examples/host_vars/rt/hosts.yml delete mode 100644 Ansible/examples/host_vars/ssl/hosts.yml delete mode 100644 Ansible/examples/host_vars/xray/hosts.yml create mode 100644 Ansible/examples/inventory/platform/hosts.ini create mode 100644 Ansible/examples/inventory/rt-xray/hosts.ini create mode 100644 Ansible/examples/inventory/rt/hosts.ini create mode 100644 Ansible/examples/inventory/xray/hosts.ini create mode 100644 Ansible/examples/playbook-platform.yml delete mode 100644 Ansible/examples/playbook-rt-ha.yml delete mode 100644 Ansible/examples/playbook-ssl.yml delete mode 100644 Ansible/infra/aws/lb-rt-xray-ha-centos78.json delete mode 100644 Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json delete mode 100644 Ansible/infra/azure/lb-rt-xray-ha.json delete mode 100644 Ansible/pipelines.yaml delete mode 100644 Ansible/test/aws/playbook-ha-install.yaml delete mode 100644 Ansible/test/aws/playbook-ha-upgrade.yaml delete mode 100755 Ansible/test/aws/runAwsInstall.sh delete mode 100755 Ansible/test/aws/runAwsUpgrade.sh delete mode 100644 Ansible/test/azure/playbook-ha-install.yaml delete mode 100755 Ansible/test/azure/runAzure.sh delete mode 100644 Ansible/test/tests/.gradle/6.5/executionHistory/executionHistory.bin delete mode 100644 Ansible/test/tests/.gradle/6.5/executionHistory/executionHistory.lock delete mode 100644 Ansible/test/tests/.gradle/6.5/fileChanges/last-build.bin delete mode 100644 Ansible/test/tests/.gradle/6.5/fileContent/fileContent.lock delete mode 100644 Ansible/test/tests/.gradle/6.5/fileHashes/fileHashes.bin delete mode 100644 Ansible/test/tests/.gradle/6.5/fileHashes/fileHashes.lock delete mode 100644 Ansible/test/tests/.gradle/6.5/gc.properties delete mode 100644 Ansible/test/tests/.gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 Ansible/test/tests/.gradle/buildOutputCleanup/cache.properties delete mode 100644 Ansible/test/tests/.gradle/buildOutputCleanup/outputFiles.bin delete mode 100644 Ansible/test/tests/.gradle/checksums/checksums.lock delete mode 100644 Ansible/test/tests/.gradle/vcs-1/gc.properties delete mode 100755 Ansible/test/tests/README.md delete mode 100644 Ansible/test/tests/build.gradle delete mode 100644 Ansible/test/tests/gradle/wrapper/gradle-wrapper.jar delete mode 100644 Ansible/test/tests/gradle/wrapper/gradle-wrapper.properties delete mode 100755 Ansible/test/tests/gradlew delete mode 100644 Ansible/test/tests/gradlew.bat delete mode 100644 Ansible/test/tests/settings.gradle delete mode 100644 Ansible/test/tests/src/test/groovy/steps/RepositorySteps.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/testng.xml delete mode 100644 Ansible/test/tests/src/test/groovy/tests/HealthCheckTest.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/utils/ConfigurationUtil.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/utils/DSL.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/utils/EnvironmentConfig.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/utils/ProcessOutputStream.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/utils/Shell.groovy delete mode 100644 Ansible/test/tests/src/test/groovy/utils/WorkSpaceManager.groovy delete mode 100644 Ansible/test/tests/src/test/resources/enableRabbitMQ.json delete mode 100644 Ansible/test/tests/src/test/resources/integration.json delete mode 100644 Ansible/test/tests/src/test/resources/repositories/CreateDefault.yaml delete mode 100644 Ansible/test/tests/src/test/resources/repositories/CreateJCR.yaml delete mode 100644 Ansible/test/tests/src/test/resources/repositories/artifact.zip delete mode 100644 Ansible/test/tests/src/test/resources/testenv.yaml delete mode 100644 Ansible/test/tests/src/test/resources/testenv_tpl.yaml delete mode 100644 ansible.cfg diff --git a/Ansible/CHANGELOG.md b/Ansible/CHANGELOG.md deleted file mode 100644 index ece5411..0000000 --- a/Ansible/CHANGELOG.md +++ /dev/null @@ -1,21 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -## [1.1.2] - 2020-10-29 -- Updated default versions to RT 7.10.2 and Xray 3.10.3. -- Removed obsolete gradle tests. - -## [1.1.1] - 2020-10-15 -- added idempotence to artifactory installer -- added fix for derby deployments -- Migration to reduce changes during playbook runs contains breaking changes. You either must run once before upgrade, or provide playbook with valid credentials to access version information for it to perform properly. -- First time installers need not worry about above - -## [1.1.0] - 2020-09-27 - -- Validated for Artifactory 7.7.8 and Xray 3.8.6. -- Added offline support for Artifactory and Xray. -- Added support for configurable Postgres pg_hba.conf. -- Misc fixes due to Artifactory 7.7.8. -- Published 1.1.0 to [Ansible Galaxy](https://galaxy.ansible.com/jfrog/installers). diff --git a/Ansible/README.md b/Ansible/README.md deleted file mode 100644 index d60a876..0000000 --- a/Ansible/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# JFrog Ansible Installers Collection - -This Ansible directory consists of the following directories that support the JFrog Ansible collection. - - * [ansible_collections directory](ansible_collections) - This directory contains the Ansible collection package that has the Ansible roles for Artifactory and Xray. See the collection [README](ansible_collections/README.md) for details on the available roles and variables. - * [examples directory](examples) - This directory contains example playbooks for various architectures from single Artifactory (RT) deployments to high-availability setups. - * [infra directory](infra) - This directory contains example infrastructure templates that can be used for testing and as example deployments. - * [test directory](test) - This directory contains Gradle tests that can be used to verify a deployment. It also has Ansible playbooks for creating infrastructure, provisioning software and testing with Gradle. - - ## Tested Artifactory and Xray Versions - The following versions of Artifactory and Xray have been validated with this collection. Other versions and combinations may also work. - - -| collection_version | artifactory_version | xray_version | -|--------------------|---------------------|--------------| -| 1.1.2 | 7.10.2 | 3.10.3 | -| 1.1.1 | 7.10.2 | 3.9.1 | -| 1.1.0 | 7.7.8 | 3.8.6 | -| 1.0.9 | 7.7.3 | 3.8.0 | -| 1.0.8 | 7.7.3 | 3.8.0 | -| 1.0.8 | 7.7.1 | 3.5.2 | -| 1.0.8 | 7.6.1 | 3.5.2 | -| 1.0.7 | 7.6.1 | 3.5.2 | -| 1.0.6 | 7.5.0 | 3.3.0 | -| 1.0.6 | 7.4.3 | 3.3.0 | - - ## Getting Started - - 1. Install this collection from Ansible Galaxy. This collection is also available in RedHat Automation Hub. - - ``` - ansible-galaxy collection install jfrog.installers - ``` - - Ensure you reference the collection in your playbook when using these roles. - - ``` - --- - - hosts: xray - collections: - - jfrog.installers - roles: - - xray - - ``` - - 2. Ansible uses SSH to connect to hosts. Ensure that your SSH private key is on your client and the public keys are installed on your Ansible hosts. - - 3. Create your inventory file. Use one of the examples from the [examples directory](examples) to construct an inventory file (hosts.yml) with the host addresses and variables. - - 4. Create your playbook. Use one of the examples from the [examples directory](examples) to construct a playbook using the JFrog Ansible roles. These roles will be applied to your inventory and provision software. - - 5. Then execute with the following command to provision the JFrog software with Ansible. Variables can also be passed in at the command-line. - -``` -ansible-playbook -i hosts.yml playbook.yml --extra-vars "master_key=$(openssl rand -hex 32) join_key=$(openssl rand -hex 32)" -``` - -## Autogenerating Master and Join Keys -You may want to auto-generate your master amd join keys and apply it to all the nodes. - -``` -ansible-playbook -i hosts.yml playbook.yml --extra-vars "master_key=$(openssl rand -hex 32) join_key=$(openssl rand -hex 32)" -``` - -## Using [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html) to Encrypt Vars -Some vars you may want to keep secret. You may put these vars into a separate file and encrypt them using [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html). - -``` -ansible-vault encrypt secret-vars.yml --vault-password-file ~/.vault_pass.txt -``` - -then in your playbook include the secret vars file. - -``` -- hosts: primary - - vars_files: - - ./vars/secret-vars.yml - - ./vars/vars.yml - - roles: - - artifactory -``` - -## Bastion Hosts -In many cases, you may want to run this Ansible collection through a Bastion host to provision JFrog servers. You can include the following Var for a host or group of hosts: - -``` -ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A user@host -W %h:%p"' - -eg. -ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ azureDeployment.deployment.outputs.lbIp.value }} -W %h:%p"' -``` -## Upgrades -The Artifactory and Xray roles support software updates. To use a role to perform a software update only, use the _artifactory_upgrade_only_ or _xray_upgrade_only_ variable and specify the version. See the following example. - -``` -- hosts: artifactory - vars: - artifactory_version: "{{ lookup('env', 'artifactory_version_upgrade') }}" - artifactory_upgrade_only: true - roles: - - artifactory - -- hosts: xray - vars: - xray_version: "{{ lookup('env', 'xray_version_upgrade') }}" - xray_upgrade_only: true - roles: - - xray -``` - -## Building the Collection Archive -1. Go to the [ansible_collections/jfrog/installers directory](ansible_collections/jfrog/installers). -2. Update the galaxy.yml meta file as needed. Update the version. -3. Build the archive. (Requires Ansible 2.9+) -``` -ansible-galaxy collection build -``` - -## OS support -* Current ansible collection only supports ubuntu and its flavours -* Centos/RHEL and SELinux support is coming soon, stay tuned :) diff --git a/Ansible/ansible_collections/.ansible-lint b/Ansible/ansible_collections/.ansible-lint deleted file mode 100644 index a59f903..0000000 --- a/Ansible/ansible_collections/.ansible-lint +++ /dev/null @@ -1,8 +0,0 @@ -# -# Ansible managed -# -exclude_paths: - - ./meta/version.yml - - ./meta/exception.yml - - ./meta/preferences.yml - - ./molecule/default/verify.yml diff --git a/Ansible/ansible_collections/.yamllint b/Ansible/ansible_collections/.yamllint deleted file mode 100644 index c5ae64b..0000000 --- a/Ansible/ansible_collections/.yamllint +++ /dev/null @@ -1,12 +0,0 @@ ---- -extends: default - -rules: - braces: - max-spaces-inside: 1 - level: error - brackets: - max-spaces-inside: 1 - level: error - line-length: disable - truthy: disable diff --git a/Ansible/ansible_collections/jfrog/installers/README.md b/Ansible/ansible_collections/jfrog/installers/README.md deleted file mode 100644 index 88f2bdf..0000000 --- a/Ansible/ansible_collections/jfrog/installers/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# JFrog Ansible Installers Collection - -## Getting Started - - 1. Install this collection from Ansible Galaxy. This collection is also available in RedHat Automation Hub. - - ``` - ansible-galaxy collection install jfrog.installers - ``` - - Ensure you reference the collection in your playbook when using these roles. - - ``` - --- - - hosts: xray - collections: - - jfrog.installers - roles: - - xray - - ``` - - 2. Ansible uses SSH to connect to hosts. Ensure that your SSH private key is on your client and the public keys are installed on your Ansible hosts. - - 3. Create your inventory file. Use one of the examples from the [examples directory](https://github.com/jfrog/JFrog-Cloud-Installers/tree/master/Ansible/examples) to construct an inventory file (hosts.yml) with the host addresses and variables. - - 4. Create your playbook. Use one of the examples from the [examples directory](https://github.com/jfrog/JFrog-Cloud-Installers/tree/master/Ansible/examples) to construct a playbook using the JFrog Ansible roles. These roles will be applied to your inventory and provision software. - - 5. Then execute with the following command to provision the JFrog software with Ansible. Variables can also be passed in at the command-line. - - ``` -ansible-playbook -i hosts.yml playbook.yml --extra-vars "master_key=$(openssl rand -hex 16) join_key=$(openssl rand -hex 16)" -``` - -## Autogenerating Master and Join Keys -You may want to auto-generate your master amd join keys and apply it to all the nodes. - -``` -ansible-playbook -i hosts.yml playbook.yml --extra-vars "master_key=$(openssl rand -hex 16) join_key=$(openssl rand -hex 16)" -``` - -## Using [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html) to Encrypt Vars -Some vars you may want to keep secret. You may put these vars into a separate file and encrypt them using [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html). - -``` -ansible-vault encrypt secret-vars.yml --vault-password-file ~/.vault_pass.txt -``` - -then in your playbook include the secret vars file. - -``` -- hosts: primary - - vars_files: - - ./vars/secret-vars.yml - - ./vars/vars.yml - - roles: - - artifactory -``` - -## Bastion Hosts -In many cases, you may want to run this Ansible collection through a Bastion host to provision JFrog servers. You can include the following Var for a host or group of hosts: - -``` -ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A user@host -W %h:%p"' - -eg. -ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ azureDeployment.deployment.outputs.lbIp.value }} -W %h:%p"' -``` - -## Upgrades -The Artifactory and Xray roles support software upgrades. To use a role to perform a software upgrade only, use the _artifactory_upgrade_only_ or _xray_upgrade_only_ variables and specify the version. See the following example. - -``` -- hosts: artifactory - vars: - artifactory_version: "{{ lookup('env', 'artifactory_version_upgrade') }}" - artifactory_upgrade_only: true - roles: - - artifactory - -- hosts: xray - vars: - xray_version: "{{ lookup('env', 'xray_version_upgrade') }}" - xray_upgrade_only: true - roles: - - xray -``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/jfrog-installers-1.1.1.tar.gz b/Ansible/ansible_collections/jfrog/installers/jfrog-installers-1.1.1.tar.gz deleted file mode 100644 index 02495d51a30e116f39202e707eadad9b486caafd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31024 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 diff --git a/Ansible/ansible_collections/jfrog/installers/jfrog-installers-1.1.2.tar.gz b/Ansible/ansible_collections/jfrog/installers/jfrog-installers-1.1.2.tar.gz deleted file mode 100644 index a9fdeb67f4a74b4a7af2c556480e1e0bcabe915b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31828 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
    AS}r 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 MxTznd79HjP0UTH$`2YX_ diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/README.md b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/README.md deleted file mode 100644 index 50ecaf6..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# artifactory -The artifactory role installs the Artifactory Pro software onto the host. Per the Vars below, it will configure a node as primary or secondary. This role uses secondary roles artifactory_nginx to install nginx. - -1.1.1 contains breaking changes. To mitigate this, use the role before doing any upgrades, let it mitigate the path changes, and then run again with your upgrade. - -## Role Variables -* _artifactory_version_: The version of Artifactory to install. eg. "7.4.1" -* _master_key_: This is the Artifactory [Master Key](https://www.jfrog.com/confluence/display/JFROG/Managing+Keys). See below to [autogenerate this key](#autogenerating-master-and-join-keys). -* _join_key_: This is the Artifactory [Join Key](https://www.jfrog.com/confluence/display/JFROG/Managing+Keys). See below to [autogenerate this key](#autogenerating-master-and-join-keys). -* _db_download_url_: This is the download URL for the JDBC driver for your database. eg. "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" -* _db_type_: This is the database type. eg. "postgresql" -* _db_driver_: This is the JDBC driver class. eg. "org.postgresql.Driver" -* _db_url_: This is the JDBC database url. eg. "jdbc:postgresql://10.0.0.120:5432/artifactory" -* _db_user_: The database user to configure. eg. "artifactory" -* _db_password_: The database password to configure. "Art1fact0ry" -* _server_name_: This is the server name. eg. "artifactory.54.175.51.178.xip.io" -* _artifactory_system_yaml_: Your own [system YAML](https://www.jfrog.com/confluence/display/JFROG/System+YAML+Configuration+File) file can be specified and used. **If specified, this file will be used rather than constructing a file from the parameters above.** -* _binary_store_file_: Your own [binary store file](https://www.jfrog.com/confluence/display/JFROG/Configuring+the+Filestore) can be used. If specified, the default cluster-file-system will not be used. -* _artifactory_upgrade_only_: Perform an software upgrade only. Default is false. - -### primary vars (vars used by the primary Artifactory server) -* _artifactory_is_primary_: For the primary node this must be set to **true**. -* _artifactory_license1 - 5_: These are the cluster licenses. -* _artifactory_license_file_: Your own license file can be used. **If specified, a license file constructed from the licenses above will not be used.** - -### secondary vars (vars used by the secondary Artifactory server) -* _artifactory_is_primary_: For the secondary node(s) this must be set to **false**. - -Additional variables can be found in [defaults/main.yml](./defaults/main.yml). - -## Example Playbook -``` ---- -- hosts: primary - roles: - - artifactory -``` - -## Upgrades -The Artifactory role supports software upgrades. To use a role to perform a software upgrade only, use the _artifactory_upgrade_only_ variable and specify the version. See the following example. - -``` -- hosts: artifactory - vars: - artifactory_version: "{{ lookup('env', 'artifactory_version_upgrade') }}" - artifactory_upgrade_only: true - roles: - - artifactory -``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/defaults/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/defaults/main.yml deleted file mode 100644 index 1a8ca54..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/defaults/main.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -# defaults file for artifactory -# indicates were this collection was downlaoded from (galaxy, automation_hub, standalone) -ansible_marketplace: standalone - -# The version of Artifactory to install -artifactory_version: 7.10.2 - -# licenses file - specify a licenses file or specify up to 5 licenses -artifactory_license1: -artifactory_license2: -artifactory_license3: -artifactory_license4: -artifactory_license5: - -# whether to enable HA -artifactory_ha_enabled: true - -# value for whether a host is primary. this should be set in host vars -artifactory_is_primary: true - -# The location where Artifactory should install. -jfrog_home_directory: /opt/jfrog - -# The location where Artifactory should store data. -artifactory_file_store_dir: /data - -# Pick the Artifactory flavour to install, can be also cpp-ce, jcr, pro. -artifactory_flavour: pro - -extra_java_opts: -server -Xms2g -Xmx14g -Xss256k -XX:+UseG1GC -artifactory_system_yaml_template: system.yaml.j2 -artifactory_tar: https://dl.bintray.com/jfrog/artifactory-pro/org/artifactory/pro/jfrog-artifactory-pro/{{ artifactory_version }}/jfrog-artifactory-pro-{{ artifactory_version }}-linux.tar.gz -artifactory_home: "{{ jfrog_home_directory }}/artifactory" -artifactory_untar_home: "{{ jfrog_home_directory }}/artifactory-{{ artifactory_flavour }}-{{ artifactory_version }}" - -artifactory_user: artifactory -artifactory_group: artifactory - -# Set the parameters required for the service. -service_list: - - name: artifactory - description: Start script for Artifactory - start_command: "{{ artifactory_home }}/bin/artifactory.sh start" - stop_command: "{{ artifactory_home }}/bin/artifactory.sh stop" - type: forking - status_pattern: artifactory - user_name: "{{ artifactory_user }}" - group_name: "{{ artifactory_group }}" - -# if this is an upgrade -artifactory_upgrade_only: false - -#default username and password -artifactory_app_username: admin -artifactory_app_user_pass: password diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/handlers/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/handlers/main.yml deleted file mode 100644 index 6f8fcda..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/handlers/main.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -# handlers file for artifactory -- name: systemctl daemon-reload - systemd: - daemon_reload: yes - -- name: restart artifactory - service: - name: artifactory - state: restarted diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/install.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/install.yml deleted file mode 100644 index 9537459..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/install.yml +++ /dev/null @@ -1,228 +0,0 @@ ---- -- debug: - msg: "Performing installation of Artifactory..." - -- name: install nginx - include_role: - name: artifactory_nginx - -- name: create group for artifactory - group: - name: "{{ artifactory_group }}" - state: present - become: yes - -- name: create user for artifactory - user: - name: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - system: yes - become: yes - -- name: ensure jfrog_home_directory exists - file: - path: "{{ jfrog_home_directory }}" - state: directory - become: yes - -- name: Local Copy artifactory - unarchive: - src: "{{ local_artifactory_tar }}" - dest: "{{ jfrog_home_directory }}" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - creates: "{{ artifactory_untar_home }}" - become: yes - when: local_artifactory_tar is defined - register: downloadartifactory - until: downloadartifactory is succeeded - retries: 3 - -- name: download artifactory - unarchive: - src: "{{ artifactory_tar }}" - dest: "{{ jfrog_home_directory }}" - remote_src: yes - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - creates: "{{ artifactory_untar_home }}" - become: yes - when: artifactory_tar is defined - register: downloadartifactory - until: downloadartifactory is succeeded - retries: 3 - -- name: Create artifactory home folder - file: - state: directory - path: "{{ artifactory_home }}" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: Create Symlinks for var folder - file: - state: link - src: "{{ artifactory_untar_home }}/var" - dest: "{{ artifactory_home }}/var" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: Create Symlinks for app folder - file: - state: link - src: "{{ artifactory_untar_home }}/app" - dest: "{{ artifactory_home }}/app" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: ensure artifactory_file_store_dir exists - file: - path: "{{ artifactory_file_store_dir }}" - state: directory - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: ensure data exists - file: - path: "{{ artifactory_home }}/var/data" - state: directory - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: ensure etc exists - file: - path: "{{ artifactory_home }}/var/etc" - state: directory - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: use specified system yaml - copy: - src: "{{ artifactory_system_yaml }}" - dest: "{{ artifactory_home }}/var/etc/system.yaml" - become: yes - when: artifactory_system_yaml is defined - -- name: configure system yaml template - template: - src: "{{ artifactory_system_yaml_template }}" - dest: "{{ artifactory_home }}/var/etc/system.yaml" - become: yes - when: artifactory_system_yaml is not defined - -- name: ensure {{ artifactory_home }}/var/etc/security/ exists - file: - path: "{{ artifactory_home }}/var/etc/security/" - state: directory - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: configure master key - template: - src: master.key.j2 - dest: "{{ artifactory_home }}/var/etc/security/master.key" - become: yes - -- name: configure join key - template: - src: join.key.j2 - dest: "{{ artifactory_home }}/var/etc/security/join.key" - become: yes - -- name: ensure {{ artifactory_home }}/var/etc/artifactory/info/ exists - file: - path: "{{ artifactory_home }}/var/etc/artifactory/info/" - state: directory - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: configure installer info - template: - src: installer-info.json.j2 - dest: "{{ artifactory_home }}/var/etc/artifactory/info/installer-info.json" - become: yes - -- name: use specified binary store - copy: - src: "{{ binary_store_file }}" - dest: "{{ artifactory_home }}/var/etc/binarystore.xml" - become: yes - when: binary_store_file is defined - -- name: use default binary store - template: - src: binarystore.xml.j2 - dest: "{{ artifactory_home }}/var/etc/binarystore.xml" - become: yes - when: binary_store_file is not defined - -- name: use license file - copy: - src: "{{ artifactory_license_file }}" - dest: "{{ artifactory_home }}/var/etc/artifactory/artifactory.cluster.license" - become: yes - when: artifactory_license_file is defined and artifactory_is_primary == true - -- name: use license strings - template: - src: artifactory.cluster.license.j2 - dest: "{{ artifactory_home }}/var/etc/artifactory/artifactory.cluster.license" - become: yes - when: artifactory_license_file is not defined and artifactory_is_primary == true - -- name: Copy local database driver - copy: - src: "{{ db_local_location }}" - dest: "{{ artifactory_home }}/var/bootstrap/artifactory/tomcat/lib" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - when: db_local_location is defined - become: yes - -- name: download database driver - get_url: - url: "{{ db_download_url }}" - dest: "{{ artifactory_home }}/var/bootstrap/artifactory/tomcat/lib" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - when: db_download_url is defined - become: yes - -- name: create artifactory service - shell: "{{ artifactory_home }}/app/bin/installService.sh" - become: yes - -- name: Ensure permissions are correct - file: - path: "{{ jfrog_home_directory }}" - group: "{{ artifactory_group }}" - owner: "{{ artifactory_user }}" - recurse: yes - become: yes - -- name: start and enable the primary node - service: - name: artifactory - state: started - become: yes - when: artifactory_is_primary == true - -- name: random wait before restarting to prevent secondary nodes from hitting DB first - pause: - seconds: "{{ 120 | random + 10}}" - when: artifactory_is_primary == false - -- name: start and enable the secondary nodes - service: - name: artifactory - state: started - become: yes - when: artifactory_is_primary == false diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/legacy_migration.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/legacy_migration.yml deleted file mode 100644 index e3e15d5..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/legacy_migration.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -- name: MV artifactory home to artifactory untar home - command: "mv {{ artifactory_home }} {{ temp_untar_home }}" - become: yes -- name: Ensure untar home permissions are correct - file: - state: directory - path: "{{ temp_untar_home }}" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes -- name: Create artifactory home folder - file: - state: directory - path: "{{ artifactory_home }}" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes -- name: Create Symlinks for var folder - file: - state: link - src: "{{ temp_untar_home }}/var" - dest: "{{ artifactory_home }}/var" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes -- name: Create Symlinks for app folder - file: - state: link - src: "{{ temp_untar_home }}/app" - dest: "{{ artifactory_home }}/app" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/main.yml deleted file mode 100644 index 65728de..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/main.yml +++ /dev/null @@ -1,44 +0,0 @@ -- name: Rectify Legacy Installation Block - block: - - name: Check to see if artifactory has a service and stop it - service: - name: artifactory - state: stopped - become: yes - - name: Check symlink method - stat: - path: /opt/jfrog/artifactory/app - register: newMethod - - name: Check artifactory version - uri: - url: "{{ web_method }}://{{ artifactory_server_url }}:{{ url_port }}/artifactory/api/system/version" - url_username: "{{ artifactory_app_username }}" - url_password: "{{ artifactory_app_user_pass }}" - register: artifactory_installed_version - - name: Debug defunct installation - debug: - var: artifactory_installed_version.json.version - - name: Setup temporary untar home - set_fact: - temp_untar_home: "{{ jfrog_home_directory }}/artifactory-{{ artifactory_flavour }}-{{ artifactory_installed_version }}" - - name: Rectify legacy installation - include_tasks: "legacy_migration.yml" - when: (not newMethod.stat.islnk) and newMethod.stat.exists - rescue: - - name: Check to see if artifactory has a service and stop it - service: - name: artifactory - state: stopped - - name: Setup temporary untar home (assuming version is set var for version) - set_fact: - temp_untar_home: "{{ jfrog_home_directory }}/artifactory-{{ artifactory_flavour }}-{{ artifactory_version }}" - - name: Rectify legacy installation - include_tasks: "legacy_migration.yml" - when: (not newMethod.stat.islnk) and newMethod.stat.exists - always: - - name: perform installation - include_tasks: "install.yml" - when: not artifactory_upgrade_only - - name: perform upgrade - include_tasks: "upgrade.yml" - when: artifactory_upgrade_only \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/upgrade.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/upgrade.yml deleted file mode 100644 index 5ac0fd8..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/tasks/upgrade.yml +++ /dev/null @@ -1,94 +0,0 @@ ---- -- debug: - msg: "Performing upgrade of Artifactory..." - -- name: stop artifactory - service: - name: artifactory - state: stopped - become: yes - -- name: ensure jfrog_home_directory exists - file: - path: "{{ jfrog_home_directory }}" - state: directory - become: yes - -- name: Local Copy artifactory - unarchive: - src: "{{ local_artifactory_tar }}" - dest: "{{ jfrog_home_directory }}" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - creates: "{{ artifactory_untar_home }}" - become: yes - when: local_artifactory_tar is defined - register: downloadartifactory - until: downloadartifactory is succeeded - retries: 3 - -- name: download artifactory - unarchive: - src: "{{ artifactory_tar }}" - dest: "{{ jfrog_home_directory }}" - remote_src: yes - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - creates: "{{ artifactory_untar_home }}" - become: yes - when: artifactory_tar is defined - register: downloadartifactory - until: downloadartifactory is succeeded - retries: 3 - -#- name: Delete artifactory app -# file: -# path: "{{ artifactory_home }}/app" -# state: absent -# become: yes - -#- name: CP new app to artifactory app -# command: "cp -r {{ artifactory_untar_home }}/app {{ artifactory_home }}/app" -# become: yes - -#- name: Delete untar directory -# file: -# path: "{{ artifactory_untar_home }}" -# state: absent -# become: yes - -- name: Create Symlinks for app folder - file: - state: link - src: "{{ artifactory_untar_home }}/app" - dest: "{{ artifactory_home }}/app" - owner: "{{ artifactory_user }}" - group: "{{ artifactory_group }}" - become: yes - -- name: Ensure permissions are correct - file: - path: "{{ jfrog_home_directory }}" - group: "{{ artifactory_group }}" - owner: "{{ artifactory_user }}" - recurse: yes - become: yes - -- name: start and enable the primary node - service: - name: artifactory - state: restarted - become: yes - when: artifactory_is_primary == true - -- name: random wait before restarting to prevent secondary nodes from hitting DB first - pause: - seconds: "{{ 120 | random + 10}}" - when: artifactory_is_primary == false - -- name: start and enable the secondary nodes - service: - name: artifactory - state: restarted - become: yes - when: artifactory_is_primary == false diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/artifactory.cluster.license.j2 b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/artifactory.cluster.license.j2 deleted file mode 100644 index 3f674f6..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/artifactory.cluster.license.j2 +++ /dev/null @@ -1,31 +0,0 @@ -{% if artifactory_license1 %} -{% if artifactory_license1|length %} -{{ artifactory_license1 }} -{% endif %} -{% endif %} -{% if artifactory_license2 %} - - -{% if artifactory_license2|length %} -{{ artifactory_license2 }} -{% endif %} -{% endif %} -{% if artifactory_license3 %} - - -{% if artifactory_license3|length %} -{{ artifactory_license3 }} -{% endif %} -{% endif %} -{% if artifactory_license4 %} - -{% if artifactory_license4|length %} -{{ artifactory_license4 }} -{% endif %} -{% endif %} -{% if artifactory_license5 %} - -{% if artifactory_license5|length %} -{{ artifactory_license5 }} -{% endif %} -{% endif %} diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/installer-info.json.j2 b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/installer-info.json.j2 deleted file mode 100644 index f475256..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/installer-info.json.j2 +++ /dev/null @@ -1,12 +0,0 @@ -{ - "productId": "Ansible_artifactory/1.0.0", - "features": [ - { - "featureId": "Partner/ACC-006973" - }, - { - "featureId": "Channel/{{ ansible_marketplace }}" - } - ] -} - diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/join.key.j2 b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/join.key.j2 deleted file mode 100644 index 17d05d2..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/join.key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ join_key }} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/master.key.j2 b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/master.key.j2 deleted file mode 100644 index 0462a64..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/master.key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ master_key }} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/system.yaml.j2 b/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/system.yaml.j2 deleted file mode 100644 index a7fede0..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/system.yaml.j2 +++ /dev/null @@ -1,44 +0,0 @@ -## @formatter:off -## JFROG ARTIFACTORY SYSTEM CONFIGURATION FILE -## HOW TO USE: comment-out any field and keep the correct yaml indentation by deleting only the leading '#' character. -configVersion: 1 - -## NOTE: JFROG_HOME is a place holder for the JFrog root directory containing the deployed product, the home directory for all JFrog products. -## Replace JFROG_HOME with the real path! For example, in RPM install, JFROG_HOME=/opt/jfrog - -## NOTE: Sensitive information such as passwords and join key are encrypted on first read. -## NOTE: The provided commented key and value is the default. - -## SHARED CONFIGURATIONS -## A shared section for keys across all services in this config -shared: - - ## Node Settings - node: - ## A unique id to identify this node. - ## Default: auto generated at startup. - id: {{ ansible_machine_id }} - - ## Sets this node as primary in HA installation - primary: {{ artifactory_is_primary }} - - ## Sets this node as part of HA installation - haEnabled: {{ artifactory_ha_enabled }} - - ## Database Configuration - database: - ## One of: mysql, oracle, mssql, postgresql, mariadb - ## Default: Embedded derby - - ## Example for mysql/postgresql - type: "{{ db_type }}" -{%+ if db_type == 'derby' -%} -# driver: "{{ db_driver }}" -# url: "{{ db_url }}" -# username: "{{ db_user }}" -{%+ else -%} - driver: "{{ db_driver }}" - url: "{{ db_url }}" - username: "{{ db_user }}" -{%+ endif -%} - password: "{{ db_password }}" \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/.travis.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/.travis.yml deleted file mode 100644 index 36bbf62..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -language: python -python: "2.7" - -# Use the new container infrastructure -sudo: false - -# Install ansible -addons: - apt: - packages: - - python-pip - -install: - # Install ansible - - pip install ansible - - # Check ansible version - - ansible --version - - # Create ansible.cfg with correct roles_path - - printf '[defaults]\nroles_path=../' >ansible.cfg - -script: - # Basic role syntax check - - ansible-playbook tests/test.yml -i tests/inventory --syntax-check - -notifications: - webhooks: https://galaxy.ansible.com/api/v1/notifications/ \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/defaults/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/defaults/main.yml deleted file mode 100644 index 5818d2b..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# defaults file for artifactory_nginx \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/handlers/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/handlers/main.yml deleted file mode 100644 index f07f4d4..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/handlers/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# handlers file for artifactory_nginx \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/main.yml deleted file mode 100644 index fba3324..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/main.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -- name: install nginx - block: - - debug: - msg: "Attempting nginx installation without dependencies for potential offline mode." - - name: install nginx without dependencies - package: - name: nginx - state: present - register: package_res - retries: 5 - delay: 60 - become: yes - until: package_res is success - rescue: - - debug: - msg: "Attempting nginx installation with dependencies for potential online mode." - - name: install dependencies - include_tasks: "{{ ansible_os_family }}.yml" - - name: install nginx after dependency installation - package: - name: nginx - state: present - register: package_res - retries: 5 - delay: 60 - become: yes - until: package_res is success - -- name: configure main nginx conf file. - copy: - src: nginx.conf - dest: /etc/nginx/nginx.conf - owner: root - group: root - mode: '0755' - become: yes - -- name: configure the artifactory nginx conf - template: - src: artifactory.conf.j2 - dest: /etc/nginx/conf.d/artifactory.conf - owner: root - group: root - mode: '0755' - become: yes - -- name: restart nginx - service: - name: nginx - state: restarted - enabled: yes - become: yes diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/.travis.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/.travis.yml deleted file mode 100644 index 36bbf62..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -language: python -python: "2.7" - -# Use the new container infrastructure -sudo: false - -# Install ansible -addons: - apt: - packages: - - python-pip - -install: - # Install ansible - - pip install ansible - - # Check ansible version - - ansible --version - - # Create ansible.cfg with correct roles_path - - printf '[defaults]\nroles_path=../' >ansible.cfg - -script: - # Basic role syntax check - - ansible-playbook tests/test.yml -i tests/inventory --syntax-check - -notifications: - webhooks: https://galaxy.ansible.com/api/v1/notifications/ \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/defaults/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/defaults/main.yml deleted file mode 100644 index 5818d2b..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# defaults file for artifactory_nginx \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/handlers/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/handlers/main.yml deleted file mode 100644 index f07f4d4..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/handlers/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# handlers file for artifactory_nginx \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/.travis.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/.travis.yml deleted file mode 100644 index 9d4d136..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -language: python - -services: - - docker - -env: - global: - - DEBUG=--debug - matrix: - - MOLECULE_DISTRO=centos7 MOLECULE_SCENARIO=default - - MOLECULE_DISTRO=centos7 MOLECULE_SCENARIO=version11 - # - MOLECULE_DISTRO: fedora27 - # - MOLECULE_DISTRO: fedora29 - - MOLECULE_DISTRO=ubuntu1604 MOLECULE_SCENARIO=default - - MOLECULE_DISTRO=ubuntu1604 MOLECULE_SCENARIO=version11 - - MOLECULE_DISTRO=ubuntu1804 MOLECULE_SCENARIO=default - - MOLECULE_DISTRO=ubuntu1804 MOLECULE_SCENARIO=version11 - # - MOLECULE_DISTRO: debian9 - -before_install: - - sudo apt-get -qq update - - sudo apt-get install -y net-tools -install: - - pip install molecule docker-py - -script: - - molecule --version - - ansible --version - - molecule $DEBUG test -s $MOLECULE_SCENARIO diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/README.md b/Ansible/ansible_collections/jfrog/installers/roles/postgres/README.md deleted file mode 100644 index eccb452..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# postgres -The postgres role will install Postgresql software and configure a database and user to support an Artifactory or Xray server. - -### Role Variables -* _db_users_: This is a list of database users to create. eg. db_users: - { db_user: "artifactory", db_password: "Art1fAct0ry" } -* _dbs_: This is the database to create. eg. dbs: - { db_name: "artifactory", db_owner: "artifactory" } - -By default, the [_pg_hba.conf_](https://www.postgresql.org/docs/9.1/auth-pg-hba-conf.html) client authentication file is configured for open access for development purposes through the _postgres_allowed_hosts_ variable: - -``` -postgres_allowed_hosts: - - { type: "host", database: "all", user: "all", address: "0.0.0.0/0", method: "trust"} -``` - -**THIS SHOULD NOT BE USED FOR PRODUCTION.** - -**Update this variable to only allow access from Artifactory and Xray.** - -## Example Playbook -``` ---- -- hosts: database - roles: - - postgres -``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/handlers/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/handlers/main.yml deleted file mode 100644 index 5341b3d..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/handlers/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- - -- name: restart postgres - systemd: name={{ postgres_server_service_name }} state=restarted diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/main.yml deleted file mode 100644 index c267ba9..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/main.yml +++ /dev/null @@ -1,105 +0,0 @@ ---- -- name: define distribution-specific variables - include_vars: "{{ ansible_os_family }}.yml" - -- name: create directory for bind mount if necessary - file: - path: "{{ postgres_server_bind_mount_var_lib_pgsql_target }}" - state: directory - become: yes - when: postgres_server_bind_mount_var_lib_pgsql - - -- name: perform bind mount if necessary - mount: - path: "/var/lib/pgsql" - src: "{{ postgres_server_bind_mount_var_lib_pgsql_target }}" - opts: bind - state: mounted - fstype: none - become: yes - when: postgres_server_bind_mount_var_lib_pgsql - -- name: perform installation - include_tasks: "{{ ansible_os_family }}.yml" - -- name: extend path - copy: - dest: /etc/profile.d/postgres-path.sh - mode: a=rx - content: "export PATH=$PATH:/usr/pgsql-{{ postgres_server_version }}/bin" - become: yes - -- name: initialize PostgreSQL database cluster - environment: - LC_ALL: "en_US.UTF-8" - vars: - ansible_become: "{{ postgres_server_initdb_become }}" - ansible_become_user: "{{ postgres_server_user }}" - command: "{{ postgres_server_cmd_initdb }} {{ postgres_server_data_location }}" - args: - creates: "{{ postgres_server_data_location }}/PG_VERSION" - -- name: install postgres configuration - template: - src: "{{ item }}.j2" - dest: "{{ postgres_server_config_location }}/{{ item }}" - owner: postgres - group: postgres - mode: u=rw,go=r - vars: - ansible_become: "{{ postgres_server_initdb_become }}" - ansible_become_user: "{{ postgres_server_user }}" - loop: - - pg_hba.conf - - postgresql.conf - -- name: enable postgres service - systemd: - name: "{{ postgres_server_service_name }}" - state: started - enabled: yes - become: yes - -- name: Hold until Postgresql is up and running - wait_for: - port: 5432 - -- name: Create users - become_user: postgres - become: yes - postgresql_user: - name: "{{ item.db_user }}" - password: "{{ item.db_password }}" - conn_limit: "-1" - loop: "{{ db_users|default([]) }}" - no_log: true # secret passwords - -- name: Create a database - become_user: postgres - become: yes - postgresql_db: - name: "{{ item.db_name }}" - owner: "{{ item.db_owner }}" - encoding: UTF-8 - loop: "{{ dbs|default([]) }}" - -- name: Grant privs on db - become_user: postgres - become: yes - postgresql_privs: - database: "{{ item.db_name }}" - role: "{{ item.db_owner }}" - state: present - privs: ALL - type: database - loop: "{{ dbs|default([]) }}" - -- name: restart postgres - service: - name: "{{ postgres_server_service_name }}" - state: restarted - become: yes - -- debug: - msg: "Restarted postgres service {{ postgres_server_service_name }}" \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/Debian.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/Debian.yml deleted file mode 100644 index 1c1a7f4..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/Debian.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- - -postgres_server_cmd_initdb: /usr/lib/postgresql/{{ postgres_server_version }}/bin/initdb -D -postgres_server_initdb_become: yes -postgres_server_data_location: /var/lib/postgresql/{{ postgres_server_version }}/main -postgres_server_config_location: /etc/postgresql/{{ postgres_server_version }}/main -postgres_server_service_name: postgresql@{{ postgres_server_version }}-main - -postgres_server_config_data_directory: "/var/lib/postgresql/{{ postgres_server_version }}/main" -postgres_server_config_hba_file: "/etc/postgresql/{{ postgres_server_version }}/main/pg_hba.conf" -postgres_server_config_ident_file: "/etc/postgresql/{{ postgres_server_version }}/main/pg_ident.conf" -postgres_server_config_external_pid_file: "/var/run/postgresql/{{ postgres_server_version }}-main.pid" diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat.yml deleted file mode 100644 index f6faafd..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- - -postgres_server_cmd_initdb: /usr/pgsql-{{ postgres_server_version }}/bin/postgresql{{ postgres_server_pkg_version }}-setup initdb -D -postgres_server_data_location: /var/lib/pgsql/{{ postgres_server_version }}/data -postgres_server_config_location: "{{ postgres_server_data_location }}" -postgres_server_service_name: postgresql-{{ postgres_server_version }} - -postgres_server_config_data_directory: null -postgres_server_config_hba_file: null -postgres_server_config_ident_file: null -postgres_server_config_external_pid_file: null diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-9.6.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-9.6.yml deleted file mode 100644 index 56d0263..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-9.6.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- - -postgres_server_cmd_initdb: /usr/pgsql-{{ postgres_server_version }}/bin/postgresql{{ postgres_server_pkg_version }}-setup initdb -postgres_server_initdb_become: false diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-default.yml b/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-default.yml deleted file mode 100644 index 3d974c2..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/vars/RedHat_pg-default.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- - -postgres_server_cmd_initdb: /usr/pgsql-{{ postgres_server_version }}/bin/initdb -D /var/lib/pgsql/{{ postgres_server_version }}/data -postgres_server_initdb_become: yes diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/.travis.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/.travis.yml deleted file mode 100644 index 36bbf62..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -language: python -python: "2.7" - -# Use the new container infrastructure -sudo: false - -# Install ansible -addons: - apt: - packages: - - python-pip - -install: - # Install ansible - - pip install ansible - - # Check ansible version - - ansible --version - - # Create ansible.cfg with correct roles_path - - printf '[defaults]\nroles_path=../' >ansible.cfg - -script: - # Basic role syntax check - - ansible-playbook tests/test.yml -i tests/inventory --syntax-check - -notifications: - webhooks: https://galaxy.ansible.com/api/v1/notifications/ \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/README.md b/Ansible/ansible_collections/jfrog/installers/roles/xray/README.md deleted file mode 100644 index 2604b26..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# xray -The xray role will install Xray software onto the host. An Artifactory server and Postgress database is required. - -### Role Variables -* _xray_version_: The version of Artifactory to install. eg. "3.3.0" -* _jfrog_url_: This is the URL to the Artifactory base URL. eg. "http://ec2-54-237-207-135.compute-1.amazonaws.com" -* _master_key_: This is the Artifactory [Master Key](https://www.jfrog.com/confluence/display/JFROG/Managing+Keys). See below to [autogenerate this key](#autogenerating-master-and-join-keys). -* _join_key_: This is the Artifactory [Join Key](https://www.jfrog.com/confluence/display/JFROG/Managing+Keys). See below to [autogenerate this key](#autogenerating-master-and-join-keys). -* _db_type_: This is the database type. eg. "postgresql" -* _db_driver_: This is the JDBC driver class. eg. "org.postgresql.Driver" -* _db_url_: This is the database url. eg. "postgres://10.0.0.59:5432/xraydb?sslmode=disable" -* _db_user_: The database user to configure. eg. "xray" -* _db_password_: The database password to configure. "xray" -* _xray_system_yaml_: Your own [system YAML](https://www.jfrog.com/confluence/display/JFROG/System+YAML+Configuration+File) file can be specified and used. If specified, this file will be used rather than constructing a file from the parameters above. -* _xray_upgrade_only_: Perform an software upgrade only. Default is false. - -Additional variables can be found in [defaults/main.yml](./defaults/main.yml). -## Example Playbook -``` ---- -- hosts: xray - roles: - - xray -``` - -## Upgrades -The Xray role supports software upgrades. To use a role to perform a software upgrade only, use the _xray_upgrade_only_ variables and specify the version. See the following example. - -``` -- hosts: xray - vars: - xray_version: "{{ lookup('env', 'xray_version_upgrade') }}" - xray_upgrade_only: true - roles: - - xray -``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/defaults/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/defaults/main.yml deleted file mode 100644 index fd674bf..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/defaults/main.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# defaults file for xray -# indicates were this collection was downlaoded from (galaxy, automation_hub, standalone) -ansible_marketplace: standalone - -# The version of xray to install -xray_version: 3.10.3 - -# whether to enable HA -xray_ha_enabled: true - -# The location where xray should install. -jfrog_home_directory: /opt/jfrog - -# The remote xray download file -xray_tar: https://dl.bintray.com/jfrog/jfrog-xray/xray-linux/{{ xray_version }}/jfrog-xray-{{ xray_version }}-linux.tar.gz - -#The xray install directory -xray_untar_home: "{{ jfrog_home_directory }}/jfrog-xray-{{ xray_version }}-linux" -xray_home: "{{ jfrog_home_directory }}/xray" - -#xray users and groups -xray_user: xray -xray_group: xray - -# if this is an upgrade -xray_upgrade_only: false - -xray_system_yaml_template: system.yaml.j2 diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/handlers/main.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/handlers/main.yml deleted file mode 100644 index f236fe3..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/handlers/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# handlers file for xray \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/Debian.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/Debian.yml deleted file mode 100644 index ec28e0a..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/Debian.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -- name: Install db5.3-util - apt: - deb: "{{ xray_home }}/app/third-party/misc/db5.3-util_5.3.28-3ubuntu3_amd64.deb" - ignore_errors: yes - become: yes - -- name: Install db-util - apt: - deb: "{{ xray_home }}/app/third-party/misc/db-util_1_3a5.3.21exp1ubuntu1_all.deb" - ignore_errors: yes - become: yes - -- name: Install libssl - apt: - deb: "{{ xray_home }}/app/third-party/rabbitmq/libssl1.1_1.1.0j-1_deb9u1_amd64.deb" - ignore_errors: yes - become: yes - -- name: Install socat - apt: - deb: "{{ xray_home }}/app/third-party/rabbitmq/socat_1.7.3.1-2+deb9u1_amd64.deb" - become: yes - -- name: Install libwxbase3.0-0v5 - apt: - name: libwxbase3.0-0v5 - update_cache: yes - state: present - become: yes - -- name: Install erlang 21.2.1-1 - apt: - deb: "{{ xray_home }}/app/third-party/rabbitmq/esl-erlang_21.2.1-1~ubuntu~xenial_amd64.deb" - when: xray_version is version("3.8.0","<") - become: yes - -- name: Install erlang 22.3.4.1-1 - apt: - deb: "{{ xray_home }}/app/third-party/rabbitmq/esl-erlang_22.3.4.1-1_ubuntu_xenial_amd64.deb" - when: xray_version is version("3.8.0",">=") - become: yes \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/RedHat.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/RedHat.yml deleted file mode 100644 index a24f774..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/RedHat.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: Install db-utl - yum: - name: "{{ xray_home }}/app/third-party/misc/libdb-utils-5.3.21-19.el7.x86_64.rpm" - state: present - become: yes - -- name: Install socat - yum: - name: "{{ xray_home }}/app/third-party/rabbitmq/socat-1.7.3.2-2.el7.x86_64.rpm" - state: present - become: yes - -- name: Install erlang 21.1.4-1 - yum: - name: "{{ xray_home }}/app/third-party/rabbitmq/erlang-21.1.4-1.el7.centos.x86_64.rpm" - state: present - when: xray_version is version("3.8.0","<") - become: yes - -- name: Install erlang 22.3.4.1-1 - yum: - name: "{{ xray_home }}/app/third-party/rabbitmq/erlang-22.3.4.1-1.el7.centos.x86_64.rpm" - state: present - when: xray_version is version("3.8.0",">=") - become: yes \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/install.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/install.yml deleted file mode 100644 index 64155c8..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/install.yml +++ /dev/null @@ -1,111 +0,0 @@ ---- -- debug: - msg: "Performing installation of Xray..." - -- name: create group for xray - group: - name: "{{ xray_group }}" - state: present - become: yes - -- name: create user for xray - user: - name: "{{ xray_user }}" - group: "{{ xray_group }}" - system: yes - become: yes - -- name: ensure jfrog_home_directory exists - file: - path: "{{ jfrog_home_directory }}" - state: directory - become: yes - -- name: download xray - unarchive: - src: "{{ xray_tar }}" - dest: "{{ jfrog_home_directory }}" - remote_src: yes - owner: "{{ xray_user }}" - group: "{{ xray_group }}" - creates: "{{ xray_untar_home }}" - become: yes - register: downloadxray - until: downloadxray is succeeded - retries: 3 - -- name: MV untar directory to xray home - command: "mv {{ xray_untar_home }} {{ xray_home }}" - become: yes - -- debug: - msg: "Running dependency installation for {{ ansible_os_family }}" - -- name: perform dependency installation - include_tasks: "{{ ansible_os_family }}.yml" - -- name: ensure etc exists - file: - path: "{{ xray_home }}/var/etc" - state: directory - owner: "{{ xray_user }}" - group: "{{ xray_group }}" - become: yes - -- name: use specified system yaml - copy: - src: "{{ xray_system_yaml }}" - dest: "{{ xray_home }}/var/etc/system.yaml" - become: yes - when: xray_system_yaml is defined - -- name: configure system yaml template - template: - src: "{{ xray_system_yaml_template }}" - dest: "{{ xray_home }}/var/etc/system.yaml" - become: yes - when: xray_system_yaml is not defined - -- name: ensure {{ xray_home }}/var/etc/security/ exists - file: - path: "{{ xray_home }}/var/etc/security/" - state: directory - owner: "{{ xray_user }}" - group: "{{ xray_group }}" - become: yes - -- name: configure master key - template: - src: master.key.j2 - dest: "{{ xray_home }}/var/etc/security/master.key" - become: yes - -- name: configure join key - template: - src: join.key.j2 - dest: "{{ xray_home }}/var/etc/security/join.key" - become: yes - -- name: ensure {{ xray_home }}/var/etc/info/ exists - file: - path: "{{ xray_home }}/var/etc/info/" - state: directory - owner: "{{ xray_user }}" - group: "{{ xray_group }}" - become: yes - -- name: configure installer info - template: - src: installer-info.json.j2 - dest: "{{ xray_home }}/var/etc/info/installer-info.json" - become: yes - -- name: create xray service - shell: "{{ xray_home }}/app/bin/installService.sh" - become: yes - -- name: start and enable xray - service: - name: xray - state: restarted - become: yes \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/upgrade.yml b/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/upgrade.yml deleted file mode 100644 index 623661c..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/upgrade.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- -- debug: - msg: "Performing upgrade of Xray..." - -- name: stop xray - service: - name: xray - state: stopped - become: yes - -- name: ensure jfrog_home_directory exists - file: - path: "{{ jfrog_home_directory }}" - state: directory - become: yes - -- name: download xray - unarchive: - src: "{{ xray_tar }}" - dest: "{{ jfrog_home_directory }}" - remote_src: yes - owner: "{{ xray_user }}" - group: "{{ xray_group }}" - creates: "{{ xray_untar_home }}" - become: yes - register: downloadxray - until: downloadxray is succeeded - retries: 3 - -- name: Delete xray app - file: - path: "{{ xray_home }}/app" - state: absent - become: yes - -- name: CP new app to xray app - command: "cp -r {{ xray_untar_home }}/app {{ xray_home }}/app" - become: yes - -- name: Delete untar directory - file: - path: "{{ xray_untar_home }}" - state: absent - become: yes - -- name: create xray service - shell: "{{ xray_home }}/app/bin/installService.sh" - become: yes - -- name: start and enable xray - service: - name: xray - state: restarted - become: yes \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/installer-info.json.j2 b/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/installer-info.json.j2 deleted file mode 100644 index a76c88c..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/installer-info.json.j2 +++ /dev/null @@ -1,11 +0,0 @@ -{ - "productId": "Ansible_artifactory/1.0.0", - "features": [ - { - "featureId": "Partner/ACC-006973" - }, - { - "featureId": "Channel/{{ ansible_marketplace }}" - } - ] -} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/join.key.j2 b/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/join.key.j2 deleted file mode 100644 index 17d05d2..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/join.key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ join_key }} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/master.key.j2 b/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/master.key.j2 deleted file mode 100644 index 0462a64..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/master.key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ master_key }} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/system.yaml.j2 b/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/system.yaml.j2 deleted file mode 100644 index 206eb77..0000000 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/templates/system.yaml.j2 +++ /dev/null @@ -1,36 +0,0 @@ -## @formatter:off -## JFROG ARTIFACTORY SYSTEM CONFIGURATION FILE -## HOW TO USE: comment-out any field and keep the correct yaml indentation by deleting only the leading '#' character. -configVersion: 1 - -## NOTE: JFROG_HOME is a place holder for the JFrog root directory containing the deployed product, the home directory for all JFrog products. -## Replace JFROG_HOME with the real path! For example, in RPM install, JFROG_HOME=/opt/jfrog - -## NOTE: Sensitive information such as passwords and join key are encrypted on first read. -## NOTE: The provided commented key and value is the default. - -## SHARED CONFIGURATIONS -## A shared section for keys across all services in this config -shared: - ## Base URL of the JFrog Platform Deployment (JPD) - ## This is the URL to the machine where JFrog Artifactory is deployed, or the load balancer pointing to it. It is recommended to use DNS names rather than direct IPs. - ## Examples: "http://jfrog.acme.com" or "http://10.20.30.40:8082" - jfrogUrl: {{ jfrog_url }} - - ## Node Settings - node: - ## A unique id to identify this node. - ## Default: auto generated at startup. - id: {{ ansible_machine_id }} - - ## Database Configuration - database: - ## One of: mysql, oracle, mssql, postgresql, mariadb - ## Default: Embedded derby - - ## Example for mysql/postgresql - type: "{{ db_type }}" - driver: "{{ db_driver }}" - url: "{{ db_url }}" - username: "{{ db_user }}" - password: "{{ db_password }}" \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/README.md b/Ansible/ansible_collections/jfrog/platform/README.md new file mode 100644 index 0000000..1d24d83 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/README.md @@ -0,0 +1,112 @@ +# JFrog Platform Ansible Collection + +This Ansible directory consists of the following directories that support the JFrog Platform collection. + + * [ansible_collections directory](ansible_collections) - This directory contains the Ansible collection package that has the Ansible roles for Artifactory, Distribution, Missioncontrol and Xray. See the roles README for details on the product roles and variables. + * [examples directory](examples) - This directory contains example playbooks for various architectures. + + + ## Getting Started + + 1. Install this collection from Ansible Galaxy. This collection is also available in RedHat Automation Hub. + + ``` + ansible-galaxy collection install jfrog.platform + ``` + + Ensure you reference the collection in your playbook when using these roles. + + ``` + --- + - hosts: artifactory_servers + collections: + - jfrog.platform + roles: + - artifactory + + ``` + + 2. Ansible uses SSH to connect to hosts. Ensure that your SSH private key is on your client and the public keys are installed on your Ansible hosts. + + 3. Create your inventory file. Use one of the examples from the [examples directory](examples) to construct an inventory file (hosts.ini) with the host addresses + + 4. Create your playbook. Use one of the examples from the [examples directory](examples) to construct a playbook using the JFrog Ansible roles. These roles will be applied to your inventory and provision software. + + 5. Then execute with the following command to provision the JFrog Platform with Ansible. + +``` +ansible-playbook -vv platform.yml -i hosts.ini" +``` + +## Generating Master and Join Keys +**Note** : If you don't provide these keys, they will be set to defaults (check groupvars/all/vars.yaml file) +For production deployments,You may want to generate your master amd join keys and apply it to all the nodes. +**IMPORTANT** : Save below generated master and join keys for future upgrades + +``` +MASTER_KEY_VALUE=$(openssl rand -hex 32) +JOIN_KEY_VALUE=$(openssl rand -hex 32) +ansible-playbook -vv platform.yml -i hosts.ini --extra-vars "master_key=$MASTER_KEY_VALUE join_key=$JOIN_KEY_VALUE" +``` + +## Using [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html) to Encrypt Vars +Some vars you may want to keep secret. You may put these vars into a separate file and encrypt them using [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html). + +``` +ansible-vault encrypt secret-vars.yml --vault-password-file ~/.vault_pass.txt +``` + +then in your playbook include the secret vars file. + +``` +- hosts: artifactory_servers + + vars_files: + - ./vars/secret-vars.yml + - ./vars/vars.yml + + roles: + - artifactory +``` + +## Upgrades +All JFrog product roles support software updates. To use a role to perform a software update only, use the __upgrade_only_ variable and specify the version. See the following example. + +``` +- hosts: artifactory_servers + vars: + artifactory_version: "{{ lookup('env', 'artifactory_version_upgrade') }}" + artifactory_upgrade_only: true + roles: + - artifactory + +- hosts: xray_servers + vars: + xray_version: "{{ lookup('env', 'xray_version_upgrade') }}" + xray_upgrade_only: true + roles: + - xray +``` + +## Building the Collection Archive +1. Go to the [ansible_collections/jfrog/platform directory](ansible_collections/jfrog/platform). +2. Update the galaxy.yml meta file as needed. Update the version. +3. Build the archive. (Requires Ansible 2.9+) +``` +ansible-galaxy collection build +``` + +## OS support +The JFrog Platform Ansible Collection can be installed on the following operating systems: + +* Ubuntu LTS versions (16.04/18.04/20.4) +* Centos/RHEL 7.x/8.x +* Debian 9.x/10.x + +## Known issues +* Refer [here](https://github.com/jfrog/JFrog-Cloud-Installers/issues?q=is%3Aopen+is%3Aissue+label%3AAnsible) +* By default, ansible_python_interpreter: "/usr/bin/python3" used , For Centos/RHEL-7, Set this to "/usr/bin/python" . For example +``` +ansible-playbook -vv platform.yml -i hosts.ini -e 'ansible_python_interpreter=/usr/bin/python' +``` + diff --git a/Ansible/ansible_collections/jfrog/platform/ansible.cfg b/Ansible/ansible_collections/jfrog/platform/ansible.cfg new file mode 100644 index 0000000..5c2352e --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +host_key_checking = false +stdout_callback = debug +remote_tmp = /tmp/.ansible/tmp +private_key_file=~/.ssh/ansible-jfrog.key +timeout = 20 diff --git a/Ansible/ansible_collections/jfrog/platform/artifactory.yml b/Ansible/ansible_collections/jfrog/platform/artifactory.yml new file mode 100644 index 0000000..b0a9eef --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/artifactory.yml @@ -0,0 +1,4 @@ +--- +- hosts: artifactory_servers + roles: + - artifactory diff --git a/Ansible/ansible_collections/jfrog/platform/distribution.yml b/Ansible/ansible_collections/jfrog/platform/distribution.yml new file mode 100644 index 0000000..d1e90e5 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/distribution.yml @@ -0,0 +1,4 @@ +--- +- hosts: distribution_servers + roles: + - distribution diff --git a/Ansible/ansible_collections/jfrog/installers/galaxy.yml b/Ansible/ansible_collections/jfrog/platform/galaxy.yml similarity index 80% rename from Ansible/ansible_collections/jfrog/installers/galaxy.yml rename to Ansible/ansible_collections/jfrog/platform/galaxy.yml index d407f59..c649f5d 100644 --- a/Ansible/ansible_collections/jfrog/installers/galaxy.yml +++ b/Ansible/ansible_collections/jfrog/platform/galaxy.yml @@ -6,10 +6,10 @@ namespace: "jfrog" # The name of the collection. Has the same character restrictions as 'namespace' -name: "installers" +name: "platform" # The version of the collection. Must be compatible with semantic versioning -version: "1.1.2" +version: "7.18.5" # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: "README.md" @@ -17,13 +17,13 @@ readme: "README.md" # A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) # @nicks:irc/im.site#channel' authors: - - "Jeff Fry " + - "JFrog Maintainers Team " ### OPTIONAL but strongly recommended # A short summary description of the collection -description: "This collection provides roles for installing Artifactory and Xray. Additionally, it provides optional SSL and Postgresql roles if these are needed for your deployment." +description: "This collection provides roles for installing JFrog Platform which includes Artifactory, Distribution, Mission-control and Xray. Additionally, it provides optional SSL and Postgresql roles if these are needed for your deployment." # Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only # accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' @@ -37,10 +37,14 @@ license_file: "" # A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character # requirements as 'namespace' and 'name' tags: - - artifactory - - xray - jfrog + - platform + - devops - application + - artifactory + - distribution + - missioncontrol + - xray # Collections that this collection requires to be installed for it to be usable. The key of the dict is the # collection label 'namespace.name'. The value is a version range @@ -49,13 +53,13 @@ tags: dependencies: {} # The URL of the originating SCM repository -repository: "https://github.com/jfrog/JFrog-Cloud-Installers/" +repository: "https://github.com/jfrog/JFrog-Cloud-Installers/Ansible" # The URL to any online docs documentation: "https://github.com/jfrog/JFrog-Cloud-Installers/blob/master/Ansible/README.md" # The URL to the homepage of the collection/project -homepage: "https://github.com/jfrog/JFrog-Cloud-Installers/" +homepage: "https://github.com/jfrog/JFrog-Cloud-Installers/Ansible" # The URL to the collection issue tracker issues: "https://github.com/jfrog/JFrog-Cloud-Installers/issues" diff --git a/Ansible/ansible_collections/jfrog/platform/group_vars/all/package_version.yml b/Ansible/ansible_collections/jfrog/platform/group_vars/all/package_version.yml new file mode 100644 index 0000000..7000464 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/group_vars/all/package_version.yml @@ -0,0 +1,8 @@ +# The version of products to install +artifactory_version: 7.18.5 +xray_version: 3.24.2 +distribution_version: 2.7.1 +missioncontrol_version: 4.7.3 + +# platform collection version +platform_collection_version: 7.18.5 diff --git a/Ansible/ansible_collections/jfrog/platform/group_vars/all/vars.yml b/Ansible/ansible_collections/jfrog/platform/group_vars/all/vars.yml new file mode 100755 index 0000000..d9701dd --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/group_vars/all/vars.yml @@ -0,0 +1,74 @@ +--- +# Defaults +## Note : These values are global and can be overridden in role//defaults/main.yaml file +## For production deployments,You may want to generate your master amd join keys and apply it to all the nodes. +master_key: ee69d96880726d3abf6b42b97d2ae589111ea95c2a8bd5876ec5cd9e8ee34f86 +join_key: 83da88eaaa08dfed5b86888fcec85f19ace0c3ff8747bcefcec2c9769ad4043d + +jfrog_url: >- + {%- for host in groups['artifactory_servers'] -%} + "http://{{ hostvars[host]['ansible_host'] }}:8082" + {%- endfor -%} + +# Artifactory DB details +artifactory_db_type: postgresql +artifactory_db_driver: org.postgresql.Driver +artifactory_db_name: artifactory +artifactory_db_user: artifactory +artifactory_db_password: password +artifactory_db_url: >- + {%- for item in groups['postgres_servers'] -%} + jdbc:postgresql://{{ hostvars[item]['ansible_host'] }}:5432/{{ artifactory_db_name }} + {%- endfor -%} + +# Xray DB details +xray_db_type: postgresql +xray_db_driver: org.postgresql.Driver +xray_db_name: xray +xray_db_user: xray +xray_db_password: password +xray_db_url: >- + {%- for item in groups['postgres_servers'] -%} + postgres://{{ hostvars[item]['ansible_host'] }}:5432/{{ xray_db_name }}?sslmode=disable + {%- endfor -%} + +# Distribution DB details +distribution_db_type: postgresql +distribution_db_driver: org.postgresql.Driver +distribution_db_name: distribution +distribution_db_user: distribution +distribution_db_password: password +distribution_db_url: >- + {%- for item in groups['postgres_servers'] -%} + jdbc:postgresql://{{ hostvars[item]['ansible_host'] }}:5432/{{ distribution_db_name }}?sslmode=disable + {%- endfor -%} + +# MissionControl DB details +mc_db_type: postgresql +mc_db_driver: org.postgresql.Driver +mc_db_name: mc +mc_db_user: mc +mc_db_password: password +mc_db_url: >- + {%- for item in groups['postgres_servers'] -%} + jdbc:postgresql://{{ hostvars[item]['ansible_host'] }}:5432/{{ mc_db_name }}?sslmode=disable + {%- endfor -%} + +# Postgresql users and databases/schemas +db_users: + - { db_user: "{{ artifactory_db_user }}", db_password: "{{ artifactory_db_password }}" } + - { db_user: "{{ xray_db_user }}", db_password: "{{ xray_db_password }}" } + - { db_user: "{{ distribution_db_user }}", db_password: "{{ distribution_db_password }}" } + - { db_user: "{{ mc_db_user }}", db_password: "{{ mc_db_password }}" } +dbs: + - { db_name: "{{ artifactory_db_name }}", db_owner: "{{ artifactory_db_user }}" } + - { db_name: "{{ xray_db_name }}", db_owner: "{{ xray_db_user }}" } + - { db_name: "{{ distribution_db_name }}", db_owner: "{{ distribution_db_user }}" } + - { db_name: "{{ mc_db_name }}", db_owner: "{{ mc_db_user }}" } +mc_schemas: + - jfmc_server + - insight_server + - insight_scheduler + +# For Centos/RHEL-7, Set this to "/usr/bin/python" +ansible_python_interpreter: "/usr/bin/python3" \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/hosts.ini b/Ansible/ansible_collections/jfrog/platform/hosts.ini new file mode 100644 index 0000000..b721a54 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/hosts.ini @@ -0,0 +1,23 @@ +[postgres_servers] +postgres-1 ansible_host=10.70.64.85 private_ip=10.70.64.85 + +[artifactory_servers] +artifactory-1 ansible_host=10.70.64.84 private_ip=10.70.64.84 + +[xray_servers] +xray-1 ansible_host=10.70.64.83 private_ip=10.70.64.83 + +[distribution_servers] +distribution-1 ansible_host=10.70.64.82 private_ip=10.70.64.82 + +[missionControl_servers] +missionControl-1 ansible_host=10.70.64.79 private_ip=10.70.64.79 + +[xray_secondary_servers] +xray-2 ansible_host=0.0.0.0 private_ip=0.0.0.0 + +[distribution_secondary_servers] +distribution-2 ansible_host=0.0.0.0 private_ip=0.0.0.0 + +[missionControl_secondary_servers] +missionControl-2 ansible_host=0.0.0.0 private_ip=0.0.0.0 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/jfrog-platform-7.18.5.tar.gz b/Ansible/ansible_collections/jfrog/platform/jfrog-platform-7.18.5.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c565760f80bb9e4c0393ed0c71147791c6ec75e2 GIT binary patch literal 55136 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�Jz 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

    v<*=;F|<803ZL#n>mooht$A@Q%UHBT?S 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 b + +# + +# + +# To enable HA, set to true +artifactory_ha_enabled: false + +# By default, all nodes are primary (CNHA) - https://www.jfrog.com/confluence/display/JFROG/High+Availability#HighAvailability-Cloud-NativeHighAvailability +artifactory_taskAffinity: any + +# The location where Artifactory should install. +jfrog_home_directory: /opt/jfrog + +# The location where Artifactory should store data. +artifactory_file_store_dir: /data + +# Pick the Artifactory flavour to install, can be also cpp-ce, jcr, pro. +artifactory_flavour: pro + +artifactory_extra_java_opts: -server -Xms512m -Xmx2g -Xss256k -XX:+UseG1GC +artifactory_system_yaml_template: system.yaml.j2 +artifactory_tar: https://releases.jfrog.io/artifactory/artifactory-pro/org/artifactory/pro/jfrog-artifactory-pro/{{ artifactory_version }}/jfrog-artifactory-pro-{{ artifactory_version }}-linux.tar.gz +artifactory_home: "{{ jfrog_home_directory }}/artifactory" +artifactory_untar_home: "{{ jfrog_home_directory }}/artifactory-{{ artifactory_flavour }}-{{ artifactory_version }}" + +postgres_driver_download_url: https://repo1.maven.org/maven2/org/postgresql/postgresql/42.2.20/postgresql-42.2.20.jar + +artifactory_user: artifactory +artifactory_group: artifactory + +artifactory_daemon: artifactory + +artifactory_uid: 1030 +artifactory_gid: 1030 + +# if this is an upgrade +artifactory_upgrade_only: false + +#default username and password +artifactory_admin_username: admin +artifactory_admin_password: password diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/handlers/main.yml new file mode 100644 index 0000000..4cd96cc --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/handlers/main.yml @@ -0,0 +1,7 @@ +--- +# handlers file for distribution +- name: restart artifactory + become: yes + systemd: + name: "{{ artifactory_daemon }}" + state: restarted diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/meta/main.yml similarity index 88% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory/meta/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory/meta/main.yml index c128393..e604dfc 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/meta/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/meta/main.yml @@ -1,5 +1,5 @@ galaxy_info: - author: "Jeff Fry " + author: "JFrog Maintainers Team " description: "The artifactory role installs the Artifactory Pro software onto the host. Per the Vars below, it will configure a node as primary or secondary. This role uses secondary roles artifactory_nginx to install nginx." company: JFrog diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/install.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/install.yml new file mode 100644 index 0000000..74aec64 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/install.yml @@ -0,0 +1,161 @@ +--- +- debug: + msg: "Performing installation of Artifactory version : {{ artifactory_version }} " + +- name: install nginx + include_role: + name: artifactory_nginx + when: artifactory_nginx_ssl_enabled == false + +- name: install nginx with SSL + include_role: + name: artifactory_nginx_ssl + when: artifactory_nginx_ssl_enabled == true + +- name: Ensure group artifactory exist + become: yes + group: + name: "{{ artifactory_group }}" + gid: "{{ artifactory_gid }}" + state: present + +- name: Ensure user artifactory exist + become: yes + user: + uid: "{{ artifactory_uid }}" + name: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + create_home: yes + home: "{{ artifactory_home }}" + shell: /bin/bash + state: present + +- name: Download artifactory + become: yes + unarchive: + src: "{{ artifactory_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + creates: "{{ artifactory_untar_home }}" + when: artifactory_tar is defined + register: downloadartifactory + until: downloadartifactory is succeeded + retries: 3 + +- name: Check if app directory exists + become: yes + stat: + path: "{{ artifactory_home }}/app" + register: app_dir_check + +- name: Copy untar directory to artifactory home + become: yes + command: "cp -r {{ artifactory_untar_home }}/. {{ artifactory_home }}" + when: not app_dir_check.stat.exists + +- name: Create required directories + become: yes + file: + path: "{{ item }}" + state: directory + recurse: yes + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + loop: + - "{{ artifactory_file_store_dir }}" + - "{{ artifactory_home }}/var/data" + - "{{ artifactory_home }}/var/etc" + - "{{ artifactory_home }}/var/etc/security/" + - "{{ artifactory_home }}/var/etc/artifactory/info/" + +- name: Configure systemyaml + become: yes + template: + src: "{{ artifactory_system_yaml_template }}" + dest: "{{ artifactory_home }}/var/etc/system.yaml" + notify: restart artifactory + +- name: Configure master key + become: yes + copy: + dest: "{{ artifactory_home }}/var/etc/security/master.key" + content: | + {{ master_key }} + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + mode: 0640 + +- name: Configure join key + become: yes + copy: + dest: "{{ artifactory_home }}/var/etc/security/join.key" + content: | + {{ join_key }} + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + mode: 0640 + notify: restart artifactory + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/info/installer-info.json" + notify: restart artifactory + +- name: Configure binary store + become: yes + template: + src: binarystore.xml.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/binarystore.xml" + notify: restart artifactory + +- name: Configure single license + become: yes + template: + src: artifactory.lic.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/artifactory.lic" + when: artifactory_single_license is defined + notify: restart artifactory + +- name: Configure HA licenses + become: yes + template: + src: artifactory.cluster.license.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/artifactory.cluster.license" + when: artifactory_licenses is defined + notify: restart artifactory + +- name: Download database driver + become: yes + get_url: + url: "{{ postgres_driver_download_url }}" + dest: "{{ artifactory_home }}/var/bootstrap/artifactory/tomcat/lib" + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + when: postgres_driver_download_url is defined + notify: restart artifactory + +- name: Create artifactory service + become: yes + shell: "{{ artifactory_home }}/app/bin/installService.sh" + +- name: Ensure permissions are correct + become: yes + file: + path: "{{ jfrog_home_directory }}" + group: "{{ artifactory_group }}" + owner: "{{ artifactory_user }}" + recurse: yes + +- name: Restart artifactory + meta: flush_handlers + +- name : Wait for artifactory to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/main.yml new file mode 100644 index 0000000..3afccb3 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/main.yml @@ -0,0 +1,6 @@ +- name: perform installation + include_tasks: "install.yml" + when: not artifactory_upgrade_only +- name: perform upgrade + include_tasks: "upgrade.yml" + when: artifactory_upgrade_only \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/upgrade.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/upgrade.yml new file mode 100644 index 0000000..547c41d --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/tasks/upgrade.yml @@ -0,0 +1,105 @@ +--- +- debug: + msg: "Performing upgrade of Artifactory version to : {{ artifactory_version }} " + +- name: Stop artifactory + become: yes + systemd: + name: "{{ artifactory_daemon }}" + state: stopped + +- name: Ensure jfrog_home_directory exists + become: yes + file: + path: "{{ jfrog_home_directory }}" + state: directory + +- name: Download artifactory for upgrade + become: yes + unarchive: + src: "{{ artifactory_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + creates: "{{ artifactory_untar_home }}" + when: artifactory_tar is defined + register: downloadartifactory + until: downloadartifactory is succeeded + retries: 3 + +- name: Delete artifactory app directory + become: yes + file: + path: "{{ artifactory_home }}/app" + state: absent + +- name: Copy new app to artifactory app + become: yes + command: "cp -r {{ artifactory_untar_home }}/app/. {{ artifactory_home }}/app" + +- name: Configure join key + become: yes + copy: + dest: "{{ artifactory_home }}/var/etc/security/join.key" + content: | + {{ join_key }} + owner: "{{ artifactory_user }}" + group: "{{ artifactory_group }}" + mode: 0640 + notify: restart artifactory + +- name: Configure single license + become: yes + template: + src: artifactory.lic.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/artifactory.lic" + when: artifactory_single_license is defined + notify: restart artifactory + +- name: Configure HA licenses + become: yes + template: + src: artifactory.cluster.license.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/artifactory.cluster.license" + when: artifactory_licenses is defined + notify: restart artifactory + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/info/installer-info.json" + notify: restart artifactory + +- name: Configure binary store + become: yes + template: + src: binarystore.xml.j2 + dest: "{{ artifactory_home }}/var/etc/artifactory/binarystore.xml" + notify: restart artifactory + +- name: Configure systemyaml + become: yes + template: + src: "{{ artifactory_system_yaml_template }}" + dest: "{{ artifactory_home }}/var/etc/system.yaml" + notify: restart artifactory + +- name: Ensure permissions are correct + become: yes + file: + path: "{{ jfrog_home_directory }}" + group: "{{ artifactory_group }}" + owner: "{{ artifactory_user }}" + recurse: yes + +- name: Restart artifactory + meta: flush_handlers + +- name : Wait for artifactory to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.cluster.license.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.cluster.license.j2 new file mode 100644 index 0000000..8fa3367 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.cluster.license.j2 @@ -0,0 +1,3 @@ +{% if (artifactory_licenses) and (artifactory_licenses|length > 0) %} +{{ artifactory_licenses }} +{% endif %} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.lic.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.lic.j2 new file mode 100644 index 0000000..49fa0ca --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/artifactory.lic.j2 @@ -0,0 +1,3 @@ +{% if (artifactory_single_license) and (artifactory_single_license|length > 0) %} +{{ artifactory_single_license }} +{% endif %} diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/binarystore.xml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/binarystore.xml.j2 similarity index 91% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/binarystore.xml.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/binarystore.xml.j2 index f85f16f..a06e211 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory/templates/binarystore.xml.j2 +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/binarystore.xml.j2 @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/installer-info.json.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/installer-info.json.j2 new file mode 100644 index 0000000..639e741 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/installer-info.json.j2 @@ -0,0 +1,9 @@ +{{ ansible_managed | comment }} +{ + "productId": "Ansible_Artifactory/{{ platform_collection_version }}-{{ artifactory_version }}", + "features": [ + { + "featureId": "Channel/{{ ansible_marketplace }}" + } + ] +} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/system.yaml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/system.yaml.j2 new file mode 100644 index 0000000..876afd5 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory/templates/system.yaml.j2 @@ -0,0 +1,17 @@ +configVersion: 1 +shared: + extraJavaOpts: "{{ artifactory_extra_java_opts }}" + node: + id: {{ ansible_date_time.iso8601_micro | to_uuid }} + ip: {{ ansible_host }} + taskAffinity: {{ artifactory_taskAffinity }} + haEnabled: {{ artifactory_ha_enabled }} + database: + type: "{{ artifactory_db_type }}" + driver: "{{ artifactory_db_driver }}" + url: "{{ artifactory_db_url }}" + username: "{{ artifactory_db_user }}" + password: "{{ artifactory_db_password }}" +router: + entrypoints: + internalPort: 8046 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/README.md b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/README.md similarity index 65% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/README.md rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/README.md index 6a6cb60..75da2e8 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/README.md +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/README.md @@ -2,4 +2,4 @@ This role installs NGINX for artifactory. This role is automatically called by the artifactory role and isn't intended to be used separately. ## Role Variables -* _server_name_: This is the server name. eg. "artifactory.54.175.51.178.xip.io" \ No newline at end of file +* _server_name_: **mandatory** This is the server name. eg. "artifactory.54.175.51.178.xip.io" \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/defaults/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/defaults/main.yml new file mode 100644 index 0000000..72c1819 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# defaults file for artifactory_nginx +## For production deployments,You SHOULD change it. +server_name: test.artifactory.com + +nginx_daemon: nginx + diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/files/nginx.conf b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/files/nginx.conf similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/files/nginx.conf rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/files/nginx.conf diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/handlers/main.yml new file mode 100644 index 0000000..ddfbae0 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/handlers/main.yml @@ -0,0 +1,8 @@ +--- +# handlers file for artifactory_nginx +- name: restart nginx + become: yes + systemd: + name: "{{ nginx_daemon }}" + state: restarted + enabled: yes diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/meta/main.yml similarity index 87% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/meta/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/meta/main.yml index bb133f7..5dbaba7 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/meta/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/meta/main.yml @@ -1,5 +1,5 @@ galaxy_info: - author: "Jeff Fry " + author: "JFrog Maintainers Team " description: "This role installs NGINX for artifactory. This role is automatically called by the artifactory role and isn't intended to be used separately." company: JFrog diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/Debian.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/Debian.yml similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/Debian.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/Debian.yml index cc41ad0..5ab7957 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/Debian.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/Debian.yml @@ -1,9 +1,9 @@ --- - name: apt-get update + become: yes apt: update_cache: yes register: package_res retries: 5 delay: 60 - become: yes until: package_res is success diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/RedHat.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/RedHat.yml similarity index 63% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/RedHat.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/RedHat.yml index 93c4168..9d806fa 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/tasks/RedHat.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/RedHat.yml @@ -1,6 +1,6 @@ --- - name: epel-release + become: yes yum: name: epel-release - state: present - become: yes \ No newline at end of file + state: present \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/main.yml new file mode 100644 index 0000000..7a2a319 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/tasks/main.yml @@ -0,0 +1,35 @@ +--- +- name: Install dependencies + include_tasks: "{{ ansible_os_family }}.yml" + +- name: Install nginx after dependency installation + become: yes + package: + name: nginx + state: present + register: package_res + retries: 5 + delay: 60 + until: package_res is success + +- name: Configure main nginx conf file. + become: yes + copy: + src: nginx.conf + dest: /etc/nginx/nginx.conf + owner: root + group: root + mode: '0755' + +- name: Configure the artifactory nginx conf + become: yes + template: + src: artifactory.conf.j2 + dest: /etc/nginx/conf.d/artifactory.conf + owner: root + group: root + mode: '0755' + notify: restart nginx + +- name: Restart nginx + meta: flush_handlers \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/templates/artifactory.conf.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/templates/artifactory.conf.j2 similarity index 95% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/templates/artifactory.conf.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/templates/artifactory.conf.j2 index 58280d9..a3f6eb1 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/templates/artifactory.conf.j2 +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/templates/artifactory.conf.j2 @@ -1,6 +1,6 @@ ########################################################### ## this configuration was generated by JFrog Artifactory ## - ########################################################### +########################################################### ## add HA entries when ha is configure upstream artifactory { diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/vars/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/vars/main.yml similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx/vars/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx/vars/main.yml diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/README.md b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/README.md similarity index 72% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/README.md rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/README.md index 9a32719..cb43b09 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/README.md +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/README.md @@ -5,12 +5,3 @@ The artifactory_nginx_ssl role installs and configures nginx for SSL. * _server_name_: This is the server name. eg. "artifactory.54.175.51.178.xip.io" * _certificate_: This is the SSL cert. * _certificate_key_: This is the SSL private key. - -## Example Playbook -``` ---- -- hosts: primary - roles: - - artifactory - - artifactory_nginx_ssl -``` diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/defaults/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/defaults/main.yml new file mode 100644 index 0000000..8dea698 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/defaults/main.yml @@ -0,0 +1,7 @@ +--- +# defaults file for artifactory_nginx + +## For production deployments,You SHOULD change it. +# server_name: test.artifactory.com + +nginx_daemon: nginx diff --git a/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/handlers/main.yml new file mode 100644 index 0000000..ac1192c --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/handlers/main.yml @@ -0,0 +1,8 @@ +--- +# handlers file for artifactory_nginx_ssl +- name: restart nginx + become: yes + systemd: + name: "{{ nginx_daemon }}" + state: restarted + enabled: yes diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/meta/main.yml similarity index 84% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/meta/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/meta/main.yml index 5715d56..64dff56 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/meta/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/meta/main.yml @@ -1,5 +1,5 @@ galaxy_info: - author: "Jeff Fry " + author: "JFrog Maintainers Team " description: "The artifactory_nginx_ssl role installs and configures nginx for SSL." company: JFrog diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/tasks/main.yml similarity index 66% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/tasks/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/tasks/main.yml index ea18fe2..447699d 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/tasks/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/tasks/main.yml @@ -1,41 +1,40 @@ --- # tasks file for artifactory_nginx -- name: configure the artifactory nginx conf +- name: Configure the artifactory nginx conf + become: yes template: src: artifactory.conf.j2 dest: /etc/nginx/conf.d/artifactory.conf owner: root group: root mode: '0755' - become: yes + notify: restart nginx -- name: ensure nginx dir exists +- name: Ensure nginx dir exists + become: yes file: path: "/var/opt/jfrog/nginx/ssl" state: directory - become: yes -- name: configure certificate +- name: Configure certificate + become: yes template: src: certificate.pem.j2 dest: "/var/opt/jfrog/nginx/ssl/cert.pem" - become: yes + notify: restart nginx -- name: ensure pki exists +- name: Ensure pki exists + become: yes file: path: "/etc/pki/tls" state: directory - become: yes -- name: configure key +- name: Configure key + become: yes template: src: certificate.key.j2 dest: "/etc/pki/tls/cert.key" - become: yes + notify: restart nginx -- name: restart nginx - service: - name: nginx - state: restarted - enabled: yes - become: yes \ No newline at end of file +- name: Restart nginx + meta: flush_handlers diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 similarity index 96% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 index 315a601..20df8db 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 +++ b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/artifactory.conf.j2 @@ -1,6 +1,6 @@ ########################################################### ## this configuration was generated by JFrog Artifactory ## - ########################################################### +########################################################### ## add HA entries when ha is configure upstream artifactory { diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/certificate.key.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/certificate.key.j2 similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/certificate.key.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/certificate.key.j2 diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/certificate.pem.j2 b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/certificate.pem.j2 similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/templates/certificate.pem.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/templates/certificate.pem.j2 diff --git a/Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/vars/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/vars/main.yml similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/artifactory_nginx_ssl/vars/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/artifactory_nginx_ssl/vars/main.yml diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/README.md b/Ansible/ansible_collections/jfrog/platform/roles/distribution/README.md new file mode 100644 index 0000000..d805f00 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/README.md @@ -0,0 +1,26 @@ +# Distribution +The Distribution role will install distribution software onto the host. An Artifactory server and Postgress database is required. + +### Role Variables +* _distribution_upgrade_only_: Perform an software upgrade only. Default is false. + +Additional variables can be found in [defaults/main.yml](./defaults/main.yml). +## Example Playbook +``` +--- +- hosts: distribution_servers + roles: + - distribution +``` + +## Upgrades +The distribution role supports software upgrades. To use a role to perform a software upgrade only, use the _xray_upgrade_only_ variables and specify the version. See the following example. + +``` +- hosts: distributionservers + vars: + distribution_version: "{{ lookup('env', 'distribution_version_upgrade') }}" + distribution_upgrade_only: true + roles: + - distribution +``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/defaults/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/defaults/main.yml new file mode 100644 index 0000000..31e2c0a --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/defaults/main.yml @@ -0,0 +1,43 @@ +--- +# defaults file for distribution +# indicates were this collection was downlaoded from (galaxy, automation_hub, standalone) +ansible_marketplace: standalone + +# whether to enable HA +distribution_ha_enabled: false + +distribution_ha_node_type : master + +# The location where distribution should install. +jfrog_home_directory: /opt/jfrog + +# The remote distribution download file +distribution_tar: https://releases.jfrog.io/artifactory/jfrog-distribution/distribution-linux/{{ distribution_version }}/jfrog-distribution-{{ distribution_version }}-linux.tar.gz + +#The distribution install directory +distribution_untar_home: "{{ jfrog_home_directory }}/jfrog-distribution-{{ distribution_version }}-linux" +distribution_home: "{{ jfrog_home_directory }}/distribution" + +distribution_install_script_path: "{{ distribution_home }}/app/bin" +distribution_thirdparty_path: "{{ distribution_home }}/app/third-party" +distribution_archive_service_cmd: "{{ distribution_install_script_path }}/installService.sh" + +#distribution users and groups +distribution_user: distribution +distribution_group: distribution + +distribution_uid: 1040 +distribution_gid: 1040 + +distribution_daemon: distribution + +flow_type: archive + +# Redis details +distribution_redis_url: "redis://localhost:6379" +distribution_redis_password: password + +# if this is an upgrade +distribution_upgrade_only: false + +distribution_system_yaml_template: system.yaml.j2 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/handlers/main.yml new file mode 100644 index 0000000..702c6ae --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/handlers/main.yml @@ -0,0 +1,7 @@ +--- +# handlers file for distribution +- name: restart distribution + become: yes + systemd: + name: "{{ distribution_daemon }}" + state: restarted diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/meta/main.yml new file mode 100644 index 0000000..b760917 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/meta/main.yml @@ -0,0 +1,16 @@ +galaxy_info: + author: "JFrog Maintainers Team " + description: "The distribution role will install distribution software onto the host. An Artifactory server and Postgress database is required." + company: JFrog + + issue_tracker_url: "https://github.com/jfrog/JFrog-Cloud-Installers/issues" + + license: license (Apache-2.0) + + min_ansible_version: 2.9 + + galaxy_tags: + - distribution + - jfrog + +dependencies: [] \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/expect.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/expect.yml new file mode 100644 index 0000000..06f61dc --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/expect.yml @@ -0,0 +1,44 @@ +- name: Prepare expect scenario script + set_fact: + expect_scenario: | + set timeout 300 + spawn {{ exp_executable_cmd }} + expect_before timeout { exit 1 } + set CYCLE_END 0 + set count 0 + + while { $CYCLE_END == 0 } { + expect { + {% for each_request in exp_scenarios %} + -nocase -re {{ '{' }}{{ each_request.expecting }}.*} { + send "{{ each_request.sending }}\n" + } + {% endfor %} + eof { + set CYCLE_END 1 + } + } + set count "[expr $count + 1]" + if { $count > 16} { + exit 128 + } + } + + expect eof + lassign [wait] pid spawnid os_error_flag value + + if {$os_error_flag == 0} { + puts "INSTALLER_EXIT_STATUS-$value" + } else { + puts "INSTALLER_EXIT_STATUS-$value" + } + +- name: Interactive with expect + become: yes + ignore_errors: yes + shell: | + {{ expect_scenario }} + args: + executable: /usr/bin/expect + chdir: "{{ exp_dir }}" + register: exp_result diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/install.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/install.yml new file mode 100644 index 0000000..7e6124b --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/install.yml @@ -0,0 +1,155 @@ +--- +- debug: + msg: "Performing installation of Distribution version - {{ distribution_version }}" + +- name: Install expect dependency + yum: + name: expect + state: present + become: yes + when: ansible_os_family == 'Redhat' + +- name: Install expect dependency + apt: + name: expect + state: present + update_cache: yes + become: yes + when: ansible_os_family == 'Debian' + +- name: Ensure group jfdistribution exist + become: yes + group: + name: "{{ distribution_group }}" + gid: "{{ distribution_gid }}" + state: present + +- name: Ensure user distribution exist + become: yes + user: + uid: "{{ distribution_uid }}" + name: "{{ distribution_user }}" + group: "{{ distribution_group }}" + create_home: yes + home: "{{ distribution_home }}" + shell: /bin/bash + state: present + +- name: Download distribution + become: yes + unarchive: + src: "{{ distribution_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + creates: "{{ distribution_untar_home }}" + register: downloaddistribution + until: downloaddistribution is succeeded + retries: 3 + +- name: Check if app directory exists + become: yes + stat: + path: "{{ distribution_home }}/app" + register: app_dir_check + +- name: Copy untar directory to distribution home + become: yes + command: "cp -r {{ distribution_untar_home }}/. {{ distribution_home }}" + when: not app_dir_check.stat.exists + +- name: Create required directories + become: yes + file: + path: "{{ item }}" + state: directory + recurse: yes + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + loop: + - "{{ distribution_home }}/var/etc" + - "{{ distribution_home }}/var/etc/security/" + - "{{ distribution_home }}/var/etc/info/" + - "{{ distribution_home }}/var/etc/redis/" + +- name: Configure master key + become: yes + copy: + dest: "{{ distribution_home }}/var/etc/security/master.key" + content: | + {{ master_key }} + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + mode: 0640 + +- name: Check if install.sh wrapper script exist + become: yes + stat: + path: "{{ distribution_install_script_path }}/install.sh" + register: install_wrapper_script + +- name: Include interactive installer scripts + include_vars: script/archive.yml + +- name: Install Distribution + include_tasks: expect.yml + vars: + exp_executable_cmd: "./install.sh -u {{ distribution_user }} -g {{ distribution_group }}" + exp_dir: "{{ distribution_install_script_path }}" + exp_scenarios: "{{ distribution_installer_scenario['main'] }}" + args: + apply: + environment: + YQ_PATH: "{{ distribution_thirdparty_path }}/yq" + when: install_wrapper_script.stat.exists + +- name: Configure redis config + become: yes + template: + src: "redis.conf.j2" + dest: "{{ distribution_home }}/var/etc/redis/redis.conf" + notify: restart distribution + +- name: Configure systemyaml + become: yes + template: + src: "{{ distribution_system_yaml_template }}" + dest: "{{ distribution_home }}/var/etc/system.yaml" + notify: restart distribution + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ distribution_home }}/var/etc/info/installer-info.json" + notify: restart distribution + +- name: Update distribution permissions + become: yes + file: + path: "{{ distribution_home }}" + state: directory + recurse: yes + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + mode: '0755' + +- name: Install Distribution as a service + become: yes + shell: | + {{ distribution_archive_service_cmd }} + args: + chdir: "{{ distribution_install_script_path }}" + register: check_service_status_result + ignore_errors: yes + +- name: Restart distribution + meta: flush_handlers + +- name : Wait for distribution to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/main.yml new file mode 100644 index 0000000..841c88b --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/main.yml @@ -0,0 +1,6 @@ +- name: perform installation + include_tasks: "install.yml" + when: not distribution_upgrade_only +- name: perform upgrade + include_tasks: "upgrade.yml" + when: distribution_upgrade_only \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/upgrade.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/upgrade.yml new file mode 100644 index 0000000..4e83e9e --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/tasks/upgrade.yml @@ -0,0 +1,111 @@ +--- +- debug: + msg: "Performing upgrade of Distribution version to {{ distribution_version }} " + +- name: Stop distribution + become: yes + systemd: + name: "{{ distribution_daemon }}" + state: stopped + +- name: Download distribution for upgrade + become: yes + unarchive: + src: "{{ distribution_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + creates: "{{ distribution_untar_home }}" + register: downloaddistribution + until: downloaddistribution is succeeded + retries: 3 + +- name: Delete distribution app + become: yes + file: + path: "{{ distribution_home }}/app" + state: absent + +- name: Copy new app to distribution app + become: yes + command: "cp -r {{ distribution_untar_home }}/app/. {{ distribution_home }}/app" + +- name: Check if install.sh wrapper script exist + become: yes + stat: + path: "{{ distribution_install_script_path }}/install.sh" + register: install_wrapper_script + +- name: Include interactive installer scripts + include_vars: script/archive.yml + +- name: Install Distribution + include_tasks: expect.yml + vars: + exp_executable_cmd: "./install.sh -u {{ distribution_user }} -g {{ distribution_group }}" + exp_dir: "{{ distribution_install_script_path }}" + exp_scenarios: "{{ distribution_installer_scenario['main'] }}" + args: + apply: + environment: + YQ_PATH: "{{ distribution_thirdparty_path }}/yq" + when: install_wrapper_script.stat.exists + +- name: Ensure {{ distribution_home }}/var/etc/redis exists + become: yes + file: + path: "{{ distribution_home }}/var/etc/redis/" + state: directory + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + +- name: Configure redis config + become: yes + template: + src: "redis.conf.j2" + dest: "{{ distribution_home }}/var/etc/redis/redis.conf" + notify: restart distribution + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ distribution_home }}/var/etc/info/installer-info.json" + notify: restart distribution + +- name: Configure systemyaml + become: yes + template: + src: "{{ distribution_system_yaml_template }}" + dest: "{{ distribution_home }}/var/etc/system.yaml" + notify: restart distribution + +- name: Update Distribution base dir owner and group + become: yes + file: + path: "{{ distribution_home }}" + state: directory + recurse: yes + owner: "{{ distribution_user }}" + group: "{{ distribution_group }}" + mode: '0755' + +- name: Install Distribution as a service + become: yes + shell: | + {{ distribution_archive_service_cmd }} + args: + chdir: "{{ distribution_install_script_path }}" + register: check_service_status_result + ignore_errors: yes + +- name: Restart distribution + meta: flush_handlers + +- name : Wait for distribution to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/installer-info.json.j2 b/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/installer-info.json.j2 new file mode 100644 index 0000000..906e994 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/installer-info.json.j2 @@ -0,0 +1,9 @@ +{{ ansible_managed | comment }} +{ + "productId": "Ansible_Distribution/{{ platform_collection_version }}-{{ distribution_version }}", + "features": [ + { + "featureId": "Channel/{{ ansible_marketplace }}" + } + ] +} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/redis.conf.j2 b/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/redis.conf.j2 new file mode 100644 index 0000000..a1d083f --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/redis.conf.j2 @@ -0,0 +1,15 @@ +{{ ansible_managed | comment }} +# Redis configuration file + +# data directory for redis +dir {{ distribution_home }}/var/data/redis + +# log directory for redis +logfile {{ distribution_home }}/var/log/redis/redis.log + +# pid file location for redis +pidfile {{ distribution_home }}/app/run/redis.pid + +# password for redis +# if changed, the same should be set as value for shared.redis.password in JF_PRODUCT_HOME/var/etc/system.yaml +requirepass {{ distribution_redis_password }} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/system.yaml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/system.yaml.j2 new file mode 100644 index 0000000..79fa4a7 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/templates/system.yaml.j2 @@ -0,0 +1,20 @@ +configVersion: 1 +shared: + jfrogUrl: {{ jfrog_url }} + node: + ip: {{ ansible_host }} + id: {{ ansible_date_time.iso8601_micro | to_uuid }} + database: + type: "{{ distribution_db_type }}" + driver: "{{ distribution_db_driver }}" + url: "{{ distribution_db_url }}" + username: "{{ distribution_db_user }}" + password: "{{ distribution_db_password }}" + redis: + connectionString: "{{ distribution_redis_url }}" + password: "{{ distribution_redis_password }}" + security: + joinKey: {{ join_key }} +router: + entrypoints: + internalPort: 8046 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/main.yml new file mode 100644 index 0000000..cd21505 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/main.yml @@ -0,0 +1,2 @@ +--- + diff --git a/Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/script/archive.yml b/Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/script/archive.yml new file mode 100644 index 0000000..0f3c195 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/distribution/vars/script/archive.yml @@ -0,0 +1,42 @@ +distribution_installer_scenario: + main: + - { + "expecting": "(data|installation) directory \\(", + "sending": "{{ distribution_home }}" + } + - { + "expecting": "join key.*:", + "sending": "{{ join_key }}" + } + - { + "expecting": "jfrog url:", + "sending": "{{ jfrog_url }}" + } + - { + "expecting": "do you want to continue", + "sending": "y" + } + - { + "expecting": "please specify the ip address of this machine", + "sending": "{% if distribution_ha_node_type is defined and distribution_ha_node_type == 'master' %}{{ ansible_host }}{% else %}{{ ansible_host }}{% endif %}" + } + - { + "expecting": "are you adding an additional node", + "sending": "{% if distribution_ha_node_type is defined and distribution_ha_node_type == 'master' %}n{% else %}y{% endif %}" + } + - { + "expecting": "do you want to install postgresql", + "sending": "n" + } + - { + "expecting": "postgresql url.*example", + "sending": "{{ distribution_db_url }}" + } + - { + "expecting": "(postgresql|database)?\\s?username.*", + "sending": "{{ distribution_db_user }}" + } + - { + "expecting": "(confirm\\s?)?(postgresql|database)?\\s?password.*:", + "sending": "{{ distribution_db_password }}" + } diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/README.md b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/README.md new file mode 100644 index 0000000..2f0e3ce --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/README.md @@ -0,0 +1,26 @@ +# MissionControl +The missioncontrol role will install missioncontrol software onto the host. An Artifactory server and Postgress database is required. + +### Role Variables +* _mc_upgrade_only_: Perform an software upgrade only. Default is false. + +Additional variables can be found in [defaults/main.yml](./defaults/main.yml). +## Example Playbook +``` +--- +- hosts: missioncontrol_servers + roles: + - missioncontrol +``` + +## Upgrades +The missioncontrol role supports software upgrades. To use a role to perform a software upgrade only, use the _xray_upgrade_only_ variables and specify the version. See the following example. + +``` +- hosts: missioncontrol_servers + vars: + missioncontrol_version: "{{ lookup('env', 'missioncontrol_version_upgrade') }}" + mc_upgrade_only: true + roles: + - missioncontrol +``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/defaults/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/defaults/main.yml new file mode 100644 index 0000000..f1bd22b --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/defaults/main.yml @@ -0,0 +1,58 @@ +--- +# defaults file for mc +# indicates were this collection was downlaoded from (galaxy, automation_hub, standalone) +ansible_marketplace: standalone + +# whether to enable HA +mc_ha_enabled: false + +mc_ha_node_type : master + +# The location where mc should install. +jfrog_home_directory: /opt/jfrog + +# The remote mc download file +mc_tar: https://releases.jfrog.io/artifactory/jfrog-mc/linux/{{ missionControl_version }}/jfrog-mc-{{ missionControl_version }}-linux.tar.gz + + +#The mc install directory +mc_untar_home: "{{ jfrog_home_directory }}/jfrog-mc-{{ missionControl_version }}-linux" +mc_home: "{{ jfrog_home_directory }}/mc" + +mc_install_script_path: "{{ mc_home }}/app/bin" +mc_thirdparty_path: "{{ mc_home }}/app/third-party" +mc_archive_service_cmd: "{{ mc_install_script_path }}/installService.sh" + +#mc users and groups +mc_user: jfmc +mc_group: jfmc + +mc_uid: 1050 +mc_gid: 1050 + +mc_daemon: mc + +# MissionContol ElasticSearch Details +es_uid: 1060 +es_gid: 1060 + +mc_es_conf_base: "/etc/elasticsearch" +mc_es_user: admin +mc_es_password: admin +mc_es_url: "http://localhost:8082" +mc_es_base_url: "http://localhost:8082/elasticsearch" +mc_es_transport_port: 9300 + +mc_es_home: "/usr/share/elasticsearch" +mc_es_data_dir: "/var/lib/elasticsearch" +mc_es_log_dir: "/var/log/elasticsearch" +mc_es_java_home: "/usr/share/elasticsearch/jdk" +mc_es_script_path: "/usr/share/elasticsearch/bin" +mc_es_searchgaurd_home: "/usr/share/elasticsearch/plugins/search-guard-7" + +flow_type: archive + +# if this is an upgrade +mc_upgrade_only: false + +mc_system_yaml_template: system.yaml.j2 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.key b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.key new file mode 100644 index 0000000..229172c --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDY1nDD1cW5ykZV +rTXrAMJeLuZknW9tg+4s8R+XYrzRMTNr9tAXEYNEa+T92HtqrKaVZtdGiQ6NmS95 +EYezEgVmyGQEuuVlY8ChcX8XgpBsJPBV4+XIRju+RSyEW+ZNkT3EWTRKab+KSgN2 +aZ2OT16UqfJd3JjATZw//xXHRWhCQhchX3nNyzkIgENPtdtSweSLG4NjOHY08U7g +Zee21MCqa/58NVECJXlqK/Tfw/3SPgCmSHLLCyybWfClLmXXIjBuSTtSOLDPj4pw +VrZeR0aePs7ZNJnX/tUICNSZeNzs7+n9QUoAiKYSNKSdDw270Lbo5GQdWuM7nkrc +2txeH8wvAgMBAAECggEAGzbuzZAVp40nlAvlPyrH5PeQmwLXarCq7Uu7Yfir0hA8 +Gp9429cALqThXKrAR/yF+9eodTCGebxxejR6X5MyHQWm5/Znts307fjyBoqwgveF +N9fJOIBNce1PT7K+Y5szBrhbbmt59Wqh/J6iKQD1J0YdJoKlTp1vBZPdBoxDhZfN +TgayY4e71ox7Vew+QrxDXzMA3J+EbbBXFL2yOmpNI/FPpEtbCE9arjSa7oZXJAvd +Aenc6GYctkdbtjpX7zHXz5kHzaAEdmorR+q3w6k8cDHBvc+UoRYgLz3fBaVhhQca +rP4PYp04ztIn3qcOpVoisUkpsQcev2cJrWeFW0WgAQKBgQD7ZFsGH8cE84zFzOKk +ee53zjlmIvXqjQWzSkmxy9UmDnYxEOZbn6epK2I5dtCbU9ZZ3f4KM8TTAM5GCOB+ +j4cN/rqM7MdhkgGL/Dgw+yxGVlwkSsQMil16vqdCIRhEhqjChc7KaixuaBNtIBV0 ++9ZRfoS5fEjrctX4/lULwS6EAQKBgQDcz/C6PV3mXk8u7B48kGAJaKbafh8S3BnF +V0zA7qI/aQHuxmLGIQ7hNfihdZwFgYG4h5bXvBKGsxwu0JGvYDNL44R9zXuztsVX +PEixV572Bx87+mrVEt3bwj3lhbohzorjSF2nnJuFA+FZ0r4sQwudyZ2c8yCqRVhI +mfj36FWQLwKBgHNw1zfNuee1K6zddCpRb8eGZOdZIJJv5fE6KPNDhgLu2ymW+CGV +BDn0GSwIOq1JZ4JnJbRrp3O5x/9zLhwQLtWnZuU2CiztDlbJIMilXuSB3dgwmSyl +EV4/VLFSX0GAkNia96YN8Y9Vra4L8K6Cwx0zOyGuSBIO7uFjcYxvTrwBAoGAWeYn +AgweAL6Ayn/DR7EYCHydAfO7PvhxXZDPZPVDBUIBUW9fo36uCi7pDQNPBEbXw4Mg +fLDLch/V55Fu3tHx0IHO3VEdfet5qKyYg+tCgrQfmVG40QsfXGtWu+2X/E+U6Df8 +OVNfVeZghytv1aFuR01gaBfsQqZ87QITBQuIWm0CgYAKdzhETd+jBBLYyOCaS8mh +zQr/ljIkrZIwPUlBkj6TAsmTJTbh7O6lf50CQMEHyE0MNFOHrvkKn89BObXcmwtV +92parLTR7RAeaPMRxCZs4Xd/oABYVGFjMa7TVNA2S6HReDqqTpJrCCkyVuYkr1f2 +OflnwX2RlaWl45n0qkwkTw== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.pem b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.pem new file mode 100644 index 0000000..d1ee43f --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/localhost.pem @@ -0,0 +1,51 @@ +-----BEGIN CERTIFICATE----- +MIIEcjCCA1qgAwIBAgIGAXY81RkkMA0GCSqGSIb3DQEBCwUAMG4xEzARBgoJkiaJ +k/IsZAEZFgNjb20xFTATBgoJkiaJk/IsZAEZFgVqZnJvZzEUMBIGA1UECgwLamZy +b2csIEluYy4xCzAJBgNVBAsMAkNBMR0wGwYDVQQDDBRzaWduaW5nLmNhLmpmcm9n +LmNvbTAeFw0yMDEyMDcxMDUyNDhaFw0zMDEyMDUxMDUyNDhaMGwxEzARBgoJkiaJ +k/IsZAEZFgNjb20xGTAXBgoJkiaJk/IsZAEZFglsb2NhbGhvc3QxGDAWBgNVBAoM +D2xvY2FsaG9zdCwgSW5jLjEMMAoGA1UECwwDT3BzMRIwEAYDVQQDDAlsb2NhbGhv +c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY1nDD1cW5ykZVrTXr +AMJeLuZknW9tg+4s8R+XYrzRMTNr9tAXEYNEa+T92HtqrKaVZtdGiQ6NmS95EYez +EgVmyGQEuuVlY8ChcX8XgpBsJPBV4+XIRju+RSyEW+ZNkT3EWTRKab+KSgN2aZ2O +T16UqfJd3JjATZw//xXHRWhCQhchX3nNyzkIgENPtdtSweSLG4NjOHY08U7gZee2 +1MCqa/58NVECJXlqK/Tfw/3SPgCmSHLLCyybWfClLmXXIjBuSTtSOLDPj4pwVrZe +R0aePs7ZNJnX/tUICNSZeNzs7+n9QUoAiKYSNKSdDw270Lbo5GQdWuM7nkrc2txe +H8wvAgMBAAGjggEWMIIBEjCBmgYDVR0jBIGSMIGPgBSh7peJvc4Im3WkR6/FaUD/ +aYDa8qF0pHIwcDETMBEGCgmSJomT8ixkARkWA2NvbTEaMBgGCgmSJomT8ixkARkW +Cmpmcm9namZyb2cxFDASBgNVBAoMC0pGcm9nLCBJbmMuMQswCQYDVQQLDAJDQTEa +MBgGA1UEAwwRcm9vdC5jYS5qZnJvZy5jb22CAQIwHQYDVR0OBBYEFIuWN8D/hFhl +w0bdSyG+PmymjpVUMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMCAGA1Ud +JQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAUBgNVHREEDTALgglsb2NhbGhv +c3QwDQYJKoZIhvcNAQELBQADggEBAJQJljyNH/bpvmiYO0+d8El+BdaU7FI2Q2Sq +1xBz/qBQSVmUB0iIeblTdQ58nYW6A/pvh8EnTWE7tRPXw3WQR4it8ldGSDQe2zHt +9U0hcC7DSzYGxlHLm0UI/LNwzdRy0kY8LArE/zGDSQ+6hp2Op21IHtzGfJnILG5G +OZdDWOB/e4cQw2/AcnsrapJU4MJCx28l0N9aSx4wr7SNosHuYOO8CimAdsqQukVt +rcrJZyHNvG5eQUVuQnZRywXDX6tLj8HQHfYLRaMqD57GMU0dg/kvYTYrYR/krbcG +Qf1D/9GCsn081fYblSfSSRRxrbhdYcoI/6xNHIC2y7bO8ZJD9zw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBwMRMwEQYKCZImiZPyLGQB +GRYDY29tMRowGAYKCZImiZPyLGQBGRYKamZyb2dqZnJvZzEUMBIGA1UECgwLSkZy +b2csIEluYy4xCzAJBgNVBAsMAkNBMRowGAYDVQQDDBFyb290LmNhLmpmcm9nLmNv +bTAeFw0yMDEyMDcxMDUyNDhaFw0zMDEyMDUxMDUyNDhaMG4xEzARBgoJkiaJk/Is +ZAEZFgNjb20xFTATBgoJkiaJk/IsZAEZFgVqZnJvZzEUMBIGA1UECgwLamZyb2cs +IEluYy4xCzAJBgNVBAsMAkNBMR0wGwYDVQQDDBRzaWduaW5nLmNhLmpmcm9nLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCe74VmqSryFPESO/oq +bgspiOSwGheG/AbUf/2XXPLZNbZJ/hhuI6T+iSW5FYy3jETwwODDlF8GBN6R33+U +gNCjXIMBDUOWkETe1fD2zj1HMTC6angykKJy2Xkw+sWniELbYfTu+SLHsBMPQnVI +jFwDLcbSMbs7ieU/IuQTEnEZxPiKcokOaF7vPntfPwdvRoGwMR0VuX7h+20Af1Il +3ntOuoasoV66K6KuiBRkSBcsV2ercCRQlpXCvIsTJVWASpSTNrpKy8zejjePw/xs +ieMGSo6WIxnIJnOLTJWnrw8sZt0tiNrLbB8npSvP67uUMDGhrZ3Tnro9JtujquOE +zMUCAwEAAaOB4zCB4DASBgNVHRMBAf8ECDAGAQH/AgEAMIGaBgNVHSMEgZIwgY+A +FBX3TQRxJRItQ/hi81MA3eZggFs7oXSkcjBwMRMwEQYKCZImiZPyLGQBGRYDY29t +MRowGAYKCZImiZPyLGQBGRYKamZyb2dqZnJvZzEUMBIGA1UECgwLSkZyb2csIElu +Yy4xCzAJBgNVBAsMAkNBMRowGAYDVQQDDBFyb290LmNhLmpmcm9nLmNvbYIBATAd +BgNVHQ4EFgQUoe6Xib3OCJt1pEevxWlA/2mA2vIwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBCwUAA4IBAQAzkcvT1tTjnjguRH4jGPxP1fidiM0DWiWZQlRT9Evt +BkltRwkqOZIdrBLy/KJbOxRSCRaKpxyIYd5bWrCDCWvXArBFDY9j3jGGk8kqXb0/ +VajEKDjHXzJM7HXAzyJO2hKVK4/OoPlzhKqR1ZbZF1F8Omzo7+oNwPqf5Y5hnn2M +qrUWxE216mWE8v7gvbfu39w9XKTFH1/RPgAAJet2dunyLbz3W5NgyBbCWGj/qJCz +TUDD9I8az/XX73HLpkXbcEY5/qrPV6EQWzf+ec4EcgrEi0f8gTKzl7OQaqYDxObk +yixmONVlwYD2FpWqJYAfg04u/CRQMXPPCdUQh/eKrHUg +-----END CERTIFICATE----- \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/root-ca.pem b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/root-ca.pem new file mode 100644 index 0000000..3672009 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/root-ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDvjCCAqagAwIBAgIBATANBgkqhkiG9w0BAQsFADBwMRMwEQYKCZImiZPyLGQB +GRYDY29tMRowGAYKCZImiZPyLGQBGRYKamZyb2dqZnJvZzEUMBIGA1UECgwLSkZy +b2csIEluYy4xCzAJBgNVBAsMAkNBMRowGAYDVQQDDBFyb290LmNhLmpmcm9nLmNv +bTAeFw0yMDEyMDcxMDUyNDdaFw0zMDEyMDUxMDUyNDdaMHAxEzARBgoJkiaJk/Is +ZAEZFgNjb20xGjAYBgoJkiaJk/IsZAEZFgpqZnJvZ2pmcm9nMRQwEgYDVQQKDAtK +RnJvZywgSW5jLjELMAkGA1UECwwCQ0ExGjAYBgNVBAMMEXJvb3QuY2EuamZyb2cu +Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxyTSYCbGefbdAHgW +zxXhCh7gvOUzyThaC6bcvY7yMqVu3YPxMAV1LEz+J0VMeGvu5HzONyGq89TaIKtr +AyZKxM957Q/TK0NPi0HUIT1wZKPuH89DeH79gfBjyv8XMUhFzKxAaosEa4rhkAMe +B4ukk9twfGotKU1y4j6m1V1gckeDZDRIW4tNzQbEBsL+ZcxDnCeSAAHW3Djb5yzQ +Yj3LPIRN0yu0fL8oN4yVn5tysAfXTum7HIuyKp3gfxhQgSXGVIDHd7Z1HcLrUe2o +2Z7dlsrFCUgHPccOxyFzxGI8bCPFYU75QqbxP699L1chma0It/2D0YxcrXhRkzzg +wzrBFwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFBX3TQRx +JRItQ/hi81MA3eZggFs7MB0GA1UdDgQWBBQV900EcSUSLUP4YvNTAN3mYIBbOzAO +BgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggEBAH5XYiOBvHdd3bRfyHeo +Y2i7+u59VU3HDdOm/FVI0JqkzFAp6DLk6Ow5w/2MXbasga03lJ9SpHvKVne+VOaH +Df7xEqCIZeQVofNyOfsl4NOu6NgPSlQx0FZ6lPToZDBGp7D6ftnJcUujGk0W9y7k +GwxojLnP1f/KyjYTCCK6sDXwSn3fZGF5WmnHlzZEyKlLQoLNoEZ1uTjg2CRsa/RU +QxobwNzHGbrLZw5pfeoiF7G27RGoUA/S6mfVFQJVDP5Y3/xJRii56tMaJPwPh0sN +QPLbNvNgeU1dET1msMBnZvzNUko2fmBc2+pU7PyrL9V2pgfHq981Db1ShkNYtMhD +bMw= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles.yml new file mode 100644 index 0000000..a659b12 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles.yml @@ -0,0 +1,7 @@ +_sg_meta: + type: "roles" + config_version: 2 + +sg_anonymous: + cluster_permissions: + - cluster:monitor/health diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles_mapping.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles_mapping.yml new file mode 100644 index 0000000..f7abca6 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sg_roles_mapping.yml @@ -0,0 +1,48 @@ +# In this file users, backendroles and hosts can be mapped to Search Guard roles. +# Permissions for Search Guard roles are configured in sg_roles.yml +_sg_meta: + type: "rolesmapping" + config_version: 2 + +## Demo roles mapping +SGS_ALL_ACCESS: + description: "Maps admin to SGS_ALL_ACCESS" + reserved: true + backend_roles: + - "admin" + +SGS_OWN_INDEX: + description: "Allow full access to an index named like the username" + reserved: false + users: + - "*" + +SGS_LOGSTASH: + reserved: false + backend_roles: + - "logstash" + +SGS_KIBANA_USER: + description: "Maps kibanauser to SGS_KIBANA_USER" + reserved: false + backend_roles: + - "kibanauser" + +SGS_READALL: + reserved: true + backend_roles: + - "readall" + +SGS_MANAGE_SNAPSHOTS: + reserved: true + backend_roles: + - "snapshotrestore" + +SGS_KIBANA_SERVER: + reserved: true + users: + - "kibanaserver" + +sg_anonymous: + backend_roles: + - sg_anonymous_backendrole diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.key b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.key new file mode 100644 index 0000000..61192d9 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCa3GuNbI30EdRs +S2Dmq87i/4Y7QeOldogzmNYH3m7GMjPFJcJg11Yc2HsAbBYs86fW6gGvO+68bFmY +X5kYvPN+L8KRUCSvmvjHCGf7ULmxiG2Wh7RPzQaAdvqqkMGW1QDwwxA25tP9KfZv +nP/08CPmboP8rcCEhX6HCVh0Im+WT3BBxkikjhVaVru2cLPtKtgtBX7a3HY7XMfp +DRYhXZNf+ZxfWewLQhNNndHwjtuJooLHdtX4WEXUhsrXS7/I+M7BdL/fB0ptwfvg +x1WvC2JnvNnvgdMBoUevlHjugWBVGo4AhOpFqAmQ8MxXZUhPGinDxjFvwrHYwYm0 +w7tVAnTbAgMBAAECggEAAr7esZKzD5ilnWx7RkKMikAvFyKUkJXvnq6RXXFZoZKm +/5tPtABEOKbYekoU3SPgeWkLseK568YBbqXM9ySsLerpSIvVIq1T660pHsowP32/ +8MoRkmYOPRj6WgcX/UetEan7r66ktfT9AJpM6gDgzFm5Zgz0knvFawJ7w8Yzqmks +8JqjA1E433xEUtc00Qm4z7You1I5eyrz1zKxBPZATVM6ScbDq2WXqwgIGUbnAHG2 +6PADvOPP+8Kl0/JNC+SkE8J+KvfCYnJIDZaWTCjdd4cjkFAAHXi16BvF6PY3veel +/LT2nr1/YmcADCt4wuWGn+1HRF+mJgjqTVcfQSJrbQKBgQDJG45Hmku7fnNAn/A9 +FPHmo7CpymxXpg12yf7BuKr4irpJpa6WmXB6EsxCy91rffQTDEh8TnpJG6yj5vyJ +b0dEt3u8RtBfx49UhKG/pDYi9mnUuazH0u6BHu+w4fRi3Cju7sY4qM4aj8rnAlU0 +2DnXWEKIfhd+1cXDwyI8DyuvfwKBgQDFIV7ZgI1weZv7EnNiIKs65y4NWG4uG7jB +Z+Wx8xx9n5OKVxw21NPt2pZzzW3Y3+pRXypcjH13XPrZxfaUt1Y8ylC3/DHFgsid +iXyfjmit4TWiW9busC09Q8YwFZZbMWj/Wd1PRav3/zDICf3B1QRXEqqpYfUtAbXf +SaanZNGopQKBgQDFwO77weHOkN1MIvndVoc4QKYrj/1Rgtuif6afX7Pfiqr8WIuB +U4iiwXFSDZ3BYa1sPZvZgGIHGct9sFmL23y9OZ/W19t3E4kBlxpmlFcXsi8HGz2n +kOcu2Pjheo8R12P475rDhFqHC/Z9inG28RiPhR6HkVYRRqydf3hejpxqiQKBgEJw +ZM9ZjFIEKpYMOecwq4VGtTa6Pyg7H6HPqpK3JTsRtWBCy7ePM35O1bZh3kvh689R +C631i7PXGpSbK+gjgmUqqtnXnc67rXGrDN2Z2Z4A8VqvKVl490ZWuU0reWly1bh6 +SSSWjsceswo4k9XoPXY7TFmaMk/g67M913VDfYYhAoGAXp6HYCZga72N6RdB38TY +i08c/O/xksfkNVo0SuVqr99uQ5TN+d2+o+t5H9Fekl1y9jUSK6q6q6+Vp8zSiyzV +GwAWk9u8dBGoNiWs4cOtQAdyeLbGDIHbIv4jeRqqSl87H6R6wJY4+fWdfm9/KEG7 +N957kwur+XYzE0RfG5wgS3o= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.pem b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.pem new file mode 100644 index 0000000..9c672f6 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/files/searchguard/sgadmin.pem @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIIESjCCAzKgAwIBAgIGAXY81RknMA0GCSqGSIb3DQEBCwUAMG4xEzARBgoJkiaJ +k/IsZAEZFgNjb20xFTATBgoJkiaJk/IsZAEZFgVqZnJvZzEUMBIGA1UECgwLamZy +b2csIEluYy4xCzAJBgNVBAsMAkNBMR0wGwYDVQQDDBRzaWduaW5nLmNhLmpmcm9n +LmNvbTAeFw0yMDEyMDcxMDUyNDlaFw0zMDEyMDUxMDUyNDlaMGYxEzARBgoJkiaJ +k/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdzZ2FkbWluMRYwFAYDVQQKDA1z +Z2FkbWluLCBJbmMuMQwwCgYDVQQLDANPcHMxEDAOBgNVBAMMB3NnYWRtaW4wggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCa3GuNbI30EdRsS2Dmq87i/4Y7 +QeOldogzmNYH3m7GMjPFJcJg11Yc2HsAbBYs86fW6gGvO+68bFmYX5kYvPN+L8KR +UCSvmvjHCGf7ULmxiG2Wh7RPzQaAdvqqkMGW1QDwwxA25tP9KfZvnP/08CPmboP8 +rcCEhX6HCVh0Im+WT3BBxkikjhVaVru2cLPtKtgtBX7a3HY7XMfpDRYhXZNf+Zxf +WewLQhNNndHwjtuJooLHdtX4WEXUhsrXS7/I+M7BdL/fB0ptwfvgx1WvC2JnvNnv +gdMBoUevlHjugWBVGo4AhOpFqAmQ8MxXZUhPGinDxjFvwrHYwYm0w7tVAnTbAgMB +AAGjgfUwgfIwgZoGA1UdIwSBkjCBj4AUoe6Xib3OCJt1pEevxWlA/2mA2vKhdKRy +MHAxEzARBgoJkiaJk/IsZAEZFgNjb20xGjAYBgoJkiaJk/IsZAEZFgpqZnJvZ2pm +cm9nMRQwEgYDVQQKDAtKRnJvZywgSW5jLjELMAkGA1UECwwCQ0ExGjAYBgNVBAMM +EXJvb3QuY2EuamZyb2cuY29tggECMB0GA1UdDgQWBBSSIpvK2db0wJf7bw1mhYt8 +A0JUQTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSUBAf8EDDAK +BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAn3cM0PDh8vTJS8zZ7HylMpZl +SaZwd3sxshhBKx4JEc85WQPp60nVADqVhnkVa1rfQQURaMP87hqmzf9eOcesnjn6 +17eSVpDpZ0B1qV46hJd15yYKqFLavqtFpy0ePpk4EoanwJUikphT3yuIB6v3gqfY +h20t7/XmkjEwfGkmgmXOZNb9uOpKjkotWRR/IslSMxoozsdWYQLaqA0De/7Tqpmi +mortmVTOtZCX/ZChuN2XzqUnWZT+xIJomAj4ZCOlw03Yd9eUhrDZBmrYHiUmS4VO +wWFDER3zhwncjg0X2rOqL6N5P8TIfqpVgf1VuDhTAj/GY1ZKrXol28WwQQCA9w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBwMRMwEQYKCZImiZPyLGQB +GRYDY29tMRowGAYKCZImiZPyLGQBGRYKamZyb2dqZnJvZzEUMBIGA1UECgwLSkZy +b2csIEluYy4xCzAJBgNVBAsMAkNBMRowGAYDVQQDDBFyb290LmNhLmpmcm9nLmNv +bTAeFw0yMDEyMDcxMDUyNDhaFw0zMDEyMDUxMDUyNDhaMG4xEzARBgoJkiaJk/Is +ZAEZFgNjb20xFTATBgoJkiaJk/IsZAEZFgVqZnJvZzEUMBIGA1UECgwLamZyb2cs +IEluYy4xCzAJBgNVBAsMAkNBMR0wGwYDVQQDDBRzaWduaW5nLmNhLmpmcm9nLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCe74VmqSryFPESO/oq +bgspiOSwGheG/AbUf/2XXPLZNbZJ/hhuI6T+iSW5FYy3jETwwODDlF8GBN6R33+U +gNCjXIMBDUOWkETe1fD2zj1HMTC6angykKJy2Xkw+sWniELbYfTu+SLHsBMPQnVI +jFwDLcbSMbs7ieU/IuQTEnEZxPiKcokOaF7vPntfPwdvRoGwMR0VuX7h+20Af1Il +3ntOuoasoV66K6KuiBRkSBcsV2ercCRQlpXCvIsTJVWASpSTNrpKy8zejjePw/xs +ieMGSo6WIxnIJnOLTJWnrw8sZt0tiNrLbB8npSvP67uUMDGhrZ3Tnro9JtujquOE +zMUCAwEAAaOB4zCB4DASBgNVHRMBAf8ECDAGAQH/AgEAMIGaBgNVHSMEgZIwgY+A +FBX3TQRxJRItQ/hi81MA3eZggFs7oXSkcjBwMRMwEQYKCZImiZPyLGQBGRYDY29t +MRowGAYKCZImiZPyLGQBGRYKamZyb2dqZnJvZzEUMBIGA1UECgwLSkZyb2csIElu +Yy4xCzAJBgNVBAsMAkNBMRowGAYDVQQDDBFyb290LmNhLmpmcm9nLmNvbYIBATAd +BgNVHQ4EFgQUoe6Xib3OCJt1pEevxWlA/2mA2vIwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBCwUAA4IBAQAzkcvT1tTjnjguRH4jGPxP1fidiM0DWiWZQlRT9Evt +BkltRwkqOZIdrBLy/KJbOxRSCRaKpxyIYd5bWrCDCWvXArBFDY9j3jGGk8kqXb0/ +VajEKDjHXzJM7HXAzyJO2hKVK4/OoPlzhKqR1ZbZF1F8Omzo7+oNwPqf5Y5hnn2M +qrUWxE216mWE8v7gvbfu39w9XKTFH1/RPgAAJet2dunyLbz3W5NgyBbCWGj/qJCz +TUDD9I8az/XX73HLpkXbcEY5/qrPV6EQWzf+ec4EcgrEi0f8gTKzl7OQaqYDxObk +yixmONVlwYD2FpWqJYAfg04u/CRQMXPPCdUQh/eKrHUg +-----END CERTIFICATE----- \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/handlers/main.yml new file mode 100644 index 0000000..016570c --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/handlers/main.yml @@ -0,0 +1,7 @@ +--- +# handlers file for missioncontrol +- name: restart missioncontrol + become: yes + systemd: + name: "{{ mc_daemon }}" + state: restarted diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/meta/main.yml new file mode 100644 index 0000000..2a11e72 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/meta/main.yml @@ -0,0 +1,16 @@ +galaxy_info: + author: "JFrog Maintainers Team " + description: "The missionControl role will install missionControl software onto the host. An Artifactory server and Postgress database is required." + company: JFrog + + issue_tracker_url: "https://github.com/jfrog/JFrog-Cloud-Installers/issues" + + license: license (Apache-2.0) + + min_ansible_version: 2.9 + + galaxy_tags: + - missionControl + - jfrog + +dependencies: [] \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/expect.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/expect.yml new file mode 100644 index 0000000..06f61dc --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/expect.yml @@ -0,0 +1,44 @@ +- name: Prepare expect scenario script + set_fact: + expect_scenario: | + set timeout 300 + spawn {{ exp_executable_cmd }} + expect_before timeout { exit 1 } + set CYCLE_END 0 + set count 0 + + while { $CYCLE_END == 0 } { + expect { + {% for each_request in exp_scenarios %} + -nocase -re {{ '{' }}{{ each_request.expecting }}.*} { + send "{{ each_request.sending }}\n" + } + {% endfor %} + eof { + set CYCLE_END 1 + } + } + set count "[expr $count + 1]" + if { $count > 16} { + exit 128 + } + } + + expect eof + lassign [wait] pid spawnid os_error_flag value + + if {$os_error_flag == 0} { + puts "INSTALLER_EXIT_STATUS-$value" + } else { + puts "INSTALLER_EXIT_STATUS-$value" + } + +- name: Interactive with expect + become: yes + ignore_errors: yes + shell: | + {{ expect_scenario }} + args: + executable: /usr/bin/expect + chdir: "{{ exp_dir }}" + register: exp_result diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/install.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/install.yml new file mode 100644 index 0000000..14b2c30 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/install.yml @@ -0,0 +1,150 @@ +--- +- debug: + msg: "Performing installation of missionControl version - {{ missioncontrol_version }}" + +- name: Install expect dependency + become: yes + yum: + name: expect + state: present + when: ansible_os_family == 'Redhat' + +- name: Install expect dependency + become: yes + apt: + name: expect + state: present + update_cache: yes + when: ansible_os_family == 'Debian' + +- name: Ensure group jfmc exist + become: yes + group: + name: "{{ mc_group }}" + gid: "{{ mc_gid }}" + state: present + +- name: Ensure user jfmc exist + become: yes + user: + uid: "{{ mc_uid }}" + name: "{{ mc_user }}" + group: "{{ mc_group }}" + create_home: yes + home: "{{ mc_home }}" + shell: /bin/bash + state: present + +- name: Download mc + become: yes + unarchive: + src: "{{ mc_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ mc_user }}" + group: "{{ mc_group }}" + creates: "{{ mc_untar_home }}" + register: downloadmc + until: downloadmc is succeeded + retries: 3 + +- name: Check if app directory exists + become: yes + stat: + path: "{{ mc_home }}/app" + register: app_dir_check + +- name: Copy untar directory to mc home + become: yes + command: "cp -r {{ mc_untar_home }}/. {{ mc_home }}" + when: not app_dir_check.stat.exists + +- name: Create required directories + become: yes + file: + path: "{{ item }}" + state: directory + recurse: yes + owner: "{{ mc_user }}" + group: "{{ mc_group }}" + loop: + - "{{ mc_home }}/var/etc" + - "{{ mc_home }}/var/etc/security/" + - "{{ mc_home }}/var/etc/info/" + +- name: Configure master key + become: yes + copy: + dest: "{{ mc_home }}/var/etc/security/master.key" + content: | + {{ master_key }} + owner: "{{ mc_user }}" + group: "{{ mc_group }}" + mode: 0640 + +- name: Setup elasticsearch + import_tasks: setup-elasticsearch.yml + +- name: Check if install.sh wrapper script exist + become: yes + stat: + path: "{{ mc_install_script_path }}/install.sh" + register: install_wrapper_script + +- name: Include interactive installer scripts + include_vars: script/archive.yml + +- name: Install JFMC + include_tasks: expect.yml + vars: + exp_executable_cmd: "./install.sh -u {{ mc_user }} -g {{ mc_group }}" + exp_dir: "{{ mc_install_script_path }}" + exp_scenarios: "{{ mc_installer_scenario['main'] }}" + args: + apply: + environment: + YQ_PATH: "{{ mc_thirdparty_path }}/yq" + when: install_wrapper_script.stat.exists + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ mc_home }}/var/etc/info/installer-info.json" + notify: restart missioncontrol + +- name: Configure systemyaml + become: yes + template: + src: "{{ mc_system_yaml_template }}" + dest: "{{ mc_home }}/var/etc/system.yaml" + notify: restart missioncontrol + +- name: Update correct permissions + become: yes + file: + path: "{{ mc_home }}" + state: directory + recurse: yes + owner: "{{ mc_user }}" + group: "{{ mc_group }}" + mode: '0755' + +- name: Install mc as a service + become: yes + shell: | + {{ mc_archive_service_cmd }} + args: + chdir: "{{ mc_install_script_path }}" + register: check_service_status_result + ignore_errors: yes + +- name: Restart missioncontrol + meta: flush_handlers + +- name : Wait for missionControl to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/main.yml new file mode 100644 index 0000000..6786b82 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/main.yml @@ -0,0 +1,6 @@ +- name: perform installation + include_tasks: "install.yml" + when: not mc_upgrade_only +- name: perform upgrade + include_tasks: "upgrade.yml" + when: mc_upgrade_only \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-elasticsearch.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-elasticsearch.yml new file mode 100644 index 0000000..768e508 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-elasticsearch.yml @@ -0,0 +1,179 @@ +- name: Ensure group elasticsearch exists + become: yes + group: + name: elasticsearch + gid: "{{ es_gid }}" + state: present + +- name: Ensure user elasticsearch exists + become: yes + user: + name: elasticsearch + uid: "{{ es_uid }}" + group: elasticsearch + create_home: yes + home: "{{ mc_es_home }}" + shell: /bin/bash + state: present + +- name: Create required directories + become: yes + file: + path: "{{ item }}" + state: directory + mode: 0755 + recurse: yes + owner: elasticsearch + group: elasticsearch + loop: + - "{{ mc_es_conf_base }}" + - "{{ mc_es_data_dir }}" + - "{{ mc_es_log_dir }}" + - "{{ mc_es_home }}" + +- name: Set max file descriptors limit + become: yes + pam_limits: + domain: 'elasticsearch' + limit_type: '-' + limit_item: nofile + value: '65536' + +- name: Update nproc limit + become: yes + pam_limits: + domain: 'elasticsearch' + limit_type: '-' + limit_item: nproc + value: '4096' + +- name: Setting sysctl values + become: yes + sysctl: name={{ item.name }} value={{ item.value }} sysctl_set=yes + loop: + - { name: "vm.max_map_count", value: 262144} + ignore_errors: yes + +- name: Find elasticsearch package + become: yes + find: + paths: "{{ mc_home }}/app/third-party/elasticsearch" + patterns: "^elasticsearch-oss-.+\\.tar.gz$" + use_regex: yes + file_type: file + register: check_elasticsearch_package_result + +- name: Set elasticsearch package file name + set_fact: + mc_elasticsearch_package: "{{ check_elasticsearch_package_result.files[0].path }}" + when: check_elasticsearch_package_result.matched > 0 + +- name: Ensure /usr/share/elasticsearch exists + file: + path: "{{ mc_es_home }}" + state: directory + owner: elasticsearch + group: elasticsearch + become: yes + +- name: Extract elasticsearch package + become: yes + become_user: elasticsearch + ignore_errors: yes + unarchive: + src: "{{ mc_elasticsearch_package }}" + dest: "{{ mc_es_home }}" + remote_src: yes + extra_opts: + - --strip-components=1 + owner: elasticsearch + group: elasticsearch + register: unarchive_result + when: check_elasticsearch_package_result.matched > 0 + +- name: Copy elasticsearch config files to ES_PATH_CONF dir + become: yes + command: "cp -r {{ mc_es_home }}/config/. {{ mc_es_conf_base }}/" + +- name: Remove elasticsearch config dir + become: yes + file: + path: "{{ mc_es_home }}/config" + state: absent + +- name: Generate HA elasticsearch.yml template file + become: yes + ignore_errors: yes + template: + src: templates/ha/{{ mc_ha_node_type }}.elasticsearch.yml.j2 + dest: "{{ mc_es_conf_base }}/elasticsearch.yml" + owner: elasticsearch + group: elasticsearch + when: + - unarchive_result.extract_results.rc | default(128) == 0 + - flow_type in ["ha-cluster", "ha-upgrade"] + +- name: Generate elasticsearch.yml template file + become: yes + template: + src: templates/elasticsearch.yml.j2 + dest: "{{ mc_es_conf_base }}/elasticsearch.yml" + owner: elasticsearch + group: elasticsearch + when: + - unarchive_result.extract_results.rc | default(128) == 0 + - flow_type in ["archive", "upgrade"] + +- name: Create empty unicast_hosts.txt file + become: yes + file: + path: "{{ mc_es_conf_base }}/unicast_hosts.txt" + state: touch + mode: 0664 + owner: elasticsearch + group: elasticsearch + +- name: Setup searchguard plugin + import_tasks: setup-searchguard.yml + +- name: Update directories permissions + become: yes + file: + path: "{{ item }}" + state: directory + mode: 0755 + recurse: yes + owner: elasticsearch + group: elasticsearch + loop: + - "{{ mc_es_conf_base }}" + - "{{ mc_es_data_dir }}" + - "{{ mc_es_log_dir }}" + - "{{ mc_es_home }}" + +- name: Start elasticsearch + become: yes + become_user: elasticsearch + shell: "{{ mc_es_script_path }}/elasticsearch -d" + environment: + JAVA_HOME: "{{ mc_es_java_home }}" + ES_PATH_CONF: "{{ mc_es_conf_base }}/" + register: start_elasticsearch_result + when: unarchive_result.extract_results.rc | default(128) == 0 + +- name: Wait for elasticsearch to start + pause: + seconds: 15 + +- name: Init searchguard plugin + become: yes + become_user: elasticsearch + shell: | + ./sgadmin.sh -p {{ mc_es_transport_port }} -cacert root-ca.pem \ + -cert sgadmin.pem -key sgadmin.key -cd {{ mc_es_searchgaurd_home }}/sgconfig/ -nhnv -icl + args: + chdir: "{{ mc_es_searchgaurd_home }}/tools/" + environment: + JAVA_HOME: "{{ mc_es_java_home }}" + register: install_searchguard_result + when: check_searchguard_bundle_result.matched == 1 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-searchguard.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-searchguard.yml new file mode 100644 index 0000000..54fcaaf --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/setup-searchguard.yml @@ -0,0 +1,100 @@ +- name: Copy elasticsearch certificate + become: yes + copy: + mode: 0600 + src: files/searchguard/localhost.pem + dest: "{{ mc_es_conf_base }}/localhost.pem" + owner: elasticsearch + group: elasticsearch + +- name: Copy elasticsearch private key + become: yes + copy: + mode: 0600 + src: files/searchguard/localhost.key + dest: "{{ mc_es_conf_base }}/localhost.key" + owner: elasticsearch + group: elasticsearch + +- name: Copy searchguard root ca + become: yes + copy: + mode: 0600 + src: files/searchguard/root-ca.pem + dest: "{{ mc_es_conf_base }}/root-ca.pem" + owner: elasticsearch + group: elasticsearch + +- name: Find searchguard bundle + find: + paths: "{{ mc_home }}/app/third-party/elasticsearch/" + patterns: "^search-guard-.+\\.zip$" + use_regex: yes + file_type: file + register: check_searchguard_bundle_result + +- name: Install searchguard plugin + become: yes + become_user: elasticsearch + ignore_errors: yes + shell: | + {{ mc_es_script_path }}/elasticsearch-plugin install \ + -b file://{{ check_searchguard_bundle_result.files[0].path }} + environment: + JAVA_HOME: "{{ mc_es_java_home }}" + ES_PATH_CONF: "{{ mc_es_conf_base }}/" + register: install_searchguard_result + when: check_searchguard_bundle_result.matched == 1 + +- name: Copy searchguard admin certificate + become: yes + copy: + mode: 0600 + src: files/searchguard/sgadmin.pem + dest: "{{ mc_es_searchgaurd_home }}/tools/sgadmin.pem" + owner: elasticsearch + group: elasticsearch + +- name: Copy searchguard admin private key + become: yes + copy: + mode: 0600 + src: files/searchguard/sgadmin.key + dest: "{{ mc_es_searchgaurd_home }}/tools/sgadmin.key" + owner: elasticsearch + group: elasticsearch + +- name: Copy searchguard root ca + become: yes + copy: + mode: 0600 + src: files/searchguard/root-ca.pem + dest: "{{ mc_es_searchgaurd_home }}/tools/root-ca.pem" + owner: elasticsearch + group: elasticsearch + +- name: Copy roles template + become: yes + copy: + mode: 0600 + src: files/searchguard/sg_roles.yml + dest: "{{ mc_es_searchgaurd_home }}/sgconfig/sg_roles.yml" + owner: elasticsearch + group: elasticsearch + +- name: Copy roles template + become: yes + copy: + mode: 0600 + src: files/searchguard/sg_roles_mapping.yml + dest: "{{ mc_es_searchgaurd_home }}/sgconfig/sg_roles_mapping.yml" + owner: elasticsearch + group: elasticsearch + +- name: Check execution bit + become: yes + file: + path: "{{ mc_es_searchgaurd_home }}/tools/sgadmin.sh" + owner: elasticsearch + group: elasticsearch + mode: 0700 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-elasticsearch.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-elasticsearch.yml new file mode 100644 index 0000000..527284e --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-elasticsearch.yml @@ -0,0 +1,113 @@ +- name: Get elasticsearch pid + shell: "ps -ef | grep -v grep | grep -w elasticsearch | awk '{print $2}'" + register: elasticsearch_pid + +- name: Stop elasticsearch before upgrade + become: yes + shell: kill -9 {{ elasticsearch_pid.stdout }} + when: elasticsearch_pid.stdout | length > 0 + +- name: Waiting until all running processes are killed + wait_for: + path: "/proc/{{ elasticsearch_pid.stdout }}/status" + state: absent + when: elasticsearch_pid.stdout | length > 0 + +- name: Find searchguard bundle for removal + become: yes + find: + paths: "{{ mc_home }}/app/third-party/elasticsearch/" + patterns: "^search-guard-.+\\.zip$" + use_regex: yes + file_type: file + register: check_searchguard_bundle_result + +- name: Remove searchguard plugin + become: yes + become_user: elasticsearch + ignore_errors: yes + shell: | + {{ mc_es_script_path }}/elasticsearch-plugin remove {{ check_searchguard_bundle_result.files[0].path }} + environment: + JAVA_HOME: "{{ mc_es_java_home }}" + ES_PATH_CONF: "{{ mc_es_conf_base }}/config" + register: remove_searchguard_result + when: check_searchguard_bundle_result.matched == 1 + +- name: Delete elasticsearch home dir + become: yes + file: + path: "{{ mc_es_home }}" + state: absent + +- name: Create elasticsearch home dir + become: yes + file: + path: "{{ mc_es_home }}" + state: directory + mode: 0755 + owner: elasticsearch + group: elasticsearch + +- name: Find elasticsearch package + become: yes + find: + paths: "{{ mc_home }}/app/third-party/elasticsearch" + patterns: "^elasticsearch-oss-.+\\.tar.gz$" + use_regex: yes + file_type: file + register: check_elasticsearch_package_result + +- name: Set elasticsearch package file name + set_fact: + mc_elasticsearch_package: "{{ check_elasticsearch_package_result.files[0].path }}" + when: check_elasticsearch_package_result.matched > 0 + +- name: Extract elasticsearch package + become: yes + become_user: elasticsearch + ignore_errors: yes + unarchive: + src: "{{ mc_elasticsearch_package }}" + dest: "{{ mc_es_home }}" + remote_src: yes + extra_opts: + - --strip-components=1 + - --exclude=config + owner: elasticsearch + group: elasticsearch + register: unarchive_result + when: check_elasticsearch_package_result.matched > 0 + +- name: Generate HA elasticsearch.yml template file + become: yes + ignore_errors: yes + template: + src: templates/ha/{{ mc_ha_node_type }}.elasticsearch.yml.j2 + dest: "{{ mc_es_conf_base }}/elasticsearch.yml" + owner: elasticsearch + group: elasticsearch + when: unarchive_result.extract_results.rc | default(128) == 0 + +- name: Create empty unicast_hosts.txt file + become: yes + file: + path: "{{ mc_es_conf_base }}/unicast_hosts.txt" + state: touch + mode: 0644 + owner: elasticsearch + group: elasticsearch + +- name: Upgrade searchguard plugin + import_tasks: upgrade-searchguard.yml + +- name: Start elasticsearch + become: yes + become_user: elasticsearch + ignore_errors: yes + shell: "{{ mc_es_script_path }}/elasticsearch -d" + environment: + JAVA_HOME: "{{ mc_es_java_home }}" + ES_PATH_CONF: "{{ mc_es_conf_base }}/" + when: unarchive_result.extract_results.rc | default(128) == 0 + register: start_elastcsearch_upgraded diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-searchguard.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-searchguard.yml new file mode 100644 index 0000000..cde3228 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade-searchguard.yml @@ -0,0 +1,100 @@ +- name: Create elasticsearch config path folder + become: yes + file: + path: "{{ mc_es_conf_base }}/searchguard" + state: directory + mode: 0755 + owner: elasticsearch + group: elasticsearch + +- name: Copy elasticsearch certificate + become: yes + copy: + mode: 0600 + src: files/searchguard/localhost.pem + dest: "{{ mc_es_conf_base }}/localhost.pem" + owner: elasticsearch + group: elasticsearch + +- name: Copy elasticsearch private key + become: yes + copy: + mode: 0600 + src: files/searchguard/localhost.key + dest: "{{ mc_es_conf_base }}/localhost.key" + owner: elasticsearch + group: elasticsearch + +- name: Copy searchguard admin certificate + become: yes + copy: + mode: 0600 + src: files/searchguard/sgadmin.pem + dest: "{{ mc_es_conf_base }}/searchguard/sgadmin.pem" + owner: elasticsearch + group: elasticsearch + +- name: Copy searchguard admin private key + become: yes + copy: + mode: 0600 + src: files/searchguard/sgadmin.key + dest: "{{ mc_es_conf_base }}/searchguard/sgadmin.key" + owner: elasticsearch + group: elasticsearch + +- name: Copy searchguard root ca + become: yes + copy: + mode: 0600 + src: files/searchguard/root-ca.pem + dest: "{{ mc_es_conf_base }}/root-ca.pem" + owner: elasticsearch + group: elasticsearch + +- name: Find searchguard bundle + find: + paths: "{{ mc_home }}/app/third-party/elasticsearch/" + patterns: "^search-guard-.+\\.zip$" + use_regex: yes + file_type: file + register: check_searchguard_bundle_result + +- name: Install searchguard plugin + become: yes + become_user: elasticsearch + ignore_errors: yes + shell: | + {{ mc_es_script_path }}/elasticsearch-plugin install \ + -b file://{{ check_searchguard_bundle_result.files[0].path }} + environment: + JAVA_HOME: "{{ mc_es_java_home }}" + ES_PATH_CONF: "{{ mc_es_conf_base }}/" + register: install_searchguard_result + when: check_searchguard_bundle_result.matched == 1 + +- name: Copy roles template + become: yes + copy: + mode: 0600 + src: files/searchguard/sg_roles.yml + dest: "{{ mc_es_home }}/plugins/search-guard-7/sgconfig/sg_roles.yml" + owner: elasticsearch + group: elasticsearch + +- name: Copy roles template + become: yes + copy: + mode: 0600 + src: files/searchguard/sg_roles_mapping.yml + dest: "{{ mc_es_home }}/plugins/search-guard-7/sgconfig/sg_roles_mapping.yml" + owner: elasticsearch + group: elasticsearch + +- name: Check execution bit + become: yes + file: + path: "{{ mc_es_home }}/plugins/search-guard-7/tools/sgadmin.sh" + owner: elasticsearch + group: elasticsearch + mode: 0700 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade.yml new file mode 100644 index 0000000..b988568 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/tasks/upgrade.yml @@ -0,0 +1,96 @@ +--- +- debug: + msg: "Performing Upgrade of missionControl version - {{ missioncontrol_version }}" + +- name: Stop mc service + become: yes + systemd: + name: "{{ mc_daemon }}" + state: stopped + +- name: Download mc for upgrade + unarchive: + src: "{{ mc_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ mc_user }}" + group: "{{ mc_group }}" + creates: "{{ mc_untar_home }}" + become: yes + register: downloadmc + until: downloadmc is succeeded + retries: 3 + +- name: Delete current app folder + become: yes + file: + path: "{{ mc_home }}/app" + state: absent + +- name: Copy new app to mc app + command: "cp -r {{ mc_untar_home }}/app/. {{ mc_home }}/app" + become: yes + +- name: Delete untar directory + file: + path: "{{ mc_untar_home }}" + state: absent + become: yes + +- name: Upgrade elasticsearch + import_tasks: upgrade-elasticsearch.yml + +- name: Check if install.sh wrapper script exist + become: yes + stat: + path: "{{ mc_install_script_path }}/install.sh" + register: upgrade_wrapper_script + +- name: Include interactive installer scripts + include_vars: script/archive.yml + +- name: Upgrade JFMC + include_tasks: expect.yml + vars: + exp_executable_cmd: "./install.sh -u {{ mc_user }} -g {{ mc_group }}" + exp_dir: "{{ mc_install_script_path }}" + exp_scenarios: "{{ mc_installer_scenario['main'] }}" + args: + apply: + environment: + YQ_PATH: "{{ mc_thirdparty_path }}/yq" + when: upgrade_wrapper_script.stat.exists + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ mc_home }}/var/etc/info/installer-info.json" + notify: restart missioncontrol + +- name: Configure systemyaml + template: + src: "{{ mc_system_yaml_template }}" + dest: "{{ mc_home }}/var/etc/system.yaml" + become: yes + notify: restart missioncontrol + +- name: Update correct permissions + become: yes + file: + path: "{{ mc_home }}" + state: directory + recurse: yes + owner: "{{ mc_user }}" + group: "{{ mc_group }}" + mode: '0755' + +- name: Restart missioncontrol + meta: flush_handlers + +- name : Wait for missionControl to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/elasticsearch.yml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/elasticsearch.yml.j2 new file mode 100644 index 0000000..f755a30 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/elasticsearch.yml.j2 @@ -0,0 +1,21 @@ +discovery.seed_providers: file +transport.port: {{ mc_es_transport_port }} +transport.host: 0.0.0.0 +transport.publish_host: {{ ansible_host }} +network.host: 0.0.0.0 +node.name: {{ ansible_host }} +cluster.initial_master_nodes: {{ ansible_host }} +bootstrap.memory_lock: false +path.data: {{ mc_es_data_dir }} +path.logs: {{ mc_es_log_dir }} + +searchguard.ssl.transport.pemcert_filepath: localhost.pem +searchguard.ssl.transport.pemkey_filepath: localhost.key +searchguard.ssl.transport.pemtrustedcas_filepath: root-ca.pem +searchguard.ssl.transport.enforce_hostname_verification: false +searchguard.ssl.transport.resolve_hostname: false +searchguard.nodes_dn: +- CN=localhost,OU=Ops,O=localhost\, Inc.,DC=localhost,DC=com +searchguard.authcz.admin_dn: +- CN=sgadmin,OU=Ops,O=sgadmin\, Inc.,DC=sgadmin,DC=com +searchguard.enterprise_modules_enabled: false diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.elasticsearch.yml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.elasticsearch.yml.j2 new file mode 100644 index 0000000..e5ff5c2 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.elasticsearch.yml.j2 @@ -0,0 +1,14 @@ +discovery.seed_providers: file + +{% if mc_elasticsearch_package | regex_search(".*oss-7.*") %} +cluster.initial_master_nodes: {{ ansible_host }} +{% endif %} + +path.data: {{ mc_es_home }}/data +path.logs: {{ mc_es_home }}/logs + +network.host: 0.0.0.0 +node.name: {{ ansible_host }} +transport.host: 0.0.0.0 +transport.port: 9300 +transport.publish_host: {{ ansible_host }} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.system.yaml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.system.yaml.j2 new file mode 100644 index 0000000..f1a60cc --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/master.system.yaml.j2 @@ -0,0 +1,21 @@ +configVersion: 1 +shared: + jfrogUrl: {{ jfrog_url }} + node: + ip: {{ ansible_host }} + database: + type: "{{ mc_db_type }}" + driver: "{{ mc_db_driver }}" + url: "{{ mc_db_url }}" + username: "{{ mc_db_user }}" + password: "{{ mc_db_password }}" + elasticsearch: + unicastFile: {{ mc_es_conf_base }}/unicast_hosts.txt + password: {{ mc_es_password }} + url: {{ mc_es_url }} + username: {{ mc_es_user }} + security: + joinKey: {{ join_key }} +router: + entrypoints: + internalPort: 8046 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.elasticsearch.yml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.elasticsearch.yml.j2 new file mode 100644 index 0000000..8c6f135 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.elasticsearch.yml.j2 @@ -0,0 +1,11 @@ +#bootstrap.memory_lock: true +discovery.seed_providers: file + +path.data: {{ mc_es_home }}/data +path.logs: {{ mc_es_home }}/logs + +network.host: 0.0.0.0 +node.name: {{ ansible_host }} +transport.host: 0.0.0.0 +transport.port: 9300 +transport.publish_host: {{ ansible_host }} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.system.yaml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.system.yaml.j2 new file mode 100644 index 0000000..d10c44d --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/ha/slave.system.yaml.j2 @@ -0,0 +1,22 @@ +configVersion: 1 +shared: + jfrogUrl: {{ jfrog_url }} + node: + ip: {{ ansible_host }} + database: + type: "{{ mc_db_type }}" + driver: "{{ mc_db_driver }}" + url: "{{ mc_db_url }}" + username: "{{ mc_db_user }}" + password: "{{ mc_db_password }}" + elasticsearch: + unicastFile: {{ mc_es_conf_base }}/unicast_hosts.txt + clusterSetup: YES + password: {{ mc_es_password }} + url: {{ mc_es_url }} + username: {{ mc_es_user }} + security: + joinKey: {{ join_key }} +router: + entrypoints: + internalPort: 8046 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/installer-info.json.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/installer-info.json.j2 new file mode 100644 index 0000000..5e02d5b --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/installer-info.json.j2 @@ -0,0 +1,9 @@ +{{ ansible_managed | comment }} +{ + "productId": "Ansible_MissionControl/{{ platform_collection_version }}-{{ missionControl_version }}", + "features": [ + { + "featureId": "Channel/{{ ansible_marketplace }}" + } + ] +} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/system.yaml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/system.yaml.j2 new file mode 100644 index 0000000..d6b3b33 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/templates/system.yaml.j2 @@ -0,0 +1,35 @@ +configVersion: 1 +shared: + jfrogUrl: {{ jfrog_url }} + node: + ip: {{ mc_primary_ip }} + id: {{ ansible_date_time.iso8601_micro | to_uuid }} + database: + type: "{{ mc_db_type }}" + driver: "{{ mc_db_driver }}" + url: "{{ mc_db_url }}" + elasticsearch: + unicastFile: {{ mc_es_conf_base }}/config/unicast_hosts.txt + password: {{ mc_es_password }} + url: {{ mc_es_url }} + username: {{ mc_es_user }} + security: + joinKey: {{ join_key }} +mc: + database: + username: "{{ mc_db_user }}" + password: "{{ mc_db_password }}" + schema: "jfmc_server" +insight-scheduler: + database: + username: "{{ mc_db_user }}" + password: "{{ mc_db_password }}" + schema: "insight_scheduler" +insight-server: + database: + username: "{{ mc_db_user }}" + password: "{{ mc_db_password }}" + schema: "insight_server" +router: + entrypoints: + internalPort: 8046 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/main.yml @@ -0,0 +1 @@ +--- diff --git a/Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/script/archive.yml b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/script/archive.yml new file mode 100644 index 0000000..6d66540 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/missionControl/vars/script/archive.yml @@ -0,0 +1,58 @@ +mc_installer_scenario: + main: + - { + "expecting": "(data|installation) directory \\(", + "sending": "{{ mc_home }}" + } + - { + "expecting": "jfrog url( \\(.+\\))?:(?!.*Skipping prompt)", + "sending": "{{ jfrog_url }}" + } + - { + "expecting": "join key:(?!.*Skipping prompt)", + "sending": "{{ join_key }}" + } + - { + "expecting": "please specify the ip address of this machine(?!.*Skipping prompt)", + "sending": "{% if mc_ha_node_type is defined and mc_ha_node_type == 'master' %}{{ ansible_host }}{% else %}{{ ansible_host }}{% endif %}" + } + - { + "expecting": "are you adding an additional node", + "sending": "{% if mc_ha_node_type is defined and mc_ha_node_type == 'master' %}n{% else %}y{% endif %}" + } + - { + "expecting": "do you want to install postgresql", + "sending": "n" + } + - { + "expecting": "do you want to install elasticsearch", + "sending": "n" + } + - { + "expecting": "(postgresql|database) url.+\\[jdbc:postgresql.+\\]:", + "sending": "{{ mc_db_url }}" + } + - { + "expecting": "(postgresql|database) password", + "sending": "{{ mc_db_password }}" + } + - { + "expecting": "(postgresql|database) username", + "sending": "{{ mc_db_user }}" + } + - { + "expecting": "confirm database password", + "sending": "{{ mc_db_password }}" + } + - { + "expecting": "elasticsearch url:(?!.*Skipping prompt)", + "sending": "{{ mc_es_url }}" + } + - { + "expecting": "elasticsearch username:", + "sending": "{{ mc_es_user }}" + } + - { + "expecting": "elasticsearch password:", + "sending": "{{ mc_es_password }}" + } diff --git a/Ansible/ansible_collections/jfrog/platform/roles/postgres/README.md b/Ansible/ansible_collections/jfrog/platform/roles/postgres/README.md new file mode 100644 index 0000000..05389ce --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/README.md @@ -0,0 +1,23 @@ +# postgres +The postgres role will install Postgresql software and configure a database and user to support an Artifactory or Xray server. + +### Role Variables + +By default, the [_pg_hba.conf_](https://www.postgresql.org/docs/13/auth-pg-hba-conf.html) client authentication file is configured for open access for development purposes through the _postgres_allowed_hosts_ variable: + +``` +postgres_allowed_hosts: + - { type: "host", database: "all", user: "all", address: "0.0.0.0/0", method: "trust"} +``` + +**THIS SHOULD NOT BE USED FOR PRODUCTION.** + +**Update this variable to only allow access from Artifactory, Distibution, MissionControl and Xray.** + +## Example Playbook +``` +--- +- hosts: postgres_servers + roles: + - postgres +``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/defaults/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/defaults/main.yml similarity index 82% rename from Ansible/ansible_collections/jfrog/installers/roles/postgres/defaults/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/postgres/defaults/main.yml index e980ceb..67a999f 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/defaults/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/defaults/main.yml @@ -1,21 +1,21 @@ --- -# Put database into alternative location with a bind mount. -postgres_server_bind_mount_var_lib_pgsql: false - -# Where to put database. -postgres_server_bind_mount_var_lib_pgsql_target: "" - # Default version of Postgres server to install. -postgres_server_version: "9.6" +postgres_version: 13 + +# Default listen_addresses of Postgres server +postgres_listen_addresses: 0.0.0.0 + +# Default port of Postgres server +postgres_port: 5432 # Server version in package: -postgres_server_pkg_version: "{{ postgres_server_version|replace('.', '') }}" +postgres_server_pkg_version: "{{ postgres_version|replace('.', '') }}" # Whether or not the files are on ZFS. postgres_server_volume_is_zfs: false # Postgres setting max_connections. -postgres_server_max_connections: 100 +postgres_server_max_connections: 1000 # Postgres setting shared_buffers. postgres_server_shared_buffers: 128MB @@ -48,8 +48,9 @@ postgres_server_max_locks_per_transaction: 64 postgres_server_random_page_cost: "4.0" # User name that the postgres user runs as. -postgres_server_user: postgres +postgres_user: postgres +postgres_locale: "en_US.UTF-8" # Whether or not to lock checkpoints. postgres_server_log_checkpoints: false @@ -85,5 +86,10 @@ postgres_server_auto_explain_log_analyze: true # Sets the hosts that can access the database postgres_allowed_hosts: - - { type: "host", database: "all", user: "all", address: "0.0.0.0/0", method: "trust"} - + - { + type: "host", + database: "all", + user: "all", + address: "0.0.0.0/0", + method: "trust", + } diff --git a/Ansible/ansible_collections/jfrog/platform/roles/postgres/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/handlers/main.yml new file mode 100644 index 0000000..fc9ffec --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart postgresql + become: yes + systemd: + name: "{{ postgresql_daemon }}" + state: restarted diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/meta/main.yml similarity index 86% rename from Ansible/ansible_collections/jfrog/installers/roles/postgres/meta/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/postgres/meta/main.yml index 674d197..e6f64de 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/meta/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/meta/main.yml @@ -1,5 +1,5 @@ galaxy_info: - author: "Jeff Fry " + author: "JFrog Maintainers Team " description: "The postgres role will install Postgresql software and configure a database and user to support an Artifactory or Xray server." company: JFrog diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/Debian.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/Debian.yml similarity index 59% rename from Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/Debian.yml rename to Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/Debian.yml index 04c9e91..948ac74 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/Debian.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/Debian.yml @@ -1,37 +1,33 @@ --- -- name: install python2 psycopg2 - apt: - name: python-psycopg2 - update_cache: yes +- name: install acl, python3-psycopg2 become: yes - ignore_errors: yes - -- name: install python3 psycopg2 apt: - name: python3-psycopg2 + name: + - acl + - python3-psycopg2 + state: present update_cache: yes - become: yes ignore_errors: yes - name: add postgres apt key + become: yes apt_key: url: https://www.postgresql.org/media/keys/ACCC4CF8.asc id: "0x7FCC7D46ACCC4CF8" + validate_certs: no state: present - become: yes - name: register APT repository + become: yes apt_repository: repo: deb http://apt.postgresql.org/pub/repos/apt/ {{ ansible_distribution_release }}-pgdg main state: present filename: pgdg - become: yes - name: install postgres packages + become: yes apt: name: - - postgresql-{{ postgres_server_version }} - - postgresql-server-dev-{{ postgres_server_version }} - - postgresql-contrib-{{ postgres_server_version }} + - postgresql-{{ postgres_version }} + - postgresql-contrib-{{ postgres_version }} state: present - become: yes diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/RedHat.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/RedHat.yml similarity index 65% rename from Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/RedHat.yml rename to Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/RedHat.yml index a30eba9..d535bf1 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/tasks/RedHat.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/RedHat.yml @@ -1,31 +1,41 @@ --- - name: install EPEL repository + become: yes yum: name=epel-release state=present when: > # not for Fedora ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux' - become: yes -- name: install python2 psycopg2 +- name: install acl + become: yes yum: name: - - python-psycopg2 + - acl - sudo - wget - perl state: present + ignore_errors: yes -- name: install python3 psycopg2 +- name: install python3-psycopg2 + become: yes yum: name: - python3-psycopg2 - - sudo - - wget - - perl state: present + when: ansible_distribution_major_version == '8' + +- name: install python2-psycopg2 + become: yes + yum: + name: + - python-psycopg2 + state: present + when: ansible_distribution_major_version == '7' - name: fixup some locale issues + become: yes lineinfile: dest: /etc/default/locale line: 'LANGUAGE="{{ item }}"' @@ -38,11 +48,11 @@ - name: get latest version vars: base: http://download.postgresql.org/pub/repos/yum - ver: "{{ ansible_distribution_version }}" + ver: "{{ ansible_distribution_major_version }}" shell: | set -eo pipefail - wget -O - {{ base }}/{{ postgres_server_version }}/redhat/rhel-{{ ver }}-x86_64/ 2>/dev/null | \ - grep 'pgdg-redhat' | \ + wget -O - {{ base }}/reporpms/EL-{{ ver }}-x86_64/ 2>/dev/null | \ + grep 'pgdg-redhat-repo-latest' | \ perl -pe 's/^.*rpm">//g' | \ perl -pe 's/<\/a>.*//g' | \ tail -n 1 @@ -51,22 +61,21 @@ changed_when: false check_mode: false register: latest_version - tags: [skip_ansible_lint] # yes, I want wget here + tags: [skip_ansible_lint] - name: config postgres repository + become: yes vars: base: http://download.postgresql.org/pub/repos/yum - ver: "{{ ansible_distribution_version }}" + ver: "{{ ansible_distribution_major_version }}" yum: - name: "{{ base }}/{{ postgres_server_version }}/redhat/rhel-{{ ver }}-x86_64/{{ latest_version.stdout }}" + name: "{{ base }}/reporpms/EL-{{ ver }}-x86_64/{{ latest_version.stdout }}" state: present - become: yes - name: install postgres packages + become: yes yum: name: - postgresql{{ postgres_server_pkg_version }}-server - postgresql{{ postgres_server_pkg_version }}-contrib - - postgresql{{ postgres_server_pkg_version }}-devel - state: present - become: yes + state: present \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/main.yml new file mode 100644 index 0000000..59612e5 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/tasks/main.yml @@ -0,0 +1,118 @@ +--- +- name: define OS-specific variables + include_vars: "{{ ansible_os_family }}.yml" + +- name: perform installation + include_tasks: "{{ ansible_os_family }}.yml" + +- name: Set PostgreSQL environment variables. + become: yes + template: + src: postgres.sh.j2 + dest: /etc/profile.d/postgres.sh + mode: 0644 + notify: restart postgresql + +- name: Ensure PostgreSQL data directory exists. + become: yes + become_user: postgres + file: + path: "{{ postgresql_data_dir }}" + owner: postgres + group: postgres + state: directory + mode: 0700 + +- name: Initialize PostgreSQL database cluster + become: yes + become_user: postgres + command: "{{ postgresql_bin_path }}/initdb -D {{ postgresql_data_dir }}" + args: + creates: "{{ postgresql_data_dir }}/PG_VERSION" + environment: + LC_ALL: "{{ postgres_locale }}" + +- name: Setup postgres configuration files + become: yes + become_user: postgres + template: + src: "{{ item }}.j2" + dest: "{{ postgresql_config_path }}/{{ item }}" + owner: postgres + group: postgres + mode: u=rw,go=r + loop: + - pg_hba.conf + - postgresql.conf + notify: restart postgresql + +- name: Ensure PostgreSQL is started and enabled on boot + become: yes + systemd: + name: "{{ postgresql_daemon }}" + state: started + enabled: yes + +- name: Hold until Postgresql is up and running + wait_for: + port: "{{ postgres_port }}" + +- name: Create users + become: yes + become_user: postgres + postgresql_user: + name: "{{ item.db_user }}" + password: "{{ item.db_password }}" + conn_limit: "-1" + loop: "{{ db_users|default([]) }}" + no_log: true # secret passwords + +- name: Create a database + become: yes + become_user: postgres + postgresql_db: + name: "{{ item.db_name }}" + owner: "{{ item.db_owner }}" + encoding: UTF-8 + lc_collate: "{{ postgres_locale }}" + lc_ctype: "{{ postgres_locale }}" + template: template0 + loop: "{{ dbs|default([]) }}" + +- name: Check if MC schemas already exists + become: yes + become_user: postgres + command: psql -d {{ mc_db_name }} -t -c "\dn" + register: mc_schemas_loaded + +- name: Create schemas for mission-control + become: yes + become_user: postgres + command: psql -d {{ mc_db_name }} -c 'CREATE SCHEMA {{ item }} authorization {{ mc_db_user }}' + loop: "{{ mc_schemas|default([]) }}" + when: "mc_schemas_loaded.stdout is defined and '{{ item }}' not in mc_schemas_loaded.stdout" + +- name: Grant all privileges to mc user on its schema + become: yes + become_user: postgres + postgresql_privs: + database: "{{ mc_db_name}}" + privs: ALL + type: schema + roles: "{{ mc_db_user }}" + objs: "{{ item }}" + loop: "{{ mc_schemas|default([]) }}" + +- name: Grant privs on db + become: yes + become_user: postgres + postgresql_privs: + database: "{{ item.db_name }}" + role: "{{ item.db_owner }}" + state: present + privs: ALL + type: database + loop: "{{ dbs|default([]) }}" + +- debug: + msg: "Restarted postgres systemd {{ postgresql_daemon }}" diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/templates/pg_hba.conf.j2 b/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/pg_hba.conf.j2 similarity index 76% rename from Ansible/ansible_collections/jfrog/installers/roles/postgres/templates/pg_hba.conf.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/pg_hba.conf.j2 index d051806..b861022 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/templates/pg_hba.conf.j2 +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/pg_hba.conf.j2 @@ -1,3 +1,9 @@ +{{ ansible_managed | comment }} +# PostgreSQL Client Authentication Configuration File +# =================================================== +# +# See: https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html + # TYPE DATABASE USER ADDRESS METHOD ## localhost connections through Unix port (user name), IPv4, IPv6 (MD5 pw). local all all peer @@ -8,4 +14,5 @@ host all all ::1/128 md5 {% for host in postgres_allowed_hosts %} {{ host.type | default('host') }} {{ host.database | default('all') }} {{ host.user | default('all') }} {{ host.address | default('0.0.0.0/0') }} {{ item.auth | default('trust') }} {% endfor %} -{% endif %} \ No newline at end of file +{% endif %} + diff --git a/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgres.sh.j2 b/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgres.sh.j2 new file mode 100644 index 0000000..ecb4eea --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgres.sh.j2 @@ -0,0 +1,4 @@ +{{ ansible_managed | comment }} +export PGDATA={{ postgresql_data_dir }} +export LC_ALL={{ postgres_locale }} +export PATH=$PATH:{{ postgresql_bin_path }} diff --git a/Ansible/ansible_collections/jfrog/installers/roles/postgres/templates/postgresql.conf.j2 b/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgresql.conf.j2 similarity index 87% rename from Ansible/ansible_collections/jfrog/installers/roles/postgres/templates/postgresql.conf.j2 rename to Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgresql.conf.j2 index c213a99..3fd1cda 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/postgres/templates/postgresql.conf.j2 +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/templates/postgresql.conf.j2 @@ -1,3 +1,4 @@ +{{ ansible_managed | comment }} # ----------------------------- # PostgreSQL configuration file # ----------------------------- @@ -16,9 +17,9 @@ # # This file is read on server startup and when the server receives a SIGHUP # signal. If you edit the file on a running system, you have to SIGHUP the -# server for the changes to take effect, or use "pg_ctl reload". Some -# parameters, which are marked below, require a server shutdown and restart to -# take effect. +# server for the changes to take effect, run "pg_ctl reload", or execute +# "SELECT pg_reload_conf()". Some parameters, which are marked below, +# require a server shutdown and restart to take effect. # # Any parameter can also be given as a command-line option to the server, e.g., # "postgres -c log_connections=on". Some parameters can be changed at run time @@ -38,35 +39,16 @@ # The default values of these variables are driven from the -D command-line # option or PGDATA environment variable, represented here as ConfigDir. -{% if postgres_server_config_data_directory is not none %} -data_directory = '{{ postgres_server_config_data_directory }}' -{% else %} -#data_directory = 'ConfigDir' # use data in another directory +data_directory = '{{ postgresql_data_dir }}' # use data in another directory # (change requires restart) -{% endif %} - -{% if postgres_server_config_data_directory %} -hba_file = '{{ postgres_server_config_hba_file }}' -{% else %} -#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file +hba_file = '{{ postgresql_config_path }}/pg_hba.conf' # host-based authentication file # (change requires restart) -{% endif %} - -{% if postgres_server_config_data_directory %} -ident_file = '{{ postgres_server_config_ident_file }}' -{% else %} -#ident_file = 'ConfigDir/pg_ident.conf' # host-based authentication file +ident_file = '{{ postgresql_config_path }}/pg_ident.conf' # ident configuration file # (change requires restart) -{% endif %} -{% if postgres_server_config_external_pid_file %} -external_pid_file = '{{ postgres_server_config_external_pid_file }}' -{% else %} # If external_pid_file is not explicitly set, no extra PID file is written. -#external_pid_file = '' # write an extra PID file +external_pid_file = '{{ postgresql_external_pid_file }}' # write an extra PID file # (change requires restart) -{% endif %} - #------------------------------------------------------------------------------ # CONNECTIONS AND AUTHENTICATION @@ -74,14 +56,14 @@ external_pid_file = '{{ postgres_server_config_external_pid_file }}' # - Connection Settings - -listen_addresses = '0.0.0.0' # what IP address(es) to listen on; +listen_addresses = '{{ postgres_listen_addresses }}' # what IP address(es) to listen on; # comma-separated list of addresses; # defaults to 'localhost'; use '*' for all # (change requires restart) -#port = 5432 # (change requires restart) +port = {{ postgres_port }} # (change requires restart) max_connections = {{ postgres_server_max_connections }} # (change requires restart) #superuser_reserved_connections = 3 # (change requires restart) -#unix_socket_directories = '/var/run/postgresql, /tmp' # comma-separated list of directories +#unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories # (change requires restart) #unix_socket_group = '' # (change requires restart) #unix_socket_permissions = 0777 # begin with 0 to use octal notation @@ -91,7 +73,19 @@ max_connections = {{ postgres_server_max_connections }} # (change requires res #bonjour_name = '' # defaults to the computer name # (change requires restart) -# - Security and Authentication - +# - TCP settings - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default +#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds; + # 0 selects the system default + +# - Authentication - #authentication_timeout = 1min # 1s-600s #ssl = off # (change requires restart) @@ -111,16 +105,6 @@ max_connections = {{ postgres_server_max_connections }} # (change requires res #krb_server_keyfile = '' #krb_caseins_users = off -# - TCP Keepalives - -# see "man 7 tcp" for details - -#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; - # 0 selects the system default -#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; - # 0 selects the system default -#tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default - #------------------------------------------------------------------------------ # RESOURCE USAGE (except WAL) @@ -186,7 +170,7 @@ max_parallel_workers_per_gather = {{ postgres_server_max_parallel_workers_per_g #old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate # (change requires restart) #backend_flush_after = 0 # measured in pages, 0 disables -{% if postgres_server_version|string != "9.6" %} +{% if postgres_version|string != "9.6" %} parallel_leader_participation = {{ "on" if postgres_server_parallel_leader_participation else "off" }} max_parallel_maintenance_workers = {{ postgres_server_max_parallel_maintenance_workers }} {% endif %} @@ -244,6 +228,41 @@ checkpoint_completion_target = 0.8 # checkpoint target duration, 0.0 - 1.0 #archive_timeout = 0 # force a logfile segment switch after this # number of seconds; 0 disables +# - Archive Recovery - + +# These are only used in recovery mode. + +#restore_command = '' # command to use to restore an archived logfile segment + # placeholders: %p = path of file to restore + # %f = file name only + # e.g. 'cp /mnt/server/archivedir/%f %p' + # (change requires restart) +#archive_cleanup_command = '' # command to execute at every restartpoint +#recovery_end_command = '' # command to execute at completion of recovery + +# - Recovery Target - + +# Set these only when performing a targeted recovery. + +#recovery_target = '' # 'immediate' to end recovery as soon as a + # consistent state is reached + # (change requires restart) +#recovery_target_name = '' # the named restore point to which recovery will proceed + # (change requires restart) +#recovery_target_time = '' # the time stamp up to which recovery will proceed + # (change requires restart) +#recovery_target_xid = '' # the transaction ID up to which recovery will proceed + # (change requires restart) +#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed + # (change requires restart) +#recovery_target_inclusive = on # Specifies whether to stop: + # just after the specified recovery target (on) + # just before the recovery target (off) + # (change requires restart) +#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID + # (change requires restart) +#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown' + # (change requires restart) #------------------------------------------------------------------------------ # REPLICATION @@ -294,7 +313,6 @@ checkpoint_completion_target = 0.8 # checkpoint target duration, 0.0 - 1.0 #wal_retrieve_retry_interval = 5s # time to wait before retrying to # retrieve WAL after a failed attempt - #------------------------------------------------------------------------------ # QUERY TUNING #------------------------------------------------------------------------------ @@ -309,9 +327,14 @@ checkpoint_completion_target = 0.8 # checkpoint target duration, 0.0 - 1.0 #enable_material = on #enable_mergejoin = on #enable_nestloop = on +#enable_parallel_append = on #enable_seqscan = on #enable_sort = on #enable_tidscan = on +#enable_partitionwise_join = off +#enable_partitionwise_aggregate = off +#enable_parallel_hash = on +#enable_partition_pruning = on # - Planner Cost Constants - @@ -322,7 +345,18 @@ random_page_cost = {{ postgres_server_random_page_cost }} #cpu_operator_cost = 0.0025 # same scale as above #parallel_tuple_cost = 0.1 # same scale as above #parallel_setup_cost = 1000.0 # same scale as above -#min_parallel_relation_size = 8MB + +#jit_above_cost = 100000 # perform JIT compilation if available + # and query more expensive than this; + # -1 disables +#jit_inline_above_cost = 500000 # inline small functions if query is + # more expensive than this; -1 disables +#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if + # query is more expensive than this; + # -1 disables + +#min_parallel_table_scan_size = 8MB +#min_parallel_index_scan_size = 512kB #effective_cache_size = 4GB # - Genetic Query Optimizer - @@ -344,6 +378,9 @@ random_page_cost = {{ postgres_server_random_page_cost }} #join_collapse_limit = 8 # 1 disables collapsing of explicit # JOIN clauses #force_parallel_mode = off +#jit = on # allow JIT compilation +#plan_cache_mode = auto # auto, force_generic_plan or + # force_custom_plan #------------------------------------------------------------------------------ @@ -480,7 +517,7 @@ log_statement = '{{ postgres_server_log_statements }}' # none, ddl, mod, all #log_temp_files = -1 # log temporary files equal or larger # than the specified size in kilobytes; # -1 disables, 0 logs all temp files -log_timezone = 'Europe/Berlin' +log_timezone = 'Etc/UTC' # - Process Title - diff --git a/Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/Debian.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/Debian.yml new file mode 100644 index 0000000..122f95f --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/Debian.yml @@ -0,0 +1,6 @@ +--- +postgresql_data_dir: "/var/lib/postgresql/{{ postgres_version }}/main" +postgresql_bin_path: "/usr/lib/postgresql/{{ postgres_version }}/bin" +postgresql_config_path: "/etc/postgresql/{{ postgres_version }}/main" +postgresql_daemon: postgresql@{{ postgres_version}}-main +postgresql_external_pid_file: "/var/run/postgresql/{{ postgres_version }}-main.pid" diff --git a/Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/RedHat.yml b/Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/RedHat.yml new file mode 100644 index 0000000..a4a5f37 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/postgres/vars/RedHat.yml @@ -0,0 +1,6 @@ +--- +postgresql_bin_path: "/usr/pgsql-{{ postgres_version }}/bin" +postgresql_data_dir: "/var/lib/pgsql/{{ postgres_version}}/data" +postgresql_config_path: "/var/lib/pgsql/{{ postgres_version}}/data" +postgresql_daemon: postgresql-{{ postgres_version}}.service +postgresql_external_pid_file: "/var/run/postgresql/{{ postgres_version }}-main.pid" diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/README.md b/Ansible/ansible_collections/jfrog/platform/roles/xray/README.md new file mode 100644 index 0000000..c53af51 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/README.md @@ -0,0 +1,26 @@ +# Xray +The xray role will install Xray software onto the host. An Artifactory server and Postgress database is required. + +### Role Variables +* _xray_upgrade_only_: Perform an software upgrade only. Default is false. + +Additional variables can be found in [defaults/main.yml](./defaults/main.yml). +## Example Playbook +``` +--- +- hosts: xray_servers + roles: + - xray +``` + +## Upgrades +The Xray role supports software upgrades. To use a role to perform a software upgrade only, use the _xray_upgrade_only_ variables and specify the version. See the following example. + +``` +- hosts: xray_servers + vars: + xray_version: "{{ lookup('env', 'xray_version_upgrade') }}" + xray_upgrade_only: true + roles: + - xray +``` \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/defaults/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/defaults/main.yml new file mode 100644 index 0000000..c57c008 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/defaults/main.yml @@ -0,0 +1,77 @@ +--- +# defaults file for xray +# indicates were this collection was downlaoded from (galaxy, automation_hub, standalone) +ansible_marketplace: standalone + +# whether to enable HA +xray_ha_enabled: false + +xray_ha_node_type : master + +# The location where xray should install. +jfrog_home_directory: /opt/jfrog + +# The remote xray download file +xray_tar: https://releases.jfrog.io/artifactory/jfrog-xray/xray-linux/{{ xray_version }}/jfrog-xray-{{ xray_version }}-linux.tar.gz + +#The xray install directory +xray_untar_home: "{{ jfrog_home_directory }}/jfrog-xray-{{ xray_version }}-linux" +xray_home: "{{ jfrog_home_directory }}/xray" + +xray_install_script_path: "{{ xray_home }}/app/bin" +xray_thirdparty_path: "{{ xray_home }}/app/third-party" +xray_archive_service_cmd: "{{ xray_install_script_path }}/installService.sh" + +#xray users and groups +xray_user: xray +xray_group: xray + +xray_uid: 1035 +xray_gid: 1035 + +xray_daemon: xray + +flow_type: archive + +#rabbitmq user +xray_rabbitmq_user: guest +xray_rabbitmq_password: guest +xray_rabbitmq_url: "amqp://localhost:5672/" +xray_rabbitmq_default_cookie: "XRAY_RABBITMQ_COOKIE" + +# if this is an upgrade +xray_upgrade_only: false + +xray_system_yaml_template: system.yaml.j2 + +linux_distro: "{{ ansible_distribution | lower }}{{ansible_distribution_major_version}}" + +xray_db_util_search_filter: + ubuntu16: + db5: 'db5.3-util.*ubuntu.*amd64\.deb' + db: 'db-util.*ubuntu.*all.deb' + ubuntu18: + db5: 'db5.3-util.*ubuntu.*amd64\.deb' + db: 'db-util.*ubuntu.*all.deb' + ubuntu20: + db5: 'db5.3-util.*ubuntu.*amd64\.deb' + db: 'db-util.*ubuntu.*all.deb' + debian8: + db5: 'db5.3-util.*deb8.*amd64\.deb' + db: 'db-util_([0-9]{1,3}\.?){3}_all\.deb' + debian9: + db5: 'db5.3-util.*deb9.*amd64\.deb' + db: 'db-util_([0-9]{1,3}\.?){3}_all\.deb' + debian10: + db5: 'TBD' + db: 'db-util_([0-9]{1,3}\.?){3}.*nmu1_all\.deb' + + +yum_python_interpreter: >- + {%- if linux_distro is not defined -%} + /usr/bin/python3 + {%- elif linux_distro in ['centos7', 'rhel7'] -%} + /usr/bin/python + {%- else -%} + /usr/bin/python3 + {%- endif -%} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/handlers/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/handlers/main.yml new file mode 100644 index 0000000..9af3a06 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/handlers/main.yml @@ -0,0 +1,7 @@ +--- +# handlers file for xray +- name: restart xray + become: yes + systemd: + name: "{{ xray_daemon }}" + state: restarted diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/meta/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/meta/main.yml similarity index 86% rename from Ansible/ansible_collections/jfrog/installers/roles/xray/meta/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/xray/meta/main.yml index b2be45e..c01401f 100644 --- a/Ansible/ansible_collections/jfrog/installers/roles/xray/meta/main.yml +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/meta/main.yml @@ -1,5 +1,5 @@ galaxy_info: - author: "Jeff Fry " + author: "JFrog Maintainers Team " description: "The xray role will install Xray software onto the host. An Artifactory server and Postgress database is required." company: JFrog diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/expect.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/expect.yml new file mode 100644 index 0000000..06f61dc --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/expect.yml @@ -0,0 +1,44 @@ +- name: Prepare expect scenario script + set_fact: + expect_scenario: | + set timeout 300 + spawn {{ exp_executable_cmd }} + expect_before timeout { exit 1 } + set CYCLE_END 0 + set count 0 + + while { $CYCLE_END == 0 } { + expect { + {% for each_request in exp_scenarios %} + -nocase -re {{ '{' }}{{ each_request.expecting }}.*} { + send "{{ each_request.sending }}\n" + } + {% endfor %} + eof { + set CYCLE_END 1 + } + } + set count "[expr $count + 1]" + if { $count > 16} { + exit 128 + } + } + + expect eof + lassign [wait] pid spawnid os_error_flag value + + if {$os_error_flag == 0} { + puts "INSTALLER_EXIT_STATUS-$value" + } else { + puts "INSTALLER_EXIT_STATUS-$value" + } + +- name: Interactive with expect + become: yes + ignore_errors: yes + shell: | + {{ expect_scenario }} + args: + executable: /usr/bin/expect + chdir: "{{ exp_dir }}" + register: exp_result diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/install.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/install.yml new file mode 100644 index 0000000..d279367 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/install.yml @@ -0,0 +1,165 @@ +--- +- debug: + msg: "Performing installation of Xray version : {{ xray_version }}" + +- debug: + msg: "ansible_os_family: {{ ansible_os_family }}" + +- name: Install expect dependency + become: yes + yum: + name: expect + state: present + when: ansible_os_family == 'RedHat' + +- name: Install expect dependency + become: yes + apt: + name: expect + state: present + update_cache: yes + when: ansible_os_family == 'Debian' + +- name: Ensure group xray exist + become: yes + group: + name: "{{ xray_group }}" + gid: "{{ xray_gid }}" + state: present + +- name: Ensure user xray exist + become: yes + user: + uid: "{{ xray_uid }}" + name: "{{ xray_user }}" + group: "{{ xray_group }}" + create_home: yes + home: "{{ xray_home }}" + shell: /bin/bash + state: present + +- name: Download xray + become: yes + unarchive: + src: "{{ xray_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ xray_user }}" + group: "{{ xray_group }}" + creates: "{{ xray_untar_home }}" + register: downloadxray + until: downloadxray is succeeded + retries: 3 + +- name: Check if app directory exists + become: yes + stat: + path: "{{ xray_home }}/app" + register: app_dir_check + +- name: Copy untar directory to xray home + become: yes + command: "cp -r {{ xray_untar_home }}/. {{ xray_home }}" + when: not app_dir_check.stat.exists + +- name: Create required directories + become: yes + file: + path: "{{ item }}" + state: directory + recurse: yes + owner: "{{ xray_user }}" + group: "{{ xray_group }}" + loop: + - "{{ xray_home }}/var/etc" + - "{{ xray_home }}/var/etc/info/" + - "{{ xray_home }}/var/etc/security/" + +- name: Configure master key + become: yes + copy: + dest: "{{ xray_home }}/var/etc/security/master.key" + content: | + {{ master_key }} + owner: "{{ xray_user }}" + group: "{{ xray_group }}" + mode: 0640 + +- name: Setup rabbitmq + import_tasks: rabbitmq/setup/RedHat.yml + when: ansible_os_family == 'RedHat' + +- name: Setup rabbitmq + import_tasks: rabbitmq/setup/Debian.yml + when: ansible_os_family == 'Debian' + +- name: Check if install.sh wrapper script exist + become: yes + stat: + path: "{{ xray_install_script_path }}/install.sh" + register: install_wrapper_script + +- name: Include interactive installer scripts + include_vars: script/archive.yml + +- name: Install xray + include_tasks: expect.yml + vars: + exp_executable_cmd: "./install.sh -u {{ xray_user }} -g {{ xray_group }}" + exp_dir: "{{ xray_install_script_path }}" + exp_scenarios: "{{ xray_installer_scenario['main'] }}" + args: + apply: + environment: + YQ_PATH: "{{ xray_thirdparty_path }}/yq" + when: install_wrapper_script.stat.exists + ignore_errors: yes + +- name: Configure rabbitmq config + become: yes + template: + src: "rabbitmq.conf.j2" + dest: "{{ xray_home }}/app/bin/rabbitmq/rabbitmq.conf" + notify: restart xray + +- name: Configure systemyaml + become: yes + template: + src: "{{ xray_system_yaml_template }}" + dest: "{{ xray_home }}/var/etc/system.yaml" + notify: restart xray + +- name: Configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ xray_home }}/var/etc/info/installer-info.json" + notify: restart xray + +- name: Ensure permissions are correct + become: yes + file: + path: "{{ jfrog_home_directory }}" + state: directory + owner: "{{ xray_user }}" + group: "{{ xray_group }}" + recurse: yes + +- name: Install xray as a service + become: yes + shell: | + {{ xray_archive_service_cmd }} + args: + chdir: "{{ xray_install_script_path }}" + register: check_service_status_result + ignore_errors: yes + +- name: Restart xray + meta: flush_handlers + +- name : Wait for xray to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/main.yml similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/xray/tasks/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/main.yml diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/check/archive.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/check/archive.yml new file mode 100644 index 0000000..528b474 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/check/archive.yml @@ -0,0 +1,63 @@ +- name: Check rabbitmq cluster_keepalive_interval option + become: yes + ignore_errors: yes + shell: | + ./rabbitmqctl --erlang-cookie {{ xray_rabbitmq_default_cookie }} eval \ + 'application:get_env(rabbit, cluster_keepalive_interval).' \ + | tr -d '}{' | cut -d ',' -f2 + args: + chdir: "{{ xray_home }}/app/third-party/rabbitmq/sbin/" + environment: + LC_ALL: en_US.UTF-8 + LC_CTYPE: en_US.UTF-8 + register: cluster_keepalive_interval_value + +- name: Check rabbitmq handshake_timeout option + become: yes + ignore_errors: yes + shell: | + ./rabbitmqctl --erlang-cookie {{ xray_rabbitmq_default_cookie }} eval \ + 'application:get_env(rabbit, handshake_timeout).' \ + | tr -d '}{' | cut -d ',' -f2 + args: + chdir: "{{ xray_home }}/app/third-party/rabbitmq/sbin/" + environment: + LC_ALL: en_US.UTF-8 + LC_CTYPE: en_US.UTF-8 + register: handshake_timeout_value + +- name: Check rabbitmq vm_memory_high_watermark.relative option + become: yes + ignore_errors: yes + shell: | + ./rabbitmqctl --erlang-cookie {{ xray_rabbitmq_default_cookie }} eval \ + 'application:get_env(rabbit, vm_memory_high_watermark).' \ + | tr -d '}{' | cut -d ',' -f2 + args: + chdir: "{{ xray_home }}/app/third-party/rabbitmq/sbin/" + environment: + LC_ALL: en_US.UTF-8 + LC_CTYPE: en_US.UTF-8 + register: vm_memory_high_watermark_relative_value + +- name: Store result + include_role: + name: report + vars: + stop_testing_if_fail: false + test_description: "{{ test_ext_description }}Check rabbitmq custom options values. INST-775" + test_host: "{{ inventory_hostname }}" + test_result: >- + {{ + vm_memory_high_watermark_relative_value.stdout == rabbitmq_custom_values['vm_memory_high_watermark'] + and cluster_keepalive_interval_value.stdout == rabbitmq_custom_values['cluster_keepalive_interval'] + and handshake_timeout_value.stdout == rabbitmq_custom_values['handshake_timeout'] + }} + report_action: "store-result" + log_result: >- + {{ + {} + | combine({'handshake_timeout': {'real': handshake_timeout_value.stdout, 'expected': rabbitmq_custom_values.handshake_timeout}}) + | combine({'vm_memory_high_watermark': {'real': vm_memory_high_watermark_relative_value.stdout, 'expected': rabbitmq_custom_values.vm_memory_high_watermark}}) + | combine({'cluster_keepalive_interval': {'real': cluster_keepalive_interval_value.stdout, 'expected': rabbitmq_custom_values.cluster_keepalive_interval}}) + }} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/Debian.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/Debian.yml new file mode 100644 index 0000000..ca527e8 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/Debian.yml @@ -0,0 +1,102 @@ +- name: Find libssl package + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^libssl.+\\.deb$" + use_regex: yes + file_type: file + register: check_libssl_package_result + +- name: Set libssl package file name + set_fact: + xray_libssl_package: "{{ check_libssl_package_result.files[0].path }}" + when: check_libssl_package_result.matched > 0 + +- name: Install libssl package + become: yes + apt: + deb: "{{ xray_libssl_package }}" + register: install_libssl_package_result + when: + - ansible_distribution_release == 'xenial' + - check_libssl_package_result.matched > 0 + +- name: Find socat package + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^socat.+\\.deb$" + use_regex: yes + file_type: file + register: check_socat_package_result + +- name: Set socat package file name + set_fact: + xray_socat_package: "{{ check_socat_package_result.files[0].path }}" + when: check_socat_package_result.matched > 0 + +- name: Install socat package + become: yes + ignore_errors: yes + apt: + deb: "{{ xray_socat_package }}" + register: install_socat_package_result + when: check_socat_package_result.matched > 0 + +- name: Find erlang package + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^(esl-)?erlang.+{{ ansible_distribution_release }}.+\\.deb$" + use_regex: yes + file_type: file + register: check_erlang_package_result + +- name: Set erlang package file name + set_fact: + xray_erlang_package: "{{ check_erlang_package_result.files[0].path }}" + when: check_erlang_package_result.matched > 0 + +- name: Install erlang package + become: yes + apt: + deb: "{{ xray_erlang_package }}" + register: install_erlang_package_result + when: check_erlang_package_result.matched > 0 + +- name: Find db5-util package + find: + paths: "{{ xray_home }}/app/third-party/misc/" + patterns: ["{{ xray_db_util_search_filter[linux_distro]['db5'] }}"] + use_regex: yes + file_type: file + register: check_db5_util_package_result + +- name: Set db5-util package file name + set_fact: + xray_db5_util_package: "{{ check_db5_util_package_result.files[0].path }}" + when: check_db5_util_package_result.matched > 0 + +- name: Install db5-util package + become: yes + apt: + deb: "{{ xray_db5_util_package }}" + register: install_db5_util_package_result + when: check_db5_util_package_result.matched > 0 + +- name: Find db-util package + find: + paths: "{{ xray_home }}/app/third-party/misc/" + patterns: ["{{ xray_db_util_search_filter[linux_distro]['db'] }}"] + use_regex: yes + file_type: file + register: check_db_util_package_result + +- name: Set db-util package file name + set_fact: + xray_db_util_package: "{{ check_db_util_package_result.files[0].path }}" + when: check_db_util_package_result.matched > 0 + +- name: Install db-util package + become: yes + apt: + deb: "{{ xray_db_util_package }}" + register: install_db_util_package_result + when: check_db_util_package_result.matched > 0 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/RedHat.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/RedHat.yml new file mode 100644 index 0000000..89fde95 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/setup/RedHat.yml @@ -0,0 +1,59 @@ +- name: Set package prefix + set_fact: + rhel_package_prefix: >- + {%- if linux_distro in ['centos7','rhel7'] -%} + el7 + {%- elif linux_distro in ['centos8','rhel8'] -%} + el8 + {%- endif -%} + +- debug: + msg: "rhel_package_prefix: {{ rhel_package_prefix }}" + +- name: Find socat package + become: yes + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^socat.+{{ rhel_package_prefix }}.+\\.rpm$" + use_regex: yes + file_type: file + register: check_socat_package_result + +- name: Set socat package file name + set_fact: + xray_socat_package: "{{ check_socat_package_result.files[0].path }}" + when: check_socat_package_result.matched > 0 + +- name: Install socat package + become: yes + yum: + name: "{{ xray_socat_package }}" + state: present + vars: + ansible_python_interpreter: "{{ yum_python_interpreter }}" + register: install_socat_package_result + when: check_socat_package_result.matched > 0 + +- name: Find erlang package + become: yes + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^(esl-)?erlang.+{{ rhel_package_prefix }}.+\\.rpm$" + use_regex: yes + file_type: file + register: check_erlang_package_result + +- name: Set erlang package file name + set_fact: + xray_erlang_package: "{{ check_erlang_package_result.files[0].path }}" + when: check_erlang_package_result.matched > 0 + +- name: Install erlang package + become: yes + yum: + name: "{{ xray_erlang_package }}" + state: present + vars: + ansible_python_interpreter: "{{ yum_python_interpreter }}" + register: install_erlang_package_result + when: check_erlang_package_result.matched > 0 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/status/archive.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/status/archive.yml new file mode 100644 index 0000000..3567e4a --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/status/archive.yml @@ -0,0 +1,12 @@ +- name: Get rabbitmq ha cluster status + become: yes + ignore_errors: yes + shell: | + ./rabbitmqctl --erlang-cookie {{ xray_rabbitmq_default_cookie }} \ + --formatter json cluster_status | jq . + args: + chdir: "{{ xray_home }}/app/third-party/rabbitmq/sbin/" + environment: + LC_ALL: en_US.UTF-8 + LC_CTYPE: en_US.UTF-8 + register: ha_rabbitmq_cluster_status diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/Debian.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/Debian.yml new file mode 100644 index 0000000..4441abc --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/Debian.yml @@ -0,0 +1,20 @@ +- name: Find erlang package + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^(esl-)?erlang.+{{ ansible_distribution_release }}.+\\.deb$" + use_regex: yes + file_type: file + register: check_erlang_package_result + +- name: Set erlang package file name + set_fact: + xray_erlang_package: "{{ check_erlang_package_result.files[0].path }}" + when: check_erlang_package_result.matched > 0 + +- name: Install erlang package + become: yes + apt: + deb: "{{ xray_erlang_package }}" + state: present + register: install_erlang_package_result + when: check_erlang_package_result.matched > 0 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/RedHat.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/RedHat.yml new file mode 100644 index 0000000..4bb43ce --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/rabbitmq/upgrade/RedHat.yml @@ -0,0 +1,32 @@ +- name: Set package prefix + set_fact: + rhel_package_prefix: >- + {%- if linux_distro in ['centos7','rhel7'] -%} + el7 + {%- elif linux_distro in ['centos8','rhel8'] -%} + el8 + {%- endif -%} + +- name: Find erlang package + become: yes + find: + paths: "{{ xray_home }}/app/third-party/rabbitmq/" + patterns: "^(esl-)?erlang.+{{ rhel_package_prefix }}.+\\.rpm$" + use_regex: yes + file_type: file + register: check_erlang_package_result + +- name: Set erlang package file name + set_fact: + xray_erlang_package: "{{ check_erlang_package_result.files[0].path }}" + when: check_erlang_package_result.matched > 0 + +- name: Install erlang package + become: yes + yum: + name: "{{ xray_erlang_package }}" + state: present + vars: + ansible_python_interpreter: "{{ yum_python_interpreter }}" + register: install_erlang_package_result + when: check_erlang_package_result.matched > 0 diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/upgrade.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/upgrade.yml new file mode 100644 index 0000000..31279b4 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/tasks/upgrade.yml @@ -0,0 +1,112 @@ +--- +- debug: + msg: "Performing upgrade of Xray version to {{ xray_version }}..." + +- name: stop xray + become: yes + systemd: + name: "{{ xray_daemon }}" + state: stopped + +- name: download xray for upgrade + become: yes + unarchive: + src: "{{ xray_tar }}" + dest: "{{ jfrog_home_directory }}" + remote_src: yes + owner: "{{ xray_user }}" + group: "{{ xray_group }}" + creates: "{{ xray_untar_home }}" + + register: downloadxray + until: downloadxray is succeeded + retries: 3 + +- name: Delete xray app + become: yes + file: + path: "{{ xray_home }}/app" + state: absent + +- name: Copy new app to xray app + become: yes + command: "cp -r {{ xray_untar_home }}/app/. {{ xray_home }}/app" + +- name: Upgrade rabbitmq + import_tasks: rabbitmq/upgrade/RedHat.yml + when: ansible_os_family == 'RedHat' + +- name: Upgrade rabbitmq + import_tasks: rabbitmq/upgrade/Debian.yml + when: ansible_os_family == 'Debian' + +- name: Check if install.sh wrapper script exist + become: yes + stat: + path: "{{ xray_install_script_path }}/install.sh" + register: install_wrapper_script + +- name: Include interactive installer scripts + include_vars: script/archive.yml + +- name: Install xray + include_tasks: expect.yml + vars: + exp_executable_cmd: "./install.sh -u {{ xray_user }} -g {{ xray_group }}" + exp_dir: "{{ xray_install_script_path }}" + exp_scenarios: "{{ xray_installer_scenario['main'] }}" + args: + apply: + environment: + YQ_PATH: "{{ xray_thirdparty_path }}/yq" + when: install_wrapper_script.stat.exists + ignore_errors: yes + +- name: Configure rabbitmq config + become: yes + template: + src: "rabbitmq.conf.j2" + dest: "{{ xray_home }}/app/bin/rabbitmq/rabbitmq.conf" + notify: restart xray + +- name: Configure systemyaml + become: yes + template: + src: "{{ xray_system_yaml_template }}" + dest: "{{ xray_home }}/var/etc/system.yaml" + notify: restart xray + +- name: configure installer info + become: yes + template: + src: installer-info.json.j2 + dest: "{{ xray_home }}/var/etc/info/installer-info.json" + notify: restart xray + +- name: Ensure permissions are correct + become: yes + file: + path: "{{ jfrog_home_directory }}" + state: directory + owner: "{{ xray_user }}" + group: "{{ xray_group }}" + recurse: yes + +- name: Install xray as a service + become: yes + shell: | + {{ xray_archive_service_cmd }} + args: + chdir: "{{ xray_install_script_path }}" + register: check_service_status_result + ignore_errors: yes + +- name: Restart xray + meta: flush_handlers + +- name : wait for xray to be fully deployed + uri: url=http://127.0.0.1:8082/router/api/v1/system/health timeout=130 + register: result + until: result.status == 200 + retries: 25 + delay: 5 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/installer-info.json.j2 b/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/installer-info.json.j2 new file mode 100644 index 0000000..00c97cb --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/installer-info.json.j2 @@ -0,0 +1,9 @@ +{{ ansible_managed | comment }} +{ + "productId": "Ansible_Xray/{{ platform_collection_version }}-{{ xray_version }}", + "features": [ + { + "featureId": "Channel/{{ ansible_marketplace }}" + } + ] +} \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/rabbitmq.conf.j2 b/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/rabbitmq.conf.j2 new file mode 100644 index 0000000..2acca65 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/rabbitmq.conf.j2 @@ -0,0 +1,9 @@ +loopback_users.guest = false +listeners.tcp.default = 5672 +hipe_compile = false +management.listener.port = 15672 +management.listener.ssl = false +cluster_partition_handling = autoheal +default_user = {{ xray_rabbitmq_user }} + +default_pass = {{ xray_rabbitmq_password }} diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/system.yaml.j2 b/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/system.yaml.j2 new file mode 100644 index 0000000..e51192b --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/templates/system.yaml.j2 @@ -0,0 +1,24 @@ +configVersion: 1 +shared: + jfrogUrl: {{ jfrog_url }} + node: + ip: {{ ansible_host }} + id: {{ ansible_date_time.iso8601_micro | to_uuid }} + database: + type: "{{ xray_db_type }}" + driver: "{{ xray_db_driver }}" + url: "{{ xray_db_url }}" + username: "{{ xray_db_user }}" + password: "{{ xray_db_password }}" + rabbitMq: + autoStop: true + erlangCookie: + value: "{{ xray_rabbitmq_default_cookie }}" + url: "{{ xray_rabbitmq_url }}" + username: "{{ xray_rabbitmq_user }}" + password: "{{xray_rabbitmq_password }}" + security: + joinKey: {{ join_key }} +router: + entrypoints: + internalPort: 8046 \ No newline at end of file diff --git a/Ansible/ansible_collections/jfrog/installers/roles/xray/vars/main.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/vars/main.yml similarity index 100% rename from Ansible/ansible_collections/jfrog/installers/roles/xray/vars/main.yml rename to Ansible/ansible_collections/jfrog/platform/roles/xray/vars/main.yml diff --git a/Ansible/ansible_collections/jfrog/platform/roles/xray/vars/script/archive.yml b/Ansible/ansible_collections/jfrog/platform/roles/xray/vars/script/archive.yml new file mode 100644 index 0000000..1a84f91 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/roles/xray/vars/script/archive.yml @@ -0,0 +1,54 @@ +xray_installer_scenario: + main: + - { + "expecting": "have you disconnected artifactory xray pairings", + "sending": "y" + } + - { + "expecting": "(data|installation) directory \\(", + "sending": "{{ xray_home }}" + } + - { + "expecting": "jfrog url( \\(.+\\))?:(?!.*Skipping prompt)", + "sending": "{{ jfrog_url }}" + } + - { + "expecting": "join key:(?!.*Skipping prompt)", + "sending": "{{ join_key }}" + } + - { + "expecting": "please specify the ip address of this machine(?!.*Skipping prompt)", + "sending": "{% if xray_ha_node_type is defined and xray_ha_node_type == 'master' %}{{ ansible_host }}{% else %}{{ ansible_host }}{% endif %}" + } + - { + "expecting": "are you adding an additional node", + "sending": "{% if xray_ha_node_type is defined and xray_ha_node_type == 'master' %}n{% else %}y{% endif %}" + } + - { + "expecting": "do you want to install postgresql", + "sending": "n" + } + - { + "expecting": "(postgresql|database) url", + "sending": "{{ xray_db_url }}" + } + - { + "expecting": "(postgresql|database) password", + "sending": "{{ xray_db_password }}" + } + - { + "expecting": "(postgresql|database) username", + "sending": "{{ xray_db_user }}" + } + - { + "expecting": "confirm database password", + "sending": "{{ xray_db_password }}" + } + - { + "expecting": "rabbitmq active node name:", + "sending": "{{ ansible_machine_id }}" + } + - { + "expecting": "rabbitmq active node ip:", + "sending": "{{ ansible_host }}" + } diff --git a/Ansible/ansible_collections/jfrog/platform/xray.yml b/Ansible/ansible_collections/jfrog/platform/xray.yml new file mode 100644 index 0000000..62d7ca9 --- /dev/null +++ b/Ansible/ansible_collections/jfrog/platform/xray.yml @@ -0,0 +1,4 @@ +--- +- hosts: xray_servers + roles: + - xray diff --git a/Ansible/examples/host_vars/rt-ha/hosts.yml b/Ansible/examples/host_vars/rt-ha/hosts.yml deleted file mode 100644 index 5a702ac..0000000 --- a/Ansible/examples/host_vars/rt-ha/hosts.yml +++ /dev/null @@ -1,52 +0,0 @@ ---- -all: - vars: - ansible_user: "ubuntu" - ansible_ssh_private_key_file: "{{ lookup('env', 'ansible_key') }}" - children: - database: - hosts: - #artifactory database - 52.86.32.79: - db_users: - - { db_user: "artifactory", db_password: "{{ lookup('env', 'artifactory_password') }}" } - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - artifactory: - vars: - artifactory_version: 7.4.1 - artifactory_ha_enabled: true - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "jdbc:postgresql://10.0.0.160:5432/artifactory" - db_user: "artifactory" - db_password: "{{ lookup('env', 'artifactory_password') }}" - server_name: "ec2-100-25-104-198.compute-1.amazonaws.com" - certificate: | - -----BEGIN CERTIFICATE----- - x - -----END CERTIFICATE----- - certificate_key: | - -----BEGIN PRIVATE KEY----- - x - -----END PRIVATE KEY----- - children: - primary: - hosts: - 100.25.104.198: - artifactory_is_primary: true - artifactory_license1: x - artifactory_license2: x - artifactory_license3: x - artifactory_license4: x - artifactory_license5: x - secondary: - hosts: - 54.160.107.157: - 35.153.79.44: - vars: - artifactory_is_primary: false - diff --git a/Ansible/examples/host_vars/rt-xray-ha/hosts.yml b/Ansible/examples/host_vars/rt-xray-ha/hosts.yml deleted file mode 100644 index cbb3ef7..0000000 --- a/Ansible/examples/host_vars/rt-xray-ha/hosts.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- -all: - vars: - ansible_user: "ubuntu" - ansible_ssh_private_key_file: "{{ lookup('env', 'ansible_key') }}" - children: - database: - hosts: - #artifactory database - 52.86.32.79: - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - db_users: - - { db_user: "artifactory", db_password: "{{ lookup('env', 'artifactory_password') }}" } - #xray database - 100.25.152.93: - dbs: - - { db_name: "xraydb", db_owner: "xray" } - db_users: - - { db_user: "xray", db_password: "{{ lookup('env', 'xray_password') }}" } - artifactory: - vars: - artifactory_version: 7.4.1 - artifactory_ha_enabled: true - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "jdbc:postgresql://10.0.0.51:5432/artifactory" - db_user: "artifactory" - db_password: "{{ lookup('env', 'artifactory_password') }}" - server_name: "ec2-18-210-33-94.compute-1.amazonaws.com" - children: - primary: - hosts: - 18.210.33.94: - artifactory_is_primary: true - artifactory_license1: x - artifactory_license2: x - artifactory_license3: x - artifactory_license4: x - artifactory_license5: x - xray: - vars: - xray_version: 3.3.0 - jfrog_url: http://ec2-18-210-33-94.compute-1.amazonaws.com - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "postgres://10.0.0.5:5432/xraydb?sslmode=disable" - db_user: "xray" - db_password: "{{ lookup('env', 'xray_password') }}" - hosts: -# 34.229.56.166: - 54.237.68.180 diff --git a/Ansible/examples/host_vars/rt-xray/hosts.yml b/Ansible/examples/host_vars/rt-xray/hosts.yml deleted file mode 100644 index 8a844a5..0000000 --- a/Ansible/examples/host_vars/rt-xray/hosts.yml +++ /dev/null @@ -1,45 +0,0 @@ ---- -all: - vars: - ansible_user: "ubuntu" - ansible_ssh_private_key_file: "{{ lookup('env', 'ansible_key') }}" - children: - database: - hosts: - 34.239.107.0: - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - - { db_name: "xraydb", db_owner: "xray" } - db_users: - - { db_user: "artifactory", db_password: "{{ lookup('env', 'artifactory_password') }}" } - - { db_user: "xray", db_password: "{{ lookup('env', 'xray_password') }}" } - artifactory: - hosts: - 54.237.207.135: - artifactory_version: 7.4.1 - artifactory_license1: x - artifactory_license2: x - artifactory_license3: x - artifactory_license4: x - artifactory_license5: x - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "jdbc:postgresql://10.0.0.59:5432/artifactory" - db_user: "artifactory" - db_password: "{{ lookup('env', 'artifactory_password') }}" - server_name: "ec2-54-237-207-135.compute-1.amazonaws.com" - xray: - hosts: - 100.25.104.174: - xray_version: 3.3.0 - jfrog_url: "http://ec2-54-237-207-135.compute-1.amazonaws.com" - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "postgres://10.0.0.59:5432/xraydb?sslmode=disable" - db_user: "xray" - db_password: "{{ lookup('env', 'xray_password') }}" diff --git a/Ansible/examples/host_vars/rt/hosts.yml b/Ansible/examples/host_vars/rt/hosts.yml deleted file mode 100644 index f030ff6..0000000 --- a/Ansible/examples/host_vars/rt/hosts.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -all: - vars: - ansible_user: "ubuntu" - children: - database: - hosts: - 54.83.163.100: - db_users: - - { db_user: "artifactory", db_password: "{{ lookup('env', 'artifactory_password') }}" } - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - primary: - hosts: - 54.165.47.191: - artifactory_version: 7.4.1 - artifactory_is_primary: true - artifactory_license_file: "{{ lookup('env', 'artifactory_license_file') }}" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "jdbc:postgresql://10.0.0.219:5432/artifactory" - db_user: "artifactory" - db_password: "{{ lookup('env', 'artifactory_password') }}" - server_name: "ec2-54-165-47-191.compute-1.amazonaws.com" \ No newline at end of file diff --git a/Ansible/examples/host_vars/ssl/hosts.yml b/Ansible/examples/host_vars/ssl/hosts.yml deleted file mode 100644 index eaf20e1..0000000 --- a/Ansible/examples/host_vars/ssl/hosts.yml +++ /dev/null @@ -1,40 +0,0 @@ ---- -all: - vars: - ansible_user: "ubuntu" - ansible_ssh_private_key_file: "{{ lookup('env', 'ansible_key') }}" - children: - database: - hosts: - 52.86.32.79: - db_users: - - { db_user: "artifactory", db_password: "{{ lookup('env', 'artifactory_password') }}" } - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - primary: - hosts: - 100.25.104.198: - artifactory_version: 7.4.1 - artifactory_is_primary: true - artifactory_license1: x - artifactory_license2: x - artifactory_license3: x - artifactory_license4: x - artifactory_license5: x - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "jdbc:postgresql://10.0.0.160:5432/artifactory" - db_user: "artifactory" - db_password: "{{ lookup('env', 'artifactory_password') }}" - server_name: "ec2-100-25-104-198.compute-1.amazonaws.com" - certificate: | - -----BEGIN CERTIFICATE----- - x - -----END CERTIFICATE----- - certificate_key: | - -----BEGIN PRIVATE KEY----- - x - -----END PRIVATE KEY----- diff --git a/Ansible/examples/host_vars/xray/hosts.yml b/Ansible/examples/host_vars/xray/hosts.yml deleted file mode 100644 index e48a9fd..0000000 --- a/Ansible/examples/host_vars/xray/hosts.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -all: - vars: - ansible_user: "centos" - children: - xray: - vars: - xray_version: 3.3.0 - jfrog_url: http://ec2-18-210-33-94.compute-1.amazonaws.com - master_key: "c97b862469de0d94fbb7d48130637a5a" - join_key: "9bcca98f375c0728d907cc6ee39d4f02" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_url: "postgres://10.0.0.5:5432/xraydb?sslmode=disable" - db_user: "xray" - db_password: "{{ lookup('env', 'xray_password') }}" - hosts: - 3.17.132.222 diff --git a/Ansible/examples/inventory/platform/hosts.ini b/Ansible/examples/inventory/platform/hosts.ini new file mode 100644 index 0000000..ae5095a --- /dev/null +++ b/Ansible/examples/inventory/platform/hosts.ini @@ -0,0 +1,15 @@ +# Replace x.x.x.x with public Ips of servers +[postgres_servers] +postgres-1 ansible_host=x.x.x.x + +[artifactory_servers] +artifactory-1 ansible_host=x.x.x.x + +[xray_servers] +xray-1 ansible_host=x.x.x.x + +[distribution_servers] +distribution-1 ansible_host=x.x.x.x + +[missionControl_servers] +missionControl-1 ansible_host=x.x.x.x diff --git a/Ansible/examples/inventory/rt-xray/hosts.ini b/Ansible/examples/inventory/rt-xray/hosts.ini new file mode 100644 index 0000000..139157a --- /dev/null +++ b/Ansible/examples/inventory/rt-xray/hosts.ini @@ -0,0 +1,9 @@ +# Replace x.x.x.x with public Ips of servers +[postgres_servers] +postgres-1 ansible_host=x.x.x.x + +[artifactory_servers] +artifactory-1 ansible_host=x.x.x.x + +[xray_servers] +xray-1 ansible_host=x.x.x.x diff --git a/Ansible/examples/inventory/rt/hosts.ini b/Ansible/examples/inventory/rt/hosts.ini new file mode 100644 index 0000000..02aef40 --- /dev/null +++ b/Ansible/examples/inventory/rt/hosts.ini @@ -0,0 +1,6 @@ +# Replace x.x.x.x with public Ips of servers +[postgres_servers] +postgres-1 ansible_host=x.x.x.x + +[artifactory_servers] +artifactory-1 ansible_host=x.x.x.x diff --git a/Ansible/examples/inventory/xray/hosts.ini b/Ansible/examples/inventory/xray/hosts.ini new file mode 100644 index 0000000..94f6a8f --- /dev/null +++ b/Ansible/examples/inventory/xray/hosts.ini @@ -0,0 +1,6 @@ +# Replace x.x.x.x with public Ips of servers +[postgres_servers] +postgres-1 ansible_host=x.x.x.x + +[xray_servers] +xray-1 ansible_host=x.x.x.x diff --git a/Ansible/examples/playbook-platform.yml b/Ansible/examples/playbook-platform.yml new file mode 100644 index 0000000..f9c6f0e --- /dev/null +++ b/Ansible/examples/playbook-platform.yml @@ -0,0 +1,30 @@ +--- +- hosts: postgres_servers + collections: + - jfrog.platform + roles: + - postgres + +- hosts: artifactory_servers + collections: + - jfrog.platform + roles: + - artifactory + +- hosts: xray_servers + collections: + - jfrog.platform + roles: + - xray + +- hosts: distribution_servers + collections: + - jfrog.platform + roles: + - distribution + +- hosts: missioncontrol_servers + collections: + - jfrog.platform + roles: + - missioncontrol diff --git a/Ansible/examples/playbook-rt-ha.yml b/Ansible/examples/playbook-rt-ha.yml deleted file mode 100644 index 57fc65c..0000000 --- a/Ansible/examples/playbook-rt-ha.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -- hosts: database - collections: - - jfrog.installers - roles: - - postgres - -- hosts: primary:secondary - collections: - - jfrog.installers - roles: - - artifactory - - artifactory_nginx_ssl \ No newline at end of file diff --git a/Ansible/examples/playbook-rt-xray.yml b/Ansible/examples/playbook-rt-xray.yml index 6081198..6a1b9b3 100644 --- a/Ansible/examples/playbook-rt-xray.yml +++ b/Ansible/examples/playbook-rt-xray.yml @@ -1,18 +1,18 @@ --- -- hosts: database +- hosts: postgres-servers collections: - - jfrog.installers + - jfrog.platform roles: - postgres -- hosts: artifactory +- hosts: artifactory-servers collections: - - jfrog.installers + - jfrog.platform roles: - artifactory -- hosts: xray +- hosts: xray-servers collections: - - jfrog.installers + - jfrog.platform roles: - xray \ No newline at end of file diff --git a/Ansible/examples/playbook-rt.yml b/Ansible/examples/playbook-rt.yml index 72ffbec..1761a97 100644 --- a/Ansible/examples/playbook-rt.yml +++ b/Ansible/examples/playbook-rt.yml @@ -1,12 +1,12 @@ --- -- hosts: database +- hosts: postgres_servers collections: - - jfrog.installers + - jfrog.platform roles: - postgres -- hosts: primary +- hosts: artifactory_servers collections: - - jfrog.installers + - jfrog.platform roles: - artifactory diff --git a/Ansible/examples/playbook-ssl.yml b/Ansible/examples/playbook-ssl.yml deleted file mode 100644 index 7370111..0000000 --- a/Ansible/examples/playbook-ssl.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -- hosts: database - collections: - - jfrog.installers - roles: - - postgres - -- hosts: primary - collections: - - jfrog.installers - roles: - - artifactory - - artifactory_nginx_ssl diff --git a/Ansible/examples/playbook-xray.yml b/Ansible/examples/playbook-xray.yml index 3f0e5a4..ba6a8b6 100644 --- a/Ansible/examples/playbook-xray.yml +++ b/Ansible/examples/playbook-xray.yml @@ -1,6 +1,12 @@ --- -- hosts: xray +- hosts: postgres_servers collections: - - jfrog.installers + - jfrog.platform roles: - - xray \ No newline at end of file + - postgres + +- hosts: xray_servers + collections: + - jfrog.platform + roles: + - xray diff --git a/Ansible/infra/aws/lb-rt-xray-ha-centos78.json b/Ansible/infra/aws/lb-rt-xray-ha-centos78.json deleted file mode 100644 index 73859a8..0000000 --- a/Ansible/infra/aws/lb-rt-xray-ha-centos78.json +++ /dev/null @@ -1,769 +0,0 @@ -{ - "Description": "This template deploys a VPC, with a pair of public and private subnets spread across two Availability Zones. It deploys an internet gateway, with a default route on the public subnets. It deploys a pair of NAT gateways (one in each AZ), and default routes for them in the private subnets.", - "Parameters": { - "SSHKeyName": { - "Description": "Name of the ec2 key you need one to use this template", - "Type": "AWS::EC2::KeyPair::KeyName", - "Default": "choose-key" - }, - "EnvironmentName": { - "Description": "An environment name that is prefixed to resource names", - "Type": "String", - "Default": "Ansible" - }, - "VpcCIDR": { - "Description": "Please enter the IP range (CIDR notation) for this VPC", - "Type": "String", - "Default": "10.192.0.0/16" - }, - "PublicSubnet1CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone", - "Type": "String", - "Default": "10.192.10.0/24" - }, - "PublicSubnet2CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone", - "Type": "String", - "Default": "10.192.11.0/24" - }, - "PrivateSubnet1CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone", - "Type": "String", - "Default": "10.192.20.0/24" - }, - "PrivateSubnet2CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone", - "Type": "String", - "Default": "10.192.21.0/24" - } - }, - "Mappings": { - "RegionToAmazonAMI": { - "us-east-1": { - "HVM64": "ami-02e98f78" - }, - "us-east-2": { - "HVM64": "ami-01e36b7901e884a10" - }, - "us-west-1": { - "HVM64": "ami-074e2d6769f445be5" - }, - "us-west-2": { - "HVM64": "ami-01ed306a12b7d1c96" - } - } - }, - "Resources": { - "VPC": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": { - "Ref": "VpcCIDR" - }, - "EnableDnsSupport": true, - "EnableDnsHostnames": true, - "Tags": [ - { - "Key": "Name", - "Value": { - "Ref": "EnvironmentName" - } - } - ] - } - }, - "InternetGateway": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": { - "Ref": "EnvironmentName" - } - } - ] - } - }, - "InternetGatewayAttachment": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "InternetGatewayId": { - "Ref": "InternetGateway" - }, - "VpcId": { - "Ref": "VPC" - } - } - }, - "PublicSubnet1": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 0, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PublicSubnet1CIDR" - }, - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Public Subnet (AZ1)" - } - } - ] - } - }, - "PublicSubnet2": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 1, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PublicSubnet2CIDR" - }, - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Public Subnet (AZ2)" - } - } - ] - } - }, - "PrivateSubnet1": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 0, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PrivateSubnet1CIDR" - }, - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Subnet (AZ1)" - } - } - ] - } - }, - "PrivateSubnet2": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 1, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PrivateSubnet2CIDR" - }, - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Subnet (AZ2)" - } - } - ] - } - }, - "NatGateway1EIP": { - "Type": "AWS::EC2::EIP", - "DependsOn": "InternetGatewayAttachment", - "Properties": { - "Domain": "vpc" - } - }, - "NatGateway2EIP": { - "Type": "AWS::EC2::EIP", - "DependsOn": "InternetGatewayAttachment", - "Properties": { - "Domain": "vpc" - } - }, - "NatGateway1": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "NatGateway1EIP", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "PublicSubnet1" - } - } - }, - "NatGateway2": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "NatGateway2EIP", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "PublicSubnet2" - } - } - }, - "PublicRouteTable": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Public Routes" - } - } - ] - } - }, - "DefaultPublicRoute": { - "Type": "AWS::EC2::Route", - "DependsOn": "InternetGatewayAttachment", - "Properties": { - "RouteTableId": { - "Ref": "PublicRouteTable" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "InternetGateway" - } - } - }, - "PublicSubnet1RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PublicRouteTable" - }, - "SubnetId": { - "Ref": "PublicSubnet1" - } - } - }, - "PublicSubnet2RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PublicRouteTable" - }, - "SubnetId": { - "Ref": "PublicSubnet2" - } - } - }, - "PrivateRouteTable1": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Routes (AZ1)" - } - } - ] - } - }, - "DefaultPrivateRoute1": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable1" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "NatGateway1" - } - } - }, - "PrivateSubnet1RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable1" - }, - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - }, - "PrivateRouteTable2": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Routes (AZ2)" - } - } - ] - } - }, - "DefaultPrivateRoute2": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable2" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "NatGateway2" - } - } - }, - "PrivateSubnet2RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable2" - }, - "SubnetId": { - "Ref": "PrivateSubnet2" - } - } - }, - "EC2SecurityGroup": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "SSH, Port 80, Database", - "VpcId": { - "Ref": "VPC" - }, - "SecurityGroupIngress": [ - { - "IpProtocol": "tcp", - "FromPort": 22, - "ToPort": 22, - "CidrIp": "0.0.0.0/0" - }, - { - "IpProtocol": "tcp", - "FromPort": 5432, - "ToPort": 5432, - "CidrIp": "0.0.0.0/0" - }, - { - "IpProtocol": "tcp", - "FromPort": 8082, - "ToPort": 8082, - "CidrIp": "0.0.0.0/0" - }, - { - "IpProtocol": "tcp", - "FromPort": 80, - "ToPort": 80, - "SourceSecurityGroupId": { - "Ref": "ELBSecurityGroup" - } - } - ] - } - }, - "ELBSecurityGroup": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "SSH and Port 80", - "VpcId": { - "Ref": "VPC" - }, - "SecurityGroupIngress": [ - { - "IpProtocol": "tcp", - "FromPort": 80, - "ToPort": 80, - "CidrIp": "0.0.0.0/0" - } - ] - } - }, - "BastionInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "true", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PublicSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "bastion" - } - ], - "Tenancy": "default" - } - }, - "RTPriInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "rtprimary" - } - ], - "Tenancy": "default" - } - }, - "RTSecInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet2" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "rtsecondary" - } - ], - "Tenancy": "default" - } - }, - "XrayInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "xray" - } - ], - "Tenancy": "default" - } - }, - "DBInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "database" - } - ], - "Tenancy": "default" - } - }, - "EC2TargetGroup": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "HealthCheckIntervalSeconds": 30, - "HealthCheckProtocol": "HTTP", - "HealthCheckTimeoutSeconds": 15, - "HealthyThresholdCount": 2, - "Matcher": { - "HttpCode": "200,302" - }, - "Name": "EC2TargetGroup", - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "deregistration_delay.timeout_seconds", - "Value": "20" - } - ], - "Targets": [ - { - "Id": { - "Ref": "RTPriInstance" - } - }, - { - "Id": { - "Ref": "RTSecInstance" - }, - "Port": 80 - } - ], - "UnhealthyThresholdCount": 3, - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": "EC2TargetGroup" - }, - { - "Key": "Port", - "Value": 80 - } - ] - } - }, - "ALBListener": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "Type": "forward", - "TargetGroupArn": { - "Ref": "EC2TargetGroup" - } - } - ], - "LoadBalancerArn": { - "Ref": "ApplicationLoadBalancer" - }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "ApplicationLoadBalancer": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "Scheme": "internet-facing", - "Subnets": [ - { - "Ref": "PublicSubnet1" - }, - { - "Ref": "PublicSubnet2" - } - ], - "SecurityGroups": [ - { - "Ref": "ELBSecurityGroup" - } - ] - } - } - }, - - "Outputs": { - "VPC": { - "Description": "Virtual Private Cloud", - "Value": { - "Ref": "VPC" - } - }, - "ALBHostName": { - "Description": "Application Load Balancer Hostname", - "Value": { - "Fn::GetAtt": [ - "ApplicationLoadBalancer", - "DNSName" - ] - } - }, - "BastionInstancePublic": { - "Description": "Bastion", - "Value": { "Fn::GetAtt" : [ "BastionInstance", "PublicIp" ]} - }, - "BastionInstancePrivate": { - "Description": "Bastion", - "Value": { "Fn::GetAtt" : [ "BastionInstance", "PrivateIp" ]} - }, - "RTPriInstancePrivate": { - "Description": "RTPriInstance", - "Value": { "Fn::GetAtt" : [ "RTPriInstance", "PrivateIp" ]} - }, - "RTSecInstancePrivate": { - "Description": "RTSecInstance", - "Value": { "Fn::GetAtt" : [ "RTSecInstance", "PrivateIp" ]} - }, - "XrayInstancePrivate": { - "Description": "XrayInstance", - "Value": { "Fn::GetAtt" : [ "XrayInstance", "PrivateIp" ]} - }, - "DBInstancePrivate": { - "Description": "DBInstance", - "Value": { "Fn::GetAtt" : [ "DBInstance", "PrivateIp" ]} - } - } -} \ No newline at end of file diff --git a/Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json b/Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json deleted file mode 100644 index 867e1df..0000000 --- a/Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json +++ /dev/null @@ -1,769 +0,0 @@ -{ - "Description": "This template deploys a VPC, with a pair of public and private subnets spread across two Availability Zones. It deploys an internet gateway, with a default route on the public subnets. It deploys a pair of NAT gateways (one in each AZ), and default routes for them in the private subnets.", - "Parameters": { - "SSHKeyName": { - "Description": "Name of the ec2 key you need one to use this template", - "Type": "AWS::EC2::KeyPair::KeyName", - "Default": "choose-key" - }, - "EnvironmentName": { - "Description": "An environment name that is prefixed to resource names", - "Type": "String", - "Default": "Ansible" - }, - "VpcCIDR": { - "Description": "Please enter the IP range (CIDR notation) for this VPC", - "Type": "String", - "Default": "10.192.0.0/16" - }, - "PublicSubnet1CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone", - "Type": "String", - "Default": "10.192.10.0/24" - }, - "PublicSubnet2CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone", - "Type": "String", - "Default": "10.192.11.0/24" - }, - "PrivateSubnet1CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone", - "Type": "String", - "Default": "10.192.20.0/24" - }, - "PrivateSubnet2CIDR": { - "Description": "Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone", - "Type": "String", - "Default": "10.192.21.0/24" - } - }, - "Mappings": { - "RegionToAmazonAMI": { - "us-east-1": { - "HVM64": "ami-03e33c1cefd1d3d74" - }, - "us-east-2": { - "HVM64": "ami-07d9419c80dc1113c" - }, - "us-west-1": { - "HVM64": "ami-0ee1a20d6b0c6a347" - }, - "us-west-2": { - "HVM64": "ami-0813245c0939ab3ca" - } - } - }, - "Resources": { - "VPC": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": { - "Ref": "VpcCIDR" - }, - "EnableDnsSupport": true, - "EnableDnsHostnames": true, - "Tags": [ - { - "Key": "Name", - "Value": { - "Ref": "EnvironmentName" - } - } - ] - } - }, - "InternetGateway": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": { - "Ref": "EnvironmentName" - } - } - ] - } - }, - "InternetGatewayAttachment": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "InternetGatewayId": { - "Ref": "InternetGateway" - }, - "VpcId": { - "Ref": "VPC" - } - } - }, - "PublicSubnet1": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 0, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PublicSubnet1CIDR" - }, - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Public Subnet (AZ1)" - } - } - ] - } - }, - "PublicSubnet2": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 1, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PublicSubnet2CIDR" - }, - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Public Subnet (AZ2)" - } - } - ] - } - }, - "PrivateSubnet1": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 0, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PrivateSubnet1CIDR" - }, - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Subnet (AZ1)" - } - } - ] - } - }, - "PrivateSubnet2": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "AvailabilityZone": { - "Fn::Select": [ - 1, - { - "Fn::GetAZs": "" - } - ] - }, - "CidrBlock": { - "Ref": "PrivateSubnet2CIDR" - }, - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Subnet (AZ2)" - } - } - ] - } - }, - "NatGateway1EIP": { - "Type": "AWS::EC2::EIP", - "DependsOn": "InternetGatewayAttachment", - "Properties": { - "Domain": "vpc" - } - }, - "NatGateway2EIP": { - "Type": "AWS::EC2::EIP", - "DependsOn": "InternetGatewayAttachment", - "Properties": { - "Domain": "vpc" - } - }, - "NatGateway1": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "NatGateway1EIP", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "PublicSubnet1" - } - } - }, - "NatGateway2": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "NatGateway2EIP", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "PublicSubnet2" - } - } - }, - "PublicRouteTable": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Public Routes" - } - } - ] - } - }, - "DefaultPublicRoute": { - "Type": "AWS::EC2::Route", - "DependsOn": "InternetGatewayAttachment", - "Properties": { - "RouteTableId": { - "Ref": "PublicRouteTable" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "InternetGateway" - } - } - }, - "PublicSubnet1RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PublicRouteTable" - }, - "SubnetId": { - "Ref": "PublicSubnet1" - } - } - }, - "PublicSubnet2RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PublicRouteTable" - }, - "SubnetId": { - "Ref": "PublicSubnet2" - } - } - }, - "PrivateRouteTable1": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Routes (AZ1)" - } - } - ] - } - }, - "DefaultPrivateRoute1": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable1" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "NatGateway1" - } - } - }, - "PrivateSubnet1RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable1" - }, - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - }, - "PrivateRouteTable2": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": { - "Fn::Sub": "${EnvironmentName} Private Routes (AZ2)" - } - } - ] - } - }, - "DefaultPrivateRoute2": { - "Type": "AWS::EC2::Route", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable2" - }, - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "NatGateway2" - } - } - }, - "PrivateSubnet2RouteTableAssociation": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "PrivateRouteTable2" - }, - "SubnetId": { - "Ref": "PrivateSubnet2" - } - } - }, - "EC2SecurityGroup": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "SSH, Port 80, Database", - "VpcId": { - "Ref": "VPC" - }, - "SecurityGroupIngress": [ - { - "IpProtocol": "tcp", - "FromPort": 22, - "ToPort": 22, - "CidrIp": "0.0.0.0/0" - }, - { - "IpProtocol": "tcp", - "FromPort": 5432, - "ToPort": 5432, - "CidrIp": "0.0.0.0/0" - }, - { - "IpProtocol": "tcp", - "FromPort": 8082, - "ToPort": 8082, - "CidrIp": "0.0.0.0/0" - }, - { - "IpProtocol": "tcp", - "FromPort": 80, - "ToPort": 80, - "SourceSecurityGroupId": { - "Ref": "ELBSecurityGroup" - } - } - ] - } - }, - "ELBSecurityGroup": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "SSH and Port 80", - "VpcId": { - "Ref": "VPC" - }, - "SecurityGroupIngress": [ - { - "IpProtocol": "tcp", - "FromPort": 80, - "ToPort": 80, - "CidrIp": "0.0.0.0/0" - } - ] - } - }, - "BastionInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "true", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PublicSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "bastion" - } - ], - "Tenancy": "default" - } - }, - "RTPriInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "rtprimary" - } - ], - "Tenancy": "default" - } - }, - "RTSecInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet2" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "rtsecondary" - } - ], - "Tenancy": "default" - } - }, - "XrayInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "xray" - } - ], - "Tenancy": "default" - } - }, - "DBInstance": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": { - "Fn::FindInMap": [ - "RegionToAmazonAMI", - { - "Ref": "AWS::Region" - }, - "HVM64" - ] - }, - "InstanceInitiatedShutdownBehavior": "stop", - "InstanceType": "t2.medium", - "KeyName": { - "Ref": "SSHKeyName" - }, - "Monitoring": "true", - "NetworkInterfaces": [ - { - "AssociatePublicIpAddress": "false", - "DeviceIndex": "0", - "GroupSet": [ - { - "Ref": "EC2SecurityGroup" - } - ], - "SubnetId": { - "Ref": "PrivateSubnet1" - } - } - ], - "Tags": [ - { - "Key": "Name", - "Value": "database" - } - ], - "Tenancy": "default" - } - }, - "EC2TargetGroup": { - "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", - "Properties": { - "HealthCheckIntervalSeconds": 30, - "HealthCheckProtocol": "HTTP", - "HealthCheckTimeoutSeconds": 15, - "HealthyThresholdCount": 2, - "Matcher": { - "HttpCode": "200,302" - }, - "Name": "EC2TargetGroup", - "Port": 80, - "Protocol": "HTTP", - "TargetGroupAttributes": [ - { - "Key": "deregistration_delay.timeout_seconds", - "Value": "20" - } - ], - "Targets": [ - { - "Id": { - "Ref": "RTPriInstance" - } - }, - { - "Id": { - "Ref": "RTSecInstance" - }, - "Port": 80 - } - ], - "UnhealthyThresholdCount": 3, - "VpcId": { - "Ref": "VPC" - }, - "Tags": [ - { - "Key": "Name", - "Value": "EC2TargetGroup" - }, - { - "Key": "Port", - "Value": 80 - } - ] - } - }, - "ALBListener": { - "Type": "AWS::ElasticLoadBalancingV2::Listener", - "Properties": { - "DefaultActions": [ - { - "Type": "forward", - "TargetGroupArn": { - "Ref": "EC2TargetGroup" - } - } - ], - "LoadBalancerArn": { - "Ref": "ApplicationLoadBalancer" - }, - "Port": 80, - "Protocol": "HTTP" - } - }, - "ApplicationLoadBalancer": { - "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", - "Properties": { - "Scheme": "internet-facing", - "Subnets": [ - { - "Ref": "PublicSubnet1" - }, - { - "Ref": "PublicSubnet2" - } - ], - "SecurityGroups": [ - { - "Ref": "ELBSecurityGroup" - } - ] - } - } - }, - - "Outputs": { - "VPC": { - "Description": "Virtual Private Cloud", - "Value": { - "Ref": "VPC" - } - }, - "ALBHostName": { - "Description": "Application Load Balancer Hostname", - "Value": { - "Fn::GetAtt": [ - "ApplicationLoadBalancer", - "DNSName" - ] - } - }, - "BastionInstancePublic": { - "Description": "Bastion", - "Value": { "Fn::GetAtt" : [ "BastionInstance", "PublicIp" ]} - }, - "BastionInstancePrivate": { - "Description": "Bastion", - "Value": { "Fn::GetAtt" : [ "BastionInstance", "PrivateIp" ]} - }, - "RTPriInstancePrivate": { - "Description": "RTPriInstance", - "Value": { "Fn::GetAtt" : [ "RTPriInstance", "PrivateIp" ]} - }, - "RTSecInstancePrivate": { - "Description": "RTSecInstance", - "Value": { "Fn::GetAtt" : [ "RTSecInstance", "PrivateIp" ]} - }, - "XrayInstancePrivate": { - "Description": "XrayInstance", - "Value": { "Fn::GetAtt" : [ "XrayInstance", "PrivateIp" ]} - }, - "DBInstancePrivate": { - "Description": "DBInstance", - "Value": { "Fn::GetAtt" : [ "DBInstance", "PrivateIp" ]} - } - } -} \ No newline at end of file diff --git a/Ansible/infra/azure/lb-rt-xray-ha.json b/Ansible/infra/azure/lb-rt-xray-ha.json deleted file mode 100644 index 1211d17..0000000 --- a/Ansible/infra/azure/lb-rt-xray-ha.json +++ /dev/null @@ -1,679 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "vnetName": { - "type": "string", - "defaultValue": "vnet01", - "metadata": { - "description": "Name of new vnet to deploy into." - } - }, - "vnetAddressRange": { - "type": "string", - "defaultValue": "10.0.0.0/16", - "metadata": { - "description": "IP prefix for available addresses in vnet address space." - } - }, - "subnetAddressRange": { - "type": "string", - "defaultValue": "10.0.0.0/24", - "metadata": { - "description": "Subnet IP prefix MUST be within vnet IP prefix address space." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for all resources." - } - }, - "adminPublicKey": { - "type": "string", - "metadata": { - "description": "The ssh public key for the VMs." - } - }, - "sizeOfDiskInGB": { - "type": "int", - "defaultValue": 128, - "minValue": 128, - "maxValue": 1024, - "metadata": { - "description": "Size of data disk in GB 128-1024" - } - }, - "vmSize": { - "type": "string", - "defaultValue": "Standard_D2s_v3", - "metadata": { - "description": "Size of the VMs" - } - }, - "numberOfArtifactory": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 5, - "metadata": { - "description": "Number of Artifactory servers." - } - }, - "numberOfXray": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 5, - "metadata": { - "description": "Number of Xray servers." - } - }, - "numberOfDb": { - "type": "int", - "defaultValue": 1, - "minValue": 1, - "maxValue": 2, - "metadata": { - "description": "Number of database servers." - } - } - }, - "variables": { - "vnetName": "[parameters('vnetName')]", - "vnetAddressRange": "[parameters('vnetAddressRange')]", - "subnetAddressRange": "[parameters('subnetAddressRange')]", - "subnetName": "mainSubnet", - "loadBalancerName": "LB", - "loadBalancerIp": "lbIp", - "numberOfArtifactory": "[parameters('numberOfArtifactory')]", - "numberOfXray": "[parameters('numberOfXray')]", - "numberOfDb": "[parameters('numberOfDb')]", - "availabilitySetName": "availSet", - "vmArtPri": "vmArtPri", - "vmArtSec": "vmArtSec", - "vmXray": "vmXray", - "vmDb": "vmDb", - "storageAccountNameDiag": "[concat('diag',uniqueString(resourceGroup().id))]", - "subnet-id": "[resourceId('Microsoft.Network/virtualNetworks/subnets',variables('vnetName'),variables('subnetName'))]", - "imagePublisher": "Canonical", - "imageOffer": "UbuntuServer", - "imageSku": "16.04-LTS", - "mainNsg": "mainNsg", - "adminUsername": "ubuntu" - }, - "resources": [ - { - "apiVersion": "2019-08-01", - "type": "Microsoft.Network/publicIPAddresses", - "name": "[variables('loadBalancerIp')]", - "location": "[parameters('location')]", - "properties": { - "publicIPAllocationMethod": "Static" - } - }, - { - "type": "Microsoft.Compute/availabilitySets", - "name": "[variables('availabilitySetName')]", - "apiVersion": "2019-12-01", - "location": "[parameters('location')]", - "sku": { - "name": "Aligned" - }, - "properties": { - "platformFaultDomainCount": 2, - "platformUpdateDomainCount": 2 - } - }, - { - "apiVersion": "2019-06-01", - "type": "Microsoft.Storage/storageAccounts", - "name": "[variables('storageAccountNameDiag')]", - "location": "[parameters('location')]", - "kind": "StorageV2", - "sku": { - "name": "Standard_LRS" - } - }, - { - "comments": "Simple Network Security Group for subnet [Subnet]", - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2019-08-01", - "name": "[variables('mainNsg')]", - "location": "[parameters('location')]", - "properties": { - "securityRules": [ - { - "name": "allow-ssh", - "properties": { - "description": "Allow SSH", - "protocol": "TCP", - "sourcePortRange": "*", - "destinationPortRange": "22", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 100, - "direction": "Inbound", - "sourcePortRanges": [], - "destinationPortRanges": [], - "sourceAddressPrefixes": [], - "destinationAddressPrefixes": [] - } - }, - { - "name": "allow-http", - "properties": { - "description": "Allow HTTP", - "protocol": "TCP", - "sourcePortRange": "*", - "destinationPortRange": "80", - "sourceAddressPrefix": "*", - "destinationAddressPrefix": "*", - "access": "Allow", - "priority": 110, - "direction": "Inbound", - "sourcePortRanges": [], - "destinationPortRanges": [], - "sourceAddressPrefixes": [], - "destinationAddressPrefixes": [] - } - } - ] - } - }, - { - "apiVersion": "2019-08-01", - "type": "Microsoft.Network/virtualNetworks", - "name": "[variables('vnetName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mainNsg'))]" - ], - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('vnetAddressRange')]" - ] - }, - "subnets": [ - { - "name": "[variables('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressRange')]", - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mainNsg'))]" - } - } - } - ] - } - }, - { - "apiVersion": "2018-10-01", - "name": "[variables('loadBalancerName')]", - "type": "Microsoft.Network/loadBalancers", - "location": "[parameters('location')]", - "dependsOn": [ - "[concat('Microsoft.Network/publicIPAddresses/',variables('loadBalancerIp'))]" - ], - "properties": { - "frontendIpConfigurations": [ - { - "name": "LBFE", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('loadBalancerIp'))]" - } - } - } - ], - "backendAddressPools": [ - { - "name": "LBArt" - } - ], - "inboundNatRules": [ - { - "name": "ssh", - "properties": { - "frontendIPConfiguration": { - "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations',variables('loadBalancerName'),'LBFE')]" - }, - "frontendPort": 22, - "backendPort": 22, - "enableFloatingIP": false, - "idleTimeoutInMinutes": 4, - "protocol": "Tcp", - "enableTcpReset": false - } - } - ], - "loadBalancingRules": [ - { - "properties": { - "frontendIPConfiguration": { - "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', variables('loadBalancerName'), 'LBFE')]" - }, - "backendAddressPool": { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('loadBalancerName'), 'LBArt')]" - }, - "probe": { - "id": "[resourceId('Microsoft.Network/loadBalancers/probes', variables('loadBalancerName'), 'lbprobe')]" - }, - "protocol": "Tcp", - "frontendPort": 80, - "backendPort": 80, - "idleTimeoutInMinutes": 15 - }, - "name": "lbrule" - } - ], - "probes": [ - { - "properties": { - "protocol": "Tcp", - "port": 80, - "intervalInSeconds": 15, - "numberOfProbes": 2 - }, - "name": "lbprobe" - } - ] - } - }, - { - "apiVersion": "2019-08-01", - "type": "Microsoft.Network/networkInterfaces", - "name": "[variables('vmArtPri')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('vnetName')]", - "[variables('loadBalancerName')]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnet-id')]" - }, - "loadBalancerBackendAddressPools": [ - { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('loadBalancerName'),'LBArt')]" - } - ], - "loadBalancerInboundNatRules": [ - { - "id": "[resourceId('Microsoft.Network/loadBalancers/inboundNatRules', variables('loadBalancerName'), 'ssh')]" - } - ] - } - } - ] - } - }, - { - "apiVersion": "2019-08-01", - "type": "Microsoft.Network/networkInterfaces", - "name": "[concat(variables('vmArtSec'),copyindex())]", - "copy": { - "name": "netIntLoop", - "count": "[sub(variables('numberOfArtifactory'),1)]" - }, - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('vnetName')]", - "[variables('loadBalancerName')]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnet-id')]" - }, - "loadBalancerBackendAddressPools": [ - { - "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('loadBalancerName'),'LBArt')]" - } - ] - } - } - ] - } - }, - { - "apiVersion": "2019-08-01", - "type": "Microsoft.Network/networkInterfaces", - "name": "[concat(variables('vmXray'),copyindex())]", - "copy": { - "name": "netXrLoop", - "count": "[variables('numberOfXray')]" - }, - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('vnetName')]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnet-id')]" - } - } - } - ] - } - }, - { - "apiVersion": "2019-08-01", - "type": "Microsoft.Network/networkInterfaces", - "name": "[concat(variables('vmDb'),copyindex())]", - "copy": { - "name": "netDbLoop", - "count": "[variables('numberOfDb')]" - }, - "location": "[parameters('location')]", - "dependsOn": [ - "[variables('vnetName')]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[variables('subnet-id')]" - } - } - } - ] - } - }, - { - "apiVersion": "2019-12-01", - "type": "Microsoft.Compute/virtualMachines", - "name": "[variables('vmArtPri')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]", - "[resourceId('Microsoft.Network/networkInterfaces', variables('vmArtPri'))]", - "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - ], - "properties": { - "availabilitySet": { - "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[variables('vmArtPri')]", - "adminUsername": "[variables('adminUsername')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]", - "keyData": "[parameters('adminPublicKey')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[variables('imageSku')]", - "version": "latest" - }, - "osDisk": { - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('vmArtPri'))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": true, - "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]" - } - } - } - }, - { - "apiVersion": "2019-12-01", - "type": "Microsoft.Compute/virtualMachines", - "name": "[concat(variables('vmArtSec'), copyindex())]", - "copy": { - "name": "virtualMachineLoop", - "count": "[sub(variables('numberOfArtifactory'),1)]" - }, - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]", - "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmArtSec'),copyindex()))]", - "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - ], - "properties": { - "availabilitySet": { - "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[concat(variables('vmArtSec'), copyindex())]", - "adminUsername": "[variables('adminUsername')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]", - "keyData": "[parameters('adminPublicKey')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[variables('imageSku')]", - "version": "latest" - }, - "osDisk": { - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('vmArtSec'),copyindex()))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": true, - "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]" - } - } - } - }, - { - "apiVersion": "2019-12-01", - "type": "Microsoft.Compute/virtualMachines", - "name": "[concat(variables('vmXray'), copyindex())]", - "copy": { - "name": "virtualMachineLoop", - "count": "[variables('numberOfXray')]" - }, - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]", - "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmXray'),copyindex()))]", - "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - ], - "properties": { - "availabilitySet": { - "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[concat(variables('vmXray'), copyindex())]", - "adminUsername": "[variables('adminUsername')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]", - "keyData": "[parameters('adminPublicKey')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[variables('imageSku')]", - "version": "latest" - }, - "osDisk": { - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('vmXray'),copyindex()))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": true, - "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]" - } - } - } - }, - { - "apiVersion": "2019-12-01", - "type": "Microsoft.Compute/virtualMachines", - "name": "[concat(variables('vmDb'), copyindex())]", - "copy": { - "name": "virtualMachineLoop", - "count": "[variables('numberOfDb')]" - }, - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]", - "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmDb'),copyindex()))]", - "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - ], - "properties": { - "availabilitySet": { - "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]" - }, - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[concat(variables('vmDb'), copyindex())]", - "adminUsername": "[variables('adminUsername')]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]", - "keyData": "[parameters('adminPublicKey')]" - } - ] - } - } - }, - "storageProfile": { - "imageReference": { - "publisher": "[variables('imagePublisher')]", - "offer": "[variables('imageOffer')]", - "sku": "[variables('imageSku')]", - "version": "latest" - }, - "osDisk": { - "createOption": "FromImage" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('vmDb'),copyindex()))]" - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": true, - "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]" - } - } - } - } - ], - "outputs": { - "lbIp": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('loadBalancerIp'))).ipAddress]" - }, - "vmArtPriIp": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/networkInterfaces', variables('vmArtPri'))).ipConfigurations[0].properties.privateIPAddress]" - }, - "vmArtSecArrIp": { - "type": "array", - "copy": { - "count": "[sub(variables('numberOfArtifactory'),1)]", - "input": "[reference(resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmArtSec'),copyindex()))).ipConfigurations[0].properties.privateIPAddress]" - } - }, - "vmXrayArrIp": { - "type": "array", - "copy": { - "count": "[variables('numberOfXray')]", - "input": "[reference(resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmXray'),copyindex()))).ipConfigurations[0].properties.privateIPAddress]" - } - }, - "vmDbArrIp": { - "type": "array", - "copy": { - "count": "[variables('numberOfDb')]", - "input": "[reference(resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmDb'),copyindex()))).ipConfigurations[0].properties.privateIPAddress]" - } - } - } -} \ No newline at end of file diff --git a/Ansible/pipelines.yaml b/Ansible/pipelines.yaml deleted file mode 100644 index 83fb517..0000000 --- a/Ansible/pipelines.yaml +++ /dev/null @@ -1,58 +0,0 @@ -resources: - - name: ansibleRepo - type: GitRepo - configuration: - gitProvider: jefferyfryGithub - path: jefferyfry/JFrog-Cloud-Installers -pipelines: - - name: ansible_automation_pipeline - steps: - - name: execute_aws_ansible_playbook - type: Bash - configuration: - runtime: - type: image - image: - auto: - language: java - versions: - - "8" - integrations: - - name: ansibleAwsKeys - - name: ansibleEnvVars - - name: ansiblePrivateKey - inputResources: - - name: ansibleRepo - execution: - onStart: - - echo "Executing AWS Ansible playbook..." - onExecute: - - sudo apt-get update - - sudo apt-get install gnupg2 - - sudo apt-get install software-properties-common - - sudo apt-add-repository --yes --update ppa:ansible/ansible - - sudo apt -y --allow-unauthenticated install ansible - - sudo pip install packaging - - sudo pip install boto3 botocore - - cd dependencyState/resources/ansibleRepo - - echo 'Setting environment variables...' - - export artifactory_version="$int_ansibleEnvVars_artifactory_version" - - export xray_version="$int_ansibleEnvVars_xray_version" - - export artifactory_license1="$int_ansibleEnvVars_artifactory_license1" - - export artifactory_license2="$int_ansibleEnvVars_artifactory_license2" - - export artifactory_license3="$int_ansibleEnvVars_artifactory_license3" - - export master_key="$int_ansibleEnvVars_master_key" - - export join_key="$int_ansibleEnvVars_join_key" - - export ssh_public_key_name="$int_ansibleEnvVars_ssh_public_key_name" - - export cfn_template="$int_ansibleEnvVars_cfn_template" - - export stack_name="$int_ansibleEnvVars_stack_name" - - export AWS_ACCESS_KEY_ID="$int_ansibleEnvVars_AWS_ACCESS_KEY_ID" - - export AWS_SECRET_KEY="$int_ansibleEnvVars_AWS_SECRET_KEY" - - printenv - - pwd - - ls - - eval $(ssh-agent -s) - - ssh-add <(echo "$int_ansiblePrivateKey_key") - - ansible-playbook Ansible/test/aws/playbook-ha-install.yaml - onComplete: - - echo "AWS Ansible playbook complete." \ No newline at end of file diff --git a/Ansible/test/aws/playbook-ha-install.yaml b/Ansible/test/aws/playbook-ha-install.yaml deleted file mode 100644 index 0587e30..0000000 --- a/Ansible/test/aws/playbook-ha-install.yaml +++ /dev/null @@ -1,151 +0,0 @@ ---- -- name: Provision AWS test infrastructure - hosts: localhost - tasks: - - shell: 'pwd' - register: cmd - - - debug: - msg: "{{ cmd.stdout }}" - - name: Create AWS test system - cloudformation: - stack_name: "{{ lookup('env', 'stack_name') }}" - state: "present" - region: "us-east-1" - disable_rollback: true - template: "{{ lookup('env', 'cfn_template') }}" - template_parameters: - SSHKeyName: "{{ lookup('env', 'ssh_public_key_name') }}" - tags: - Stack: "{{ lookup('env', 'stack_name') }}" - register: AWSDeployment - - name: Get AWS deployment details - debug: - var: AWSDeployment - - - name: Add bastion - add_host: - hostname: "{{ AWSDeployment.stack_outputs.BastionInstancePublic }}" - groups: bastion - ansible_user: "ubuntu" - - name: Add new RT primary to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.RTPriInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - artifactory_version: "{{ lookup('env', 'artifactory_version') }}" - db_url: "jdbc:postgresql://{{ AWSDeployment.stack_outputs.DBInstancePrivate }}:5432/artifactory" - server_name: "{{ AWSDeployment.stack_outputs.ALBHostName }}" - artifactory_is_primary: true - artifactory_license1: "{{ lookup('env', 'artifactory_license1') }}" - artifactory_license2: "{{ lookup('env', 'artifactory_license2') }}" - artifactory_license3: "{{ lookup('env', 'artifactory_license3') }}" - groups: - - artifactory - - - name: Add RT secondaries to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.RTSecInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - artifactory_version: "{{ lookup('env', 'artifactory_version') }}" - db_url: "jdbc:postgresql://{{ AWSDeployment.stack_outputs.DBInstancePrivate }}:5432/artifactory" - server_name: "{{ AWSDeployment.stack_outputs.ALBHostName }}" - artifactory_is_primary: false - groups: - - artifactory - - - name: Add xrays to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.XrayInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - xray_version: "{{ lookup('env', 'xray_version') }}" - jfrog_url: "http://{{ AWSDeployment.stack_outputs.ALBHostName }}" - master_key: "{{ lookup('env', 'master_key') }}" - join_key: "{{ lookup('env', 'join_key') }}" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_user: "xray" - db_password: "xray" - db_url: "postgres://{{ AWSDeployment.stack_outputs.DBInstancePrivate }}:5432/xraydb?sslmode=disable" - groups: xray - - - name: Add DBs to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.DBInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - db_users: - - { db_user: "artifactory", db_password: "Art1fAct0ry" } - - { db_user: "xray", db_password: "xray" } - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - - { db_name: "xraydb", db_owner: "xray" } - groups: database - - - name: Set up test environment file - copy: - src: ../tests/src/test/resources/testenv_tpl.yaml - dest: ../tests/src/test/resources/testenv.yaml - - - name: Set up test environment url - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'urlval' - replace: "http://{{ AWSDeployment.stack_outputs.ALBHostName }}" - - - name: Set up test environment external_ip - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'ipval' - replace: "{{ AWSDeployment.stack_outputs.ALBHostName }}" - - - name: Set up test environment rt_password - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'passval' - replace: "password" - - - name: show testenv.yaml - debug: var=item - with_file: - - ../tests/src/test/resources/testenv.yaml - - - name: Wait 300 seconds for port 22 - wait_for: - port: 22 - host: "{{ AWSDeployment.stack_outputs.BastionInstancePublic }}" - delay: 10 - - - debug: - msg: "Unified URL is at http://{{ AWSDeployment.stack_outputs.ALBHostName }}" - -- hosts: database - roles: - - postgres - -- hosts: artifactory - vars: - artifactory_ha_enabled: true - master_key: "{{ lookup('env', 'master_key') }}" - join_key: "{{ lookup('env', 'join_key') }}" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_user: "artifactory" - db_password: "Art1fAct0ry" - roles: - - artifactory - -- hosts: xray - roles: - - xray - -- name: Test - hosts: localhost - tasks: - - name: Run tests - shell: - cmd: ./gradlew clean unified_test - chdir: ../tests/ \ No newline at end of file diff --git a/Ansible/test/aws/playbook-ha-upgrade.yaml b/Ansible/test/aws/playbook-ha-upgrade.yaml deleted file mode 100644 index fa97c16..0000000 --- a/Ansible/test/aws/playbook-ha-upgrade.yaml +++ /dev/null @@ -1,172 +0,0 @@ ---- -- name: Provision AWS test infrastructure - hosts: localhost - tasks: - - shell: 'pwd' - register: cmd - - - debug: - msg: "{{ cmd.stdout }}" - - name: Create AWS test system - cloudformation: - stack_name: "{{ lookup('env', 'stack_name') }}" - state: "present" - region: "us-east-1" - disable_rollback: true - template: "{{ lookup('env', 'cfn_template') }}" - template_parameters: - SSHKeyName: "{{ lookup('env', 'ssh_public_key_name') }}" - tags: - Stack: "{{ lookup('env', 'stack_name') }}" - register: AWSDeployment - - name: Get AWS deployment details - debug: - var: AWSDeployment - - - name: Add bastion - add_host: - hostname: "{{ AWSDeployment.stack_outputs.BastionInstancePublic }}" - groups: bastion - ansible_user: "ubuntu" - - name: Add new RT primary to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.RTPriInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - artifactory_version: "{{ lookup('env', 'artifactory_version') }}" - db_url: "jdbc:postgresql://{{ AWSDeployment.stack_outputs.DBInstancePrivate }}:5432/artifactory" - server_name: "{{ AWSDeployment.stack_outputs.ALBHostName }}" - artifactory_is_primary: true - artifactory_license_file: "{{ lookup('env', 'artifactory_license_file') }}" - groups: - - artifactory - - - name: Add RT secondaries to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.RTSecInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - artifactory_version: "{{ lookup('env', 'artifactory_version') }}" - db_url: "jdbc:postgresql://{{ AWSDeployment.stack_outputs.DBInstancePrivate }}:5432/artifactory" - server_name: "{{ AWSDeployment.stack_outputs.ALBHostName }}" - artifactory_is_primary: false - groups: - - artifactory - - - name: Add xrays to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.XrayInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - xray_version: "{{ lookup('env', 'xray_version') }}" - jfrog_url: "http://{{ AWSDeployment.stack_outputs.ALBHostName }}" - master_key: "{{ lookup('env', 'master_key') }}" - join_key: "{{ lookup('env', 'join_key') }}" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_user: "xray" - db_password: "xray" - db_url: "postgres://{{ AWSDeployment.stack_outputs.DBInstancePrivate }}:5432/xraydb?sslmode=disable" - groups: xray - - - name: Add DBs to host group - add_host: - hostname: "{{ AWSDeployment.stack_outputs.DBInstancePrivate }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ AWSDeployment.stack_outputs.BastionInstancePublic }} -W %h:%p"' - db_users: - - { db_user: "artifactory", db_password: "Art1fAct0ry" } - - { db_user: "xray", db_password: "xray" } - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - - { db_name: "xraydb", db_owner: "xray" } - groups: database - - - name: Set up test environment file - copy: - src: ../tests/src/test/resources/testenv_tpl.yaml - dest: ../tests/src/test/resources/testenv.yaml - - - name: Set up test environment url - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'urlval' - replace: "http://{{ AWSDeployment.stack_outputs.ALBHostName }}" - - - name: Set up test environment external_ip - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'ipval' - replace: "{{ AWSDeployment.stack_outputs.ALBHostName }}" - - - name: Set up test environment rt_password - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'passval' - replace: "password" - - - name: show testenv.yaml - debug: var=item - with_file: - - ../tests/src/test/resources/testenv.yaml - - - name: Wait 300 seconds for port 22 - wait_for: - port: 22 - host: "{{ AWSDeployment.stack_outputs.BastionInstancePublic }}" - delay: 10 - - - debug: - msg: "Unified URL is at http://{{ AWSDeployment.stack_outputs.ALBHostName }}" - -# apply roles to install software -- hosts: database - roles: - - postgres - -- hosts: artifactory - vars: - artifactory_ha_enabled: true - master_key: "{{ lookup('env', 'master_key') }}" - join_key: "{{ lookup('env', 'join_key') }}" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_user: "artifactory" - db_password: "Art1fAct0ry" - roles: - - artifactory - -- hosts: xray - roles: - - xray - -- name: Test - hosts: localhost - tasks: - - name: Run tests - shell: - cmd: ./gradlew clean unified_test - chdir: ../tests/ - -# Now upgrade -- name: Upgrade - hosts: localhost - tasks: - - pause: - prompt: "Proceed to upgrade?" - minutes: 5 - -- hosts: artifactory - vars: - artifactory_version: "{{ lookup('env', 'artifactory_version_upgrade') }}" - artifactory_upgrade_only: true - roles: - - artifactory - -- hosts: xray - vars: - xray_version: "{{ lookup('env', 'xray_version_upgrade') }}" - xray_upgrade_only: true - roles: - - xray \ No newline at end of file diff --git a/Ansible/test/aws/runAwsInstall.sh b/Ansible/test/aws/runAwsInstall.sh deleted file mode 100755 index 6b1a735..0000000 --- a/Ansible/test/aws/runAwsInstall.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -export stack_name=$1 -export cfn_template="~/git/JFrog-Cloud-Installers/Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json" -export ssh_public_key_name=jeff-ansible -export artifactory_license_file="~/Desktop/artifactory.cluster.license" -export master_key=d8c19a03036f83ea45f2c658e22fdd60 -export join_key=d8c19a03036f83ea45f2c658e22fdd61 -export ansible_user=ubuntu -export artifactory_version="7.4.3" -export xray_version="3.4.0" -ansible-playbook Ansible/test/aws/playbook-ha-install.yaml \ No newline at end of file diff --git a/Ansible/test/aws/runAwsUpgrade.sh b/Ansible/test/aws/runAwsUpgrade.sh deleted file mode 100755 index 191fe97..0000000 --- a/Ansible/test/aws/runAwsUpgrade.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -export stack_name=$1 -export cfn_template="~/git/JFrog-Cloud-Installers/Ansible/infra/aws/lb-rt-xray-ha-ubuntu16.json" -export ssh_public_key_name=jeff-ansible -export artifactory_license_file="~/Desktop/artifactory.cluster.license" -export master_key=d8c19a03036f83ea45f2c658e22fdd60 -export join_key=d8c19a03036f83ea45f2c658e22fdd61 -export ansible_user=ubuntu -export artifactory_version="7.4.3" -export xray_version="3.4.0" -export artifactory_version_upgrade="7.6.1" -export xray_version_upgrade="3.5.2" -ansible-playbook Ansible/test/aws/playbook-ha-upgrade.yaml \ No newline at end of file diff --git a/Ansible/test/azure/playbook-ha-install.yaml b/Ansible/test/azure/playbook-ha-install.yaml deleted file mode 100644 index 6304319..0000000 --- a/Ansible/test/azure/playbook-ha-install.yaml +++ /dev/null @@ -1,165 +0,0 @@ ---- -- name: Provision Azure test infrastructure - hosts: localhost - tasks: - - name: Create azure test system - azure_rm_deployment: - resource_group: "{{ lookup('env', 'azure_resource_group') }}" - location: eastus - name: AzureAnsibleInfra - parameters: - vnetName: - value: "vnetAnsible" - vnetAddressRange: - value: "10.0.0.0/16" - subnetAddressRange: - value: "10.0.0.0/24" - location: - value: "eastus" - adminPublicKey: - value: "{{ lookup('env', 'ssh_public_key') }}" - sizeOfDiskInGB: - value: 128 - vmSize: - value: Standard_D2s_v3 - numberOfArtifactory: - value: 2 - numberOfXray: - value: 1 - numberOfDb: - value: 1 - template_link: "{{ lookup('env', 'arm_template') }}" - register: azureDeployment - - name: Get Azure deployment details - debug: - var: azureDeployment - - - name: Add bastion - add_host: - hostname: "{{ azureDeployment.deployment.outputs.lbIp.value }}" - groups: bastion - ansible_user: "ubuntu" - - name: Add new RT primary to host group - add_host: - hostname: "{{ azureDeployment.deployment.outputs.vmArtPriIp.value }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ azureDeployment.deployment.outputs.lbIp.value }} -W %h:%p"' - artifactory_version: "{{ lookup('env', 'artifactory_version') }}" - db_url: "jdbc:postgresql://{{ azureDeployment.deployment.outputs.vmDbArrIp.value[0] }}:5432/artifactory" - server_name: "rt.{{ azureDeployment.deployment.outputs.lbIp.value }}.xip.io" - artifactory_is_primary: true - artifactory_license1: "{{ lookup('env', 'artifactory_license1') }}" - artifactory_license2: "{{ lookup('env', 'artifactory_license2') }}" - artifactory_license3: "{{ lookup('env', 'artifactory_license3') }}" - groups: - - artifactory - - - name: Add RT secondaries to host group - add_host: - hostname: "{{ item }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ azureDeployment.deployment.outputs.lbIp.value }} -W %h:%p"' - artifactory_version: "{{ lookup('env', 'artifactory_version') }}" - db_url: "jdbc:postgresql://{{ azureDeployment.deployment.outputs.vmDbArrIp.value[0] }}:5432/artifactory" - server_name: "rt.{{ azureDeployment.deployment.outputs.lbIp.value }}.xip.io" - artifactory_is_primary: false - groups: - - artifactory - loop: "{{ azureDeployment.deployment.outputs.vmArtSecArrIp.value }}" - - - name: Add xrays to host group - add_host: - hostname: "{{ item }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ azureDeployment.deployment.outputs.lbIp.value }} -W %h:%p"' - xray_version: "{{ lookup('env', 'xray_version') }}" - jfrog_url: "http://rt.{{ azureDeployment.deployment.outputs.lbIp.value }}.xip.io" - master_key: "{{ lookup('env', 'master_key') }}" - join_key: "{{ lookup('env', 'join_key') }}" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_user: "xray" - db_password: "xray" - db_url: "postgres://{{ azureDeployment.deployment.outputs.vmDbArrIp.value[0] }}:5432/xraydb?sslmode=disable" - groups: xray - loop: "{{ azureDeployment.deployment.outputs.vmXrayArrIp.value }}" - - - name: Add DBs to host group - add_host: - hostname: "{{ item }}" - ansible_user: "ubuntu" - ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -A ubuntu@{{ azureDeployment.deployment.outputs.lbIp.value }} -W %h:%p"' - db_users: - - { db_user: "artifactory", db_password: "Art1fAct0ry" } - - { db_user: "xray", db_password: "xray" } - dbs: - - { db_name: "artifactory", db_owner: "artifactory" } - - { db_name: "xraydb", db_owner: "xray" } - groups: database - loop: "{{ azureDeployment.deployment.outputs.vmDbArrIp.value }}" - - - name: Set up test environment url - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'urlval' - replace: "http://rt.{{ azureDeployment.deployment.outputs.lbIp.value }}.xip.io" - - - name: Set up test environment external_ip - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'ipval' - replace: "{{ azureDeployment.deployment.outputs.lbIp.value }}" - - - name: Set up test environment rt_password - replace: - path: ../tests/src/test/resources/testenv.yaml - regexp: 'passval' - replace: "password" - - - name: show testenv.yaml - debug: var=item - with_file: - - ../tests/src/test/resources/testenv.yaml - - - name: Wait 300 seconds for port 22 - wait_for: - port: 22 - host: "{{ azureDeployment.deployment.outputs.lbIp.value }}" - delay: 10 - - - debug: - msg: "Unified URL is at http://rt.{{ azureDeployment.deployment.outputs.lbIp.value }}.xip.io" - -- hosts: database - roles: - - postgres - -- hosts: artifactory - vars: - artifactory_ha_enabled: true - master_key: "{{ lookup('env', 'master_key') }}" - join_key: "{{ lookup('env', 'join_key') }}" - db_download_url: "https://jdbc.postgresql.org/download/postgresql-42.2.12.jar" - db_type: "postgresql" - db_driver: "org.postgresql.Driver" - db_user: "artifactory" - db_password: "Art1fAct0ry" - roles: - - artifactory - -- hosts: xray - roles: - - xray - -- name: Test - hosts: localhost - tasks: - - name: Run tests - shell: - cmd: ./gradlew clean unified_test - chdir: ../tests/ - - name: Cleanup and delete resource group - azure_rm_resourcegroup: - name: "{{ lookup('env', 'azure_resource_group') }}" - force_delete_nonempty: yes - state: absent \ No newline at end of file diff --git a/Ansible/test/azure/runAzure.sh b/Ansible/test/azure/runAzure.sh deleted file mode 100755 index c9d7e80..0000000 --- a/Ansible/test/azure/runAzure.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -ansible-playbook Ansible/test/azure/playbook.yaml \ No newline at end of file diff --git a/Ansible/test/tests/.gradle/6.5/executionHistory/executionHistory.bin b/Ansible/test/tests/.gradle/6.5/executionHistory/executionHistory.bin deleted file mode 100644 index e2cad615aa20e05d9d93ed30e5eaeff02eecb843..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138306 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 Ps{f#weCUT*_51$^&=W*b diff --git a/Ansible/test/tests/.gradle/6.5/executionHistory/executionHistory.lock b/Ansible/test/tests/.gradle/6.5/executionHistory/executionHistory.lock deleted file mode 100644 index d7a4c5fd1e63ec02267c9d58b15b59a9c9bac3f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZRM7fj##ct)i-0|YDr04>D?MF0Q* diff --git a/Ansible/test/tests/.gradle/6.5/fileChanges/last-build.bin b/Ansible/test/tests/.gradle/6.5/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/Ansible/test/tests/.gradle/6.5/fileContent/fileContent.lock b/Ansible/test/tests/.gradle/6.5/fileContent/fileContent.lock deleted file mode 100644 index 1f397f728b670d0eebb7c6d0848c904a8437b09e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 ScmZRUmCa*Z#uGA`0SW*bmjXrr diff --git a/Ansible/test/tests/.gradle/6.5/fileHashes/fileHashes.bin b/Ansible/test/tests/.gradle/6.5/fileHashes/fileHashes.bin deleted file mode 100644 index 4782416b9284b5378b3efee4203b97ffa38586a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23647 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 U5-H%Q`4a=&w=2*pfJQg|2loCE82|tP diff --git a/Ansible/test/tests/.gradle/6.5/fileHashes/fileHashes.lock b/Ansible/test/tests/.gradle/6.5/fileHashes/fileHashes.lock deleted file mode 100644 index 88d74f8a5f662cf7d32cabf6de40aef0c028fca1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZSH8q%`ie|zM81~6cK2LL{@1@Zs@ diff --git a/Ansible/test/tests/.gradle/6.5/gc.properties b/Ansible/test/tests/.gradle/6.5/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/Ansible/test/tests/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Ansible/test/tests/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index cad006e55b2e84f4a8120ac1e8e4e23de64b82a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQ}3cSGg=7je*1_;;=05vQHApigX diff --git a/Ansible/test/tests/.gradle/buildOutputCleanup/cache.properties b/Ansible/test/tests/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index 9d7456f..0000000 --- a/Ansible/test/tests/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Thu Jun 18 12:50:09 PDT 2020 -gradle.version=6.5 diff --git a/Ansible/test/tests/.gradle/buildOutputCleanup/outputFiles.bin b/Ansible/test/tests/.gradle/buildOutputCleanup/outputFiles.bin deleted file mode 100644 index b2b9c929842a18bdc3ff1fb387330dea3fd5a9ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18947 zcmeI%Pe_w-7{KwjS(t959>RI3q-ep^5Y0oO#loOfniwl@m9UnHQdsR!gb@Y9gic8~ z3MwI~z;;Ro89_lrHKpB(;h%+8AkrTSt@W<=d63w}LtW(i!u#&WchCD9zt45GhT+Ul z$z{x6E9aN25I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0-Au?YCggXCI=ahBTBi@cy= zlsn8t(Uo_(8{gO~tF5oShxPx1es}bB-?7M3tMBw{ABa_Nt1bOlE3ac{^PcSUuQnc{EYUw zPd{Bv&ctz=<~^WygGSa-Y3-`AcuH~W6A-4~Jhg!a{;##f2r zc;A)9VOB`w4eGh?uk|P$?tk!YS&N0u(eq4@I(Ls z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL o_*Vjz=0-W@y(E37A1nSUW>^H}|D9_gJ7>;hmQ3e`%=~%lH>Yq}Qvd(} diff --git a/Ansible/test/tests/.gradle/checksums/checksums.lock b/Ansible/test/tests/.gradle/checksums/checksums.lock deleted file mode 100644 index 19bc2572d5ec51849eda6f2e4f923dbf29606ee8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZSn8NA}$-}^5T7@z7)art9Bu0Pcm@7C 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 z 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/Ansible/test/tests/gradlew.bat b/Ansible/test/tests/gradlew.bat deleted file mode 100644 index 6d57edc..0000000 --- a/Ansible/test/tests/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/Ansible/test/tests/settings.gradle b/Ansible/test/tests/settings.gradle deleted file mode 100644 index d30fe0d..0000000 --- a/Ansible/test/tests/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'fozzie_jfrog_tests' - diff --git a/Ansible/test/tests/src/test/groovy/steps/RepositorySteps.groovy b/Ansible/test/tests/src/test/groovy/steps/RepositorySteps.groovy deleted file mode 100644 index 3ae8b07..0000000 --- a/Ansible/test/tests/src/test/groovy/steps/RepositorySteps.groovy +++ /dev/null @@ -1,139 +0,0 @@ -package steps - - -import static io.restassured.RestAssured.given - -class RepositorySteps { - - def getHealthCheckResponse(artifactoryURL) { - return given() - .when() - .get("http://" + artifactoryURL + "/router/api/v1/system/health") - .then() - .extract().response() - } - - def ping() { - return given() - .when() - .get("/api/system/ping") - .then() - .extract().response() - } - - def createRepositories(File body, username, password) { - return given() - .auth() - .preemptive() - .basic("${username}", "${password}") - .header("Cache-Control", "no-cache") - .header("content-Type", "application/yaml") - .body(body) - .when() - .patch("/api/system/configuration") - .then() - .extract().response() - } - // https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-GetRepositories - def getRepos() { - return given() - .header("Cache-Control", "no-cache") - .header("content-Type", "application/yaml") - .when() - .get("/api/repositories") - .then() - .extract().response() - - } - // https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-DeleteRepository - def deleteRepository(repoName, username, password) { - return given() - .auth() - .preemptive() - .basic("${username}", "${password}") - .header("Cache-Control", "no-cache") - .header("content-Type", "application/yaml") - .when() - .delete("/api/repositories/" + repoName) - .then() - .extract().response() - - } - - def createDirectory(repoName, directoryName) { - return given() - .header("Cache-Control", "no-cache") - .header("content-Type", "application/yaml") - .when() - .put("/" + repoName + "/" + directoryName) - .then() - .extract().response() - - } - - def deployArtifact(repoName, directoryName, artifact, filename) { - return given() - .header("Cache-Control", "no-cache") - .header("Content-Type", "application/json") - .body(artifact) - .when() - .put("/" + repoName + "/" + directoryName + "/" + filename) - .then() - .extract().response() - - } - - def deleteItem(repoName, directoryName, artifact, filename) { - return given() - .header("Cache-Control", "no-cache") - .header("Content-Type", "application/json") - .body(artifact) - .when() - .delete("/" + repoName + "/" + directoryName + "/" + filename) - .then() - .extract().response() - - } - - def getInfo(repoName, directoryName, artifact, filename) { - return given() - .header("Cache-Control", "no-cache") - .header("Content-Type", "application/json") - .body(artifact) - .when() - .get("/api/storage/" + repoName + "/" + directoryName + "/" + filename) - .then() - .extract().response() - - } - - def createSupportBundle(name, startDate, endDate) { - return given() - .header("Cache-Control", "no-cache") - .header("Content-Type", "application/json") - .body("{ \n" + - " \"name\":\"${name}\",\n" + - " \"description\":\"desc\",\n" + - " \"parameters\":{ \n" + - " \"configuration\": \"true\",\n" + - " \"system\": \"true\", \n" + - " \"logs\":{ \n" + - " \"include\": \"true\", \n" + - " \"start_date\":\"${startDate}\",\n" + - " \"end_date\":\"${endDate}\"\n" + - " },\n" + - " \"thread_dump\":{ \n" + - " \"count\": 1,\n" + - " \"interval\": 0\n" + - " }\n" + - " }\n" + - "}") - .when() - .post("/api/system/support/bundle") - .then() - .extract().response() - - } - - -} \ No newline at end of file diff --git a/Ansible/test/tests/src/test/groovy/testng.xml b/Ansible/test/tests/src/test/groovy/testng.xml deleted file mode 100644 index cee4eb7..0000000 --- a/Ansible/test/tests/src/test/groovy/testng.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Ansible/test/tests/src/test/groovy/tests/HealthCheckTest.groovy b/Ansible/test/tests/src/test/groovy/tests/HealthCheckTest.groovy deleted file mode 100644 index 4e7fcce..0000000 --- a/Ansible/test/tests/src/test/groovy/tests/HealthCheckTest.groovy +++ /dev/null @@ -1,57 +0,0 @@ -package tests - -import io.restassured.RestAssured -import io.restassured.path.json.JsonPath -import io.restassured.response.Response -import org.hamcrest.Matchers -import org.testng.Reporter -import org.testng.annotations.BeforeSuite -import org.testng.annotations.Test -import steps.RepositorySteps -import org.yaml.snakeyaml.Yaml -import utils.Shell - -class HealthCheckTest extends RepositorySteps{ - Yaml yaml = new Yaml() - def configFile = new File("./src/test/resources/testenv.yaml") - def config = yaml.load(configFile.text) - def artifactoryURL - - - @BeforeSuite(alwaysRun = true) - def setUp() { - artifactoryURL = config.artifactory.external_ip - RestAssured.baseURI = "http://${artifactoryURL}/artifactory" - } - - - @Test(priority=0, groups="common", testName = "Health check for all 4 services") - void healthCheckTest(){ - Response response = getHealthCheckResponse(artifactoryURL) - response.then().assertThat().statusCode(200). - body("router.state", Matchers.equalTo("HEALTHY")) - - int bodySize = response.body().jsonPath().getList("services").size() - for (int i = 0; i < bodySize; i++) { - JsonPath jsonPathEvaluator = response.jsonPath() - String serviceID = jsonPathEvaluator.getString("services[" + i + "].service_id") - String nodeID = jsonPathEvaluator.getString("services[" + i + "].node_id") - response.then(). - body("services[" + i + "].state", Matchers.equalTo("HEALTHY")) - - Reporter.log("- Health check. Service \"" + serviceID + "\" on node \"" + nodeID + "\" is healthy", true) - } - - } - - @Test(priority=1, groups=["ping","common"], testName = "Ping (In HA 200 only when licences were added)") - void pingTest() { - Response response = ping() - response.then().assertThat().statusCode(200). - body(Matchers.hasToString("OK")) - Reporter.log("- Ping test. Service is OK", true) - } - - - -} diff --git a/Ansible/test/tests/src/test/groovy/utils/ConfigurationUtil.groovy b/Ansible/test/tests/src/test/groovy/utils/ConfigurationUtil.groovy deleted file mode 100644 index 208bf29..0000000 --- a/Ansible/test/tests/src/test/groovy/utils/ConfigurationUtil.groovy +++ /dev/null @@ -1,19 +0,0 @@ -package utils - -class ConfigurationUtil { - - static def getEnvironmentVariableValue(def name) { - def value = System.getProperty(name) - if (value == null) { - value = System.getenv(name) - if (value == null) { - throw new Exception("Environment variable $name not set!"); - } - } - return value - } - - - - -} diff --git a/Ansible/test/tests/src/test/groovy/utils/DSL.groovy b/Ansible/test/tests/src/test/groovy/utils/DSL.groovy deleted file mode 100644 index 6a14f48..0000000 --- a/Ansible/test/tests/src/test/groovy/utils/DSL.groovy +++ /dev/null @@ -1,81 +0,0 @@ -package utils - -import utils.ProcessOutputStream - -/** - * Created by eliom on 6/19/18. - */ -class DSL { - - /** - * Run shell command - */ - static def sh = { command, outputBuffer = null, folder = null, silent = false, customEnvVariables = null, errorBuffer = null -> - //def workdir = ConfigurationUtil.getEnvironmentVariableValue("KERMIT_WORKSPACE_DIR") - def workdir = "/Users/danielmi/projects/soldev/.kermit-workspace" - def commandFolder - if (folder != null) { - commandFolder = new File(folder, workdir) - } else { - commandFolder = workdir - } - - if (!silent) { - println "Running command at ${commandFolder}: $command" - } - def proc = null - try { - def env = System.getenv().collect { k, v -> "$k=$v" } - - if (customEnvVariables != null) { - env.addAll( customEnvVariables.collect { k, v -> "$k=$v" }) - } - - if (command instanceof List && command.size() > 0 && command[0] instanceof List) { - //Pipe Commands - command.each { - if (proc != null) { - proc = proc | it.execute(env, commandFolder) - } else { - proc = it.execute(env, commandFolder) - } - } - } else { - proc = command.execute(env, commandFolder) - } - } catch (IOException e) { - println "Failed to execute command: ${e.getMessage()}" - return -1 - } - def processOutput = new ProcessOutputStream(silent, outputBuffer == null) - def errorOutput = processOutput - if (errorBuffer != null) { - errorOutput = new ProcessOutputStream(silent, errorBuffer == null) - } - - proc.consumeProcessOutput(processOutput, errorOutput) - def exitStatus = proc.waitFor() - if (!silent) { - println "Exit: $exitStatus" - } - if (outputBuffer != null) { - outputBuffer.append(processOutput.toString()) - } - - processOutput.close() - - if (errorBuffer != null) { - errorBuffer.append(errorOutput.toString()) - errorOutput.close() - } - - return exitStatus - } - - - //... - - - - -} diff --git a/Ansible/test/tests/src/test/groovy/utils/EnvironmentConfig.groovy b/Ansible/test/tests/src/test/groovy/utils/EnvironmentConfig.groovy deleted file mode 100644 index db7d017..0000000 --- a/Ansible/test/tests/src/test/groovy/utils/EnvironmentConfig.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package utils - - - -class EnvironmentConfig { - - - - -} diff --git a/Ansible/test/tests/src/test/groovy/utils/ProcessOutputStream.groovy b/Ansible/test/tests/src/test/groovy/utils/ProcessOutputStream.groovy deleted file mode 100644 index aff11c2..0000000 --- a/Ansible/test/tests/src/test/groovy/utils/ProcessOutputStream.groovy +++ /dev/null @@ -1,32 +0,0 @@ -package utils - -public class ProcessOutputStream extends ByteArrayOutputStream{ - - private boolean silent = false; - private boolean discardOutput = false; - - public ProcessOutputStream(boolean silent, boolean discardOutput) { - this.silent = silent; - this.discardOutput = discardOutput; - } - - @Override - public synchronized void write(int b) { - if (!silent) { - System.out.write(b); - } - if (!discardOutput) { - super.write(b); - } - } - - @Override - public synchronized void write(byte[] b, int off, int len) { - if (!silent) { - System.out.write(b, off, len); - } - if (!discardOutput) { - super.write(b, off, len); - } - } -} \ No newline at end of file diff --git a/Ansible/test/tests/src/test/groovy/utils/Shell.groovy b/Ansible/test/tests/src/test/groovy/utils/Shell.groovy deleted file mode 100644 index 87d4aaf..0000000 --- a/Ansible/test/tests/src/test/groovy/utils/Shell.groovy +++ /dev/null @@ -1,17 +0,0 @@ -package utils - -class Shell { - - def executeProc(cmd) { - println(cmd) - def proc = cmd.execute() - - proc.in.eachLine {line -> - println line - } - - println proc.err.text - - proc.exitValue() - } -} diff --git a/Ansible/test/tests/src/test/groovy/utils/WorkSpaceManager.groovy b/Ansible/test/tests/src/test/groovy/utils/WorkSpaceManager.groovy deleted file mode 100644 index f1262bb..0000000 --- a/Ansible/test/tests/src/test/groovy/utils/WorkSpaceManager.groovy +++ /dev/null @@ -1,32 +0,0 @@ -package utils - -/** - * Created by eliom on 6/26/18. - */ -class WorkspaceManager { - - //TODO: Make it Thread safe - def static currentPath = [] - - def static pushPath(path) { - currentPath.push(path) - } - - def static popPath() { - currentPath.pop() - } - - def static getCurrentDir() { - def workspaceRoot = ConfigurationUtil.getWorkspaceDir() - if (currentPath.size() > 0) { - def currentDir = new File(currentPath.join('/'), workspaceRoot) - if (!currentDir.exists()) { - currentDir.mkdirs() - } - return currentDir - } else { - return workspaceRoot - } - } - -} diff --git a/Ansible/test/tests/src/test/resources/enableRabbitMQ.json b/Ansible/test/tests/src/test/resources/enableRabbitMQ.json deleted file mode 100644 index c6e54d4..0000000 --- a/Ansible/test/tests/src/test/resources/enableRabbitMQ.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "sslInsecure": false, - "maxDiskDataUsage": 80, - "monitorSamplingInterval": 300, - "mailNoSsl": false, - "messageMaxTTL": 7, - "jobInterval": 86400, - "allowSendingAnalytics": true, - "httpsPort": 443, - "enableTlsConnectionToRabbitMQ": true -} \ No newline at end of file diff --git a/Ansible/test/tests/src/test/resources/integration.json b/Ansible/test/tests/src/test/resources/integration.json deleted file mode 100644 index 08ba303..0000000 --- a/Ansible/test/tests/src/test/resources/integration.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "vendor": "whitesource5", - "api_key": "12345", - "enabled": true, - "context": "project_id", - "url": "https://saas.whitesourcesoftware.com/xray", - "description": "WhiteSource provides a simple yet powerful open source security and licenses management solution. More details at http://www.whitesourcesoftware.com.", - "test_url": "https://saas.whitesourcesoftware.com/xray/api/checkauth" -} \ No newline at end of file diff --git a/Ansible/test/tests/src/test/resources/repositories/CreateDefault.yaml b/Ansible/test/tests/src/test/resources/repositories/CreateDefault.yaml deleted file mode 100644 index ef1f5fd..0000000 --- a/Ansible/test/tests/src/test/resources/repositories/CreateDefault.yaml +++ /dev/null @@ -1,554 +0,0 @@ -localRepositories: - libs-release-local: - type: maven - description: "production deployment" - repoLayout: maven-2-default - xray: - enabled: true - libs-snapshot-local: - type: maven - description: "snapshot deployment" - repoLayout: maven-2-default - xray: - enabled: true - maven-prod-local: - type: maven - description: "production release deployment" - repoLayout: maven-2-default - xray: - enabled: true - maven-dev-local: - type: maven - description: "development release deployment" - repoLayout: maven-2-default - xray: - enabled: true - maven-release-local: - type: maven - description: "development release deployment" - repoLayout: maven-2-default - xray: - enabled: true - maven-snapshot-local: - type: maven - description: "development release deployment" - repoLayout: maven-2-default - xray: - enabled: true - gradle-prod-local: - type: gradle - description: "production deployment" - repoLayout: gradle-default - xray: - enabled: true - gradle-dev-local: - type: gradle - description: "development deployment" - repoLayout: gradle-default - xray: - enabled: true - tomcat-local: - type: generic - description: "used by demo" - repoLayout: simple-default - xray: - enabled: true - generic-prod-local: - type: generic - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - generic-dev-local: - type: generic - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - ivy-prod-local: - type: ivy - description: "production deployment" - repoLayout: "ivy-default" - xray: - enabled: true - ivy-dev-local: - type: ivy - description: "development deployment" - repoLayout: ivy-default - xray: - enabled: true - helm-prod-local: - type: helm - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - helm-dev-local: - type: helm - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - sbt-prod-local: - type: sbt - description: "production deployment" - repoLayout: sbt-default - xray: - enabled: true - sbt-dev-local: - type: sbt - description: "development deployment" - repoLayout: sbt-default - xray: - enabled: true - nuget-prod-local: - type: nuget - description: "production deployment" - repoLayout: nuget-default - xray: - enabled: true - nuget-dev-local: - type: nuget - description: "development deployment" - repoLayout: nuget-default - xray: - enabled: true - gems-prod-local: - type: gems - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - gems-dev-local: - type: gems - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - npm-prod-local: - type: npm - description: "production deployment" - repoLayout: npm-default - xray: - enabled: true - npm-dev-local: - type: npm - description: "development deployment" - repoLayout: npm-default - xray: - enabled: true - bower-prod-local: - type: bower - description: "production deployment" - repoLayout: bower-default - xray: - enabled: true - bower-dev-local: - type: bower - description: "development deployment" - repoLayout: bower-default - xray: - enabled: true - debian-prod-local: - type: debian - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - debian-dev-local: - type: debian - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - php-prod-local: - type: composer - description: "production deployment" - repoLayout: composer-default - xray: - enabled: true - php-dev-local: - type: composer - description: "development deployment" - repoLayout: composer-default - xray: - enabled: true - pypi-prod-local: - type: pypi - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - pypi-dev-local: - type: pypi - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - docker-prod-local: - type: docker - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - docker-stage-local: - type: docker - description: "stage deployment" - repoLayout: simple-default - xray: - enabled: true - docker-dev-local: - type: docker - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - docker-local: - type: docker - description: "docker deployment" - repoLayout: simple-default - xray: - enabled: true - docker-push: - type: docker - description: "docker push repo for push replication testing" - repoLayout: simple-default - xray: - enabled: true - vagrant-prod-local: - type: vagrant - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - vagrant-dev-local: - type: vagrant - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - gitlfs-prod-local: - type: gitlfs - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - gitlfs-dev-local: - type: gitlfs - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - rpm-prod-local: - type: yum - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - rpm-dev-local: - type: yum - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - conan-prod-local: - type: conan - description: "production deployment" - repoLayout: conan-default - xray: - enabled: true - conan-dev-local: - type: conan - description: "development deployment" - repoLayout: conan-default - xray: - enabled: true - chef-prod-local: - type: chef - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - chef-dev-local: - type: chef - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - puppet-prod-local: - type: puppet - description: "production deployment" - repoLayout: puppet-default - xray: - enabled: true - puppet-dev-local: - type: puppet - description: "development deployment" - repoLayout: puppet-default - xray: - enabled: true - go-prod-local: - type: go - description: "production deployment" - repoLayout: go-default - xray: - enabled: true - go-staging-local: - type: go - description: "production deployment" - repoLayout: go-default - xray: - enabled: true -remoteRepositories: - docker-remote: - type: docker - url: https://registry-1.docker.io - repoLayout: simple-default - enableTokenAuthentication: true - xray: - enabled: true - helm-remote: - type: helm - url: https://storage.googleapis.com/kubernetes-charts - repoLayout: simple-default - xray: - enabled: true - jcenter: - type: maven - url: https://jcenter.bintray.com - repoLayout: maven-2-default - xray: - enabled: true - npm-remote: - type: npm - url: https://registry.npmjs.org - repoLayout: npm-default - xray: - enabled: true - nuget-remote: - type: nuget - url: https://www.nuget.org/ - repoLayout: nuget-default - xray: - enabled: true - bower-remote: - type: bower - url: https://github.com/ - repoLayout: bower-default - xray: - enabled: true - gems-remote: - type: gems - url: https://rubygems.org/ - repoLayout: simple-default - xray: - enabled: true - debian-remote: - type: debian - url: http://archive.ubuntu.com/ubuntu/ - repoLayout: simple-default - xray: - enabled: true - php-remote: - type: composer - url: https://github.com/ - repoLayout: composer-default - xray: - enabled: true - pypi-remote: - type: pypi - url: https://files.pythonhosted.org - repoLayout: simple-default - xray: - enabled: true - rpm-remote: - type: yum - url: http://mirror.centos.org/centos/ - repoLayout: simple-default - xray: - enabled: true - chef-remote: - type: chef - url: https://supermarket.chef.io - repoLayout: simple-default - xray: - enabled: true - puppet-remote: - type: puppet - url: https://forgeapi.puppetlabs.com/ - repoLayout: puppet-default - xray: - enabled: true -virtualRepositories: - maven-release-virtual: - type: maven - repositories: - - maven-prod-local - - jcenter - - maven-release-local - - libs-release-local - description: "maven release virtual repositories" - defaultDeploymentRepo: maven-release-local - maven-snapshot-virtual: - type: maven - repositories: - - maven-snapshot-local - - jcenter - - maven-dev-local - - libs-snapshot-local - description: "maven snapshot virtual repositories" - defaultDeploymentRepo: maven-snapshot-local - gradle-virtual: - type: gradle - repositories: - - gradle-dev-local - - jcenter - - gradle-prod-local - - libs-release-local - description: "gradle virtual repositories" - defaultDeploymentRepo: gradle-dev-local - docker-PLACEHOLDERFORBUILDSTEP: - type: docker - repositories: - - docker-local - - docker-remote - - docker-dev-local - - docker-prod-local - - docker-stage-local - - docker-push - description: "docker virtual" - defaultDeploymentRepo: docker-stage-local - docker-virtual: - type: docker - repositories: - - docker-local - - docker-remote - - docker-dev-local - - docker-prod-local - - docker-stage-local - - docker-push - description: "docker virtual" - defaultDeploymentRepo: docker-stage-local - libs-release: - type: maven - repositories: - - libs-release-local - - jcenter - description: "maven libraries virtual" - defaultDeploymentRepo: libs-release-local - libs-snapshot: - type: maven - repositories: - - libs-snapshot-local - - jcenter - description: "maven libraries virtual" - defaultDeploymentRepo: libs-snapshot-local - ivy-virtual: - type: ivy - repositories: - - ivy-prod-local - - ivy-dev-local - - jcenter - description: "ivy virtual" - defaultDeploymentRepo: ivy-dev-local - generic-virtual: - type: generic - repositories: - - generic-prod-local - - generic-dev-local - description: "generic virtual" - defaultDeploymentRepo: generic-dev-local - helm-virtual: - type: helm - repositories: - - helm-prod-local - - helm-dev-local - - helm-remote - description: "helm virtual" - defaultDeploymentRepo: helm-dev-local - nuget-virtual: - type: nuget - repositories: - - nuget-prod-local - - nuget-dev-local - - nuget-remote - description: "nuget virtual" - defaultDeploymentRepo: nuget-dev-local - npm-virtual: - type: npm - repositories: - - npm-dev-local - - npm-remote - - npm-prod-local - description: "npm virtual" - defaultDeploymentRepo: npm-dev-local - chef-virtual: - type: chef - repositories: - - chef-dev-local - - chef-remote - - chef-prod-local - description: "chef virtual" - defaultDeploymentRepo: chef-dev-local - puppet-virtual: - type: puppet - repositories: - - puppet-dev-local - - puppet-remote - - puppet-prod-local - description: "puppet virtual" - defaultDeploymentRepo: puppet-dev-local - rpm-virtual: - type: yum - repositories: - - rpm-dev-local - - rpm-remote - - rpm-prod-local - description: "rpm virtual" - defaultDeploymentRepo: rpm-dev-local - gitlfs-virtual: - type: gitlfs - repositories: - - gitlfs-dev-local - - gitlfs-prod-local - description: "gitlfs virtual" - defaultDeploymentRepo: gitlfs-dev-local - pypi-virtual: - type: pypi - repositories: - - pypi-dev-local - - pypi-prod-local - - pypi-remote - description: "pypi virtual" - defaultDeploymentRepo: pypi-dev-local - bower-virtual: - type: bower - repositories: - - bower-dev-local - - bower-prod-local - - bower-remote - description: "bower virtual" - defaultDeploymentRepo: bower-dev-local - gems-virtual: - type: gems - repositories: - - gems-dev-local - - gems-prod-local - - gems-remote - description: "gems virtual" - defaultDeploymentRepo: gems-dev-local - sbt-virtual: - type: sbt - repositories: - - sbt-dev-local - - sbt-prod-local - - jcenter - description: "sbt virtual" - defaultDeploymentRepo: sbt-dev-local - go-staging: - type: go - repositories: - - go-staging-local - - go-prod-local - description: "go virtual" - defaultDeploymentRepo: go-staging-local diff --git a/Ansible/test/tests/src/test/resources/repositories/CreateJCR.yaml b/Ansible/test/tests/src/test/resources/repositories/CreateJCR.yaml deleted file mode 100644 index 38a5feb..0000000 --- a/Ansible/test/tests/src/test/resources/repositories/CreateJCR.yaml +++ /dev/null @@ -1,119 +0,0 @@ -localRepositories: - tomcat-local: - type: generic - description: "used by demo" - repoLayout: simple-default - xray: - enabled: true - generic-prod-local: - type: generic - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - generic-dev-local: - type: generic - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - helm-prod-local: - type: helm - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - helm-dev-local: - type: helm - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - docker-generator: - type: docker - description: "docker generator repo for generation testing" - repoLayout: simple-default - xray: - enabled: true - docker-prod-local: - type: docker - description: "production deployment" - repoLayout: simple-default - xray: - enabled: true - docker-stage-local: - type: docker - description: "stage deployment" - repoLayout: simple-default - xray: - enabled: true - docker-dev-local: - type: docker - description: "development deployment" - repoLayout: simple-default - xray: - enabled: true - docker-local: - type: docker - description: "docker deployment" - repoLayout: simple-default - xray: - enabled: true - docker-push: - type: docker - description: "docker push repo for push replication testing" - repoLayout: simple-default - xray: - enabled: true -virtualRepositories: - generic-virtual: - type: generic - repositories: - - generic-prod-local - - generic-dev-local - description: "generic virtual" - defaultDeploymentRepo: generic-dev-local - helm-virtual: - type: helm - repositories: - - helm-prod-local - - helm-dev-local - - helm-remote - description: "helm virtual" - defaultDeploymentRepo: helm-dev-local - docker-PLACEHOLDERFORBUILDSTEP: - type: docker - repositories: - - docker-local - - docker-remote - - docker-dev-local - - docker-prod-local - - docker-stage-local - - docker-push - description: "docker virtual" - defaultDeploymentRepo: docker-stage-local - docker-virtual: - type: docker - repositories: - - docker-local - - docker-remote - - docker-dev-local - - docker-prod-local - - docker-stage-local - - docker-push - description: "docker virtual" - defaultDeploymentRepo: docker-stage-local -remoteRepositories: - helm-remote: - type: helm - url: https://storage.googleapis.com/kubernetes-charts - repoLayout: simple-default - xray: - enabled: true - docker-remote: - type: docker - url: https://registry-1.docker.io - repoLayout: simple-default - enableTokenAuthentication: true - xray: - enabled: true \ No newline at end of file diff --git a/Ansible/test/tests/src/test/resources/repositories/artifact.zip b/Ansible/test/tests/src/test/resources/repositories/artifact.zip deleted file mode 100644 index 0e86cb54fe2c3d52b3946278043f30b86a274eaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 519 zcmWIWW@Zs#-~d9!MSTGbP@o8;IT;ifN>YnU^ePi`b3#LS8Q9m?Op62Itw3B_!Og(P z@|BT+0jQmU!COb`q>s0c-bwvcTOI`kc&yd%)IH^Wrt`ech9DqQ?;#UIfHymbnd!_w z%0T5H^8>Kjya6a90<<|k-q+FDKR7~PFCM!ic40aqIYBfzJs~OKgRf862mY{*fCi=s z63prX(u{?&0?j|9B|4b;6crr<)I5$eDTp})ALiYS5 zdg^$F@^P?f#zYwF^0|D^y|;#A5hKX;*BWA4Vu0=gxiP?-kx7IZ5pu{r1BDz6ENKL> puzLYZIHDViY$YgIU|>mO6_80zAO(1{vVlxt0>Yg@+JX_p0|0lTf`|YB diff --git a/Ansible/test/tests/src/test/resources/testenv.yaml b/Ansible/test/tests/src/test/resources/testenv.yaml deleted file mode 100644 index 3480812..0000000 --- a/Ansible/test/tests/src/test/resources/testenv.yaml +++ /dev/null @@ -1,6 +0,0 @@ -artifactory: - url: http://Ansib-Appli-1NLZU3V2AGK49-291976964.us-east-1.elb.amazonaws.com - external_ip: Ansib-Appli-1NLZU3V2AGK49-291976964.us-east-1.elb.amazonaws.com - distribution: artifactory_ha - rt_username: admin - rt_password: password \ No newline at end of file diff --git a/Ansible/test/tests/src/test/resources/testenv_tpl.yaml b/Ansible/test/tests/src/test/resources/testenv_tpl.yaml deleted file mode 100644 index 55ff648..0000000 --- a/Ansible/test/tests/src/test/resources/testenv_tpl.yaml +++ /dev/null @@ -1,6 +0,0 @@ -artifactory: - url: urlval - external_ip: ipval - distribution: artifactory_ha - rt_username: admin - rt_password: passval \ No newline at end of file diff --git a/ansible.cfg b/ansible.cfg deleted file mode 100644 index 3d08974..0000000 --- a/ansible.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[defaults] -# Installs collections into [current dir]/ansible_collections/namespace/collection_name -collections_paths = ~/.ansible/collections:/usr/share/ansible/collections:collection - -# Installs roles into [current dir]/roles/namespace.rolename -roles_path = Ansible/ansible_collections/jfrog/installers/roles - -host_key_checking = false - -deprecation_warnings=False \ No newline at end of file