diff --git a/.ansible/collections/ansible_collections/itential/deployer/.ansible/.lock b/.ansible/collections/ansible_collections/itential/deployer/.ansible/.lock new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/.trunk/.gitignore b/.ansible/collections/ansible_collections/itential/deployer/.trunk/.gitignore new file mode 100644 index 00000000..15966d08 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/.trunk/.gitignore @@ -0,0 +1,9 @@ +*out +*logs +*actions +*notifications +*tools +plugins +user_trunk.yaml +user.yaml +tmp diff --git a/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.isort.cfg b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.isort.cfg new file mode 100644 index 00000000..b9fb3f3e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile=black diff --git a/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.markdownlint.yaml b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.markdownlint.yaml new file mode 100644 index 00000000..b40ee9d7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.markdownlint.yaml @@ -0,0 +1,2 @@ +# Prettier friendly markdownlint config (all formatting rules disabled) +extends: markdownlint/style/prettier diff --git a/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.shellcheckrc b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.shellcheckrc new file mode 100644 index 00000000..8c7b1ada --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/.shellcheckrc @@ -0,0 +1,7 @@ +enable=all +source-path=SCRIPTDIR +disable=SC2154 + +# If you're having issues with shellcheck following source, disable the errors via: +# disable=SC1090 +# disable=SC1091 diff --git a/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/ruff.toml b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/ruff.toml new file mode 100644 index 00000000..f5a235cf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/.trunk/configs/ruff.toml @@ -0,0 +1,5 @@ +# Generic, formatter-friendly config. +select = ["B", "D3", "E", "F"] + +# Never enforce `E501` (line length violations). This should be handled by formatters. +ignore = ["E501"] diff --git a/.ansible/collections/ansible_collections/itential/deployer/.trunk/trunk.yaml b/.ansible/collections/ansible_collections/itential/deployer/.trunk/trunk.yaml new file mode 100644 index 00000000..f69cd4ae --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/.trunk/trunk.yaml @@ -0,0 +1,40 @@ +# This file controls the behavior of Trunk: https://docs.trunk.io/cli +# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml +version: 0.1 +cli: + version: 1.25.0 +# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) +plugins: + sources: + - id: trunk + ref: v1.7.4 + uri: https://github.com/trunk-io/plugins +# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) +runtimes: + enabled: + - go@1.21.0 + - node@22.16.0 + - python@3.10.8 +# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) +lint: + enabled: + - actionlint@1.7.10 + - bandit@1.9.3 + - black@26.1.0 + - checkov@3.2.499 + - git-diff-check + - isort@7.0.0 + - markdownlint@0.47.0 + - prettier@3.8.1 + - ruff@0.14.14 + - shellcheck@0.11.0 + - shfmt@3.6.0 + - trufflehog@3.92.5 + - yamllint@1.38.0 +actions: + disabled: + - trunk-announce + - trunk-check-pre-push + - trunk-fmt-pre-commit + enabled: + - trunk-upgrade-available diff --git a/.ansible/collections/ansible_collections/itential/deployer/CHANGELOG.md b/.ansible/collections/ansible_collections/itential/deployer/CHANGELOG.md new file mode 100644 index 00000000..56fd4f12 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/CHANGELOG.md @@ -0,0 +1,496 @@ +# Changelog + +## v3.7.1 (December 19, 2025) + +* Redis config updates https://github.com/itential/itential.deployer/pull/279 +* Remove old variables that are no longer used https://github.com/itential/itential.deployer/pull/280 +* Remove platform password encryption https://github.com/itential/itential.deployer/pull/281 +* setting vm swappiness to recommended value 1 https://github.com/itential/itential.deployer/pull/282 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.7.0...v3.7.1 + + +## v3.7.0 (December 08, 2025) + +* Fix download order in Gateway offline download playbook https://github.com/itential/itential.deployer/pull/278 +* Integrating Vault approle creation and setup https://github.com/itential/itential.deployer/pull/276 +* Update galaxy version and changelog for release 3.7.0 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.6.1...v3.7.0 + + +## v3.6.1 (December 02, 2025) + +* Fix issue with installing Platform adapters https://github.com/itential/itential.deployer/pull/277 +* Update galaxy version and changelog for release 3.6.1 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.6.0...v3.6.1 + + +## v3.6.0 (November 21, 2025) + +* Add community.general to galaxy dependencies and pin version https://github.com/itential/itential.deployer/pull/275 +* Add support for relocating Platform server and service RPMs https://github.com/itential/itential.deployer/pull/274 +* Changes to support B/G while sharing redis & mongo https://github.com/itential/itential.deployer/pull/272 +* Update galaxy version and changelog for release 3.6.0 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.5.0...v3.6.0 + + +## v3.5.0 (November 12, 2025) + +* Activate gateway python venv only for gateway user https://github.com/itential/itential.deployer/pull/264 +* Add Python test script to Gateway installs https://github.com/itential/itential.deployer/pull/257 +* Add flag to enable/disable starting Platform service https://github.com/itential/itential.deployer/pull/262 +* Add pkgconf-pkg-config to gateway build packages list for offline install https://github.com/itential/itential.deployer/pull/269 +* Add regex_escape to package name search query https://github.com/itential/itential.deployer/pull/260 +* Change gateway offline download to copy gateway wheel https://github.com/itential/itential.deployer/pull/261 +* Copy local platform packages to download location for offline installs https://github.com/itential/itential.deployer/pull/266 +* Determine offline adapter install list from download directory https://github.com/itential/itential.deployer/pull/265 +* Encrypt default Platform password https://github.com/itential/itential.deployer/pull/258 +* Fix bug when installing new adapters https://github.com/itential/itential.deployer/pull/263 +* Fix bug with offline platform install when adapter list is empty https://github.com/itential/itential.deployer/pull/267 +* Fix issues with offline gateway install https://github.com/itential/itential.deployer/pull/268 +* Open Gateway Manager port in firewall https://github.com/itential/itential.deployer/pull/270 +* Skip encryption key check when downloading Platform packages https://github.com/itential/itential.deployer/pull/256 +* Update galaxy version and changelog for release 3.5.0 [skip ci] +* Update platform_release format https://github.com/itential/itential.deployer/pull/259 +* removing nodejs repo addition on AmazonLinux2023 https://github.com/itential/itential.deployer/pull/271 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.4.0...v3.5.0 + + +## v3.4.0 (October 10, 2025) + +* Add assertion tasks to deployer roles https://github.com/itential/itential.deployer/pull/236 +* Add assertions after platform and gateway upgrades https://github.com/itential/itential.deployer/pull/237 +* Add end-tag option to changelog.py https://github.com/itential/itential.deployer/pull/232 +* Add wait until active to mongod startup https://github.com/itential/itential.deployer/pull/198 +* Configuration optimizations https://github.com/itential/itential.deployer/pull/247 +* Enable logrotate for redis https://github.com/itential/itential.deployer/pull/235 +* Fix Gateway offline collection install bug https://github.com/itential/itential.deployer/pull/255 +* Fix Vault download packages https://github.com/itential/itential.deployer/pull/240 +* Fix adapter download for offline installs https://github.com/itential/itential.deployer/pull/230 +* Fix gateway firewall configuration tasks https://github.com/itential/itential.deployer/pull/254 +* Fix issue with offline adapter install https://github.com/itential/itential.deployer/pull/234 +* Fix posrotate mongod command https://github.com/itential/itential.deployer/pull/250 +* Fix redis offline install https://github.com/itential/itential.deployer/pull/252 +* Fix uninstall of NodeJS in adapter download https://github.com/itential/itential.deployer/pull/231 +* Modified recommended http server threads comment per performance tests https://github.com/itential/itential.deployer/pull/238 +* Readme updates https://github.com/itential/itential.deployer/pull/249 +* Remove condition that prevents adjusting SELinux labels https://github.com/itential/itential.deployer/pull/246 +* Update Redis to 7.4.6 - [CVE-2025-49844] https://github.com/itential/itential.deployer/pull/251 +* Update galaxy version and changelog for release 3.4.0 [skip ci] +* Updated public repositories https://github.com/itential/itential.deployer/pull/244 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.3.0...v3.4.0 + + +## v3.3.0 (August 07, 2025) + +* Set SELinux file type for redis config templates @Nick-Andreano https://github.com/itential/itential.deployer/pull/227 +* Add Nginx support for setting up proxy to Platform https://github.com/itential/itential.deployer/pull/225 +* Add disclaimer to vault role, its not intended for production use https://github.com/itential/itential.deployer/pull/212 +* Add new property with default value https://github.com/itential/itential.deployer/pull/208 +* Add script to initialize Deployer development environment https://github.com/itential/itential.deployer/pull/223 +* Added conditional to move Platform HTTPS cert and key files https://github.com/itential/itential.deployer/pull/226 +* Added logrotate configuration for MongoDB https://github.com/itential/itential.deployer/pull/216 +* Change Redis version https://github.com/itential/itential.deployer/pull/220 +* Change `venv.sh` permissions https://github.com/itential/itential.deployer/pull/222 +* Change platform Nodejs version from 22 to 20 https://github.com/itential/itential.deployer/pull/217 +* Changed the directory structure for certificates for Platform https://github.com/itential/itential.deployer/pull/215 +* Fix vars include in Gateway download and preflight https://github.com/itential/itential.deployer/pull/228 +* Optimize ansible config paths https://github.com/itential/itential.deployer/pull/218 +* Redis version https://github.com/itential/itential.deployer/pull/224 +* Support Oracle Linux 9 https://github.com/itential/itential.deployer/pull/219 +* Support for ARM in mongo role https://github.com/itential/itential.deployer/pull/221 +* TLS enabled for mongodb https://github.com/itential/itential.deployer/pull/210 +* Update Platform Guide https://github.com/itential/itential.deployer/pull/209 +* Update galaxy version and changelog for release 3.3.0 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.2.0...v3.3.0 + + +## v3.2.0 (June 18, 2025) + +* Add warning to docs about urls that may include redirects https://github.com/itential/itential.deployer/pull/205 +* Change Remi repo URL to use OS version instead of major version https://github.com/itential/itential.deployer/pull/201 +* Consolidate common configuration tasks in platform role https://github.com/itential/itential.deployer/pull/203 +* Copy edits https://github.com/itential/itential.deployer/pull/197 +* Fix inconsistencies in Platform Guide https://github.com/itential/itential.deployer/pull/204 +* Fix redis selinux configuration https://github.com/itential/itential.deployer/pull/207 +* Update galaxy version and changelog for release 3.2.0 [skip ci] +* Update prometheus documentation https://github.com/itential/itential.deployer/pull/202 +* Update required repositories in README https://github.com/itential/itential.deployer/pull/200 +* updated README to include platform rpm https://github.com/itential/itential.deployer/pull/196 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.1.1...v3.2.0 + + +## v3.1.1 (April 07, 2025) + +* Add umask to offline pip installs https://github.com/itential/itential.deployer/pull/192 +* Fix gateway offline install https://github.com/itential/itential.deployer/pull/193 +* Offline install adapter overwrite fix https://github.com/itential/itential.deployer/pull/194 +* Remove build packages only when installed with deployer https://github.com/itential/itential.deployer/pull/191 +* Remove default encryption key, require this key for execution https://github.com/itential/itential.deployer/pull/195 +* Update galaxy version and changelog for release 3.1.1 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.1.0...v3.1.1 + + +## v3.1.0 (March 31, 2025) + +* Add umask to python app dependencies pip install https://github.com/itential/itential.deployer/pull/189 +* Added support for IAG 4.3 https://github.com/itential/itential.deployer/pull/190 +* Ansible netmiko https://github.com/itential/itential.deployer/pull/187 +* Duplicate vars https://github.com/itential/itential.deployer/pull/185 +* Os clean up https://github.com/itential/itential.deployer/pull/182 +* Pinning the ansible-lint version https://github.com/itential/itential.deployer/pull/186 +* Prometheus al23 https://github.com/itential/itential.deployer/pull/181 +* Remove dnf switch-to when installing nodejs https://github.com/itential/itential.deployer/pull/188 +* Update galaxy version and changelog for release 3.1.0 [skip ci] +* Use full path to ansible-galaxy when installing collections https://github.com/itential/itential.deployer/pull/183 +* Vault al23 https://github.com/itential/itential.deployer/pull/184 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.0.1...v3.1.0 + + +## v3.0.1 (March 14, 2025) + +* Update galaxy version and changelog for release 3.0.1 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v3.0.0...v3.0.1 + + +## v3.0.0 (March 14, 2025) + +* Fix Gateway Ansible config paths https://github.com/itential/itential.deployer/pull/229 +* Fix Redis offline install to not uninstall build packages https://github.com/itential/itential.deployer/pull/245 +* Fix issues with download playbooks not copying RPMs to control node https://github.com/itential/itential.deployer/pull/243 +* Preflight Checks https://github.com/itential/itential.deployer/pull/116 +* Release v3.0.0 +* Update galaxy and changelog for v2.6.3 +* Update galaxy version and changelog for release 3.0.0 [skip ci] +* Update galaxy.yml and changelog for v2.6.2 +* Update galaxy.yml and changelog with v2.6.1 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.6.3...v3.0.0 + + +## v2.6.3 (September 30, 2025) + +* Fix Redis offline install to not uninstall build packages https://github.com/itential/itential.deployer/pull/245 +* Update galaxy and changelog for v2.6.3 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.6.2...v2.6.3 + + +## v2.6.2 (September 29, 2025) + +* Fix issues with download playbooks not copying RPMs to control node https://github.com/itential/itential.deployer/pull/243 +* Update galaxy.yml and changelog for v2.6.2 +* Update galaxy.yml and changelog with v2.6.1 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.6.1...v2.6.2 + + +## v2.6.1 (August 07, 2025) + +* Fix Gateway Ansible config paths https://github.com/itential/itential.deployer/pull/229 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.6.0...v2.6.1 + + +## v2.6.0 (January 28, 2025) + +* Add support for installing Ansible collections on IAG servers https://github.com/itential/itential.deployer/pull/110 +* Allow core to cleanup on systemctl stop https://github.com/itential/itential.deployer/pull/113 +* Create mongo-key for replication https://github.com/itential/itential.deployer/pull/114 +* Do not overwrite the Redis Sentinel service script when installing from Remi repo https://github.com/itential/itential.deployer/pull/111 +* Escape mongo password https://github.com/itential/itential.deployer/pull/109 +* Readme updates https://github.com/itential/itential.deployer/pull/108 +* Uninstall build packages after installation https://github.com/itential/itential.deployer/pull/105 +* Update ansible-lint.yml +* Update galaxy version and changelog for release 2.6.0 [skip ci] +* Update the mongo-key tasks change from single copy to slurp https://github.com/itential/itential.deployer/pull/118 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.5.0...v2.6.0 + + +## v2.5.0 (December 20, 2024) + +* 23.2 RHEL and Rocky 8 now install node 20 instead of 18 https://github.com/itential/itential.deployer/pull/93 +* Add tasks to open prometheus exporter ports in firewalld https://github.com/itential/itential.deployer/pull/92 +* Added customer engine name https://github.com/itential/itential.deployer/pull/94 +* Change Prometheus Redis exporter to use prometheus user https://github.com/itential/itential.deployer/pull/102 +* Consolidate Redis roles https://github.com/itential/itential.deployer/pull/99 +* Redefine logic that triggers tasks for the ASA architecture https://github.com/itential/itential.deployer/pull/101 +* Update Ansible requirements in readme https://github.com/itential/itential.deployer/pull/96 +* Update galaxy version and changelog for release 2.5.0 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.4.1...v2.5.0 + + +## v2.4.1 (October 25, 2024) + +* Add README for grafana role https://github.com/itential/itential.deployer/pull/91 +* Update galaxy version and changelog for release 2.4.1 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.4.0...v2.4.1 + + +## v2.4.0 (October 25, 2024) + +* Support installation of Itential artifacts using repository URL https://github.com/itential/itential.deployer/pull/87 +* Added tuned to operational packages https://github.com/itential/itential.deployer/pull/84 +* Changlog link fix https://github.com/itential/itential.deployer/pull/83 +* Fix custom adapter symlinks when patching IAP https://github.com/itential/itential.deployer/pull/85 +* Restructure prometheus playbooks and roles https://github.com/itential/itential.deployer/pull/86 +* Separate out Grafana RabbitMQ dashboard definition https://github.com/itential/itential.deployer/pull/89 +* Support auth in MongoDB exporter https://github.com/itential/itential.deployer/pull/88 +* Update galaxy version and changelog for release 2.4.0 [skip ci] +* Use rabbitmq_default_mgt_console_port in prometheus role https://github.com/itential/itential.deployer/pull/90 +* Wrong mongo version https://github.com/itential/itential.deployer/pull/82 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.3.3...v2.4.0 + + +## v2.3.3 (September 27, 2024) + +* Fix prometheus redis exporter when auth is enabled https://github.com/itential/itential.deployer/pull/80 +* Update galaxy version and changelog for release 2.3.3 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.3.2...v2.3.3 + + +## v2.3.2 (September 25, 2024) + +* Change RabbitMQ cluster node names to short hostname https://github.com/itential/itential.deployer/pull/43 +* Fix RabbitMQ env config template +* Missing replset name https://github.com/itential/itential.deployer/pull/71 +* Update galaxy version and changelog for release 2.3.2 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.3.1...v2.3.2 + + +## v2.3.1 (September 21, 2024) + +* Add mongo host to tasks, do not use default https://github.com/itential/itential.deployer/pull/69 +* Add task to stop rabbitmq service in rabbitmq role https://github.com/itential/itential.deployer/pull/70 +* Fix ansible lint issues in all roles and playbooks https://github.com/itential/itential.deployer/pull/61 +* Fixed RabbitMQ installation when using custom variables https://github.com/itential/itential.deployer/pull/67 +* Fixed redis installation when using custom variables https://github.com/itential/itential.deployer/pull/66 +* Missing SSO parameter in authenticationProps https://github.com/itential/itential.deployer/pull/58 +* Non standard dirs https://github.com/itential/itential.deployer/pull/68 +* Support non-standard mongo port https://github.com/itential/itential.deployer/pull/65 +* Update galaxy version and changelog for release 2.3.1 [skip ci] + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.3.0...v2.3.1 + + +## v2.3.0 (September 06, 2024) + +* Configure SELinux when using custom IAP installation directory https://github.com/itential/itential.deployer/pull/39 +* Gateway 23.3 https://github.com/itential/itential.deployer/pull/29 +* IAG task fails when SELinux is disabled https://github.com/itential/itential.deployer/pull/44 +* Rename to yml https://github.com/itential/itential.deployer/pull/28 +* Update galaxy version and changelog for release 2.3.0 [skip ci] +* added redis_db_number https://github.com/itential/itential.deployer/pull/40 +* updated mongo for 2023.2 redhat/rocky 8 to version 7 https://github.com/itential/itential.deployer/pull/38 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.2.0...v2.3.0 + + +## v2.2.0 (August 12, 2024) + +* 232 rhel/rocky8 support for platform and mongo https://github.com/itential/itential.deployer/pull/15 +* Add Code of conduct and contributing guidelines https://github.com/itential/itential.deployer/pull/5 +* Add flag to disable installation of YUM repositories https://github.com/itential/itential.deployer/pull/12 +* Add jmespath requirement to docs +* Add license file https://github.com/itential/itential.deployer/pull/4 +* Add notes to docs about RabbitMQ not being required for IAP 2023.2 and newer +* Add processManagement section to mongod.conf template +* Add specs for control node to README https://github.com/itential/itential.deployer/pull/19 +* Add support for installing adapters from zip archive +* Add variables for http server threads (IAG) and IAG adapter token timeout (IAP) https://github.com/itential/itential.deployer/pull/14 +* Added conditional to prevent RabbitMQ install when iap_release is less than 2023.2 +* Correct lint issues https://github.com/itential/itential.deployer/pull/17 +* Create ansible-lint.yml +* Create publish_ansible_collection.yml +* Create updateChangelog.yml +* Fix IAG adapter service config base_path +* Fix IAP Vault token location and permissions https://github.com/itential/itential.deployer/pull/23 +* Fix MongoDB tools package list for IAP v2021.1 installs +* Fix iag_http_server_threads syntax issue in IAG properties template https://github.com/itential/itential.deployer/pull/27 +* HAProxy timeout settings update https://github.com/itential/itential.deployer/pull/7 +* Hashicorp read only support https://github.com/itential/itential.deployer/pull/11 +* Improve logging https://github.com/itential/itential.deployer/pull/10 +* Lint issues https://github.com/itential/itential.deployer/pull/18 +* Lint issues https://github.com/itential/itential.deployer/pull/20 +* Lint issues https://github.com/itential/itential.deployer/pull/22 +* Prometheus https://github.com/itential/itential.deployer/pull/24 +* Re-factor Running the Deployer section of README +* Rename documents to docs https://github.com/itential/itential.deployer/pull/6 +* Support MongoDB installs on aarch64 servers +* Update CHANGELOG.md +* Update Ports and Networking section in README https://github.com/itential/itential.deployer/pull/16 +* Update README to remove instructions for installing from Itential Ansible Galaxy https://github.com/itential/itential.deployer/pull/26 +* Update galaxy version and changelog for release 2.2.0 [skip ci] +* Update publish_ansible_collection.yml +* addded support for 23.2 on RHEL 8 for Gateway install https://github.com/itential/itential.deployer/pull/13 +* added license to galaxy file https://github.com/itential/itential.deployer/pull/8 +* delete file +* moved vault_port to common_vars https://github.com/itential/itential.deployer/pull/9 +* removed Terraform +* update changelog script +* updated iag_guide.md + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.1.2...v2.2.0 + + +## v2.1.2 (April 22, 2024) + +* Create release v2.1.2 +* Fix download adapters when custom adapters list is empty +* Readme updates +* Update CI build pipeline to fetch all tags +* Update links in mongodb role documentation + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.1.1...v2.1.2 + + +## v2.1.1 (April 10, 2024) + +* Add README documents for each component +* Add missing variables and examples to documentation +* Add script to create changelog when CI build pipeline is executed +* Create release v2.1.1 +* Update docs with variables required for installing Redis from source +* Update example inventory hostnames in README +* Update selinux role to configure SELinux only if it is enabled + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.1.0...v2.1.1 + + +## v2.1.0 (March 26, 2024) + +* Add support for installing Redis from source +* Create release 2.1.0 +* Fix rabbitmq playbook when clustering/ssl is enabled +* Update README document +* Update Redis and RabbitMQ roles to use configurable usernames/passwords +* Update Redis settings to support IAP 23.2 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.0.2...v2.1.0 + + +## v2.0.2 (March 25, 2024) + +* Rename patch IAP/IAG playbooks to support calling from collection + +Full Changelog: https://github.com/itential/itential.deployer/compare/v2.0.1...v2.0.2 + + +## v2.0.1 (March 21, 2024) + +* Add offline install functionality +* Add support for IAG and IAP 2023.2 +* Create release 2.0.0 +* Create release 2.0.1 +* Fix CI pipeline +* Fix profile name when using advanced config (HA/DR) +* Move playbooks to playbooks directory +* Update .gitlab-ci.yml file + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.5.0...v2.0.1 + + +## v1.5.0 (December 15, 2023) + +* Add Gateway task to add HTTP port to SELinux +* Add Vault task to configure ports in firewalld +* Add redis_tls common default var +* Add support for installing IAP from tar file +* Added files to install redis from repo +* Change patch playbooks to include common vars via role +* Changes to support bring-your-own-dependency +* Create release 1.5.0 +* Move dup vars to common_vars redis +* Remove dup RabbitMQ vars +* Remove duplicate IAP vars +* Remove duplicate MongoDB variables +* Remove duplicate Vault vars +* Update IAG module and collection paths +* Update SELinux configurations for IAP/Redis/MongoDB +* Vars cleanup + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.4.0...v1.5.0 + + +## v1.4.0 (October 26, 2023) + +* Bump galaxy collection version +* Bump redis version to 7.0.14 +* Check for IAG adapter and do not add it if already present +* Fixed mongo backup issues, removing bin file from remote when finished +* Minor changes for rabbit +* Minor optimizations + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.3.0...v1.4.0 + + +## v1.3.0 (October 02, 2023) + +* Add IAG HTTPS/SSL configuration +* Added missing LDAP and other properties +* Create release 1.3.0 +* Fixed Mongo tools yum reference for rhel8 +* Support mongodb replication with no arbiter + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.2.1...v1.3.0 + + +## v1.2.1 (September 22, 2023) + +* Add ansible-pylibssh to pip install for IAG 2023.1 + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.2.0...v1.2.1 + + +## v1.2.0 (September 22, 2023) + +* Add flag for determining whether to use rsync for artifact uploads + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.1.0...v1.2.0 + + +## v1.1.0 (September 19, 2023) + +* Add flag to disable binding to v6 interfaces (rabbitmq/redis) +* Add initial version of CI pipeline +* Add tls options to mongo connection string +* Added HA policy to iap vhost, other best practices in rabbit conf +* Added correct redis ACL +* Added new role that can upgrade IAG +* Added tasks to downgrade markupsafe after jinja install +* Changed and added some best practice rabbit settings +* Corrected ACL list +* IAG adapters will be built based on gateway group members +* Modifying rabbit HA policy to match ISD standards +* Release v1.1.0 +* Remove mongo init +* Removed mongodb_init role, tasks moved to mongo and platform roles + +Full Changelog: https://github.com/itential/itential.deployer/compare/v1.0.0...v1.1.0 + + +## v1.0.0 (August 21, 2023) + +* Change pip install to use builtin module +* Changed default iap log dir to match already established docs and practices +* Fix restart mongo task in mongo auth +* Fixed syntax error +* Initial commit +* Initial version + diff --git a/.ansible/collections/ansible_collections/itential/deployer/CODE_OF_CONDUCT.md b/.ansible/collections/ansible_collections/itential/deployer/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..654ff363 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/CODE_OF_CONDUCT.md @@ -0,0 +1,70 @@ +# Code of Conduct - Itential Deployer + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban +temporarily or permanently any contributor for other behaviors that they deem +inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at <>. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org/), version +[1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct/code_of_conduct.md) and +[2.0](https://www.contributor-covenant.org/version/2/0/code_of_conduct/code_of_conduct.md), +and was generated by [contributing-gen](https://github.com/bttger/contributing-gen). \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/CONTRIBUTING.md b/.ansible/collections/ansible_collections/itential/deployer/CONTRIBUTING.md new file mode 100644 index 00000000..6f970253 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/CONTRIBUTING.md @@ -0,0 +1,159 @@ + +# Contributing to Itential Deployer + +First off, thanks for taking the time to contribute! ❤️ + +All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉 + +> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: +> - Star the project +> - Tweet about it +> - Refer this project in your project's readme +> - Mention the project at local meetups and tell your friends/colleagues + + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [I Have a Question](#i-have-a-question) +- [I Want To Contribute](#i-want-to-contribute) + - [Reporting Bugs](#reporting-bugs) + - [Suggesting Enhancements](#suggesting-enhancements) + - [Your First Code Contribution](#your-first-code-contribution) + - [Improving The Documentation](#improving-the-documentation) +- [Styleguides](#styleguides) + - [Commit Messages](#commit-messages) +- [Join The Project Team](#join-the-project-team) + + +## Code of Conduct + +This project and everyone participating in it is governed by the +[Itential Deployer Code of Conduct](https://github.com/itential/deployer/blob/master/CODE_OF_CONDUCT.md). +By participating, you are expected to uphold this code. Please report unacceptable behavior +to <>. + + +## I Have a Question + +> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/itential/deployer/blob/main/README.md). + +Before you ask a question, it is best to search for existing [Issues](https://github.com/itential/deployer/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. + +If you then still feel the need to ask a question and need clarification, we recommend the following: + +- Open an [Issue](https://github.com/itential/deployer/issues/new). +- Provide as much context as you can about what you're running into. +- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. + +We will then take care of the issue as soon as possible. + + + +## I Want To Contribute + +> ### Legal Notice +> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. + +### Reporting Bugs + + +#### Before Submitting a Bug Report + +A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. + +- Make sure that you are using the latest version. +- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/itential/deployer/blob/main/README.md). If you are looking for support, you might want to check [this section](#i-have-a-question)). +- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/itential/deployer/issues?q=label%3Abug). +- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. +- Collect information about the bug: + - Stack trace (Traceback) + - OS, Platform and Version (Windows, Linux, macOS, x86, ARM) + - Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant. + - Possibly your input and the output + - Can you reliably reproduce the issue? And can you also reproduce it with older versions? + + +#### How Do I Submit a Good Bug Report? + +> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>. + + +We use GitHub issues to track bugs and errors. If you run into an issue with the project: + +- Open an [Issue](https://github.com/itential/deployer/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) +- Explain the behavior you would expect and the actual behavior. +- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. +- Provide the information you collected in the previous section. + +Once it's filed: + +- The project team will label the issue accordingly. +- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced. +- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution). + + + + +### Suggesting Enhancements + +This section guides you through submitting an enhancement suggestion for Itential Deployer, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. + + +#### Before Submitting an Enhancement + +- Make sure that you are using the latest version. +- Read the [documentation](https://github.com/itential/deployer/blob/main/README.md) carefully and find out if the functionality is already covered, maybe by an individual configuration. +- Perform a [search](https://github.com/itential/deployer/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. +- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library. + + +#### How Do I Submit a Good Enhancement Suggestion? + +Enhancement suggestions are tracked as [GitHub issues](https://github.com/itential/deployer/issues). + +- Use a **clear and descriptive title** for the issue to identify the suggestion. +- Provide a **step-by-step description of the suggested enhancement** in as many details as possible. +- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. +- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. +- **Explain why this enhancement would be useful** to most Itential Deployer users. You may also want to point out the other projects that solved it better and which could serve as inspiration. + + + +### Your First Code Contribution + + +### Improving The Documentation + + +## Styleguides +### Commit Messages + + +## Join The Project Team + + + +## Attribution +This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)! diff --git a/.ansible/collections/ansible_collections/itential/deployer/FILES.json b/.ansible/collections/ansible_collections/itential/deployer/FILES.json new file mode 100644 index 00000000..eb3d2a32 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/FILES.json @@ -0,0 +1,2539 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "CODE_OF_CONDUCT.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "22c86082bce588d60ecf8922356115fab2f4a5dc69143d9495fc1458db189c6a", + "format": 1 + }, + { + "name": "LICENSE", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3b44d79c8b047bc394ab2dd53001960bfb76c60cf0ad28693ff6dd577a489588", + "format": 1 + }, + { + "name": "CHANGELOG.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5b6b3e57b8665d7810e1f0a48a01c4acde44a4c5fe483de4e86f8108a5745037", + "format": 1 + }, + { + "name": ".trunk", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".trunk/plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".trunk/trunk.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "73ea3ae3cfdae690ed2ad4d105cd14db7149564bc7808a71f6c92f8b0f8569db", + "format": 1 + }, + { + "name": ".trunk/.gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a3a6850a4d3873929d6296fb261801a240eaa67247f219894da802b45359fd7e", + "format": 1 + }, + { + "name": ".trunk/configs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".trunk/configs/.isort.cfg", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "968e1af82279fb9bb4b6fd697ad2a83763eb6ca524403c42cf1f6f99707de619", + "format": 1 + }, + { + "name": ".trunk/configs/.shellcheckrc", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04c847ef9a565bb61def1d3d60bca0d625b2d0544a445464bedc42f0f2d84bb9", + "format": 1 + }, + { + "name": ".trunk/configs/ruff.toml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7d5f27b2681ad76dbd0e5e9ff893f78f8c6ce0ade804de044322300b60e7a0c1", + "format": 1 + }, + { + "name": ".trunk/configs/.markdownlint.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "697b0377e423ca0f494859a15e68e4a7d6c7727c2fc4c816f0c8e1b4cad0d2ec", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "854081319843a15a95afeee3d0d6f5a17bd7f57ec0ad89e6c96e1481d4e8f64a", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/mongodb_config_state.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a8e77243faeff7152b5f95212572cacd38b349014905418784854546507577a0", + "format": 1 + }, + { + "name": "plugins/modules/os_compatibility.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f25bfea60dfc89de39ec656120a901c20cf043b7e68270967c3d6662514a923f", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "00a4124ee0cad840a7b808cadcaad728184285a49db262d06aca21a9dfa031d4", + "format": 1 + }, + { + "name": "roles", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/python", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/python/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/python/tasks/create-symlinks.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "68514200d964c521c3dd8639c7d3a6ecad5975d4dc693dfc79c610f3a3408cdd", + "format": 1 + }, + { + "name": "roles/python/tasks/install-dependencies.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b8e9879f36f841fd19954590fb4b7a6b436efcbbe79e74704449e6402ab59897", + "format": 1 + }, + { + "name": "roles/python/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2b1f53db91b82a97606e7762c7146444e6476d28d2c0b88b160d964abc482dc7", + "format": 1 + }, + { + "name": "roles/python/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/redis", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/vars/platform-release-6.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bf8be2c9505f5b46afcf3f35648b144d7c0ee6f981a670d3795948821fe3bb72", + "format": 1 + }, + { + "name": "roles/redis/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a623a6dc39c80f3473c29b62337332b20c1ccd570fc546007b84f265fe0012b7", + "format": 1 + }, + { + "name": "roles/redis/vars/platform-release-undefined.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ac18f3f6fcf3271682d70808f03af201498dc89fa29d71ca95b09b46f0014925", + "format": 1 + }, + { + "name": "roles/redis/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/tasks/download-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6f68563a22b660f3897975fd3f3b32690f10851c561ab3e920d6112773716322", + "format": 1 + }, + { + "name": "roles/redis/tasks/configure-redis.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d064d87147865bfb82ab52170ff04e7d28fc561ce4572cbdf5bcc6ee1f8e85b1", + "format": 1 + }, + { + "name": "roles/redis/tasks/.DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "15a8d924afdc062cf4341120d4e7967dbeeb79a34ff7b3257ae7b0d56cd838e7", + "format": 1 + }, + { + "name": "roles/redis/tasks/preflight.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "adb24134153c16df7a855a4f1cf0e6c5d265f50e9a3525a5d64173cb777b719d", + "format": 1 + }, + { + "name": "roles/redis/tasks/install-from-source.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "20a422c7bb52539a705ff178c57e682c69e1a9eadd3d114e1db0b2fae7e33422", + "format": 1 + }, + { + "name": "roles/redis/tasks/install-remi-repo.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5057c7be2241f8fd055e530289e75bfd9f253642b004dfb21e573b9dbe76b15d", + "format": 1 + }, + { + "name": "roles/redis/tasks/install-from-repo.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3e0de8082999781c9bc2b3ef5cb651893fa5fe312468f491e7841292ef043684", + "format": 1 + }, + { + "name": "roles/redis/tasks/update-release-file.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eb03ed29ce1abb26f0b93a898efac3309076bb55b1c26dec25818b725944310e", + "format": 1 + }, + { + "name": "roles/redis/tasks/configure-selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cc18f836592247bdc04ea07d8053157463d9faf6360ec6ef6da01a16d641dc45", + "format": 1 + }, + { + "name": "roles/redis/tasks/configure-sentinel.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6b2a06134ee10a7547259a0dbdd821cbf6846fa96faf882e1ba4be35106a504f", + "format": 1 + }, + { + "name": "roles/redis/tasks/validate-vars-offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "575c3f7ed26b09268b32f71d82a33c61b7bb7ad22df647771dab37f0723e13ea", + "format": 1 + }, + { + "name": "roles/redis/tasks/configure-redis-tls.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "40bcb538a1ae7b7b9825b00c90974e77316346f535032bb3b59de5a2260525c0", + "format": 1 + }, + { + "name": "roles/redis/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "997e0e7e52c4be4dee56c2a3cbdfa86e37c0edda8ff5102bef90b4169f60b6a8", + "format": 1 + }, + { + "name": "roles/redis/tasks/install-common.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04de79384093ff8896561de70f49aa9df6433c96c245269ae4e3144f1e09ce53", + "format": 1 + }, + { + "name": "roles/redis/tasks/validate-vars.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04bb67269c8afa3296b48bc7946d6fd0a611ba61f05b0b7534a9319cab9458f2", + "format": 1 + }, + { + "name": "roles/redis/.DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a24693c93b783f7a9e852ad1bf278c3d6fe4f89badda04f3938d3ca9161388b6", + "format": 1 + }, + { + "name": "roles/redis/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/redis/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/defaults/.DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d0e833798392ac836a9266798b6716a28a0e0921013c6060e1c1111e1b3a2111", + "format": 1 + }, + { + "name": "roles/redis/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/defaults/main/sentinel.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5cb75801c13d587144e27fdc22df7068f0cfeb1d745a4926adfd4a1fb0745075", + "format": 1 + }, + { + "name": "roles/redis/defaults/main/pki.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "60ca8dbd9e9184fd2a8709a33fd0d477b8d646ae4ba66c50cb35e2b8f0575c6a", + "format": 1 + }, + { + "name": "roles/redis/defaults/main/.DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a41c3c226c78bfd4b4b467cffb14d9f303079deaee54f1a257a7624ffe102957", + "format": 1 + }, + { + "name": "roles/redis/defaults/main/redis.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95c01070ca11673d70fa833f8089a8f5ca0cff2ad181d30c9e713478df3a4c30", + "format": 1 + }, + { + "name": "roles/redis/defaults/main/offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0e32f7ed8f222004cdc98506a1d6a3e76cee4734d78f2198893d2ba037c63563", + "format": 1 + }, + { + "name": "roles/redis/defaults/main/install.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bab411dbf75436e72d6ce20d00c5c33348850681815ba64a07eb74bc13b5cd57", + "format": 1 + }, + { + "name": "roles/redis/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/files/itential_redis_sentinel.te", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "96e83e623e073206d02d99e220cb1f128852e84fb1d2cb59b132fe589bdc1ca2", + "format": 1 + }, + { + "name": "roles/redis/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/templates/redis.preflight.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a8f5392ad0dcd0c79b8e9efbc97126fa9b28f48cfe21eb462772309b55151c18", + "format": 1 + }, + { + "name": "roles/redis/templates/redis.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "22f84d73d0a697f567e3337ae17941fc6daeb0a840b727b200c432d284759d80", + "format": 1 + }, + { + "name": "roles/redis/templates/sentinel.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6fafdb08d0ca59d97a8cb4ff29bf2d06db916e282e18c9aee0b3b1f402a89d38", + "format": 1 + }, + { + "name": "roles/redis/templates/redis-sentinel.logrotate.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "22a8197a7381de2f27a46d23abc5ba114e5849822cf29b0bd01e8466298dbd45", + "format": 1 + }, + { + "name": "roles/redis/templates/redis-sentinel.service.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0430fdb630c60e9a2cd93255721a7392a4bbeafbe2e7035e979faf5a0414f806", + "format": 1 + }, + { + "name": "roles/redis/templates/redis.logrotate.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ec4d66d0a31ac5e42737dafdedced5d9c0c14efb5779c98fb8f09d460dbdb49f", + "format": 1 + }, + { + "name": "roles/redis/templates/redis.service.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c20df57bff1e0a395f0dec00c48d231dffb7144d348069a6a51bfab7916c9930", + "format": 1 + }, + { + "name": "roles/redis/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/redis/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3211f1b508411bcb5b334dc3027e52b1d785bbf924dc0c5f812272f85fc37a44", + "format": 1 + }, + { + "name": "roles/platform", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/vars/platform-release-6.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "814fbb4050ce09b88ca633f4fd397f59df54869f00edd3b89106851446914628", + "format": 1 + }, + { + "name": "roles/platform/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4473893d8ef3e4a06ac5172c70e5385dec5bd11bd78ef4d28615f4946c667a70", + "format": 1 + }, + { + "name": "roles/platform/vars/platform-release-undefined.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f79ceacd1ad4a0f22c71590484971afaba9d591f2a9412ea487121190eee9c60", + "format": 1 + }, + { + "name": "roles/platform/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/tasks/configure-platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a0999b28d04eb55127f36fb05830c6638d84947712ff4a3075f07a87a5203ed9", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "de13db0d76f877039d9820b1fda6bb2fa0e2c97815d9138d0e8aa6ce86c7c321", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-platform-archive-from-repo.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "80c931ae755317c6e615fabfc91b06033bc2a01c5dcc24afca21242614cc461b", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-python.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fad0cae906c908ed9949bfecb43514d81d35cae975d774ba33c0758014d79263", + "format": 1 + }, + { + "name": "roles/platform/tasks/create-properties-file.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "65f155b71c280b8e85657c4394171b4460d29dcfe51d09cee1269026b50db33d", + "format": 1 + }, + { + "name": "roles/platform/tasks/preflight.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "220fb34bc201d950c4d803eda95bf28974071f2070f8009ee6bcb024a48cf217", + "format": 1 + }, + { + "name": "roles/platform/tasks/copy-certs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fdf3b8cca9dfc8f40b9cb5b4fafd2e3db1f70585dd1b25ccd569f03bf5897f16", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-app-artifacts.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "176f9d39167804ca56c036290389d54dc04100dbe3a59b8f6d6137f01dfa0b9c", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-packages-platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "418aaef4129edbff421cefc5a88d7ce571de153b884b69e9997ceb2ed850da04", + "format": 1 + }, + { + "name": "roles/platform/tasks/start-service.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dac3b3ed1dbf21f84d1dfe993fd568c2ac83c19502c9514e86169e8d07dbff26", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-packages-nodejs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "46dc8ce2f10dfc36e633595846202f37ae41cabc3cdd929926bf7c96ee0f952f", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-platform-packages-relocate.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "38d8f2095cbda106d936c5657476eb1f1ef623a929debaff018bf30a4d8064c2", + "format": 1 + }, + { + "name": "roles/platform/tasks/encrypt-passwords.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "312ec0a2b45d9011c203de68dbaf45375a75c8277bc3d387cedc9fae7decf1f8", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-nodejs-repo.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "029d9edc91f60c4bdc1c83bdbe05edb3cf39561c39c83f0c2e411732543be171", + "format": 1 + }, + { + "name": "roles/platform/tasks/upgrade-platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "65821470ab39bc7e0a84eb7274717917acf87757c98fd8ffce67bcb012590cbc", + "format": 1 + }, + { + "name": "roles/platform/tasks/upload-platform-archive-from-local.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "13b35fbfb3678600a536b129cf2cb39b9a6306d4c9ca7d252865992b2a0ea0f7", + "format": 1 + }, + { + "name": "roles/platform/tasks/update-release-file.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "518a6743f6ee3b825b7f0cdb325b1d48d731a7a41d5c7d08b74aa055ec142d56", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-adapters.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d9a3628b81578fc072f073066043971da161a4adf786f3e5dd44c67df76323e", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-packages-os.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e85cd295007a53cd8ed497192467e6910cdbee420c6694a284f68e764aa234cf", + "format": 1 + }, + { + "name": "roles/platform/tasks/configure-selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bfcb62d92a1de017d476070927b6f2ac99994330e626c3a2d3b96b229fdd3013", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dcd3caef8948956b228bdd1d2e6ca8f903f9cbfe2adda7fba1fe6ff0f75d82da", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-nodejs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6d2fd2279186ce31471e5ed4980ce3bfdc4e0efb20cc031a111fb23198ca174e", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-adapters.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "91a775afc17ffb909414191f3a8e8d12bd54502b85ec48d7ef7a5e00a07ef411", + "format": 1 + }, + { + "name": "roles/platform/tasks/create-itential-user.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d5b827f55101ff6e58eea60eacf09fcbd1333356b5e11bb01dd9c5999c3e032e", + "format": 1 + }, + { + "name": "roles/platform/tasks/set-file-ownership.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a574edf5cf25e70c2a6e82a4f4685d162d388bb19bc92891662c0a2b4e72b0e0", + "format": 1 + }, + { + "name": "roles/platform/tasks/configure-vault.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "17e9783a029989c1246e8ced710e0da03df9a77264d36122468dcab53fe6a1aa", + "format": 1 + }, + { + "name": "roles/platform/tasks/install-platform-dependency-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "104a228155144c938229fe06b7f13eb6da74b1753b31797a787842ddc86f0463", + "format": 1 + }, + { + "name": "roles/platform/tasks/download-packages-python.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ba206762d8c06f6f94c3e9e6ea949dbeca5b9aefc7f9471d759b04657cb571f1", + "format": 1 + }, + { + "name": "roles/platform/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "34418577e3429be64e3d377c417cdd5d344b71dabc557ac999850c2e535d8748", + "format": 1 + }, + { + "name": "roles/platform/tasks/configure-firewalld.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e2b90c956a3f64ed8ce300b2b63d2e445c7b7094d792f1a46fdf63407888029c", + "format": 1 + }, + { + "name": "roles/platform/tasks/validate-vars.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "28caff52381122b90f755b8ab151df17df19f36a85d750f10bf81ef145b573fc", + "format": 1 + }, + { + "name": "roles/platform/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/platform/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/defaults/main/pki.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d44155847ec54b166ff0d2f64b0e46181037686ee56a8befc1a11d959b7b346d", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/brokers.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "87e755c7ccabb2277fd777118aa867470bfb11f8384332b785f8d700ca9b1a26", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/logging.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "793140500d59a5728acde8857bac1c88935b81246f1a08197e157d7275e471ec", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "be82350ec55543f41a072ddc884ce3eba56f433366fc9d2d0db169419ea72264", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/snmp.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eda4a05ad93bf5fbb2d2b81acc41ce2f142f1ea2f7a1057056346f7c31ae29b7", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/gateway_manager.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0a14ea3f46b6087c7d456b658ab9ffd24b69bd9ddfc79c8e5b978038d7f9f733", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/redis.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ae2c6a4c9ea1f0df930a7808953d263b6ead9ff242c2453a37be75f5e8d08adc", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/webserver.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0ad8597aa226eefefbb06ef085fb444a282f832b54c9190c636e876dbb3e686d", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/integration_worker.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "84b0af3f8cb8f8e1b0b0ca9af52bcc43633f3cf8c8a05b07ce5f9d7dfff557d5", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/vault.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e2f049b8902c9c7abea31487cee4930d7880dfbdd6f30743d4a54d7a689b1d2b", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/platform_ui.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d1a5fa906ba4ec84c74b418796e256b6ec69d1249d392c11e97a452a9667cc1d", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "75555cdeda56417cd1935d202b52f96d3f770350c4177035f672224e7c438021", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5cd8eaba8b536fc3a7cba9bd55a8f766fd10be15fca8b7a7c6f8e492d26dbd95", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/workflow_worker.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f8c31b572c26d76f9be47ecee39f029e2ffe0313ea62bdf0557b1f32b0a270b3", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/server.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e7f4d0c87262094852898b8c9c93f4cc213b645f4773ea79e081ecf24ebe48d7", + "format": 1 + }, + { + "name": "roles/platform/defaults/main/authentication.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bfa2efc5df6b69c625392eee7574a3742a0a680f18bd10c1820138e37365fdbc", + "format": 1 + }, + { + "name": "roles/platform/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/templates/platform.preflight.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "548bb6eb2a1de3f67221efc76eb7623b607e9ed06d9ecdf465881b07e85cc6d7", + "format": 1 + }, + { + "name": "roles/platform/templates/6-properties.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ebcb634047930b11f15dabc11c09bc675514636d460d6218ec66f56e6f349e25", + "format": 1 + }, + { + "name": "roles/platform/templates/iag_adapter_service_config.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a059714c37ffc2b877f1a69ef3aa2ca684cfced65c7a2a6abbd0aca20ac839df", + "format": 1 + }, + { + "name": "roles/platform/templates/itential-platform.service.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95693cd9d426d18ee07880466ee12c25b6b7e46cce6bbb1fb342ac43fab6e04c", + "format": 1 + }, + { + "name": "roles/platform/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/platform/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c0fed1db10ac809613409341c1874ea09fbfbc0e6fa55647938eff8d3780f869", + "format": 1 + }, + { + "name": "roles/grafana", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fd3cc0ed34e55ea54ac88d8bcf2fa4424f62d4f81599c043df94d6b6b366bed7", + "format": 1 + }, + { + "name": "roles/grafana/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ff98ca5d29c3374f050bdc269c89c2375534c19592d40ec10fea91aebe0d8dc8", + "format": 1 + }, + { + "name": "roles/grafana/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/grafana/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c09ec69c96f4cd6cba2b598b0404c003472fd45dad7ad9616579b1b07cc28f2b", + "format": 1 + }, + { + "name": "roles/grafana/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/files/definitions", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/files/definitions/default", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/files/definitions/default/grafana_dashboard_definition_iap2.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bd8ce9c96c5a9dbd9e9cc43ed8b085ed73b2dd09b0f6882c316d2da4eaf8b465", + "format": 1 + }, + { + "name": "roles/grafana/files/definitions/default/grafana_dashboard_definition_node.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "49837f5f35390d5b0a0d015d9d5c98a1546d8611b70343af08ffcc428180655b", + "format": 1 + }, + { + "name": "roles/grafana/files/definitions/default/grafana_dashboard_definition_iap.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f1e1a72f0cfbd87699f8054e6a9e08cf13db5fa80241ac78716e5265a9413208", + "format": 1 + }, + { + "name": "roles/grafana/files/definitions/default/grafana_dashboard_definition_mongo.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1e22150d6777dd449be810a3282d632a81aeac8d8d91a4afbae19ac554caeab9", + "format": 1 + }, + { + "name": "roles/grafana/files/definitions/default/grafana_dashboard_definition_redis.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1d6345733511dce2037138e25368e02bfb4e9c6158e6bbadd76bf8c3f336ea64", + "format": 1 + }, + { + "name": "roles/grafana/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/grafana/templates/grafana_datasources.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "57c751eb19fb716c6dc9badddd188af959028395e5d72a4e547e8a5dbfc21fff", + "format": 1 + }, + { + "name": "roles/grafana/templates/grafana_dashboard_config_iap.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0e52ae824bb888d0a82dabd6897691f2074737963bbead51ff42a22dbb3e09df", + "format": 1 + }, + { + "name": "roles/mongodb", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/vars/platform-release-6.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8d555b919e7c1382a296b9adf7b99412c5a0047d4726d94e201278d444f4cd91", + "format": 1 + }, + { + "name": "roles/mongodb/vars/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cb1f9317c7684f2eadc96d662d2cc0359b75845faee56cf2f8109676faf90117", + "format": 1 + }, + { + "name": "roles/mongodb/vars/platform-release-undefined.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d53f44d27dd55072fef00547cae05e05eae3e451a07833581bda12b9875b10c7", + "format": 1 + }, + { + "name": "roles/mongodb/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/tasks/enable-thp.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8451baee246939630364419d9dffabe7bbed34c81c78eaee97594de2774b7a60", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/download-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cc588707065c56e4955fb5a573fc2be9d2d54f62342fdb6e6387846e11aa75f4", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/install-python.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "65ee7f32763b835b62e4e8b980e8c6374809e0e4b9daf420756ef58a91c5ec7c", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/disable-thp.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "65833b4d1ece9690bac8a484bb8b0465dd2cbab2107b3fdb2260419376c3fb82", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/preflight.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2f4898da7f8984fbf452502dce2fd940faee4c309a6167c723f014510801e4aa", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/configure-mongodb-tls.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6ee7682dd119e2bb7dcc9efeb4279b6701409396c83921b587d5e7c1a6df268e", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/update-release-file.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e1d0147c6fd4e6e6bd1b93aad38495a08aea6b7e86b215e40d6ce583e8fbd822", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/install-mongodb-online.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "88ec4a6497ee8ff2b7dbdd5f6ea18993f6a7be8665013886f20c420dd2d4b35f", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/adjust-kernel-params.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3f8b9647e382108f1511558c3604beccfe2f263ecbfd0e9bb06cfacf85bf9a85", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/configure-selinux.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c3d8d601acdea23b0468134ef233b2d2379e0a41defc4e5a6b637acf6fcbe704", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/install-mongodb-offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0418b2a3ef4b078e22980f5ec3b51e43f6280cac35db193bedaa3f6f0550ed3e", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/configure-mongodb-auth.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a9a789547fbd25e722883fe6b277850a3d3971a40144de057308989223fb3ec0", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/configure-mongodb-logrotate.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b73cd04cb5ce268537940e6e2a6974d30764cfbc3065bf7a11212770fb468a40", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/configure-mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "50b10343a60431c85857f27cd08b20fb52de20cfa0a8876a72c58f47666b59a0", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/install-mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1c12cc8294ed05a4a327a1a27aa339c07291b527e39e6e65400d2545346c4b33", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/download-packages-python.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4fe40a5be8bfff9ebcc0facbfa0e8a7b483576ab8978999edb4771d1b9deb3a7", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fac7eeda737dfbe2bd69789121240f5aaf464e7ee9720dc0a190a413bb66e993", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/configure-mongodb-replicaset.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fee8f4e4f874f78301bf9e6eb9ee0116dbd2c8f8ae696c2c3f198fcb5e208bc3", + "format": 1 + }, + { + "name": "roles/mongodb/tasks/validate-vars.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6fb64c97be12f49299d1652ba6ba566f700eac6cc91931b495dd2e8a0e491b8a", + "format": 1 + }, + { + "name": "roles/mongodb/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/mongodb/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/defaults/main/pki.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e51616995f5c33d3b32b5155dfb9cdea917208cb386cf2f10a8fe0c6975ab430", + "format": 1 + }, + { + "name": "roles/mongodb/defaults/main/mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "517d99ef84cb9abccfac18dea44d42f73e81e05d98ceea372ccc108e4098c9b6", + "format": 1 + }, + { + "name": "roles/mongodb/defaults/main/kernel_params.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4839596f52782ab2fe201231d021308c6122959bb1b45c8183cb29ec01470e21", + "format": 1 + }, + { + "name": "roles/mongodb/defaults/main/offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e4217751a2851ddbffa8b0640a24d00be0b415531e7797728244393f24bdf2fc", + "format": 1 + }, + { + "name": "roles/mongodb/defaults/main/install.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0331231d92f6fcf88be17acfa1cc8b6c2b4ea6ea40f22058c712bd635922f1cb", + "format": 1 + }, + { + "name": "roles/mongodb/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/files/itential_mongodb_sysctl_fs.te", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7008e8bae002b0aa9d236d0a265872d5f72eb501111d20d627a73ab943fcc298", + "format": 1 + }, + { + "name": "roles/mongodb/files/itential_mongodb_proc_net.te", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2610b89852ccc165fa218538499889f46d811964fe7da8f671e6630faa458f02", + "format": 1 + }, + { + "name": "roles/mongodb/files/itential_mongodb_var_lib_nfs.te", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4a90201c65019909e898bc1b558961fa715eca5077a5bcb982cdae967aec7144", + "format": 1 + }, + { + "name": "roles/mongodb/files/itential_mongodb_sysctl_net.te", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4a15125c01d13c410c04bbc072852d99ce624eab2ee719500f4ee1d2beb66830", + "format": 1 + }, + { + "name": "roles/mongodb/files/itential_mongodb_cgroup_memory.te", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a972733f18132f1fa24d373be29c05ff8af2b35a24b93ad75bc382f44457facb", + "format": 1 + }, + { + "name": "roles/mongodb/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/templates/mongod.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "401397dd6bb76ac666e28100ddf3d66ea502a2879986a6dfe0c5b655d9f6eabf", + "format": 1 + }, + { + "name": "roles/mongodb/templates/mongodb.preflight.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4b8fdabaa616142b91049d4b5ca9bf0712d2bad4cd421eea2ac5be78a9202383", + "format": 1 + }, + { + "name": "roles/mongodb/templates/tuned.conf.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c9ae1e1405bd6b8b7509dea2af4051bded7d185da5d19e2fadc8c900b21e9d56", + "format": 1 + }, + { + "name": "roles/mongodb/templates/mongod.logrotate.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c5b59ecb5bbbd52eee88343d9f7e9594dc869ff3d4bcb5faf3343215213fb7a8", + "format": 1 + }, + { + "name": "roles/mongodb/templates/thp.service.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8dfca17b3dec0c77fc23672b6d84ed254968e397039fe1f1dbb508e70bf01d9a", + "format": 1 + }, + { + "name": "roles/mongodb/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/mongodb/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7a50fe896692153e22a0a4f0747d7ea0c2db80b95f6133cd792c6aaede676736", + "format": 1 + }, + { + "name": "roles/common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/common/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/common/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/common/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/common/defaults/main/offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "975662a29637d1aab1a600a6f156044ddab9eadf8400cc38276b5fd7488b5d5e", + "format": 1 + }, + { + "name": "roles/common/defaults/main/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5ab5c30682740701e002f16ded73035b648a9d7eb8a5a2d9f098b2275e360acc", + "format": 1 + }, + { + "name": "roles/common_vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/common_vars/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/common_vars/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/common_vars/defaults/main/preflight.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1a9dc57e2266405da44c2001401ece6b5604588b42278bfab8fdbf0172b92a0e", + "format": 1 + }, + { + "name": "roles/os", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/os/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/os/vars/release-8.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9931d83ae6ec0aaa1a440bc48218451e14d4a1b66fdd61a07e882dac563198e3", + "format": 1 + }, + { + "name": "roles/os/vars/release-9.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9931d83ae6ec0aaa1a440bc48218451e14d4a1b66fdd61a07e882dac563198e3", + "format": 1 + }, + { + "name": "roles/os/vars/release-undefined.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d9ce9386170bf5a3f842b41a75e0ba635737a60ddaf1e281ec4bf6ff37b0caf0", + "format": 1 + }, + { + "name": "roles/os/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/os/tasks/redhat.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8ded4037016033c920e4da7f8e2d28ca8e282be500d9ee1d77f2aab46f93da08", + "format": 1 + }, + { + "name": "roles/os/tasks/download-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0d91752e100269344dd1d55028f1c2f00511e0a9eadc3705eb99f593b1e6d31f", + "format": 1 + }, + { + "name": "roles/os/tasks/redhat-offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "aa220115e38c6a1733316b4e2af29b163c2f6eec528c6bf87a3b24cfaf3615db", + "format": 1 + }, + { + "name": "roles/os/tasks/redhat-online.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d4d1207beae594c3b9e733ec7b47f166ba4d26bb71fb05a5b6059a84ce1f8f91", + "format": 1 + }, + { + "name": "roles/os/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6029acf3e73af1f36684c418ffc1ea80381f40051d7cb3fa733e0592fe0ff91e", + "format": 1 + }, + { + "name": "roles/os/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/os/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/os/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/os/defaults/main/offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7ef729cee1dce4b1d117011d855c468a50879846db967b85e2d85ce20ff15874", + "format": 1 + }, + { + "name": "roles/prometheus", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/prometheus/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/prometheus/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c83493b648644214fec046e96cac8e9ae34f73c36b4c361db4a18f96dba72e8f", + "format": 1 + }, + { + "name": "roles/prometheus/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/prometheus/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/prometheus/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7067cf576dcd35931a3b255a8b0579d6fd3c9ddbe3066998f82cf7c385b4ff97", + "format": 1 + }, + { + "name": "roles/prometheus/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/prometheus/templates/scrape_configs.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "64e8bbf3b3b65ea2393eb65edd7da0416a304788e198db225b5548d20e1f1cce", + "format": 1 + }, + { + "name": "roles/prometheus/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/prometheus/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7c7993ff85e7a20574fb3c0c771462c5be3ca308f72ab161d2184890a7007893", + "format": 1 + }, + { + "name": "roles/selinux", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/selinux/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/selinux/tasks/configure-context.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e4a4263c476a2e6d34f815d792e739eba49239e968c28adbbcd2e1fc26568273", + "format": 1 + }, + { + "name": "roles/selinux/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "02042bc2672cae9370ff1c335a087ea72aadc54a2a45bfa07dd8cb0d48143c97", + "format": 1 + }, + { + "name": "roles/selinux/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/offline", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/offline/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/offline/tasks/install-rpms.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7111207d1192a2f1b460de6ac4216e4023d2861539b21861d8bc17300a74693c", + "format": 1 + }, + { + "name": "roles/offline/tasks/download-rpms.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5903897df1f00356cd90e5a0501f0f33dd3fc538c4cf5264e471b680312f950a", + "format": 1 + }, + { + "name": "roles/offline/tasks/install-wheels-archives.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dad68bd8bcc6f80edb9ea4c983b9f7dee27c5c2b18f3ffb6b74cb63981c8a7bb", + "format": 1 + }, + { + "name": "roles/offline/tasks/fetch-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "453175c97ad826fd75ff8cc424268f895707287cfa60a39f3c0891be2385442b", + "format": 1 + }, + { + "name": "roles/offline/tasks/download-adapter.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3963a1c1f1eccd6377f9fbf5199893f08420ee883c639577e57fb0b88b4b4f75", + "format": 1 + }, + { + "name": "roles/offline/tasks/install-adapter.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b95e1926cb190c86bccb3bcf350a976a23ecd0528ae3b8e568925c698fbf212f", + "format": 1 + }, + { + "name": "roles/offline/tasks/install-wheels-archive.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3bae552cdf7af8aaaeb17d7a0ba259af9a6ac4b170324932318f8a586f5aa460", + "format": 1 + }, + { + "name": "roles/offline/tasks/download-wheels.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "37b16a857b4aede253f81cd7f5b6500eebcfa7a2e52f052ee4f29807c8b93530", + "format": 1 + }, + { + "name": "roles/offline/tasks/download-adapters.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e16cd4921076c1b7b72d7614b34b73fd764ad7e8674bf087e083b813d8cf1ff3", + "format": 1 + }, + { + "name": "roles/offline/tasks/install-wheels.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e7564200e81e53a7f72a22475695864a35f79f8aab92504017571d04dbe5206b", + "format": 1 + }, + { + "name": "roles/offline/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/gateway", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/vars/gateway-release-4.3.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ec9603b5ebc5beffddb7d06322f27ad4e21cc2c918a6fb5a49087a335f97c9e0", + "format": 1 + }, + { + "name": "roles/gateway/vars/gateway-release-4.2.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a5a7a1c04a9809d8da3e2c783fc72f7e023f8d3dd55b8f4e9286642ffbcac346", + "format": 1 + }, + { + "name": "roles/gateway/vars/release-undefined.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "75ae12645ef3795ec11097d8a154180869eb3bab87bed577baaf1ff5bbae02af", + "format": 1 + }, + { + "name": "roles/gateway/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-packages.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "447c726ebae68a12742eddaa603ddda68ccaf5df4d2bb827d0f5c9ad3f655037", + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-python-rpms.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1401e152479ef8e3dbf90d3072ddc00fdf3e6f75a99123583903d341e3049ed3", + "format": 1 + }, + { + "name": "roles/gateway/tasks/install-python.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "505a2eebe7560495457329a758c30d4edf212f772f90871e0943b215f04e8946", + "format": 1 + }, + { + "name": "roles/gateway/tasks/install-python-dependencies.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "617e2ab5dd0a827219c21c49f38256b8bd4791124b7c2213397500e323c9f034", + "format": 1 + }, + { + "name": "roles/gateway/tasks/upgrade-gateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3e7c4e85cd4a4f802e91c151fb3c17122f7693ef8799a4a412f15bef3fe654e8", + "format": 1 + }, + { + "name": "roles/gateway/tasks/preflight.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "030c265c4a87f5062ba6c7bace6cc8ed7c9c40694379e5410d8d3091ec0c97a8", + "format": 1 + }, + { + "name": "roles/gateway/tasks/copy-certs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0aee98cd4d7f4225cb62aa24cf7f98baa3acc100875417c9ced04b33ca872c76", + "format": 1 + }, + { + "name": "roles/gateway/tasks/configure-gateway-https.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "83855299325e23c81f7691be3d8a11dd0d12a2aef4656bcc477661a1760c4340", + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-build-rpms.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e7dc9e0958c36d023ad388bd5d83e6ec4a3acee1c77317debef7e0b6c260a198", + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-dependency-rpms.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4567c43c19492962fd884ee225f6ccf7336aea903ecfb044e553c3d3c14bdada", + "format": 1 + }, + { + "name": "roles/gateway/tasks/update-release-file.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4e4357f97cc755b7a11722ae9807eae21c865e2f7264c8ae8b0ca6ca1836a725", + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-dependency-wheels.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f09328e46512bc96a17c546c59aee5f7794739076196e200c9f82759346c0160", + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-gateway-wheel.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "05a76c6ad4291b5eede374615ed341dc3a6a19d82c8c0f10e5cfb0ed81b166a7", + "format": 1 + }, + { + "name": "roles/gateway/tasks/create-gateway-archive.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3a54d30a7244321e27921565e4e00ef4ec7d978ab0cd36b233b81babae70ff19", + "format": 1 + }, + { + "name": "roles/gateway/tasks/download-ansible-collections.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4891a21a56385d999c768e68458ea5e5f88c4cf5cb9b9e810102005e61b001bf", + "format": 1 + }, + { + "name": "roles/gateway/tasks/install-ansible-collections-offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3b18d60b328350a28c9786b1b8118212f45467c6db115a9136cbd5c103b91159", + "format": 1 + }, + { + "name": "roles/gateway/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0929c8a406ff9dda70c130c3517be69b768a7b1146bcdb6401043bafba38c468", + "format": 1 + }, + { + "name": "roles/gateway/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "roles/gateway/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/defaults/main", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/defaults/main/pki.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c0bbff2b8894a508ae9712cd1061fb6cb6d8ccf11cff148887eb4fd242e469ba", + "format": 1 + }, + { + "name": "roles/gateway/defaults/main/gateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31c629f2b97dd10860defbe4cfbc599fc5126aeefe5310370abbf7b184a1a020", + "format": 1 + }, + { + "name": "roles/gateway/defaults/main/offline.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fdd9b989fc63390d4bbec58b707b3a45ea0b07e245c994602fa89c7a36acae11", + "format": 1 + }, + { + "name": "roles/gateway/files", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/files/scripts", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/files/scripts/verify-iag-environment.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "96cfbfcfb348a5ed013b975a3d8769d9a53f2454029b83b989e83f125b90db91", + "format": 1 + }, + { + "name": "roles/gateway/templates", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/templates/gateway.preflight.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3e950e140e2c771e30e301e295ddeb221bc10f1d23a090677bb3120bd47bb388", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.4.3.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1f989d7cf60f9630a3edd1e7f0e1f18ed83732b8fd730b70999dae67c6616a8f", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.2023.3.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a22b829a8c6bd32e3f9f885e11e2bec2d01defa86df19ff0cc5f6bc4e8427237", + "format": 1 + }, + { + "name": "roles/gateway/templates/ansible.cfg.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f3966e2dbe04d87575acb69a93e5532e29ea5da17edb9fa2e15574d6071fb823", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.2021.2.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f58f5ceddbbc66bb2407633e9615e45e31975e2dbb3278e679b916ba1286507d", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.2022.1.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6bdf0d02f52e691faeb0513b85bc57c2f1b1ce4efc7615d644ebcfbd89aa76d8", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.2023.1.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "373b132cfaa617c65bd65830e298d415515d5c8578504c82c0cedd3e34d5d01c", + "format": 1 + }, + { + "name": "roles/gateway/templates/nornir.config.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b8c720fae6dbbf100b5723fdfb32d61fde75ba1f0d1d4314f9d3ae074eb6ed20", + "format": 1 + }, + { + "name": "roles/gateway/templates/automation-gateway.service.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1e1e61c75890a627460bfb400c97769c24b58ff0daeb42c1f978e2d37dc2375f", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.4.2.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a22b829a8c6bd32e3f9f885e11e2bec2d01defa86df19ff0cc5f6bc4e8427237", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.2021.1.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "482e2eddbeef1ea5ac5d9a2c29b134ed272ef6b3d72ed1225b53ab72fee3aef0", + "format": 1 + }, + { + "name": "roles/gateway/templates/properties.2023.2.yml.j2", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "914e24c9c23e173ddb439716b967617f49c867e4191a5e22223631e9afe198a6", + "format": 1 + }, + { + "name": "roles/gateway/handlers", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/gateway/handlers/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e615f962d68c4ce89a8cd45748a1325c29a6431a085da502da4138e474e81486", + "format": 1 + }, + { + "name": "roles/preflight", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/preflight/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/preflight/vars/prod.specs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9da2176e85f0191abc600a02bea46c707ef43790c68f187424ee475f071992f9", + "format": 1 + }, + { + "name": "roles/preflight/vars/undefined.specs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "adc78c0aacdd838786450d91a1ae998ed4d0f432d4a39f765290e2e58c426b16", + "format": 1 + }, + { + "name": "roles/preflight/vars/dev.specs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ff8346a685bebc163ac63a7477a6cece22eba388e015525d2871114c476818a0", + "format": 1 + }, + { + "name": "roles/preflight/vars/staging.specs.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eaec7b09cbe871b66637942a43cbd6e8dfa051ac20dfb183a75f2654af55aacf", + "format": 1 + }, + { + "name": "roles/preflight/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/preflight/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "90cac4cc05d5a0c5738b1c861cc1d855eea97641fd072ea2f97c3da67f2c6223", + "format": 1 + }, + { + "name": "roles/preflight/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "playbooks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "playbooks/os.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "458eacd7a0214e2fed7700020e960f655080ab1490a094af065a2cb2184cd124", + "format": 1 + }, + { + "name": "playbooks/gateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4bba6a00f67b889656f6fdc250e25865de0dc51ac644091daf3734c4d8908826", + "format": 1 + }, + { + "name": "playbooks/preflight_redis.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7db720be95f8e79a0bac6ed83c0d2c3681866b5b4466f82b613ad12a8b8c1e0e", + "format": 1 + }, + { + "name": "playbooks/prometheus_site.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3ce532cfab5a9d9347d3862469f5f0ab67ce421e14b19048a5a4cb7e2ac0efcf", + "format": 1 + }, + { + "name": "playbooks/nginx_install.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "eac46dbc51dc3b924bcc5f13d22d7e1c4a79529c7e4bb24aeeeaacd85f9a5097", + "format": 1 + }, + { + "name": "playbooks/preflight.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c95c3d3ae35f29f13da09d6237302ebab98832f078a0aab9ee22a98aaa570d85", + "format": 1 + }, + { + "name": "playbooks/mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1a6987134fc56830e8de28248b27b7153b99d76f73bac692a9e90218d55edeaa", + "format": 1 + }, + { + "name": "playbooks/platform_site.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "934dbba693b99a04f7b8b41de0379364028d9dd1a4057182a043d9ea5d701c9a", + "format": 1 + }, + { + "name": "playbooks/site.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "17536fa0b37acfefa8b901f92f9e3bddb893a063213625e974cf008aa93db9aa", + "format": 1 + }, + { + "name": "playbooks/download_packages_site.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "163ae715be992a2140189b3a1fd6c7d59ae9c2e2eb44bfbd2a24d24018c42d1c", + "format": 1 + }, + { + "name": "playbooks/download_packages_gateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3c7814989e302fd3ad66850ad55c90cd705003f443de37d60de5ff28ab10afe9", + "format": 1 + }, + { + "name": "playbooks/grafana.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "14bcd605dea54aa893ea224b1113fb94a74012002aacc673e5292889eaab5f72", + "format": 1 + }, + { + "name": "playbooks/nginx.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fb255e73994871a1b4ed3b66f8116bdf70d19dbe595098f7cb17f8c66133019b", + "format": 1 + }, + { + "name": "playbooks/prometheus_exporters.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e8848f892d88ab131db3078c7805edd1dc4aa895f05866390052f8f2494bc198", + "format": 1 + }, + { + "name": "playbooks/redis.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0b5897e59345ca394cf18ade7c2f067e3828677004f51ec9f933f5431acfa073", + "format": 1 + }, + { + "name": "playbooks/download_packages_mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c8e76dc38c5fc364f645581e5998a7b9d0122946ad234add10b443d2fdbe8708", + "format": 1 + }, + { + "name": "playbooks/patch_platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "964b567f21dc8bddf01c3555bad0026b91c4fe222cf471bc52d18fa1e5dadc1f", + "format": 1 + }, + { + "name": "playbooks/download_packages_os.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2fc5a90dbca85bfdd7eb435153065a178907e64929ba3aae6edb49bf7c0f5ede", + "format": 1 + }, + { + "name": "playbooks/download_packages_platform_site.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0e7a4fa771d07f62ac5e8c7e5367f9b0ea585512ac8f92a521a54f4b77f15e2e", + "format": 1 + }, + { + "name": "playbooks/platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "15fd2a055a625a16bfed929a4f335c3c6e4e33a8c37f04a0dcd57a33b51909b5", + "format": 1 + }, + { + "name": "playbooks/download_packages_gateway_site.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "875e64f5f5cc00b2d8e4c4dce101c5f0eca8bb8b83bef9c7bdd544a3a1689d31", + "format": 1 + }, + { + "name": "playbooks/preflight_platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d89454a96fb4bbfbf6c69ae8d6ed667356bca997cab5494e9fd118c75b9df3db", + "format": 1 + }, + { + "name": "playbooks/download_packages_platform.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0d03878e63171d94e7da629b27e6274ca86a51111761d88386509ac20a35e3d4", + "format": 1 + }, + { + "name": "playbooks/nginx_configure.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7bc516ad3b9f0db8ef44d4448d8f762301f7ee614cf392f5f49a165a36b51350", + "format": 1 + }, + { + "name": "playbooks/preflight_mongodb.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6a1e1d22d1d1a3fbb17772e5b1c6e11d3f4a657ba46fcd59ea7302a7e8f45300", + "format": 1 + }, + { + "name": "playbooks/prometheus.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "18ac9d2bf8b723736aa1d37261920af39499296f5c2f4c81694fb308241db39e", + "format": 1 + }, + { + "name": "playbooks/install.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2c32772d185275a405ea46071f148e93b14b79f98e7cf7124a04e299d114ca6a", + "format": 1 + }, + { + "name": "playbooks/download_packages_redis.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3c5dc18da16755ce1b5eaf02d14c76af38643ce2d6d97bfb2e7d9671fec410ca", + "format": 1 + }, + { + "name": "playbooks/patch_gateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "86a78afb1e701cbe950c0a27c9d5f18d18c8a45304ec5fffd0ca65c29f943627", + "format": 1 + }, + { + "name": "playbooks/preflight_gateway.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f84f42eba279215c1a9a77494f33fc77de38280e777c964d2412d10f6de7fc58", + "format": 1 + }, + { + "name": "docs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "docs/preflight_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d1ad563ada0905bd559edb6362a8875166ebc8725e35d849c8d246e3b49ab8b9", + "format": 1 + }, + { + "name": "docs/itential_platform_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6a23adbdef1a3aec71400d4f6749df633f5bd6d26c12d765ce03b485637dcdbd", + "format": 1 + }, + { + "name": "docs/redis_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "07d571b8c7f813c8260f909b2ee64b73722a916794763345250f31856867bac5", + "format": 1 + }, + { + "name": "docs/mongodb_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e551ce03a3bd85b8a45284875fef6cad7c433ee01058c1cd3589cda123b86956", + "format": 1 + }, + { + "name": "docs/nginx.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e9e9dabec3c2d580c9b510d69fd99360f5002a0233590a43c2ebef3e2ab893f0", + "format": 1 + }, + { + "name": "docs/tls_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "17d058a85ba0b609f8076b1eb64edbf0a79d8d4d2dbd3f2516c725ed328fb8b7", + "format": 1 + }, + { + "name": "docs/offline_install_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "af6cc35caf240bf0ecf2194ee0e45722f3fa5608dbbf18400944295bef2dbd3b", + "format": 1 + }, + { + "name": "docs/prometheus_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8d067031627870fd0aea3931432f617a3f5b2ca4c9678a3e469a6d4d29c0dff4", + "format": 1 + }, + { + "name": "docs/itential_gateway_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c82f7c0773880afd6716f633a4da61ecde5587ff0e29e1df8f862fb23b12e104", + "format": 1 + }, + { + "name": "docs/patch_itential_platform_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecd3728d0563965f70c51527e2ce43b8dd35a19439dd5829c44402614c3dcd6d", + "format": 1 + }, + { + "name": "docs/patch_itential_gateway_guide.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "92f8d617c342d390bac98fc77ee5ef49453e1c184367f498d0b7e1b980bd0295", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ad52de6e1fd31a9744d7550770e4698cd6b3b60c93cbd037540b1ee623f98a2", + "format": 1 + }, + { + "name": "CONTRIBUTING.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "711853c1364c32eb9f4a1545dadb179076e681e35b8ad893ada1a7e9afb051a4", + "format": 1 + }, + { + "name": ".ansible", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".ansible/.lock", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": ".ansible/roles", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".ansible/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".ansible/collections", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".ansible/collections/ansible_collections", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".ansible/collections/ansible_collections/itential", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "requirements.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b474c8535d285b70071a15aebde7416bce5fc5a4952ee84c50f22ff4b1799e56", + "format": 1 + } + ], + "format": 1 +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/LICENSE b/.ansible/collections/ansible_collections/itential/deployer/LICENSE new file mode 100644 index 00000000..855433e2 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/LICENSE @@ -0,0 +1,621 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/MANIFEST.json b/.ansible/collections/ansible_collections/itential/deployer/MANIFEST.json new file mode 100644 index 00000000..153ec851 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/MANIFEST.json @@ -0,0 +1,42 @@ +{ + "collection_info": { + "namespace": "itential", + "name": "deployer", + "version": "3.7.1", + "authors": [ + "Steven Schattenberg ", + "Travis Nicks ", + "Kevin Velarde ", + "Peter Sprygada ", + "Nick Andreano ", + "Marcos Dias ", + "Hamza Qadri " + ], + "readme": "README.md", + "tags": [ + "tools", + "itential", + "deployer" + ], + "description": "Ansible collection that handles deploying Itential Platform and Automation Gateway", + "license": [], + "license_file": "LICENSE", + "dependencies": { + "ansible.posix": ">=0.0.1", + "community.general": "<12.0.0", + "community.mongodb": ">=0.0.1" + }, + "repository": "https://github.com/itential/deployer", + "documentation": "https://github.com/itential/deployer/blob/main/README.md", + "homepage": "https://galaxy.ansible.com/ui/repo/published/itential/deployer/", + "issues": "https://github.com/itential/deployer/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5c399892a4cb469ca66309270cf4d89e58b6cbacd82aeaaa5b72f7bba35dac97", + "format": 1 + }, + "format": 1 +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/README.md b/.ansible/collections/ansible_collections/itential/deployer/README.md new file mode 100644 index 00000000..ba9b809b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/README.md @@ -0,0 +1,1080 @@ +# Ansible Collection - itential.deployer + +## Table of contents + +1. [Overview](#overview) +2. [Supported Architectures](#supported-architectures) + 1. [All-in-one Architecture](#all-in-one-architecture) + 2. [Minimal Architecture](#minimal-architecture) + 3. [Highly Available Architecture](#highly-available-architecture) + 4. [Active/Standby Architecture](#activestandby-architecture) +3. [Deployer Prerequisites](#deployer-prerequisites) + 1. [Required Python, Ansible, and Ansible modules](#required-python-ansible-and-ansible-modules) + 2. [Required Public Repositories](#required-public-repositories) + 3. [Ports and Networking](#ports-and-networking) + 4. [Certificates](#certificates) + 5. [Passwords](#passwords) + 6. [Obtaining the Itential Binaries](#obtaining-the-itential-binaries) +4. [Installing and Upgrading the Deployer](#installing-and-upgrading-the-deployer) + 1. [Online Installation](#online-installation) + 2. [Offline Installation](#offline-installation) +5. [Running the Deployer](#running-the-deployer) + 1. [Confirm Requirements](#confirm-requirements) + 2. [Determine the Working and Deployer Directories](#determine-the-working-and-deployer-directories) + 3. [Create the Inventories Directory](#create-the-inventories-directory) + 4. [Download Installation Artifacts](#download-installation-artifacts) + 5. [Copy Installation Artifacts into the Files Directory](#copy-installation-artifacts-into-the-files-directory) + 6. [Create a Symlink to the Files Directory](#create-a-symlink-to-the-files-directory) + 7. [Create the Inventory File](#create-the-inventory-file) + 8. [Run the Itential Deployer](#run-the-itential-deployer) + 9. [Confirm Successful Installation](#confirm-successful-installation) +6. [Sample Inventories](#sample-inventories) + 1. [All-in-one Architecture Inventory](#all-in-one-architecture-inventory) + 2. [Minimal Architecture Inventory](#minimal-architecture-inventory) + 3. [Highly Available Architecture Inventory](#highly-available-architecture-inventory) + 4. [Active/Standby Architecture Inventory](#activestandby-architecture-inventory) +7. [Component Guides](#component-guides) + 1. [MongoDB](#mongodb) + 2. [Redis](#redis) + 3. [Hashicorp Vault](#hashicorp-vault) + 4. [Itential Platform](#itential-platform) + 5. [Itential Gateway](#itential-gateway) + 6. [Prometheus and Grafana](#prometheus-and-grafana) +8. [Patching Itential Platform and IAG](#patching-itential-platform-and-iag) +9. [Using Internal YUM Repositories](#using-internal-yum-repositories) +10. [Running the Deployer in Offline Mode](#running-the-deployer-in-offline-mode) +11. [Appendix A: Definition of "Highly Available" Dependencies](#appendix-a-definition-of-highly-available-dependencies) + +## Overview + +An Itential environment is composed of several applications working in conjunction with one another. +At its most basic, the following must be installed. + +- Itential Platform +- Itential Automation Gateway (IAG) +- Redis +- MongoDB + +Optionally, one can include Hashicorp Vault for secrets management, and Prometheus & Grafana for +metrics analysis and alerting. + +In many environments, these applications are installed across multiple systems to improve resiliency +and performance. To assist users with such installations, Itential provides the **Itential +Deployer**. + +The Itential deployer can deploy supported Itential architectures. + +## Supported Architectures + +- All-in-one Architecture +- Minimal Architecture +- Highly Available Architecture +- Active/Standby Architecture +- Blue Green Architecture + +### All-in-one Architecture + +The All-In-One architecture is an architecture where all components are installed on the same +instance. This architecture lends itself well to development environments and “throw away” +environments like those found in a CI/CD pipeline. Security considerations are non-existent +or use simple default passwords as the emphasis is placed on simplicity. + +### Minimal Architecture + +A Minimal Architecture is an architecture where all or most components are single instances and can +not gracefully tolerate failures. This architecture lends itself well to development environments. +It favors the engineer with its simplicity and enables them to do their work with few restrictions. +Security considerations should lean towards openness and ease of use but at the same time capture +the spirit of the other higher environments. In this architecture, each of the required Itential +components is a single instance. This architecture will exercise the network connectivity between +the components and can be advantageous to deploy as a development environment. + +The ideal minimal architecture will have 4 VM's with each hosting a single instance of the required +components. An acceptable variation is to have 1 VM with everything hosted on it. The number of +VM's and what is hosted where is less of a concern with the MA because the intent is simplicity and +to enable engineers to build automations and not be a highly-available environment. + +Itential recommends applying security principles to ALL environments. In the MA, this would include +configuring all components to use authentication. Optionally, we recommend using SSL when +communicating with components on other VMs but recognize that this should be enabled at the +discretion of the customer. + +### Highly Available Architecture + +A Highly Available Architecture is an architecture where all or most components are redundant and +can gracefully tolerate at least 1 catastrophic failure. This architecture is the recommended +architecture for testing environments and simple production environments. The intent is to provide +an environment that is as close to production as possible so that testing automations can provide +confidence and expose potential problems sooner in the development lifecycle. Security +considerations should mimic production requirements. In this architecture, each of the required +Itential components are installed in clusters to provide stability, mimic production, and expose any +issues with the clustering of the components. This could also serve as a production architecture. + +The ideal HA2 environment will have 9 VMs: + +- 2 VMs hosting Itential Platform. +- 3 VMs hosting MongoDB configured as a replica set. +- 3 VMs hosting Redis configured as a highly available replica set using Redis Sentinel. +- 1 VM hosting IAG. + +Itential recommends applying sound security principles to ALL environments. This would include +configuring all components to use authentication within the HA2. Additionally, we recommend using +SSL when communicating with components on other VMs and across clusters. + +### Active/Standby Architecture + +An Active/Standby Architecture (ASA) is an architecture (that is normally used for making HA2 +architectures redundant) reserved for production environments where Disaster Recovery is required. +It is not required that they be geographically redundant but they could be. The intent is to +provide a standby environment that can be used in the event of a disaster on the active stack. The +standby stack should be preconfigured to be quickly made into the active stack. Care needs to be +taken that the same level of access to 3rd party systems existing in the standby stack matches +those in the active stack. Security must be taken into account if this is used as a production +environment. + +The ideal ASA architecture will appear as two HA2 stacks except for MongoDB. One or more of the +MongoDB instances must be hosted in the standby location as a replica of the primary. Ideally, the +MongoDB cluster will consist of 5 members: 4 data-bearing members and a MongoDB arbiter. This will +allow for a cluster of three mongos in the worst-case disaster scenario. + +Itential recommends applying sound security principles to ALL environments. In the ASA, this would +include configuring all components to use authentication and use SSL when communicating with +components on other VMs and across clusters. + +### Alternative Architectures + +Its not unusual to "outsource" the management of the dependencies (Redis and MongoDB) to +either other internal teams or to external vendors such as AWS. Itential provides a way to leverage +these solutions simply by configuring them accordingly and as long as these solutions comply with +the basic requirements. For example, if Elasticache is chosen to fulfill the Redis needs then it +must use the "Redis" version and not "Memcache". Likewise for MongoDB, Mongo Atlas is supported but +not DynamoDB which is not the same. See the examples for how to implement. + +## Deployer Prerequisites + +The Itential Deployer is an Ansible project and as such requires running on a control node. That +node has its own set of dependencies. + +### Control Node Specifications + +Itential recommends using a dedicated node running the requirements listed below as the ansible +control node for the deployer project. That node should meet or exceed the following specifications: + +| Component | Value | +|-----------|----------------------| +| OS | RHEL8/9 or Rocky 8/9 | +| RAM | 4 GB | +| CPUs | 2 | +| Disk | 20 GB | + +### Required Python, Ansible, and Ansible modules + +The **Ansible Control Node** must have the following installed: + +- **Python** + - python >= 3.9 + +- **Python Modules** + - jmespath + +- **Ansible** + - ansible-core >= 2.11, < 2.17 + - ansible: >=9.x.x + +To see which Ansible version is currently installed, execute the `ansible --version` command as shown below. + +#### Example: Confirming Ansible Version + + ```bash + $ ansible --version + ansible [core 2.12.2] + config file = None + configured module search path = ['/var/home/yourname/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] + ansible python module location = /usr/local/lib/python3.9/site-packages/ansible + ansible collection location = /var/home/yourname/.ansible/collections:/usr/share/ansible/collections + executable location = /usr/local/bin/ansible + python version = 3.9.9 (main, Nov 19 2021, 00:00:00) [GCC 11.2.1 20210728 (Red Hat 11.2.1-1)] + jinja version = 3.0.3 + libyaml = True + ``` + +- **Ansible Modules**: The following ansible modules are required on the control node for the +deployer to run. + - 'ansible.posix': '>=0.0.1' + - 'community.mongodb': '>=0.0.1' + +**ⓘ Note:** +The Itential Deployer is an Ansible collection. As such, a familiarity with basic Ansible concepts +is suggested before proceeding. + +### Required Public Repositories + +On the Ansible control node, the Ansible Python module and the Itential Deployer Ansible collection +will need to be installed. + +On the target servers, the Deployer will install RPM packages using the standard YUM repositories +and Python modules using the PyPI repository. When packages are not available for the distribution, +the Deployer will either install the required repository or download the packages. + +| Component | Location | Protocol | Notes | +| :-------- | :------- | :------- | :---- | +| Ansible Control Node | | TCP | Itential and community Ansible collections | +| Ansible Control Node | | TCP | Python modules | +| Itential Gateway | | TCP | Itential packages | +| Itential Gateway | | TCP | Community Ansible collections | +| Itential Gateway | | TCP | Python modules | +| Itential Platform | | TCP | Itential packages | +| Itential Platform | | TCP | Core NPM packages | +| Itential Platform | | TCP | Python modules | +| Itential Platform | | TCP | Platform Opensource Adapters NodeJS source repository | +| MongoDB | | TCP | MongoDB YUM RPMs | +| MongoDB | | TCP | MongoDB YUM RPMs | +| MongoDB | | TCP | MongoDB YUM repository GPG Key | +| MongoDB | | TCP | MongoDB YUM repository GPG Key | +| MongoDB | | TCP | Python modules | +| Redis | | TCP | Redis YUM RPMs
When installing Redis from the Remi repository | +| Redis | | TCP | EPEL YUM RPMs
When installing Redis from the Remi repository | +| Redis | | TCP | Redis source packages
When installing Redis from source | +| Redis | | TCP | Redis source packages
When installing Redis from source | +| Vault | | TCP | Vault YUM RPMs | + +If internal YUM repositories are used, refer to the +[Using Internal YUM Repositories](#using-internal-yum-repositories) section. + +> [! WARNING] +> The Itential Deployer and the maintainers of the project can not know if any of the above URLs +> will result in a redirect. Reporitories may rely on CDNs or mirrors. If a customer is using a +> proxy or other such method to restrict access, this list may not represent the final URLs that are +> required. + +### Ports and Networking + +In a clustered environment where components are installed on more than one host, the following +network traffic flows need to be allowed. + +| Source | Destination | Port | Protocol | Description | +| ------ | ----------- | ---- | -------- | ----------- | +| Desktop Devices | Itential Platform | 3000 | TCP | Web browser connections to Itential Platform over HTTP | +| Desktop Devices | Itential Platform | 3443 | TCP | Web browser connections to Itential Platform over HTTPS | +| Desktop Devices | IAG | 8083 | TCP | Web browser connections to IAG over HTTP | +| Desktop Devices | IAG | 8443 | TCP | Web browser connections to IAG over HTTPS | +| Desktop Devices | Vault | 8200 | TCP | Web browser connections to Hashicorp Vault | +| Itential Platform | MongoDB | 27017 | TCP | Itential Platform connections to MongoDB | +| Itential Platform | Redis | 6379 | TCP | Itential Platform connections to Redis | +| Itential Platform | Redis | 26379 | TCP | Itential Platform connections to Redis Sentinel | +| Itential Platform | IAG | 8083 | TCP | Itential Platform connections to IAG over HTTP | +| Itential Platform | IAG | 8443 | TCP | Itential Platform connections to IAG over HTTPS | +| Itential Platform | Vault | 8200 | TCP | Itential Platform connections to Hashicorp Vault | +| Itential Platform | LDAP | 389 | TCP | Itential Platform connections to LDAP when LDAP adapter is used for authentication | +| Itential Platform | LDAP | 636 | TCP | Itential Platform connections to LDAP with TLS when LDAP adapter is used for authentication | +| Itential Platform | RADIUS | 1812 | UDP | Itential Platform connections to RADIUS when RADIUS adapter is used for authentication | +| MongoDB | MongoDB | 27017 | TCP | MongoDB replication | +| Redis | Redis | 6379 | TCP | Redis replication | +| Redis | Redis | 26379 | TCP | Redis Sentinel for HA | + +Notes + +- Not all ports will need to be open for every supported architecture +- Secure ports are only required when explicitly configured in the inventory + +### Certificates + +The itential deployer is not responsible for creating any SSL certificates that may be used to +further tighten security in the Itential ecosystem. However, if these certificates are provided it +can upload and configure the platform to use them. The table below describes the certificates that +can be used and what their purpose is. + +| Certificate | Description | +| :-----------| :-----------| +| Itential Platform webserver | Enables HTTPS communications with the Itential Platform webserver. | +| IAG webserver | Enables HTTPS communications with the IAG webserver. | +| MongoDB | Enables secure communications with the MongoDB server. Also used for intra-node mongo replication. | +| Redis | Enables secure communications with the Redis server. Also used for intra-node redis replication. | +| LDAP | Enables secure communications with LDAP server. | + +### Passwords + +The deployer will create several user accounts in the dependent systems. It uses default passwords +in all cases and those passwords can be overridden with the defined ansible variables. To override +these variables just define the variable in the deployer host file. + +#### MongoDB Accounts + +| User Account | Default Password | Variable Name | Description | +| :----------- | :--------------- | :------------ | :---------- | +| admin | admin | mongodb_user_admin_password | Has full root access to the mongo database. | +| itential | itential | mongodb_user_itential_password | Has read and write access to the “itential” database only. | + +#### Redis Accounts + +| User Account | Default Password | Variable Name | Description | +| :----------- | :--------------- | :------------ | :---------- | +| admin | admin | redis_user_admin_password | Has full root access to the Redis database, all channels, all keys, all commands. | +| itential | itential | redis_user_itential_password | Has full access to the Redis database, all channels, all keys, EXCEPT the following commands: asking, cluster, readonly, readwrite, bgrewriteaof, bgsave, failover, flushall, flushdb, psync, replconf, replicaof, save, shutdown, sync. | +| repluser | repluser | redis_user_repluser_password | Has access to the minimum set of commands to perform replication: psync, replconf, ping. | +| admin | sentineladmin | redis_user_sentineladmin_password | Full root access to Redis Sentinel. | +| sentineluser | sentineluser | redis_user_sentineluser_password | Has access to the minimum set of commands to perform sentinel monitoring: multi, slaveof, ping, exec, subscribe, config.rewrite, role, publish, info, client.setname, client.kill, script.kill. | + +### Obtaining the Itential Binaries + +#### SaaS + +The latest IAG whl file is available to download from hub.itential.io. + +#### On prem customers + +The Itential Platform and IAG binary files are hosted on the Itential Nexus repository. An account +is required to access Itential Nexus. If you do not have an account, contact your Itential Sales +representative. + +## Installing and Upgrading the Deployer + +### Online Installation + +The Itential Deployer can be installed via the `ansible-galaxy` utility. + +On your control node, execute the following command to install the Itential Deployer: + +```bash +ansible-galaxy collection install itential.deployer +``` + +This should also install the required ansible dependencies. When a new version of the Deployer is +available, you can upgrade using the following command: + +```bash +ansible-galaxy collection install itential.deployer --upgrade +``` + +### Offline Installation + +If your control node does not have Internet connectivity, the Itential Deployer and its +dependencies can be downloaded via another system, copied to your control node, and installed +manually. + +**ⓘ Note:** +Some of the following collections may already be installed on your control node. To verify, use the +`ansible-galaxy collection list` command. + +1. Download the following collections from the provided links: + + - [Itential Deployer](https://galaxy.ansible.com/ui/repo/published/itential/deployer/) + - [Community General](https://galaxy.ansible.com/ui/repo/published/community/general/) + - [Community MongoDB](https://galaxy.ansible.com/ui/repo/published/community/mongodb/) + - [Ansible POSIX](https://galaxy.ansible.com/ui/repo/published/ansible/posix/) + +2. Copy the downloaded collections to your control node. +3. Install the collections using the following command: + + ```bash + ansible-galaxy collection install .tar.gz + ``` + +## Running the Deployer + +Once you have have installed the Itential Deployer, run it to begin deploying Itential to your +environment. This section details a basic deployment using required variables only. + +### Confirm Requirements + +Before running the deployer we must ensure the following: + +- **Compatible OS**: Any managed nodes to be configured by the Itential Deployer must use an +operating system that is compatible with the target version of Itential Platform (and, if +applicable, IAG). For more information, refer to the [Itential Dependencies] page. +- **Hostnames**: Any hostnames used by managed nodes must be DNS-resolvable. +- **Administrative Privileges**: The `ansible` user must have administrative privileges on managed +nodes. +- **SSH Access**: The control node must have SSH connectivity to all managed nodes. + +**ⓘ Note:** +Although the Itential Deployer can be used to configure nodes that use any supported operating +system, it is optimized for RHEL 8 and 9. + +### Determine the Working and Deployer Directories + +The Itential Deployer will be installed into the user's collection directory. Because the Deployer +collection will be overwritten when it is upgraded, users should not store any inventory files, +binaries or artifacts in the Deployer collection directory. Instead, users should create a working +directory to store those files. + +The working directory can be any directory on the control node and will be referred to as the +`WORKING-DIR` in this guide. + +Determine what directory the Itential Deployer is installed to by using the `ansible-galaxy +collection list` command. In the following example, the Deployer directory is +`/Users//.ansible/collections/ansible_collections/itential/deployer`. + +#### Example: Determining the Deployer Directory + +```bash +% ansible-galaxy collection list + +# /Users//.ansible/collections/ansible_collections +Collection Version +----------------- ------- +ansible.netcommon 4.1.0 +ansible.posix 1.5.4 +ansible.utils 2.9.0 +arista.avd 3.8.2 +arista.cvp 3.6.0 +arista.eos 6.0.0 +community.general 7.3.0 +community.mongodb 1.6.1 +itential.deployer 1.0.0 +``` + +The Deployer directory will be referred to as the `DEPLOYER-DIR` in this guide. + +### Create the Inventories Directory + +The `inventories` directory should be a sub-directory of the working directory. It will contain +the hosts files. + +```bash +cd +mkdir inventories +``` + +### Determine Installation Artifacts Method + +Choose one of the following installation methods based on your requirements: + +1. **Manual Upload**: Manually download the required files onto the control node in a `files` +directory. The deployer will move these artifact files to the target nodes. +2. **Repository Download**: Provide a repository download URL with either a username/password or an +API key. The deployer will make an API request to download the files directly onto the target nodes. + +### Manual Upload + +#### Create the Files Directory + +The `files` directory should be a sub-directory of the working directory. It will contain the +Itential binaries and artifacts. + +```bash +cd +mkdir files +``` + +#### Download Installation Artifacts + +Download the Itential Platform binary along with any desired Itential Platform adapters (and, if +applicable, the IAG binary) from the [Itential Nexus Repository] to local storage. + +**ⓘ Note:** +If you are unsure which files should be downloaded for your environment, contact your Itential +Professional Services representative. + +#### Copy Installation Artifacts into the Files Directory + +Next, copy the files downloaded in the previous step to the `files` subdirectory. + +#### Example: Copying to the Files Directory + +```bash +cd /files +cp ~/Downloads/itential*.rpm . +cp ~/Downloads/automation_gateway*.whl . +``` + +#### Create a Symlink to the Files Directory + +Navigate to the playbooks directory in the Deployer directory and create a symlink to the files +directory in the working directory. + +```bash +cd /playbooks +ln -s /files . +``` + +### Repository Download + +#### Obtain the Download URL + +You can obtain the download URL from either a **Sonatype Nexus Repository** or **JFrog**. Follow +the steps below based on the repository type: + +- **For Sonatype Nexus**: Navigate to the file you wish to use and locate the **Path** parameter. +Copy the link provided in the **Path** field to obtain the download URL. +- **For JFrog**: Locate the file in the JFrog repository and copy the File URL. + +This download method supports both the Itential Platform (bin/tar/rpm) files and the IAG (whl) files. + +#### Configure Repository Credentials + +Depending on the repository you are using, you will need to provide the appropriate credentials: + +- **For Nexus**: Set the `repository_username` and `repository_password` variables. +- **For JFrog**: Set the `repository_api_key` variable. + +**ⓘ Note:** +To secure sensitive information like passwords or API keys, consider using Ansible Vault to encrypt +these variables. + +### Create the Inventory File + +Using a text editor, create an inventory file that defines your deployment environment. To do this, +assign your managed nodes to the relevant groups according to what components you would like to +install on them. In the following example: + +- All required variables have been defined. +- The managed node `example1.host.com` has been assigned to all groups, with the **exception** of +the `gateway` group. As such, all components **except** IAG will be installed on this node. +- The managed node `example2.host.com` has been assigned to the `gateway` group. As such, IAG will +be installed on this node. + +**ⓘ Note:** +Itential recommends that all inventories follow the best practices outlined in the +[Ansible documentation](https://docs.ansible.com/ansible/latest/getting_started/get_started_inventory.html). + +#### Example: Creating the Inventory File + +```bash +cd +mkdir -p inventories/dev +vi inventories/dev/hosts +``` + +
+ +#### Example: Inventory File (YAML Format) + +```yaml +all: + vars: + platform_release: 6 + + children: + redis_master: + hosts: + example1.host.com: + + mongodb: + hosts: + example1.host.com: + + platform: + hosts: + example1.host.com: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_packages: + - https://registry.aws.itential.com/repository/PLATFORM/Platform%206.0.0/itential-platform-6.0.0-1.noarch.rpm + repository_username: user.name + repository_password: !vault | + $ANSIBLE_VAULT;1.1;AES123 + 12341234123412341234123412341234123412341234123412341234123412341234123412341234 + 12341234123412341234123412341234123412341234123412341234123412341234123412341234 + 12341234123412341234123412341241234123412341234123412341234123412341234123412341 + 1234123412341324 + + gateway: + hosts: + example2.host.com: + vars: + gateway_release: 4.3 + gateway_whl_file: automation_gateway-4.3.56-py3-none-any.whl +``` + +### Run the Itential Deployer + +Navigate to the working directory and execute the following run command. + +#### Example: Running the Itential Deployer + +```bash +cd +ansible-playbook itential.deployer.site -i inventories/dev -v +``` + +### Confirm Successful Installation + +After the Itential Deployer is finished running, perform the following checks on each component to +confirm successful installation. + +#### Itential Platform and IAG + +Use a web browser to navigate to the login page of your Itential Platform/IAG servers. By default, +it is located at `http://:3000` or `http://:8083`, respectively. If the +Itential Platform/IAG login page is displayed, the installation was successful. + +If the login page is not displayed, check that the relevant service is running on the affected +server using the `sudo systemctl status itential-platform` or +`sudo systemctl status automation-gateway` command, respectively. The output should look similar to +the following examples. + +#### Example Output: Itential Platform System Status + +```bash +$ sudo systemctl status itential-platform +● itential-platform.service - Itential Automation Platform Service + Loaded: loaded (/usr/lib/systemd/system/itential-platform.service; enabled; vendor preset: disabled) + Active: active (running) since Wed 2023-02-01 15:21:45 UTC; 21h ago + Main PID: 177517 (Pronghorn core) + Tasks: 203 (limit: 23501) + Memory: 1.0G + CGroup: /system.slice/itential-platform.service + ├─177517 Pronghorn core + ├─177556 Pronghorn AGManager Application + ├─177577 Pronghorn AdminEssentials Application + ├─177588 Pronghorn AppArtifacts Application + ├─177606 Pronghorn AutomationCatalog Application + ├─177622 Pronghorn AutomationStudio Application + ├─177659 Pronghorn ConfigurationManager Application + ├─177674 Pronghorn FormBuilder Application + ├─177690 Pronghorn JsonForms Application + ├─177708 Pronghorn Jst Application + ├─177725 Pronghorn MOP Application + ├─177738 Pronghorn OperationsManager Application + ├─177758 Pronghorn Search Application + ├─177784 Pronghorn Tags Application + ├─177800 Pronghorn TemplateBuilder Application + ├─177820 Pronghorn WorkFlowEngine Application + ├─177833 Pronghorn WorkflowBuilder Application + └─177860 Pronghorn local_aaa Adapter +``` + +
+ +#### Example Output: IAG System Status + +```bash +$ sudo systemctl status automation-gateway +● automation-gateway.service - Itential Automation Gateway + Loaded: loaded (/etc/systemd/system/automation-gateway.service; enabled; vendor preset: disabled) + Active: active (running) since Tue 2023-01-17 16:48:29 UTC; 1 months 0 days ago + Main PID: 94842 (automation-gate) + Tasks: 10 (limit: 23435) + Memory: 168.8M + CGroup: /system.slice/automation-gateway.service + ├─94842 /opt/automation-gateway/venv/bin/python3 /opt/automation-gateway/venv/bin/automation-gateway --properties-file=/etc/automation-gateway/propert> + └─94844 /opt/automation-gateway/venv/bin/python3 /opt/automation-gateway/venv/bin/automation-gateway --properties-file=/etc/automation-gateway/propert> +``` + +#### MongoDB and Redis + +From the command line of each dependency server, use the `sudo systemctl status ` command +to confirm that the relevant service is running. When executing the command, replace `` +with one of the following: + +- **MongoDB**: `mongod` +- **Redis**: `redis` + +The output should look similar to the following examples. + +#### Example Output: MongoDB Status + +```bash +$ sudo systemctl status mongod +● mongod.service - MongoDB Database Server + Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; preset: disabled) + Active: active (running) since Thu 2023-06-22 04:49:56 CST; 20h ago + Docs: https://docs.mongodb.org/manual + Main PID: 54594 (mongod) + Memory: 156.7M + CPU: 46.078s + CGroup: /system.slice/mongod.service + └─54594 /usr/bin/mongod -f /etc/mongod.conf +``` + +
+ +#### Example Output: Redis Status + +```bash +$ sudo systemctl status redis +● redis.service - Redis persistent key-value database + Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; preset: disabled) + Drop-In: /etc/systemd/system/redis.service.d + └─limit.conf + Active: active (running) since Thu 2023-06-22 04:47:39 CST; 20h ago + Main PID: 15723 (redis-server) + Status: "Ready to accept connections" + Tasks: 5 (limit: 22862) + Memory: 9.7M + CPU: 13.409s + CGroup: /system.slice/redis.service + └─15723 "/usr/bin/redis-server 127.0.0.1:6379" +``` + +## Sample Inventories + +Below are simplified sample host files that describe the basic configurations to produce the +supported architectures. These are intended to be starting points only. + +### All-in-one Architecture Inventory + +Simple environment. Itential Platform and all of its dependencies all on one host. + +#### Example: All-in-one Inventory File (YAML Format) + +```yaml +all: + vars: + platform_release: 6 + + children: + redis_master: + hosts: + example1.host.com: + + mongodb: + hosts: + example1.host.com: + + platform: + hosts: + example1.host.com: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_packages: + - itential-platform-6.0.0-1.noarch.rpm + + gateway: + hosts: + example2.host.com: + vars: + gateway_release: 4.3 + gateway_whl_file: automation_gateway-4.3.56-py3-none-any.whl +``` + +### Minimal Architecture Inventory + +Similar to All-in-one but installs components on separate hosts. + +#### Example: Minimal Architecture Inventory File (YAML Format) + +```yaml +all: + vars: + platform_release: 6 + + children: + redis_master: + hosts: + redis.host.com: + + mongodb: + hosts: + mongodb.host.com: + + platform: + hosts: + itential-platform.host.com: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_packages: + - itential-platform-6.0.0-1.noarch.rpm + # MongoDB config + platform_mongo_url: mongodb://mongodb.host.com:27017/itential + # Redis config + platform_redis_host: redis.host.com + + gateway: + hosts: + automation-gateway.host.com: + vars: + gateway_release: 4.3 + gateway_whl_file: automation_gateway-4.3.56-py3-none-any.whl +``` + +### Highly Available Architecture Inventory + +Fault tolerant architecture. + +#### Example: Highly Available Architecture Inventory File (YAML Format) + +```yaml +all: + vars: + platform_release: 6 + + children: + redis_master: + hosts: + redis1.host.com: + + redis_replica: + hosts: + redis2.host.com: + redis3.host.com: + vars: + redis_replicaof: # defaults to "{{ groups['redis_master'][0] }} {{ redis_port}}" + + redis_sentinel: + hosts: + sentinel1.host.com: + sentinel2.host.com: + sentinel3.host.com: + + mongodb: + hosts: + mongodb1.host.com: + mongodb2.host.com: + mongodb3.host.com: + vars: + mongodb_replication_enabled: true + + platform: + hosts: + itential-platform1.host.com: + itential-platform2.host.com: + vars: + platform_packages: + - itential-platform-6.0.0-1.noarch.rpm + # MongoDB config + platform_mongo_url: mongodb://itential:itential@mongodb1.host.com:27017,mongodb2.host.com:27017,mongodb3.host.com:27017/itential?replicaSet=rs0 + # Redis config + platform_redis_sentinels: + - host: sentinel1.host.com + port: 26379 + - host: sentinel2.host.com + port: 26379 + - host: rsentinel3.host.com + port: 26379 + + gateway: + hosts: + automation-gateway1.host.com: + vars: + gateway_release: 4.3 + gateway_whl_file: automation_gateway-4.3.56-py3-none-any.whl +``` + +### Highly Available Architecture Inventory leveraging external dependencies + +Fault tolerant architecture using external dependencies. + +#### Example: Highly Available Architecture Inventory File using external dependencies (YAML Format) + +```yaml +all: + vars: + platform_release: 6 + children: + platform: + hosts: + itential-platform1.host.com: + itential-platform2.host.com: + vars: + platform_packages: + - itential-platform-6.0.0-1.noarch.rpm + # MongoDB config + platform_mongo_auth_enabled: true + platform_mongo_url: + # Redis config + platform_redis_host: + platform_redis_port: 6379 + platform_redis_username: itential + platform_redis_password: + # Or if connecting to Redis Sentinel + # platform_redis_sentinels: + # - host: redis1.host.com + # port: 26379 + # - host: redis2.host.com + # port: 26379 + # - host: redis3.host.com + # port: 26379 + gateway: + hosts: + automation-gateway1.host.com: + vars: + gateway_release: 4.3 + gateway_whl_file: automation_gateway-4.3.56-py3-none-any.whl +``` + +### Active/Standby Architecture Inventory + +#### Example: Active/Standby Architecture Inventory File (YAML Format) + +```yaml +all: + vars: + platform_release: 6 + + children: + redis_master: + hosts: + datacenter1.redis1.host.com: + + redis_replica: + hosts: + datacenter1.redis2.host.com: + datacenter2.redis1.host.com: + datacenter2.redis2.host.com: + vars: + redis_replicaof: # defaults to "{{ groups['redis_master'][0] }} {{ redis_port}}" + + redis_sentinel: + hosts: + datacenter1.sentinel1.host.com: + datacenter2.sentinel1.host.com: + datacenter3.sentinel1.host.com: + + mongodb: + hosts: + datacenter1.mongodb1.host.com: + datacenter1.mongodb2.host.com: + datacenter2.mongodb3.host.com: + datacenter2.mongodb4.host.com: + vars: + mongodb_replication_enabled: true + + mongodb_arbiter: + hosts: + datacenter3.mongodb-arbiter.host.com: + + platform: + hosts: + datacenter1.itential-platform1.host.com: + datacenter1.itential-platform2.host.com: + vars: + platform_packages: + - itential-platform-6.0.0-1.noarch.rpm + platform_job_worker_enabled: false + platform_task_worker_enabled: false + # MongoDB config + platform_mongo_auth_enabled: true + platform_mongo_url: mongodb://itential:itential@datacenter1.mongodb1.host.com:27017,datacenter1.mongodb2.host.com:27017,datacenter2.mongodb3.host.com:27017,datacenter2.mongodb4.host.com:27017,datacenter3.mongodb-arbiter.host.com:27017/itential?replicaset=rs0 + # Redis config + platform_redis_sentinel_username: itential + platform_redis_sentinel_password: + platform_redis_sentinels: + - host: datacenter1.sentinel1.host.com + port: 26379 + - host: datacenter2.sentinel1.host.com + port: 26379 + - host: datacenter3.sentinel1.host.com + port: 26379 + + platform_secondary: + hosts: + datacenter2.itential-platform3.host.com: + datacenter2.itential-platform4.host.com: + vars: + platform_packages: + - itential-platform-6.0.0-1.noarch.rpm + platform_job_worker_enabled: false + platform_task_worker_enabled: false + # MongoDB config + platform_mongo_auth_enabled: true + platform_mongo_url: mongodb://itential:itential@datacenter1.mongodb1.host.com:27017,datacenter1.mongodb2.host.com:27017,datacenter2.mongodb3.host.com:27017,datacenter2.mongodb4.host.com:27017,datacenter3.mongodb-arbiter.host.com:27017/itential?replicaset=rs0 + # Redis config + platform_redis_sentinel_username: itential + platform_redis_sentinel_password: + platform_redis_sentinels: + - host: datacenter1.sentinel1.host.com + port: 26379 + - host: datacenter2.sentinel1.host.com + port: 26379 + - host: datacenter3.sentinel1.host.com + port: 26379 + + gateway: + hosts: + datacenter2.automation-gateway1.host.com: + vars: + gateway_release: 4.3 + gateway_whl_file: automation_gateway-4.3.56-py3-none-any.whl +``` + +## Component Guides + +In addition to the `itential.deployer.site` playbook, there are playbooks for each component. + +Each component installed by the Itential Deployer can be granularly configured by defining +additional variables in the relevant inventory file. These additional playbooks, roles and their +corresponding variables are detailed in the following guides. + +### MongoDB + +[MongoDB Guide](docs/mongodb_guide.md) + +### Redis + +[Redis Guide](docs/redis_guide.md) + +### Hashicorp Vault + +[Hashicorp Vault Guide](docs/vault_guide.md) + +### Itential Platform + +[Itential Platform Guide](docs/itential_platform_guide.md) + +### Itential Gateway + +[Itential Gatway Guide](docs/itential_gateway_guide.md) + +### Prometheus and Grafana + +[Prometheus and Grafana Guide](docs/prometheus_guide.md) + +## Patching Itential Platform and IAG + +The Deployer supports patching Itential Platform and IAG. Refer to the following guide for +instructions on running the patch playbooks. + +[Patch Itential Platform Guide](docs/patch_itential_platform_guide.md) + +[Patch IAG Guide](docs/patch_itential_gateway_guide.md) + +## Using Internal YUM Repositories + +By default the Deployer will install YUM repositories which point to external URLs. If the +customer hosts repositories internally, the Deployer can be configured to skip installing the +repositories. + +**ⓘ Note:** +The customer will be reposible for configuring the repo files in `/etc/yum.repos.d`. + +To use internal repositories, set `common_install_yum_repos` to `false` in the `all` vars section. +For example: + +```yaml +all: + vars: + common_install_yum_repos: false +``` + +## Running the Deployer in Offline Mode + +The Deployer supports installations in air-gapped environments. Refer to the following guide for +instructions on running the Deployer in offline mode. + +[Offline Installation Guide](docs/offline_install_guide.md) + +## Appendix A: Definition of "Highly Available" Dependencies + +### Highly Available MongoDB + +MongoDB clusters operate a primary/secondary model where data written to the primary will replicate +to the secondary. There is much literature on the internet about Mongo clusters. That will not be +covered here. However, it's important to note that Itential’s preferred MongoDB cluster will assume +the following requirements: + +- Authentication between the replica members done with either a shared key or X.509 certificate. +- The database will have an admin user able to perform any operation. +- The database will have an “itential” user that is granted the least amount of privileges required +by the application. + +Initial passwords are intended to be changed. + +### Highly Available Redis + +Redis clusters operate a primary/secondary model where data written to the primary will replicate +to the secondary. There is much literature on the internet about Redis clusters. That will not be +covered here. However, it's important to note that Itential’s preferred Redis cluster will assume +the following requirements: + +- Authentication between the replica members is done with users defined in the Redis config file. +- Redis will have an admin user able to perform any operation. +- Redis will have an “itential” user that is granted the least amount of privileges required by the +application. +- Redis will have a replication user that is granted the least amount of privileges required by the +replication process. +- Initial passwords are intended to be changed. +- Redis Sentinel will be included to monitor the Redis cluster and will be colocated with Redis. +- Redis Sentinel will have an admin user able to perform a Sentinel task. +- Redis nodes maintain a low latency connection between nodes to avoid replication failures. diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/itential_gateway_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/itential_gateway_guide.md new file mode 100644 index 00000000..d601d045 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/itential_gateway_guide.md @@ -0,0 +1,145 @@ +# Gateway Roles + +The playbook and role in this section install and configure the Itential Automation Gateway (IAG). + +## Roles + +### Gateway Role + +The `gateway` role performs a base install of IAG including any OS packages required. It includes +the appropriate versions of Python, Pip, and Ansible. It creates the appropriate Linux users, +directories, log files, and systemd services. It will start the automation-gateway service when +complete. + +## Variables + +### Static Variables + +The variables located in the `vars` directory of each role are "static" and not meant to be overridden by the user. Since these variable files are included at run-time based on the IAG release and OS major version, they have a higher precedence than the variables in the inventory and are not easily overridden. + +### Gateway Role Variables + +The variables in this section may be overridden in the inventory in the `gateway` group vars. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `gateway_release` | Fixed-point | Designates which major release version of IAG to install. | N/A | +| `gateway_whl_file` | String | The name of the IAG wheel file to install. | N/A | +| `gateway_archive_download_url` | String | The URL for the download of the iag whl file from a repository. | N/A | +| `repository_username` | String | The username for authentication of the repository from gateway_archive_download_url. | N/A | +| `repository_password` | String | The password for authentication of the repository from gateway_archive_download_url. | N/A | +| `repository_api_key` | String | The API for authentication of the repository from gateway_archive_download_url. Can be used instead of username/password for authentication.| N/A | + +The `gateway_release` and either `gateway_whl_file` or `gateway_archive_download_url` must be +configured in the inventory. When `gateway_archive_download_url` is configured, the +`repository_username`/`repository_password` or `repository_api_key` must be defined. + +The following table lists the default variables located in `roles/gateway/defaults/main.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `gateway_enable_ansible` | Boolean | Flag to enable Ansible. | `true` | +| `gateway_enable_nornir` | Boolean | Flag to enable Nornir. | `true` | +| `gateway_enable_netmiko` | Boolean | Flag to enable Netmiko. | `true` | +| `gateway_enable_scripts` | Boolean | Flag to enable scripts. | `true` | +| `gateway_enable_httpreq` | Boolean | Flag to enable HTTP requests. | `true` | +| `gateway_enable_netconf` | Boolean | Flag to enable Netconf requests. | `true` | +| `gateway_enable_python_venv` | Boolean | Flag to enable Python virtual environments. | `true` | +| `gateway_enable_grpc` | Boolean | Flag to enable GRPC requests. | `true` | +| `gateway_enable_git` | Boolean | Flag to enable Git integration. | `true` | +| `gateway_install_dir` | String | The base directory where to install the IAG files. | `/opt/automation-gateway` | +| `gateway_data_dir` | String | The IAG data directory. | `/opt/automation-gateway` | +| `gateway_log_dir` | String | The IAG log directory. | `/var/log/automation-gateway` | +| `gateway_port` | Integer | The IAG HTTP listen port. | `8083` | +| `gateway_properties_location` | String | The location of the IAG configuration file. | `/etc/automation-gateway` | +| `gateway_user` | String | The IAG Linux user. | `itential` | +| `gateway_group` | String | The IAG Linux group. | `itential` | +| `gateway_https` | Boolean | Flag to enable HTTPS. | `false` | +| `gateway_https_port` | Integer | The IAG HTTPS listen port. | `8443` | +| `gateway_ssl_copy_certs` | Boolean | Flag to enable copying the IAG SSL certificate. | `true` | +| `gateway_pki_base_dir` | String | The base PKI directory for Gateway certificates. | `/etc/pki/automation-gateway` | +| `gateway_https_cert_filename` | String | HTTPS certificate filename. | `{{ inventory_hostname }}.crt` | +| `gateway_https_key_filename` | String | HTTPS private key filename. | `{{ inventory_hostname }}.key` | +| `gateway_https_ca_filename` | String | HTTPS CA bundle filename. | `ca-bundle.crt` | +| `gateway_pki_src_dir` | String | Source directory for Gateway certificates (on Ansible controller). | (set in inventory) | +| `gateway_https_cert_file` | String | Deployed HTTPS certificate path. | `{{ gateway_pki_https_dir }}/{{ gateway_https_cert_filename }}` | +| `gateway_https_key_file` | String | Deployed HTTPS private key path. | `{{ gateway_pki_private_dir }}/{{ gateway_https_key_filename }}` | +| `gateway_https_ca_file` | String | Deployed HTTPS CA bundle path. | `{{ gateway_pki_https_dir }}/{{ gateway_https_ca_filename }}` | +| `gateway_tlsv1_2` | Boolean | Flag to enable TLS 1.2. | `false` | +| `gateway_http_server_threads` | Integer | The number of http server threads for handling requests. | `{{ ansible_processor_cores * 4 }}` | + +## PKI Certificate Configuration + +Gateway requires HTTPS certificates for the API server and optionally MongoDB client certificates. + +### Certificate Requirements + +Each Gateway server requires: +- **HTTPS certificate**: `{{ inventory_hostname }}.crt` +- **HTTPS private key**: `{{ inventory_hostname }}.key` +- **CA bundle**: `ca-bundle.crt` + +### Certificate Organization + +Organize certificates per server on the Ansible controller: +certificates/ +├── gateway +│   ├── ca-bundle.crt +│   ├── ip-10-222-1-183.ec2.internal.crt +│   ├── ip-10-222-1-183.ec2.internal.key +## Configuring HTTPS + +The Gateway role supports configuring Native HTTPS. The Gateway role does not generate SSL certificates. + +To configure IAG Native HTTPS: + +* Required + * Set `gateway_https` to `true` in the inventory. + * Place the SSL certs and keys in either the playbook or role `files` directory. +* Optional + * Set SSL-related variables from `roles/gateway/defaults/main.yml` in the inventory. + +## Building the Inventory + +To install and configure IAG, add a `gateway` group and host(s) to your inventory and configure the +`gateway_release` and `gateway_whl_file`. + +## Example Inventory - Single IAG Node + +```yaml +all: + children: + gateway: + hosts: + : + ansible_host: + vars: + gateway_release: 4.3 + gateway_whl_file: +``` + +To configure IAG Native HTTPS, add the `gateway_https` flag to the `gateway` group and set it to +`true` and configure the SSL-related variables (optional). + +## Example Inventory - IAG Native SSL + +```yaml +all: + children: + gateway: + hosts: + : + ansible_host: + vars: + gateway_release: 4.3 + gateway_whl_file: + gateway_https: true +``` + +## Running the Playbook + +To execute the Gateway role, run the `gateway` playbook: + +```bash +ansible-playbook itential.deployer.gateway -i +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/itential_platform_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/itential_platform_guide.md new file mode 100644 index 00000000..78e1ae0d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/itential_platform_guide.md @@ -0,0 +1,507 @@ +# Itential Platform Guide + +The playbook and role in this section install and configure Itential Platform. There is currently +one role: + +* `platform` – Installs Itential Platform and performs a base configuration. + +## Roles + +### Platform Role + +The `platform` role performs a base install of Itential Platform including any OS packages +required. It includes the appropriate version of Python, Pip, Jinja, and TextFSM. It handles a few +security vulnerabilities. It creates the appropriate Linux users, directories, log files, and +systemd services. + +It will install the source code for each adapter that is listed. It will also install any listed +custom adapters. It can install from a Git URL or using an adapter archive generated by Adapter +Builder. + +It will install app-artifacts, which is an optional Itential application that is primarily used +only in development environments for packaging use cases together for deployment. It will restart +the automation-platform service when complete. + +When there is a device configured in the `gateway` group this role will also install and configure +an IAG adapter that points to the gateway server(s) named in the `gateway` group. + +## Variables + +### Global Variables + +The variables in this section are configured in the inventory in the `all` group vars. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `platform_release` | Fixed-point | Designates the Itential Platform major version. | N/A | + +The `platform_release` must be defined in the inventory. This variable, along with the OS major +version, is used to determine the static variables. When `platform_release` is not defined then each +installed component must explicitly list the packages that will be installed. This allows for an +easy installation for most use cases and a convenient and explicit way to customize a non-standard +install. + +### Platform Role Variables + +The variables in this section may be overridden in the inventory in the `platform` group vars. In +most cases accepting the defaults is what you want except for in some more advanced installations. + +The variable `platform_encryption_key` is required for this role to run. This value must be a 64 +character hexadecimal string. + +The following approaches may be followed for generating an encryption key: + +- Generating a randomized key value: `openssl rand -hex 32` +- Generating a key value using an existing password value as a base: `printf '%s' “$PASSWORD” | sha256sum | head -c 64` + +Whichever approach you use to generate the key, ensure the result is persisted in a secrets +repository for safe keeping before applying it to your Itential Platform installation. Losing +access to this key means losing access to secret values stored inside of Itential Platform. + +More info on the encryption key: + + +#### Installation Variables + +These variables will effect how the installation occurs. + +| Variable | Group | Type | Description | Default Value | +| :------- | :---- | :--- | :---------- | :------------ | +| `platform_packages` | `platform` | List of Strings | The Itential Platform RPMs to install. The items can either be filenames or URLs. | N/A | +| `repository_username` | `platform` | String | The username for authentication of the repository. | N/A | +| `repository_password` | `platform` | String | The password for authentication of the repository. | N/A | +| `repository_api_key` | `platform` | String | The API for authentication of the repository. Can be used instead of username/password for authentication.| N/A | + +If `platform_packages` contains URLs, either `repository_api_key` or `repository_username` and +`repository_password` must be defined. + +#### Authentication Variables + +These variables control authentication and user session behaviors. The following table lists the +default variables located in `roles/platform/defaults/main/authentication.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_auth_unique_sessions_enabled | Boolean | If true, logs out existing sessions for a user when they log in with a new session. | `false` | +| platform_auth_admin_groups | List(Object) | Members of these groups will be implicitly assigned with admin permissions. | { "provenance": "Local AAA", "group": "pronghorn_admin" } | +| platform_auth_broker_principal_enabled | Boolean | Enables a AAA adapter to custom build the principal object for a user with a "buildPrincipal" method. | `false` | +| platform_auth_session_cookie_name | String | The name of the cookie used for a user session. | `token` | +| platform_auth_session_ttl | Integer | The time in minutes before a user session expires. | 60 | +| platform_default_user_enabled | Boolean | Enables a default user to be used for login when SSO is not configured and no AAA Adapter exists. | `true` | +| platform_default_user_username | String | The username of the default user. | `admin` | +| platform_default_user_password | String | The password of the default user. | `admin` | + +#### Broker Variables + +These variables control device broker behaviors. The following table lists the default variables +located in `roles/platform/defaults/main/brokers.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_device_broker_default_adapter_priority | List(String) | A list of adapter types that manages the devices. | | +| platform_device_broker_run_command_adapter_preference | String | Runs a command on a device. | | +| platform_broker_validation_enabled | Boolean | If true, the platform will perform strict JSON Schema validation on messages into the brokers and coming back to the broker layer from adapters. | false | + +#### Integration Worker Variables + +These variables control integration worker behaviors. The following table lists the default +variables located in `roles/platform/defaults/main/integration_worker.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_integration_thread_count | Integer | The number of threads available for API requests. | 5 | +| platform_integration_timeout | Integer | The number of milliseconds until an integration request times out. | 15000 | + +#### Logger Variables + +These variables control logging and syslog integration behaviors. The following table lists the +default variables located in `roles/platform/defaults/main/logging.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_log_max_files | Integer | The maximum number of each log file to keep as rotation occurs. | 100 | +| platform_log_max_file_size | Integer | The maximum file size in bytes of each log file before rotation occurs. | 1048576 | +| platform_log_level | String | The minimum log level to display in the log file. | `info` | +| platform_log_dir | String | The absolute directory path where log files are written. | `/var/log/itential/platform` | +| platform_log_filename | String | The name of the primary platform log file. | `platform.log` | +| platform_log_level_console | String | The minimum log level to display in the console (stdout). | `warn` | +| platform_webserver_log_directory | String | The absolute directory path where webserver log files are written. | `/var/log/itential/platform` | +| platform_webserver_log_filename | String | The name of the webserver log file. | `webserver.log` | +| platform_log_level_syslog | String | The minimum log level to send to the syslog server. | `warning` | +| platform_syslog_host | String | The hostname or IP address of the syslog server. | `localhost` | +| platform_syslog_port | Integer | The port number of the syslog server. | 514 | +| platform_syslog_protocol | String | The protocol to use when sending logs to the syslog server. | `udp4` | +| platform_syslog_facility | String | The syslog facility to use when sending logs to the syslog server. | `local0` | +| platform_syslog_type | String | The syslog message format to use when sending logs to the syslog server. | `BSD` | +| platform_syslog_path | String | The path to the syslog server file. | `/dev/log` | +| platform_syslog_pid | String | The process property to include as the process id in the syslog message. | `process.pid` | +| platform_syslog_localhost | String | The hostname to include in the syslog message. | `localhost` | +| platform_syslog_app_name | String | The process property to include as the application name in the syslog message. | `process.title` | +| platform_syslog_eol | String | The end of line character to include in the syslog message. | | + +#### Platform UI Variables + +These variables control UI behaviors. The following table lists the default variables located in +`roles/platform/defaults/main/platform_ui.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_ui_layout_file | String | Path to the layout file extended in pug templates. | | +| platform_ui_home_file | String | Path to the HTML file that will be displayed as the home page for the UI. | `node_modules/@itential/iap-ui/build/index.html` | +| platform_ui_login_file | String | Path to the HTML file that will be displayed as the login page for the UI. | `node_modules/@itential/iap-ui/build/index.html` | +| platform_ui_profile_file | String | Path to the HTML file that will be displayed as the profile page for the UI. | `node_modules/@itential/iap-ui/build/index.html` | +| platform_ui_favicon_file | String | Path to the favicon file that will be displayed in the browser tab. | `ui/img/favicon.ico` | +| platform_ui_apple_touch_icon_file | String | Path to the apple touch icon file that will be displayed on iOS devices. | `ui/img/apple-touch-icon.png` | + +#### Redis Variables + +These variables control Redis integration behaviors. The following table lists the default +variables located in `roles/platform/defaults/main/redis.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_redis_db | Integer | The Redis keyspace (database number) to use for the connection. | 0 | +| platform_redis_auth_enabled | String | Flag to enable Redis authentication. | `true` | +| platform_redis_username | String | The username to use when connecting to Redis. | `itential` | +| platform_redis_password | String | The password to use when connecting to Redis. | `itential` | +| platform_redis_max_retries_per_request | Integer | The maximum number of times to retry a request to Redis when the connection is lost. | 20 | +| platform_redis_max_heartbeat_write_retries | Integer | The maximum number of times to retry writing a heartbeat message to Redis from a service. | 20 | +| platform_redis_host | String | The hostname of the Redis server. Not used when connecting to Redis Sentinels. | `localhost` | +| platform_redis_port | Integer | The port to use when connecting to this Redis instance. | 6379 | +| platform_redis_sentinels | List(Object) | The list of Redis Sentinel servers (hostnames and ports) to use for high availability. | | +| platform_redis_sentinel_username | String | The username to use when connecting to Sentinel. | `sentineluser` | +| platform_redis_sentinel_password | String | The password to use when connecting to Sentinel. | `sentineluser` | +| platform_redis_name | String | The Redis primary name. This only has meaning when Redis is running with replication enabled. The sentinels will monitor this node and consider it down only when the sentinels agree. Note: The primary name should not include special characters other than: .-_ and no whitespaces. | `itentialmaster` | +| platform_redis_tls | Object | Redis TLS configuration options for secure connections. Refer to NodeJS TLS library for all supported options. | | + +#### SNMP Variables + +These variables control SNMP behaviors. The following table lists the default variables located in +`roles/platform/defaults/main/snmp.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_snmp_alarm_configs | List(Object) | | `{ "ip": "localhost", "community": "public", "type": "trap", "properties": { "port": 161, "retries": 1, "timeout": 5000, "transport": "udp4", "trapPort": 162, "version": "V1" } }` | + +#### Vault Variables + +These variables control Hashicorp Vault integration behaviors. The following table lists the +default variables located in `roles/platform/defaults/main/vault.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_configure_vault | Boolean | Flag to enable/disable configuring Vault in Itential Platform | `false` | +| platform_vault_token_dir | String | The directory to store the vault root key in | `{{ platform_server_dir }}/keys` | +| platform_vault_url | String | The URL to the Hashicorp Vault server. | `http://localhost:8200` | +| platform_vault_auth_method | String | The authorization method to connect to Hashicorp Vault. Either token or approle. | `token` | +| platform_vault_token | String | Hashicorp Vault token used for token-based authentication | | +| platform_vault_role_id | String | Hashicorp Vault Role ID variable used for AppRole authentication | | +| platform_vault_secret_id | String | Hashicorp Vault Secret ID variable used for AppRole login | | +| platform_vault_approle_path | String | The path where the AppRole was enabled. | `approle` | +| platform_vault_token_file | String | The file path to a token file. The token is used for authentication to access Vault secrets. | `{{ platform_vault_token_dir }}/vault.token` | +| platform_redis_password_vault | Reference for the path to redis password secret and name of key in Hashicorp Vault | `$SECRET_iap $KEY_redisPassword` | +| platform_mongo_password_vault | Reference for the path to mongodb password secret and name of key in Hashicorp Vault | `$SECRET_iap $KEY_mongoDb` | +| platform_vault_role_secrets_env_file | The file path to the .env file containing Role ID and Secret ID for AppRole authentication | `{{ platform_vault_token_dir }}/vault-role-secrets.env` | +| platform_vault_secrets_endpoint | String | The endpoint for the Secrets Engine that is used. | `itential/data` | +| platform_vault_read_only | Boolean | If true, only reads secrets from Hashicorp Vault. Otherwise, the platform can write secrets to Vault for storage. | `true` | + +#### Webserver Variables + +These variables control basic webserver behaviors. The following table lists the default variables +located in `roles/platform/defaults/main/webserver.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_webserver_cache_control_enabled | Boolean | A toggle to instruct the webserver to include HTTP cache control headers on the response. | `false` | +| platform_webserver_timeout | Integer | Timeout to use for incoming HTTP requests to the platform API, in milliseconds. | 300000 | +| platform_webserver_response_header_access_control_allow_origin | String | The value of the HTTP Access-Control-Allow-Origin header returned to clients. | `"*"` | +| platform_webserver_http_enabled | Boolean | If true, allows the webserver to respond to insecure HTTP requests. | `true` | +| platform_webserver_http_port | Integer | The port on which the webserver listens for HTTP requests. | 3000 | +| platform_webserver_https_enabled | Boolean | If true, allows the webserver to respond to secure HTTPS requests. | `false` | +| platform_webserver_https_port | Integer | The port on which the webserver listens for HTTPS requests. | 3443 | +| platform_webserver_https_key | String | The path to the private key file used for HTTPS connections. | `/etc/pki/itential-platform/private/{{ inventory_hostname }}.key` | +| platform_webserver_https_passphrase | String | The passphrase for the private key used to enable TLS sessions. | | +| platform_webserver_https_cert | String | The path to the certificate file used for HTTPS connections. | `/etc/pki/itential-platform/https/{{ inventory_hostname }}.crt` | +| platform_webserver_https_secure_protocol | String | The set of allowed SSL/TLS protocol versions. | `TLS_method` | +| platform_webserver_https_ciphers | String | The allowed SSL/TLS cipher suite. | `ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA` | +| platform_webserver_https_client_reneg_limit | Integer | Specifies the number of renegotiations that are allowed in a single HTTPS connection. | 3 | +| platform_webserver_https_client_reneg_window | Integer | Specifies the time renegotiation window in seconds for a single HTTPS connection. | 600 | +| platform_webserver_http_allowed_optional_verbs | List(String) | The set of allowed HTTP verbs in addition to those defined in the standard HTTP/1.1 protocol. | | + +#### Workflow Worker Variables + +These variables control Workflow Engine behaviors. The following table lists the default variables +located in `roles/platform/defaults/main/workflow_worker.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_task_worker_enabled | Boolean | If true, will start working tasks immediately after the server startup process is complete. If false, the task worker must be enabled manually via the UI/API. | `true` | +| platform_job_worker_enabled | Boolean | If true, will allow jobs to be started after the server startup process is complete. If false, API calls to start Jobs will return an error until enabled manually via the UI/API. | `true` | + +#### MongoDB Variables + +These variables control MongoDB integration behaviors. The following table lists the default +variables located in `roles/platform/defaults/main/mongodb.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_mongo_auth_enabled | Boolean | Instructs the MongoDB driver to use the configured username/password when connecting to MongoDB. | `true` | +| platform_mongo_user | String | The username to use when connecting to MongoDB. | `itential` | +| platform_mongo_password | String | The password to use when connecting to MongoDB. | `itential` | +| platform_mongo_auth_db | String | The name of the database that the MongoDB user must authenticate against. | | +| platform_mongo_bypass_version_check | Boolean | If true, the server will not check if it is connecting to a compatible MongoDB version. | `false` | +| platform_mongo_db_name | String | The name of the MongoDB logical database to connect to. | `itential` | +| platform_mongo_url | String | The MongoDB connection string. For a replica set this will include all members of the replica set. For Mongo Atlas this will be the SRV connection format. | `mongodb://localhost:27017` | +| platform_mongo_tls_enabled | Boolean | Instruct the MongoDB driver to use TLS protocols when connecting to the database. | `false` | +| platform_mongo_tls_allow_invalid_certificates | Boolean | If true, disables the validation checks for TLS certificates on other servers in the cluster and allows the use of invalid or self-signed certificates to connect. | `false` | +| platform_mongo_tls_ca_file | String | The .pem file that contains the root certificate chain from the Certificate Authority. Specify the file name of the .pem file using absolute paths. | | +| platform_mongo_max_pool_size | Integer | The maximum number of connections in a connection pool. Each application/adapter has its own connection pool. | | + +#### Platform Variables + +These variables control core platform behaviors. The following table lists the default variables +located in `roles/platform/defaults/main/platform.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_server_dir | String | The Itential Platform installation directory. | `/opt/itential/platform/server` | +| platform_config_dir | String | The Itential Platform configuration directory. | `/etc/itential` | +| platform_pki_base_dir | String | The base PKI directory for Platform certificates. | `/etc/pki/itential-platform` | +| platform_https_cert_filename | String | HTTPS certificate filename. | `{{ inventory_hostname }}.crt` | +| platform_https_key_filename | String | HTTPS private key filename. | `{{ inventory_hostname }}.key` | +| platform_https_ca_filename | String | HTTPS CA bundle filename. | `ca-bundle.crt` | +| platform_mongodb_ca_filename | String | MongoDB client CA bundle filename. | `ca-bundle.crt` | +| platform_https_pki_src_dir | String | Source directory for HTTPS certificates. | (set in inventory) | +| platform_mongodb_pki_src_dir | String | Source directory for MongoDB client certificates. | (set in inventory) | +| platform_itential_home_dir | String | The Itential Platform itential user home directory. | `/home/itential` | +| platform_mongodb_root_ca_file_destination | String | Destination as referenced by itential user when connecting from itential host. This is ultimately stored in the mongo database to be read by Itential Platform, therefore this is the location as seen from the Itential Platform host. | `/etc/pki/itential-platform/mongodb/ca-bundle.crt` | +| platform_package_dependencies | List(String) | Required OS packages for install. | `glibc-common, openldap, openldap-clients, openssl, git` | +| platform_python_base_dependencies | List(String) | Required python packages for install. | `pip, setuptools, wheel` | +| platform_python_executable | String | The python executable locations. These will be symlinks to the appropriate executables in /usr/bin. | `/usr/bin/python{{ platform_python_version }}` | +| platform_pip_executable | String | The pip executable locations. These will be symlinks to the appropriate executables in /usr/bin. | `/usr/bin/pip{{ platform_python_version }}` | +| platform_user | String | The default user that runs the server process. | `itential` | +| platform_group | String | The default group that runs the server process. | `itential` | +| platform_upload_using_rsync | Boolean | Flag to determine whether to use rsync when uploading artifacts. | `false` | +| platform_delete_package_lock_file | Boolean | Flag to remove the package-lock.json file before running the NPM install. | `true` | +| platform_disable_git_safe_repo_checks | Boolean | Flag to disable Git safe repo check. | `true` | +| platform_npm_ignore_scripts | Boolean | Flag to prevent the NPM scripts from running when running the NPM install. | `true` | +| platform_app_artifacts_enabled | Boolean | Flag to install app-artifacts. | `false` | +| platform_start_service | Boolean | Flag to determine if the Itential Platform service is started. | `true` | + +#### Server Variables + +These variables control Itential server behaviors. The following table lists the default variables +located in `roles/platform/defaults/main/server.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| platform_profile_id | String | The name of the profile document to load from the MongoDB where legacy configuration properties are stored. Not required for installations that are using environment variables or a properties file. | | +| platform_server_id | String | An identifier for the server instance. This is used to uniquely identify the server in a multi-server environment. If not provided, the server will generate one on startup. | `{{ inventory_hostname }}` | +| platform_services | List | A whitelist of services (applications/adapters) to initialize on startup of the platform. If no value is given, all services will be initialized. | | +| platform_service_blacklist | List | The service type that will be denied CRUD operation access. | | +| platform_encrypted | Boolean | Indicates whether the platform is using encrypted code files. | `true` | +| platform_shutdown_timeout | Integer | The amount of time a service should wait before shutting down, in seconds. | 3 | +| platform_service_launch_delay | Integer | The application/adapter launch delay, in seconds. | 1 | +| platform_service_launch_timeout | Integer | The application/adapter launch timeout, in seconds. | 600 | +| platform_service_health_check_interval | Integer | How often to update service health, measured in seconds. | 5 | +| platform_service_health_check_unhealthy_threshold | Integer | The number of failed health checks in a row before a service is considered to be “unhealthy”. | 3 | +| platform_dead_process_check_enabled | Boolean | If true, the platform will periodically check for dead processes. | `false` | +| platform_dead_process_check_interval | Integer | How often to check if application/adapter stopped sending healthcheck pings, in seconds. | 5 | +| platform_dead_process_max_period | Integer | Maximum time period for application/adapter without sending healthcheck ping, in seconds. | 15 | +| platform_service_crash_recovery_max_retries | Integer | Specifies the amount of times services will retry on crash before stopping. | 10 | +| platform_service_crash_recovery_reset_retries_after_ms | Integer | Specifies the amount of times between each retry before the count will reset in milliseconds. | 60000 | +| platform_external_request_timeout | Integer | The timeout for external API requests, in seconds. | 5 | +| platform_device_count_polling_interval | Integer | The interval for how often IAP polls for the number of devices, in hours. | 24 | +| platform_audit_enabled | Boolean | If true, the platform will track detailed audit events. | `false` | + +## Building the Inventory + +### Example Inventory - Single Itential Platform Node + +To install and configure Itential Platform, add a `platform` group and host(s) to your inventory +and configure the `platform_release` and `platform_packages`. The URLs in `platform_packages` +supports Sonatype Nexus, JFrog Artifactory and Gitlab. It is recommended to use +`repository_username` and `repository_password` for Nexus and `repository_api_key` for +Artifactory and Gitlab. The following inventory shows a basic Itential Platform configuration +with a single node. + +```yaml +all: + vars: + platform_release: 6 + + children: + platform: + hosts: + : + ansible_host: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_packages: + - + - +``` + +### Example Inventory - Install Adapters + +To install Itential adapters, add the `platform_adapters` flag to the `platform` group and set it +to `true`, and configure the adapters in the `platform_adapters` variable. + +```yaml +all: + vars: + platform_release: 6 + + children: + platform: + hosts: + : + ansible_host: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_packages: + - + - + platform_adapters: + - + - + - + - +``` + +### Example Inventory - Install App-Artifact + +To install App-Artifacts, add the `platform_app_artifacts_enabled` flag to the `platform` group and +set it to `true` and configure the `platform_app_artifacts_source_file`. + +```yaml +all: + vars: + platform_release: 6 + + children: + platform: + hosts: + host1: + ansible_host: addr1 + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_app_artifacts_enabled: true + platform_app_artifacts_source_file: archive1 +``` + +### Example Inventory - Use Hashicorp Vault + +To configure the Platform to integrate with Hashicorp Vault for secrets management + +```yaml +all: + vars: + platform_release: 6 + + children: + platform: + hosts: + : + ansible_host: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_configure_vault: true + platform_vault_url: http://hashi-vault-example.com:8200 +``` + +## Running the Playbook + +To execute all Platform roles, run the `platform` playbook: + +```bash +ansible-playbook itential.deployer.platform -i +``` + +The Platform playbook and role supports the following tags: + +| Tag | Tasks | +| :-- | :---- | +| configure_os | Create required accounts and directories
Configure sudoers and firewalld | +| install_dependencies | Install NodeJS and Python | +| install_nodejs | Install NodeJS | +| install_python | Install Python | +| install_platform | Install Itential Platform | +| install_adapters | Install Itential Platform adapters | +| install_app_artifacts | Install Itential Platform App Artifacts | +| configure_selinux | Configure SELinux | +| configure_vault | Configure Hashicorp Vault | +| configure_platform | Configure Itential Platform systemd service and properties file | + +For example, to regenerate the systemd service script and platform.properties file run the platform +playbook with the `configure_platform` tag: + +```bash +ansible-playbook itential.deployer.platform -i --tags configure_platform +``` + +## Installing Platform in Alternate Directories + +By default the Platform will install files into the following directories: + +| Directory | Variable | Can Override? | +| :-------- | :------- | :------------ | +| /opt/itential/platform | platform_root_dir | Yes | +| /opt/itential/platform/server | platform_server_dir | No | +| /opt/itential/platform/services | platform_services_dir | No | +| /etc/itential | platform_config_dir | Yes | +| /etc/pki/itential-platform | platform_pki_base_dir | Yes | +| /var/log/itential | platform_log_dir | Yes | +| /home/itential | platform_itential_home_dir | Yes | + +However, the Platform directories can be overridden in the inventory. If overridden, the Deployer +will install the RPMs using the `rpm` command instead of using the Ansible `dnf` module so that +the `--relocate` flag can be used. + +Note that `platform_server_dir` and `platform_service_dir` cannot be overridden - only the +`platform_root_dir` can. + +If the `platform_root_dir` is overridden, the `platform_services_dir` will automatically be added +to the `service_directory` in `platform.properties`. + +Example overrides: + +```yaml +platform_root_dir: /app/itential/platform +platform_config_dir: /app/itential/conf +platform_pki_base_dir: /app/itential/pki +platform_log_dir: /app/itential/log +platform_itential_home_dir: /export/home/itential +``` +### PKI Certificate Configuration + +Platform requires HTTPS certificates for the web server and optionally MongoDB client certificates for mutual TLS. + +#### Certificate Requirements + +**HTTPS Certificates** (required): +- Server certificate: `{{ inventory_hostname }}.crt` +- Private key: `{{ inventory_hostname }}.key` +- CA bundle: `ca-bundle.crt` + +**MongoDB Client Certificates** (optional for mutual TLS): +- Client certificate: `client.pem` +- Client private key: `mongodb-client.key` +- CA bundle: `ca-bundle.crt` + +#### Certificate Organization + +Organize certificates per server on the Ansible controller: +certificates/ +├── platform +│   ├── ca-bundle.crt +│   ├── ip-10-222-1-169.ec2.internal.crt +│   ├── ip-10-222-1-64.ec2.internal.crt +│   ├── ip-10-222-1-64.ec2.internal.key + +#### Deployed Locations + +- Base directory: `/etc/pki/itential-platform/` +- HTTPS cert: `/etc/pki/itential-platform/https/{{ inventory_hostname }}.crt` +- HTTPS key: `/etc/pki/itential-platform/private/{{ inventory_hostname }}.key` +- MongoDB CA: `/etc/pki/itential-platform/mongodb/ca-bundle.crt` \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/mongodb_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/mongodb_guide.md new file mode 100644 index 00000000..408de275 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/mongodb_guide.md @@ -0,0 +1,331 @@ +# MongoDB Role + +The playbook and role in this section install and configure MongoDB for the Itential Automation +Platform. There is currently only one role that can install and configure MongoDB for use with the Itential +Platform. + +## MongoDB Installation + +The `mongodb` role is basically divided into two functional segments, one for the base installation +of the MongoDB software, and the other for the configuration of MongoDB. These segments can be +triggered individually by using the appropriate tag. See below for details on the available tags. + +The role performs a base install of MongoDB including any OS packages required. It includes a few +recommended kernel settings and other optimizations recommended by MongoDB. It creates the +appropriate Linux users, directories, log files, and systemd services. If the host is configured to +use SELinux the role will set the appropriate labels on files and directories. It will start the +mongod service when complete. + +Once the base installation is complete, the role will conditionally configure a replica set. After +potentially configuring a replica set, the role will then conditionally configure authorization. +After this, it will conditionally configure TLS connections. Triggering these conditional +configurations is based on the variables that are set in the host file. See below for examples. + +## MongoDB Replication + +When configured to do so, the role is responsible for configuring MongoDB as a replica set. It uses +the first host defined in the `mongodb` group in the inventory as the initial primary. It updates +the MongoDB configuration file with the replica set name and enables replication. It initializes +the replica set on the initial primary and then joins the remaining MongoDB nodes to the replica +set. It will restart the mongod service when complete. The role will detect if replication has +already been enabled and skip these tasks if it determines that replication is already enabled. + +More info on replication: + +## MongoDB Authentication + +When configured to do so, the role is designed to enable authentication on the MongoDB. It will +modify the MongoDB config file to enable authentication for a single database or a replica set. +When MongoDB is configured as a replica set it requires a key for the members of the replica set to +talk to one another. This key file is created by the role and uploaded to the appropriate location. +It uses openssl and generates a random base 64 string of 756 bytes. It will restart the mongod +service when complete. + +More info on authentication: + +More info on the key file: + +## MongoDB TLS + +When configured to do so, the role is responsible for configuring MongoDB to use a TLS connection +when connecting to the database. It is NOT responsible for creating certificates. Those must be +supplied to this role. It will copy those certificates to the correct location. It will make all +required changes to enable TLS connections in the Mongo configuration file. It will restart the +mongod service when complete. + +More info on TLS: + +## Variables + +### Static Variables + +The variables located in the `vars` directory of each role are "static" and not meant to be +overridden by the user. Since these variable files are included at run-time based on the Itential +Platform release and OS major version, they have a higher precedence than the variables in the +inventory and are not easily overridden. + +### Global Variables + +The variables in this section are configured in the inventory in the `all` group vars. + +| Variable | Group | Type | Description | Default Value | +| :------- | :---- | :--- | :---------- | :------------ | +| `platform_release` | `all` | Fixed-point | Designates the IAP major version. If this is not included then the `mongodb` device group must specify the MongoDB packages (the precise Mongo version) to install. | N/A | + +When the `platform_release` is defined in the inventory then the playbook will use default values +for the MongoDB version to install. These defaults are determined by the Itential Platform version +and represent our validated design. If this is not included then the `mongodb` device group must +specify the MongoDB packages (the precise Mongo version) to install. See below an example of how to +override the default MongoDB version. + +### MongoDB Role Variables + +The variables in this section may be overridden in the inventory in the `mongodb` group vars. + +The following table contains the most commonly overridden variables. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `mongodb_admin_db_name` | String | The name of the admin database. | `admin` | +| `mongodb_auth_enabled` | Boolean | Flag to enable MongoDB authentication. | `true` | +| `mongodb_itential_db_name` | String | The name of the itential database. | `itential` | +| `mongodb_replication_enabled` | Boolean | Flag to enable MongoDB replication | `false` | +| `mongodb_replset_name` | String | The MongoDB replica set name. | `rs0` | +| `mongodb_tls_enabled` | Boolean | Flag to enable MongoDB TLS. | `false` | +| `mongodb_pki_base_dir` | String | The base directory for PKI certificates and keys. | `/etc/pki/mongodb` | +| `mongodb_tls_server_cert_filename` | String | Server certificate filename (combined cert+key). | `{{ inventory_hostname }}.pem` | +| `mongodb_tls_ca_cert_filename` | String | CA certificate bundle filename. | `ca-bundle.crt` | +| `mongodb_replica_keyfile_filename` | String | Replica set authentication keyfile. | `replica.key` | +| `mongodb_pki_src_dir` | String | Source directory for certificates (on Ansible controller). | (set in inventory) | +| `mongodb_user_admin_password` | String | The MongoDB admin user password. | `admin` | +| `mongodb_user_itential_password` | String | The MongoDB itential user password. | `itential` | + +> :warning: It is assumed that these default passwords will be changed to meet more rigorous +security standards. These are intended to be defaults strictly used just for ease of the +installation and should be overridden in the inventory file. It is highly recommended that sensitive +data be encrypted using Ansible Vault when they are overridden so that the passwords don't actually +appear anywhere in source code. + +These variables can be used to override the default version of MongoDB that is installed. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `mongodb_packages` | List(String) | The list of MongoDB yum package names to install. | | +| `mongodb_version` | Float | The MongoDB major version being installed. | Depends on `platform_release` | + +These variables effect how and where MongoDB is installed. In most cases, these should not be +modified. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `mongodb_conf_file` | String | The location of the MongoDB configuration file. | `/etc/mongodb.conf` | +| `mongodb_data_dir` | String | The MongoDB data file directory. | `/var/lib/mongo` | +| `mongodb_gpgkey_url` | String | The fully qualified URL to the GPG key for the desired RPM file. | Depends on `mongodb_version` | +| `mongodb_group` | String | The MongoDB Linux group. | `mongod` | +| `mongodb_log_dir` | String | The MongoDB log files directory. | `/var/log/mongodb` | +| `mongodb_owner` | String | The MongoDB Linux user. | `mongod` | +| `mongodb_pid_dir` | String | Directory that stores the mongodb pid file. | `/var/run/mongodb` | +| `mongodb_port` | Integer | The MongoDB listen port. | `27017` | +| `mongodb_release_url` | String | The fully qualified URL to the repo where the MongoDB RPM packages exist. | Depends on `mongodb_version` | + +These variables apply to advanced situations. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `mongodb_python_executable` | String | The location of the python executable used by the Community.mongodb ansible tasks. | `/usr/bin/python3` | +| `mongodb_pip_executable` | String | The location of the pip executable used by the Community.mongodb ansible tasks. | `/usr/bin/pip3` | +| `mongodb_python_venv_root` | String | The location of the virtual environment used by the Community.mongodb collection. | `/var/tmp` | +| `mongodb_python_venv_name` | String | The name of the Python virtual environment used by this deployer. | `mongodb_venv` | +| `mongodb_bind_ipv6` | Boolean | Flag to enable binding to IPv6. | `true` | +| `mongodb_bind_addrs` | String | The hostnames and/or IP addresses and/or full Unix domain socket paths on which mongos or mongod should listen for client connections. You may attach mongos or mongod to any interface. To bind to multiple addresses, enter a list of comma-separated values. The inventory_hostname will be automatically added to `mongodb_bind_addrs`. If `mongodb_bind_ipv6` is set to true, '::1' will be added to `mongodb_bind_addrs`. | `127.0.0.1` | +| `mongodb_mongod_service_retries` | Integer | The number of retries when starting the mongod service. | 5 | +| `mongodb_mongod_service_delay` | Integer | The time in seconds between retries when starting the mongod service. | 10 | +| `mongodb_status_poll` | Integer | The maximum number of times to query for the replicaset status before the set converges or we fail. | 3 | +| `mongodb_status_interval` | Integer | The number of seconds to wait between polling executions. | 10 | +| `mongodb_sysctl_file` | String | The name of the MongoDB sysctl file | /etc/sysctl.d/98-mongodb.conf | +| `mongodb_net_ipv4_tcp_keepalive_time` | Integer | Time (in seconds) that a TCP connection remains idle before the kernel starts sending keepalive probes to verify the connection is still alive. | 300 | +| `mongodb_net_core_somaxconn` | Integer | Controls the backlog queue size for incoming connections. When the queue is full, new connection attempts are rejected. | 65535 | +| `mongodb_vm_zone_reclaim_mode` | Integer | Controls whether the kernel reclaims memory from local zones before allocating from remote NUMA nodes. | 0 | +| `mongodb_vm_swappiness` | Integer | Balances between swapping out anonymous pages (process memory) versus dropping page cache (file system buffers). | 1 | +| `mongodb_vm_max_map_count` | Integer | Maximum number of memory map areas (virtual memory areas/VMAs) a process can create. | 262144 | + +## Configuring TLS + +The `mongodb` role does not generate TLS certificates. Certificates must be generated by the user and organized in a per-server directory structure. + +### Certificate Requirements + +Each MongoDB server requires: +- **Server certificate**: `{{ inventory_hostname }}.pem` (combined certificate + private key in PEM format) +- **CA certificate**: `ca-bundle.crt` (Certificate Authority bundle) +- **Replica keyfile**: `replica.key` (for replica set authentication) + +### Certificate Organization + +Certificates should be organized per server on the Ansible controller: +certificates/ +├── mongodb +│   ├── ca-bundle.crt +│   ├── hostname1.pem +│   ├── hostname2.pem +│   ├── hostname3.pem +│   ├── replica.key + +### Deployed Certificate Locations + +Certificates are deployed to: +- **Base directory**: `/etc/pki/mongodb/` +- **Server cert**: `/etc/pki/mongodb/{{ inventory_hostname }}.pem` +- **CA bundle**: `/etc/pki/mongodb/ca-bundle.crt` +- **Replica keyfile**: `/etc/pki/mongodb/private/replica.key` + +## SELinux + +The `mongodb` role contains tasks to install custom SELinux profiles (located in +`roles/mongodb/files` and containing the `te` extension). If your installation requires additional +profiles, the files can be placed in the `files` directory and they will be automatically installed +by the role. + +## Building the Inventory + +To install and configure MongoDB, add a `mongodb` group and host(s) to your inventory file. The +following inventory examples demonstrate some common installation patterns. + +## Example Inventory - Single MongoDB Node accepting all defaults for Platform 6 + +This example shows a basic MongoDB configuration with a single MongoDB node accepting all default +values defined with Platform 6. + +```yaml +all: + vars: + repository_api_key: #key + platform_release: 6 + + children: + mongodb: + hosts: + : + ansible_host: +``` + +## Example Inventory - Single MongoDB Node overriding the default MongoDB version + +This example shows how to override the default version of MongoDB that is installed. Note that the +`platform_release` variable is NOT specified and the packages are explicitly defined in the +mongodb group vars. + +```yaml +all: + vars: + repository_api_key: #key + + children: + mongodb: + hosts: + : + ansible_host: + vars: + mongodb_version: 7.0 + mongodb_packages: + - mongodb-org + mongodb_python_packages: + - python3 + - python3-pip +``` + +## Example Inventory - Configuring MongoDB Replica Set accepting all other defaults + +To configure replication, add two additional nodes (at least) to the `mongodb` group, add the +`mongodb_replication_enabled` flag to the `mongodb` group vars, and set it to `true`. Optionally, +override the replica set name. + +```yaml +all: + vars: + repository_api_key: #key + platform_release: 6 + + children: + mongodb: + hosts: + : # This host will be chosen as the primary initially + ansible_host: + : + ansible_host: + : + ansible_host: + vars: + mongodb_replication_enabled: true + # Optionally override the replica set name + # mongodb_replset_name: +``` + +## Example Inventory - Configuring MongoDB TLS accepting all other defaults + +To configure a MongoDB TLS, add the `mongodb_tls` flag to the `all` group vars and set it to `true` +and configure the `mongo_cert_keyfile_source` and `mongo_root_ca_file_source`. + +```yaml +all: + vars: + repository_api_key: #key + platform_release: 6 + + children: + mongodb: + hosts: + : + ansible_host: + : + ansible_host: + : + ansible_host: + vars: + mongodb_replication_enabled: true + mongodb_tls_enabled: true + mongo_cert_keyfile_source: mongodb.pem + mongo_root_ca_file_source: rootCA.pem +``` + +## Running the Playbook + +To execute the MongoDB role, run the `mongodb` playbook: + +```bash +ansible-playbook itential.deployer.mongodb -i +``` + +## Tags + +You can also run select MongodDB segments by using the following tags: + +* `install_mongodb` +* `configure_mongodb` +* `initialize_mongo_config` + +The tag `install_mongodb` will run all of the installation tasks which will install MongoDB and +start it up in its most basic state. This tag will execute the tasks to configure SELinux. This tag +will also create the required database users even if they are not used because authorization is not +enabled. Basic installation can be achieved with this command: + +```bash +ansible-playbook itential.deployer.mongodb -i --tags install_mongodb +``` + +The tag `configure_mongodb` will run all of the configuration tasks. These tasks are conditional +depending on the features that are enabled in the global vars of the inventory file. Configuration +can be achieved with this command: + +```bash +ansible-playbook itential.deployer.mongodb -i --tags configure_mongodb +``` + +This tag can be run repeatedly if there is a need to enable these features in a consecutive manner +or to troubleshoot. However, each feature does alter the state of MongoDB and its possible that +repeated executions can put the configuration in a bad state. To "reset" the configuration to the +state that the installation tag produced you can run this command: + +```bash +ansible-playbook itential.deployer.mongodb -i --tags initialize_mongo_config +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/nginx.md b/.ansible/collections/ansible_collections/itential/deployer/docs/nginx.md new file mode 100644 index 00000000..496ebb3c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/nginx.md @@ -0,0 +1,213 @@ +# Nginx Role +The Ansible playbooks and roles discussed in this section installs and configures Nginx as a load balancer using the `nginxinc.nginx_core` collection. + +**ⓘ Note:** +These are optional playbooks and roles and are not required for operation of the Itential platform. + +## Setup + +In order to run the Nginx playbooks and roles, the `nginxinc.nginx_core` [collection](https://galaxy.ansible.com/ui/repo/published/nginxinc/nginx_core) must be +installed manually. It does not get installed automatically when the `itential.deployer` collection +is installed. + +```bash +ansible-galaxy collection install nginxinc.nginx_core +``` + +## Roles + +There are two `nginxinc.nginx_core` roles responsible for installing and configuring all of the necessary components. + +[nginxinc.nginx](https://github.com/nginxinc/ansible-role-nginx) will install Nginx. + +[nginxinc.nginx_config](https://github.com/nginxinc/ansible-role-nginx-config) will configure Nginx. + + +## Variables + +### Global Variables + +There are no global variables. + +### Nginx Role Variables +There are many variables that can be used to install and configure Nginx that are documented in [nginxinc.nginx](https://github.com/nginxinc/ansible-role-nginx) and +[nginxinc.nginx_config](https://github.com/nginxinc/ansible-role-nginx-config) codebase + + +## Building Your Inventory + +To install and configure Nginx, add `nginx` groups and hosts to +your inventory (in addition to the other Itential-related groups and hosts). + +### Example Inventory - Generic Nginx load balancer + +#### This load balancer listens on port 3443 and forwards requests to port 3000 on the servers defined in backend_servers_main using sticky sessions. + +```yaml +all: + vars: + platform_release: 6 + + children: + nginx: + hosts: + : + ansible_host: + vars: + nginx_ssl_certificate_file: + nginx_ssl_key_file: + nginx_user: + nginx_group: + + # Variables for nginx installation + nginx_setup: install + nginx_type: opensource + nginx_branch: stable + nginx_service_modify: true + nginx_service_timeout: 95 + nginx_enable: true + nginx_start: true + + # Variables for nginx configuration + nginx_config_start: true + nginx_config_debug_output: false + nginx_config_cleanup: false + nginx_config_selinux: true + nginx_config_selinux_enforcing: false + nginx_config_html_demo_template_enable: false + nginx_config_selinux_tcp_ports: + - 3443 + + nginx_config_upload_ssl_enable: true + nginx_config_upload_ssl_crt: + - src: /cert.crt + dest: /etc/nginx/ssl/ + backup: true + nginx_config_upload_ssl_key: + - src: /key.key + dest: /etc/nginx/ssl/ + backup: true + + nginx_config_main_template_enable: true + nginx_config_main_template: + template_file: nginx.conf.j2 + deployment_location: /etc/nginx/nginx.conf + backup: false + config: + main: + user: + username: nginx + group: nginx + worker_processes: auto + error_log: + file: /var/log/nginx/error.log + pid: /run/nginx.pid + core: + tcp_nopush: true + tcp_nodelay: true + types_hash_max_size: 4096 + default_type: application/octet-stream + events: + worker_connections: 1024 + + access: + - path: /var/log/nginx/access.log + http: + include: + - /etc/nginx/mime.types + - /etc/nginx/conf.d/*.conf + + nginx_config_http_template_enable: true + nginx_config_http_template: + - template_file: http/default.conf.j2 + deployment_location: /etc/nginx/conf.d/default.conf + backup: false + config: + core: + sendfile: true + tcp_nopush: true + tcp_nodelay: true + keepalive_timeout: + timeout: 75s + types_hash_max_size: 1024 + default_type: application/octet-stream + include: /etc/nginx/dynamic/upstream_main.conf + servers: + - core: + listen: + - port: 3443 + ssl: true + access_log: + - path: /var/log/nginx/upstream_main.log + format: upstreamlog + buffer: 32k + flush: 5s + client_max_body_size: 50M + ssl: + certificate: + certificate_key: + locations: + - location: / + proxy: + pass: http://backend_servers_main + ssl_verify: false + set_header: + - field: Host + value: $host + - field: X-Real-IP + value: $remote_addr + - field: X-Forwarded-For + value: $proxy_add_x_forwarded_for + - field: X-Upstream-Server + value: $upstream_addr + log: + format: + - name: main + escape: default + format: | + '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"' + - name: upstreamlog + escape: default + format: | + '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"' + + # Upstream configuration (separate file) - contains only upstream block + - template_file: http/default.conf.j2 + deployment_location: /etc/nginx/dynamic/upstream_main.conf + backup: true + config: + upstreams: + - name: backend_servers_main + servers: + - address: :3000 + max_fails: 3 + fail_timeout: 30s + - address: :3000 + max_fails: 3 + fail_timeout: 30s + ip_hash: true +``` + +## Running the Playbooks + +To execute the installation and configuration of Nginx, run the `nginx` playbook: + +```bash +ansible-playbook itential.deployer.nginx -i +``` + +To execute the installation of Nginx, run the `nginx_install` playbook: + +```bash +ansible-playbook itential.deployer.nginx_install -i +``` + +To execute the configuration of nginx_configure, run the `nginx` playbook: + +```bash +ansible-playbook itential.deployer.nginx_configure -i +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/offline_install_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/offline_install_guide.md new file mode 100644 index 00000000..639a7688 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/offline_install_guide.md @@ -0,0 +1,263 @@ +# Installing Itential in an Air-Gapped Environment + +## Overview + +It is not uncommon for customers to have environments that are air-gapped for security reasons. +The Deployer contains playbooks that will download all required packages based on the Ansible +inventory and operating system. Those packages can then be used to install the components with +the Deployer configured in offline mode. A single, non air-gapped server is required to download +the dependent packages. + +| Definitions | Description | +| :---------------- | :---------- | +| Control Node | The Ansible server. This is the server where the Deployer is installed and where the inventory files are located. | +| Target Node | The server where the Itential components will be installed. Sometimes also referred to as a managed node. | +| Package Type | A generic term for the downloaded artifacts. YUM/DNF – RPMs, Python – wheels, Zip files – archives, IAG archive – pkgs, Itential Platform adapters – adapters, Ansible Collections - collections | + +## Running the Download Playbooks + +The download playbooks must be executed on a non air-gapped server. It is critical to use a server +that has the same OS image as the Target Servers in the air-gapped environment. Otherwise, the +downloaded packages will not match, and the installation will most likely fail. It is also highly +recommended to use an image that has been updated with the latest RPMs. + +When the download playbooks are executed, all relevant packages will first be downloaded to the +Target Node and then copied to the Control Node. + +Like the installation playbooks, there are download playbooks for each component. The playbooks +are named `download_packages_.yml`, for example, `download_packages_gateway.yml`. + +For a basic execution, use the following command: + +```bash +ansible-playbook itential.deployer.download_packages_ -i +``` + +**ⓘ Note:** +Your installation might require additional options. + +The download playbooks override the `offline_install_enabled` variable to `false` since they +require YUM repos and certain packages to be installed. This will allow users to define the +`offline_install_enabled` variable in the inventory and set it to `true` and not have to remember +to change the offline install setting between runs of the download playbooks and the installation +playbooks. + +### Target Node Download Directory Structure + +By default, the download playbooks will put the artifacts in `/var/tmp/itential_packages` on the +Target Node. + +This is an example directory structure on a Target Node on a RedHat 9 server: + +#### Example: Directory Structure on Target Node + +```bash +/var/tmp/itential_packages +└── rocky_9 + ├── 2023.1 + │   └── gateway + │   ├── collections + │   ├── rpms + │   └── wheels + │   ├── app + │   └── base + └── 6 + ├── mongodb + │   ├── rpms + │   └── wheels + │   ├── app + │   └── base + ├── os + │   └── rpms + ├── platform + │   ├── adapters + │   ├── rpms + │   │   ├── dependencies + │   │   ├── nodejs + │   │   ├── platform + │   │   └── python + │   └── wheels + │   ├── app + │   └── base + └── redis +    ├── archives +    └── rpms +    └── build +``` + +### Control Node Download Directory Structure + +By default, the download playbooks will copy the artifacts to `playbooks/files/itential_packages` +on the Control Node. This directory is relative where the Deployer is installed. + +This is an example directory structure on the Control Node: + +#### Example: Directory Structure on Control Node + +```bash +playbooks/files/itential_packages +└── rocky_9 + ├── 2023.1 + │   └── gateway + │   ├── collections + │   ├── rpms + │   └── wheels + │   ├── app + │   └── base + └── 6 + ├── mongodb + │   ├── rpms + │   └── wheels + │   ├── app + │   └── base + ├── os + │   └── rpms + ├── platform + │   ├── adapters + │   ├── rpms + │   │   ├── dependencies + │   │   ├── nodejs + │   │   ├── platform + │   │   └── python + │   └── wheels + │   ├── app + │   └── base + └── redis +    ├── archives +    └── rpms +    └── build +``` + +## Running the Install Playbooks in Offline Mode + +### Copying Artifacts to Air-gapped Environment + +After all applicable download playbooks are executed, the entire +`playbooks/files/itential_packages` directory from the non air-gapped Control Node must be +archived, copied to the Control Node in the air-gapped environment, and unarchived before running +the install playbooks. + +### Defining the Inventory + +The `offline_install_enabled` variable must be defined in the inventory and set to `true` to run +in offline mode, or passed on the command line using the `--extra-vars` option. + +```yaml +all: + vars: + offline_install_enabled: true +``` + +### Running the Playbooks + +After the artifacts are copied to the Control Node in the air-gapped environment, the install +playbooks can be executed in offline mode. + +If the `offline_install_enabled` flag is set to `true` in the inventory, run the install playbooks +as you normally would. For example: + +```bash +ansible-playbook itential.deployer. -i +``` + +If the `offline_install_enabled` flag is not defined in the inventory, it must be passed as a +command line argument. For example: + +```bash +ansible-playbook itential.deployer. -i --extra-vars "offline_install_enabled=true" +``` + +In offline mode, the install playbooks will use the packages on the Control Node in the air-gapped +environment instead of installing from the YUM/DNF, Python or NodeJS repositories, from Git +(Itential Platform adapters) or from Ansible Galaxy. The packages are copied to the Target Nodes +and placed in a temporary directory and installed locally. The temporary directories are deleted +automatically. + +## Variable Reference + +All variables defined in this section work out of the box and won't need to be overridden in the +inventory in most cases. If the user wants to use different download directories, they can be +overridden by setting the `offline_target_node_root` or `offline_control_node_root` variables in +the inventory. + +### Global + +The following variables are global for all roles. + +| Variable | Type | Description | Default | +| :------- | :--- | :---------- | :------ | +| `offline_target_node_root` | String | Root directory on the target node where required packages are downloaded to by the download playbooks. | `/var/tmp` | +| `offline_control_node_root` | String | Root directory on the control node where required packages are downloaded to by the download playbooks and where the packages are uploaded from when installing in offline mode. | `{{ playbook_dir }}/files` | +| `offline_itential_packages_path` | String | Path appended to the root directory | `itential_packages/{{ ansible_distribution }}_{{ ansible_distribution_major_version }}` | + +### Itential Platform + +The following variables are defined in the `platform` role. + +| Variable | Type | Description | Default | +| :------- | :----- | :---------- | :------ | +| `platform_offline_packages_root` | String | Platform packages root directory | `{{ offline_itential_packages_path }}/{{ platform_release }}/platform` | +| `platform_offline_target_node_root` | String | Platform target node root directory | `{{ offline_target_node_root }}/{{ platform_offline_packages_root }}` | +| `platform_offline_control_node_root` | String | Platform control node root directory | `{{ offline_control_node_root }}/{{ platform_offline_packages_root }}` | +| `platform_offline_target_node_rpms_dir` | String | Platform target node RPMs directory | `{{ platform_offline_target_node_root }}/rpms` | +| `platform_offline_target_node_wheels_dir` | String | Platform target node wheels directory | `{{ platform_offline_target_node_root }}/wheels` | +| `platform_offline_target_node_adapters_dir` | String | Platform target node adapters directory | `{{ platform_offline_target_node_root }}/adapters` | +| `platform_offline_control_node_rpms_dir` | String | Platform control node RPMs directory | `{{ platform_offline_control_node_root }}/rpms` | +| `platform_offline_control_node_wheels_dir` | String | Platform control node wheels directory | `{{ platform_offline_control_node_root }}/wheels` | +| `platform_offline_control_node_adapters_dir` | String | Platform control node adapters directory | `{{ platform_offline_control_node_root }}/adapters` | + +### Itential Gateway + +The following variables are defined in the `gateway` role. + +| Variable | Type | Description | Default | +| :------- | :--- | :---------- | :------ | +| `gateway_offline_packages_root` | String | Gateway packages root directory | `{{ offline_itential_packages_path }}/{{ iag_release }}/gateway` | +| `gateway_target_node_root` | String | Gateway target node root directory | `{{ offline_target_node_root }}/{{ gateway_offline_packages_root }}` | +| `gateway_control_node_root` | String | Gateway control node root directory | `{{ offline_control_node_root }}/{{ gateway_offline_packages_root }}` | +| `gateway_offline_target_node_rpms_dir` | String | Gateway target node RPMs directory | `{{ gateway_target_node_root }}/rpms` | +| `gateway_offline_target_node_wheels_dir` | String | Gateway target node wheels directory | `{{ gateway_target_node_root }}/wheels` | +| `gateway_offline_target_node_collections_dir` | String | Gateway target node collections directory | `{{ gateway_target_node_root }}/collections` | +| `gateway_offline_control_node_rpms_dir` | String | Gateway control node RPMs directory | `{{ gateway_control_node_root }}/rpms` | +| `gateway_offline_control_node_wheels_dir` | String | Gateway control node wheels directory | `{{ gateway_control_node_root }}/wheels` | +| `gateway_offline_control_node_collections_dir` | String | Gateway control node collections directory | `{{ gateway_control_node_root }}/collections` | + +### MongoDB + +The following variables are defined in the `mongodb` role. + +| Variable | Type | Description | Default | +| :------- | :--- | :---------- | :------ | +| `mongodb_offline_packages_root` | String | MongoDB packages root directory | `{{ offline_itential_packages_path }}/{{ platform_release }}/mongodb` | +| `mongodb_offline_target_node_root` | String | MongoDB target node root directory | `{{ offline_target_node_root }}/{{ mongodb_offline_packages_root }}` | +| `mongodb_offline_control_node_root` | String |MongoDB control node root directory | `{{ offline_control_node_root }}/{{ mongodb_offline_packages_root }}` | +| `mongodb_offline_target_node_rpms_dir` | String | MongoDB target node RPMs directory | `{{ mongodb_offline_target_node_root }}/rpms` | +| `mongodb_offline_target_node_wheels_dir` | String | MongoDB target node wheels directory | `{{ mongodb_offline_target_node_root }}/wheels` | +| `mongodb_offline_control_node_rpms_dir` | String |MongoDB control node RPMs directory | `{{ mongodb_offline_control_node_root }}/rpms` | +| `mongodb_offline_control_node_wheels_dir` | String | MongoDB control node wheels directory | `{{ mongodb_offline_control_node_root }}/wheels` | + +### OS + +The following variables are defined in the `os` role. + +| Variable | Type | Description | Default | +| :------- | :--- | :---------- | :------ | +| `os_offline_packages_root` | String | OS packages root directory | `{{ offline_itential_packages_path }}/{{ platform_release }}/os` | +| `os_offline_target_node_root` | String | OS target node root directory | `{{ offline_target_node_root }}/{{ os_offline_packages_root }}` | +| `os_offline_control_node_root` | String | OS control node root directory | `{{ offline_control_node_root }}/{{ os_offline_packages_root }}` | +| `os_offline_target_node_rpms_dir` | String | OS target node RPMs directory | `{{ os_offline_target_node_root }}/rpms` | +| `os_offline_control_node_rpms_dir` | String | OS control node RPMs directory | `{{ os_offline_control_node_root }}/rpms` | + +### Redis + +The following variables are defined in the `redis` role. + +| Variable | Type | Description | Default | +| :------- | :--- | :---------- | :------ | +| `redis_offline_packages_root` | String | Redis packages root directory | `{{ offline_itential_packages_path }}/{{ platform_release }}/redis` | +| `redis_offline_target_node_root` | String | Redis target node root directory | `{{ offline_target_node_root }}/{{ redis_offline_packages_root }}` | +| `redis_offline_control_node_root` | String | Redis control node root directory | `{{ offline_control_node_root }}/{{ redis_offline_packages_root }}` | +| `redis_offline_target_node_rpms_dir` | String | Redis target node RPMs directory | `{{ redis_offline_target_node_root }}/rpms` | +| `redis_offline_target_node_archives_dir` | String | Redis target node archives directory | `{{ redis_offline_target_node_root }}/archives` | +| `redis_offline_control_node_rpms_dir` | String | Redis control node RPMs directory | `{{ redis_offline_control_node_root }}/rpms` | +| `redis_offline_control_node_archives_dir` | String | Redis control node archives directory | `{{ redis_offline_control_node_root }}/archives` | diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/patch_itential_gateway_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/patch_itential_gateway_guide.md new file mode 100644 index 00000000..ab0018ec --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/patch_itential_gateway_guide.md @@ -0,0 +1,60 @@ +# Patch IAG + +The Itential Deployer supports patch upgrades for IAG. These are also referred to as monthly +releases. For example, if IAG version 3.227.0+2023.1.1 is currently installed, it could be +upgraded to any 3.227.0+2023.1.X version. The patch upgrade playbook **DOES NOT** support major +upgrades. For major upgrades, please work with your Itential Professional Services representative. + +## Requirements + +In order to run the Patch IAG playbook, the `jmespath` Python module must be installed on the +**Ansible Control Node**. + +## Procedure + +### Download the IAG Artifact + +The IAG artifacts are hosted on the Itential Nexus repository. Please contact your Itential +Professional Services representative to get the proper credentials, locations of the artifacts and +instructions for downloading. Download the new artifact and place it in the `files` directory. + +### Update Inventory Variables + +Next, update the inventory variables. It is recommended that the inventory used during the +original IAG install is used as the baseline. Update the `gateway_whl_file` to the new version. + +#### Example: Original Inventory + +```yaml +all: + children: + gateway: + hosts: + + vars: + gateway_release: 4.3 + gateway_whl_file: +``` + +#### Example: Patch Upgrade Inventory + +```yaml +all: + children: + gateway: + hosts: + + vars: + gateway_release: 4.3 + gateway_whl_file: +``` + +### Run Patch IAG Playbook + +Finally, run the `patch_iag` playbook. + +```bash +ansible-playbook itential.deployer.patch_iag -i +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/patch_itential_platform_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/patch_itential_platform_guide.md new file mode 100644 index 00000000..af5dd10e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/patch_itential_platform_guide.md @@ -0,0 +1,86 @@ +# Patch IAP + +Itential uses semantic versioning to articulate changes made to the core products. The Itential +Deployer supports patch and minor upgrades for Itential Platform. The patch upgrade playbook +**DOES NOT** support major upgrades, for example going from 6.X.X to 7.X.X. For major upgrades, +there are typically other components that might need to be upgraded such as the dependencies. +Please work with your Itential Professional Services representative before doing an upgrade to a +new major version. + +## Requirements + +In order to run the Patch Itential Platform playbook, the `jmespath` Python module must be +installed on the **Ansible Control Node**. + +## Procedure + +### Download the Itential Platform Packages + +The Itential Platform packages are hosted on the Itential Nexus repository. Please contact your +Itential Professional Services representative to get the proper credentials, locations of the +packages and instructions for downloading. Download the new packages and place them in the +`playbooks/files` directory. + +**ⓘ Note:** +Nexus URLs are also supported in `platform_packages`. + +### Update Inventory Variables + +Next, update the inventory variables. It is recommended that the inventory used during the original +Itential Platform install is used as the baseline. Update the `platform_release` to the desired +version and update the `platform_packages` appropriately. It is highly recommended to take a backup +of MongoDB before patching. For more information: + + + +#### Example: Original Inventory + +```yaml +all: + children: + platform: + hosts: + : + ansible_host: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_release: 6 + platform_redis_host: redis1.example.com + platform_mongo_url: mongodb://itential:password@mongo1.example.com:27017/itential + platform_packages: + - itential-platform-6.0.0-rc.noarch.rpm + - itential-lifecycle_manager-6.0.0-rc.noarch.rpm + - itential-configuration_manager-6.0.0-rc.noarch.rpm + - itential-service_management-6.0.0-rc1.x86_64.rpm +``` + +#### Example: Patch Upgrade Inventory + +In this example the `itential-platform` and `itential-configuration_manager` packages are being +upgraded to 6.0.1. The `itential-lifecycle_manager` and `itential-service_management` +packages are not being upgraded. + +```yaml +all: + children: + platform: + hosts: + : + ansible_host: + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + platform_release: 6 + platform_redis_host: redis1.example.com + platform_mongo_url: mongodb://itential:password@mongo1.example.com:27017/itential + platform_packages: + - itential-platform-6.0.1-rc.noarch.rpm + - itential-configuration_manager-6.0.1-rc.noarch.rpm +``` + +### Run Patch Itential Platform Playbook + +Finally, run the `patch_platform` playbook. + +```bash +ansible-playbook itential.deployer.patch_platform -i +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/preflight_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/preflight_guide.md new file mode 100644 index 00000000..3ff13566 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/preflight_guide.md @@ -0,0 +1,83 @@ +# Overview + +The playbook and role in this section are designed to run preflight checks on the hosts for Redis, Mongodb, Platform, and Gateway. These checks will determine if the host meets the minimum recommended system specifications for the given application. + +## Preflight Role + +### General information + +The preflight role can be run separately to check the inventory host as well as when running the installation role for the other applications. By default, when installing an application using the deployer, the preflight role will not run. This behavior is controlled with the variables `preflight_run_checks` and `preflight_enforce_checks`. When `preflight_enforce_checks` is set to true, and any of the preflight checks fail, installation on the application will not proceed. + +The following checks will be made against the host. + +| Check | Description | Cause Failure +| :---- | :---------- | :---------- +| `OS` | What version of Redhat/Rocky is installed on the host | Yes +| `CPU` | How many CPU cores the host has | Yes +| `RAM` | How many RAM the host has | Yes +| `Disk Space` | How much free disk space the host has | Yes +| `SELinux` | Is SELinux being enforced | No +| `IPv6` | Is IPv6 configured | No +| `HTTP Proxy` | Is there an HTTP proxy | No +| `HTTPS Proxy` | Is there an HTTPS proxy | No +| `URLs` | Does the host have access to required URLs | No +| `AVX` | Is AVX supported (MongoDB only) | No + +The preflight role will run checks against the hosts and then transfer the results into a local directory defined by the `preflight_directory` for review. + +## Variables + +### Static Variables + +The variables located in the `vars` directory of each role are "static" and not meant to be overridden by the user. Since these variable files are included at run-time, they have a higher precedence than the variables in the inventory and are not easily overridden. + +### Common Variables + +The variables in this section may be overridden in the inventory in the `all` group vars. + +The following table lists the default variables, located in `roles/common_vars/defaults/main/preflight.yml`. + +| Variable | Group | Type | Description | Default Value +| :------- | :---- | :--- | :---------- | :------------ +| `preflight_directory` | `all` | String | Directory containing the results of the preflight checks |`/tmp/preflight` +| `preflight_mounts` | `all` | String | Which mount to check for the storage requirement | `/` +| `env` | `all` | String | Which environment specs to check the host against `dev`/`staging`/`prod` | `dev` +| `preflight_run_checks` | `all` | Boolean | Flag to run the preflight checks | `true` +| `preflight_enforce_checks` | `all` | Boolean | When true, a failed result of preflight checks will stop installation. When false, the installation will proceed | `false` + +## Building Your Inventory + +The preflight checks will not run by default when installing the redis, mongodb, platform, and gateway applications. If a host fails, by default, the deployer will continue to install the application. This behavior can be controlled by setting variables in the inventory as shown below. + +### Example Inventory + +```yaml +all: + vars: + iap_release: 2023.1 + preflight_directory: "/tmp/preflight" + preflight_mounts: "/" + preflight_env: dev + preflight_run_checks: true + preflight_enforce_checks: false +``` + +## Running the Playbook + +To execute the preflight role, run the `preflight` playbook: + +```bash +ansible-playbook itential.deployer.preflight -i +``` + +To execute the preflight role on a specific host, run the `preflight_[[application]]` playbook: + +```bash +ansible-playbook itential.deployer.preflight_redis -i + +ansible-playbook itential.deployer.preflight_mongodb -i + +ansible-playbook itential.deployer.preflight_platform -i + +ansible-playbook itential.deployer.preflight_gateway -i +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/prometheus_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/prometheus_guide.md new file mode 100644 index 00000000..0c3dc450 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/prometheus_guide.md @@ -0,0 +1,237 @@ +# Prometheus and Grafana Roles + +The playbooks and roles discussed in this section install and configure +[Prometheus](https://prometheus.io/), [Grafana](https://grafana.com/) and a set of metrics +exporters that can be used to help monitor the Itential platform. Prometheus and Grafana can be +installed on separate hosts or can be co-located together. They should not be co-located with the +other Itential-related hosts. The exporters will be installed on the Itential-related hosts where +they are exposing metrics. For example, the MongoDB exporter will be installed on the `mongodb` +hosts. + +**ⓘ Note:** +These are optional playbooks and roles and are not required for operation of the Itential platform. + +## Setup + +In order to run the Prometheus playbooks and roles, the `prometheus.prometheus` collection must be +installed manually. It does not get installed automatically when the `itential.deployer` collection +is installed. Also, this playbook requires prometheus version >= 0.22.0. + +```bash +ansible-galaxy collection install prometheus.prometheus +``` + +If you see the following error when running the Prometheus-related playbooks: + +```bash +objc[58735]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. +objc[58735]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug. +ERROR! A worker was found in a dead state +``` + +Set this environment variable: + +```bash +export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES +``` + +## Roles + +There are currently two `itential.deployer` and several `prometheus.prometheus` roles responsible +for installing all of the necessary components. + +## Deployer Roles + +### Prometheus Install Role + +The `itential.deployer.prometheus` role performs a base installation of +[Prometheus](https://prometheus.io/) by calling the `prometheus.prometheus.prometheus` role. It +then configures the Prometheus scrape targets dynamically based on the Itential-related hosts in +the inventory. By default, the scrape targets will use the `inventory_hostname` of the host and the +exporter default web listen port. Optionally, the scrape targets can be specified using the +`_web_listen_address` in the inventory. + +### Grafana Install Role + +The `itential.deployer.grafana` role performs a base installation of +[Grafana](https://grafana.com/). The Grafana installation will include some basic dashboards that +can immediately provide monitoring value of your Itential installation. + +## Prometheus Roles + +The Prometheus and Exporter roles in this section are part of the +[Ansible Prometheus Collection](https://galaxy.ansible.com/ui/repo/published/prometheus/prometheus/). + +### Prometheus Role + +The `itential.deployer` uses the community Prometheus role. Refer to the [`prometheus.prometheus.prometheus`](https://prometheus-community.github.io/ansible/branch/main/prometheus_role.html#ansible-collections-prometheus-prometheus-prometheus-role) documentation for all available configuration parameters. + +### Exporter Roles + +The `itential.deployer` uses the following community Prometheus exporter roles (refer to the linked documentation for all available configuration parameters): + +- [`prometheus.prometheus.redis_exporter`](https://prometheus-community.github.io/ansible/branch/main/redis_exporter_role.html#ansible-collections-prometheus-prometheus-redis-exporter-role) +- [`prometheus.prometheus.mongodb_exporter`](https://prometheus-community.github.io/ansible/branch/main/mongodb_exporter_role.html#ansible-collections-prometheus-prometheus-mongodb-exporter-role) +- [`prometheus.prometheus.node_exporter`](https://prometheus-community.github.io/ansible/branch/main/node_exporter_role.html#ansible-collections-prometheus-prometheus-node-exporter-role) +- [`prometheus.prometheus.process_exporter`](https://prometheus-community.github.io/ansible/branch/main/process_exporter_role.html#ansible-collections-prometheus-prometheus-process-exporter-role) + +Each exporter is a lightweight Go application that exposes the metrics on a standard HTTP endpoint. Each exporter requires a port to be opened so that Prometheus can access the metrics that are being exposed by the exporter. The following ports will be utilized by these roles: + +| Exporter | Default Port | Description | +| -------- | ------------ | ----------- | +| [node exporter](https://github.com/prometheus/node_exporter) | 9100 | The node exporter is installed on all Itential-related hosts and will expose system and sysadmin type metrics. | +| [process exporter](https://github.com/ncabatoff/process-exporter) | 9256 | The process exporter is installed on `platform` and `gateway` hosts and will expose individual processes from Itential Platform and IAG. | +| [mongodb exporter](https://github.com/percona/mongodb_exporter) | 9216 | The mongo exporter is installed on `mongodb` hosts and will expose information about the MongoDB installation and any replica sets. | +| [redis exporter](https://github.com/oliver006/redis_exporter) | 9121 | The redis exporter is installed on `redis` hosts and will expose information about the Redis installation and any replica sets. | + +#### Process Exporter Notes + +The process exporter role by default will monitor all processes on the host. To monitor only +Itential-related processes, add the `process_exporter_names` to the groups vars in the inventory. +Refer to the [Example Inventory](#example-inventory) section. + +## Variables + +### Global Variables + +There are no global variables. + +### Prometheus Role Variables + +All Prometheus variables are handled by the `prometheus.prometheus.prometheus` role. Refer to the +[Prometheus Role](#prometheus-role) section. + +### Exporters Role Variables + +All exporter variables are handled by the exporter roles. Refer to the documentation links in the +[Exporter Roles](#exporter-roles) section. + +### MongoDB Exporter Recommendations + +We recommend setting the `mongodb_exporter_global_conn_pool` variable to `true` in the `mongodb` +group variables section when MongoDB replication is enabled. Otherwise the exporter may consume +all available file descriptors and cause the mongod process to crash. + +```yaml +all: + children: + mongodb: + hosts: + : + : + vars: + mongodb_replication_enabled: true + mongodb_exporter_global_conn_pool: true +``` + +### Grafana Role Variables + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `grafana_user` | String | The Grafana linux user. | `grafana` | +| `grafana_group` | String | The Grafana linux group. | `grafana` | +| `grafana_port` | Integer | The Grafana port that is used by the application. | `3000` | +| `grafana_repo_url` | String | The public URL where the grafana application can be downloaded from. | `https://rpm.grafana.com` | +| `grafana_gpg_key` | String | The public URL where the grafana gpg key can be downloaded from. | `https://rpm.grafana.com/gpg.key` | +| `grafana_install_dir` | String | The root installation directory where grafana will be installed. | `/etc/grafana` | +| `grafana_dashboard_dir` | String | The directory path where the dashboards are uploaded to. | `/etc/grafana/provisioning/dashboards` | +| `grafana_allow_ui_updates` | Boolean | A flag to enable/disable saving dashboards in the grafana UI. | `false` | + +## Building Your Inventory + +To install and configure Prometheus and Grafana, add `prometheus` and `grafana` groups and hosts to +your inventory (in addition to the other Itential-related groups and hosts). + +### Example Inventory + +```yaml +all: + vars: + platform_release: 6 + + children: + redis: + hosts: + : + : + vars: + redis_exporter_password: + + mongodb: + hosts: + : + : + vars: + mongodb_exporter_admin_password: + + platform: + hosts: + : + : + vars: + platform_encryption_key: # 64-length hex string, representing a 256-bit AES encryption key. + process_exporter_names: | + {% raw %} + - cmdline: + - Pronghorn + - cmdline: + - python3 + {% endraw %} + + gateway: + hosts: + : + : + vars: + process_exporter_names: | + {% raw %} + - cmdline: + - python3.9 + {% endraw %} + + prometheus: + hosts: + : + + grafana: + hosts: + : +``` + +## Running the Playbooks + +To execute the installation of Prometheus, Grafana and all the exporters, run the `prometheus_site` playbook: + +```bash +ansible-playbook itential.deployer.prometheus_site -i +``` + +To install Prometheus only, run the `prometheus` playbook: + +```bash +ansible-playbook itential.deployer.prometheus -i +``` + +To install Grafana only, run the `grafana` playbook: + +```bash +ansible-playbook itential.deployer.grafana -i +``` + +To install the exports, run the `prometheus_exporters` playbook: + +```bash +ansible-playbook itential.deployer.prometheus_exports -i +``` + +You can also selectively execute portions of the role by using the following tags: + +| Tag | Description | +| ---- | ----------- | +| `prometheus_install` | This will execute the tasks to install Prometheus. | +| `itential_scrape_config_install` | This will execute the task to create the Itential scrape config file. | +| `node_exporter_install` | This will execute the tasks to install the node exporter. The node exporter is installed on all Itential-related hosts and will expose system and sysadmin type metrics. | +| `process_exporter_install` | This will execute the tasks to install the process exporter. The process exporter is installed on `platform` and `gateway` hosts. | +| `mongodb_exporter_install` | This will execute the tasks to install the mongo exporter. The mongo exporter is installed on `mongodb` hosts. | +| `redis_exporter_install` | This will execute the tasks to install the redis exporter. The redis exporter is installed on `redis` hosts. | +| `grafana_install` | This will execute the tasks to install Grafana. | diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/redis_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/redis_guide.md new file mode 100644 index 00000000..c83e2319 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/redis_guide.md @@ -0,0 +1,281 @@ +# Redis Role + +The playbook and role in this section install and configure Redis for the Itential Automation +Platform. There is one Redis-related role which installs Redis and performs a base configuration. +Optionally configures authentication and replication. + +## Redis Install + +The `redis` role performs a base install of Redis including any OS packages required. It will +compile and install any custom SELinux profiles. It creates the appropriate Linux users, +directories, log files, and systemd services. It uses a template to generate a configuration file +based on the variables defined in the redis group vars. It will start the Redis service when +complete. + +## Authentication + +Optionally, the `redis` role performs tasks to require authentication (username and password) when +communicating with the Redis server. It adjusts the Redis config file and adds each of the +required users and applies appropriate ACLs (see table). The "default" Redis user is disabled. +It modifies the Redis config file to use the appropriate user while doing replication. It adjusts +the Sentinel config file to enable the correct Sentinel user to monitor the redis cluster, if +required. It disables the default user in both Redis and Redis Sentinel. + +More info on Redis authorization: + +| User Name | Default Password | Description | +| :-------- | :--------------- | :---------- | +| admin | admin | Has full access to the Redis database. | +| itential | itential | Has access to all keys, all channels, and all commands except: -asking -cluster -readonly -readwrite -bgrewriteaof -bgsave -failover -flushall -flushdb -psync -replconf -replicaof -save -shutdown -sync | +| repluser | repluser | Has access to the minimum set of commands to perform replication. | +| sentineluser | sentineluser | Has access to the minimum set of commands to perform sentinel monitoring. | +| prometheus | prometheus | Has access to the minimum set of commands to perform Redis and Sentinel monitoring with Prometheus. Required by the optional redis_exporter service. | + +:::(Warning) (⚠ Warning: ) It is assumed that these default passwords will be changed to meet more +rigorous standards. These are intended to be defaults strictly used just for ease of the +installation. It is highly recommended that sensitive data be encrypted using Ansible Vault. + +## Replication + +Optionally, the `redis` role performs the steps required to create a Redis replica set. It uses a +template to generate a Redis Sentinel config file. It modifies the Redis config file to turn off +protected-mode. It assumes that the first host defined in the inventory file is the initial +primary. It will update the config file for the non-primary Redis servers to replicate from the +primary using hostname. It will start the Redis Sentinel service when complete. + +For more information on Redis replication: + +## Variables + +### Static Variables + +The variables located in the `vars` directory of each role are "static" and not meant to be +overridden by the user. Since these variable files are included at run-time based on the Itential +Platform release and OS major version, they have a higher precedence than the variables in the +inventory and are not easily overridden. + +### Global Variables + +The variables in this section can be configured in the inventory in the `all` group or the `redis` +group. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `platform_release` | Fixed-point | Designates the Itential Platform major version. | N/A | + +Defining `platform_release` in the inventory is optional. However, this variable, along with the +OS and major version, is used to determine the default installation variables. If +`platform_release` is not defined, then either `redis_packages` or `redis_source_url` must be +defined. Refer to the [Overriding Installation Variables](#overriding-installation-variables) +section for details. + +### Redis Role Variables + +The variables in this section may be overridden in the inventory in the `redis` group. + +### Install Variables + +The following tables lists the default variables located in `roles/redis/defaults/main/install.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `redis_install_from_source` | String | The method used to install Redis. Set to `true` to install from source (default). Set to `false` to install using DNF packages. | `true` | +| `redis_build_packages` | List | The packages required to build Redis from source | See role. | +| `redis_security_packages` | List | The packages required to configure SELinux | See role. | +| `redis_packages` | List | The Redis packages to install | Varies depending on OS and Platform release | +| `redis_source_url` | String | The Redis source URL | Varies depending on OS and Platform release | +| `redis_remi_repo_url` | String | The URL of the Remi repo RPM. Note: this is only used when the `redis_install_from_source` is set to `false` and the Remi packages are being installed. | `http://rpms.remirepo.net/enterprise/remi-release-{{ ansible_distribution_major_version }}.rpm` | +| `redis_epel_repo_url` | String | The URL of the EPEL repo RPM. Note: this is only used when the `redis_install_from_source` is set to `false` and the Remi packages are being installed. | `https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution_major_version }}.noarch.rpm` | + +### Redis Variables + +The following tables lists the default variables located in `roles/redis/defaults/main/redis.yml`. + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `redis_bin_dir` | String | The Redis binary directory. | `/usr/local/bin` (installing from source) `/usr/bin` (installing from package) | +| `redis_conf_dir` | String | The Redis configuration directory. | `/etc/redis` | +| `redis_conf_file` | String | The location of the Redis configuration file. | `/etc/redis/redis.conf` | +| `redis_log_dir` | String | The Redis log directory. | `/var/log/redis` | +| `redis_log` | String | The location of the Redis log file. | `/var/log/redis/redis.log` | +| `redis_db_filename` | String | The name of the Redis data file. | `dump.rdb` | +| `redis_data_dir` | String | The location of the Redis data directory. | `/var/lib/redis` | +| `redis_port` | Integer | The Redis listen port. | `6379` | +| `redis_owner` | String | The Redis Linux user. | `redis` | +| `redis_group` | String | The Redis Linux group. | `redis` | +| `redis_bind` | String | A space-separated list of hostnames/IP addresses on which Redis listeners will be created. | `bind 127.0.0.1 {{ ansible_default_ipv4.address }}` | +| `redis_tls_enabled` | Boolean | Flag to enable TLS connections. | `false` | + +### Auth Variables + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `redis_auth_enabled` | Boolean | Flag to enable Redis authentication. When set to to `true`, Redis authentication will be configured. | `true` | +| `redis_user_admin_password` | String | The Redis admin user's default password | `admin` | +| `redis_user_itential_password` | String | The Redis itential user's default password | `itential` | +| `redis_user_repluser_password` | String | The Redis repluser user's default password | `repluser` | +| `redis_user_sentineladmin_password` | String | The Redis Sentinel admin user's default password | `admin` | +| `redis_user_sentineluser_password` | String | The Redis Sentinel default user's default password | `sentinel` | +| `redis_user_prometheus_password` | String | The Redis prometheus user's default password | `prometheus` | + +### Replication Variables + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `redis_replicaof` | String | The Redis replicaof setting.
Use replicaof to make a Redis instance a copy of another Redis server. | "{{ groups['redis_master'][0] }} {{ redis_port}}" | + +### Sentinel Variables + +| Variable | Type | Description | Default Value | +| :------- | :--- | :---------- | :------------ | +| `redis_sentinel_conf_file` | String | The location of the Redis Sentinel configuration file. | `/etc/redis/sentinel.conf` | +| `redis_sentinel_log` | String | The location of the Redis Sentinel log file. | `/var/log/redis/sentinel.log` | +| `redis_sentinel_port` | Integer | The Redis Sentinel listen port | `26379` | +| `redis_sentinel_bind` | String | A space-separated list of hostnames/IP addresses on which Redis listeners will be created. | `bind 127.0.0.1 {{ ansible_default_ipv4.address }}` | +| `redis_sentinel_master_name` | String | The Redis master name | `itentialmaster` | +| `redis_sentinel_quorum` | String | The Sentinel quorum setting.
Auto-calculate quorum based on sentinel count (recommended).
Set to explicit number to override (must be <= number of sentinels). | `auto` | + +### Offline Variables + +There are several variables used when download and installing Redis in offline mode. These +variables will not be documented here since they will rarely need to be overridden in the inventory. + +## SELinux + +The `redis` role contains tasks to install custom SELinux profiles (located in `roles/redis/files` +and containing the `te` extension). If your use case requires additional profiles, the files can +be placed in the `files` directory and they will be automatically installed by the role. + +## Overriding Installation Variables + +This role supports installing Redis from source (default) or from packages using RPMs. The +`redis_install_from_source` flag is used to determine which method will be used. If +`redis_install_from_source` is set to `true` , the Redis source code defined by the +`redis_source_url` variable will downloaded and installed. Alternatively, if +`redis_install_from_source` is set to `false`, the Redis packages defined by the `redis_packages` +variable will be installed using DNF. When the `platform_release` is defined in the inventory, +the `redis_source_url` or `redis_packages` variable will automatically be defaulted to a supported +value for the Platform and OS. However, users can override the installation variables by defining +either the `redis_source_url` or `redis_packages` in the inventory. + +| `platform_release` defined in inventory? | `redis_install_from_source` | `redis_source_url` | `redis_packages` | +| :--------------------------------------- | :-------------------------- | :----------------- | :--------------- | +| Yes | `true` | defaulted to supported value may be overridden | N/A | +| Yes | `false` | N/A | defaulted to supported value may be overridden | +| No | `true` | must be defined in inventory | N/A | +| No | `false` | N/A | must be defined in inventory | + +When installing from packages, if the package contains `remi`, the EPEL and Remi repos will be +installed. + +The default values are not documented in this guide since they may change. The current values can +be found in `roles/redis/vars/platform-release-.yml`. + +## Building Your Inventory + +To install and configure Redis, add a `redis_master` group and host(s) to your inventory. The following +inventory shows a basic Redis configuration with a single Redis node with authentication. + +### Example Inventory - Single Redis Node + +```yaml +all: + children: + redis_master: + hosts: + : + ansible_host: + vars: + platform_release: 6 +``` + +### Example Inventory - Single Redis Node, Override Source URL + +```yaml +all: + children: + redis_master: + hosts: + : + ansible_host: + vars: + platform_release: 6 + redis_source_url: https://github.com/redis/redis/archive/7.2.7.tar.gz +``` + +### Example Inventory - Single Redis Node, Install Using Packages + +```yaml +all: + children: + redis_master: + hosts: + : + ansible_host: + vars: + platform_release: 6 + redis_install_from_source: false +``` + +To configure a Redis replica set, add the replica hosts to the `redis_replica` group and configure the `redis_replicaof` variable. + +### Example Inventory - Configure Redis Replication + +```yaml +all: + vars: + platform_release: 6 + children: + redis_master: + hosts: + : + ansible_host: + + redis_replica: + hosts: + : + ansible_host: + : + ansible_host: + vars: + redis_replicaof: # defaults to "{{ groups['redis_master'][0] }} {{ redis_port}}" +``` + +To configure Sentinels, add the sentinel hosts to the `redis_sentinel` group. + +```yaml +all: + vars: + platform_release: 6 + children: + redis_master: + hosts: + : + ansible_host: + + redis_replica: + hosts: + : + ansible_host: + : + ansible_host: + vars: + redis_replicaof: # defaults to "{{ groups['redis_master'][0] }} {{ redis_port}}" + + redis_sentinel: + hosts: + : + ansible_host: + : + ansible_host: + : + ansible_host: +``` + +## Running the Playbook + +To execute the Redis role, run the `redis` playbook: + +```bash +ansible-playbook itential.deployer.redis -i +``` diff --git a/.ansible/collections/ansible_collections/itential/deployer/docs/tls_guide.md b/.ansible/collections/ansible_collections/itential/deployer/docs/tls_guide.md new file mode 100644 index 00000000..0975fae2 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/docs/tls_guide.md @@ -0,0 +1,346 @@ +# Certificate Deployment Scenarios - Configuration Guide + +## Overview + +The deployer supports 3 certificate deployment scenarios by configuring filename variables in your inventory. + +| Scenario | Use Case | Certificates Needed | +|----------|----------|---------------------| +| **Scenario 1** | Per-host certificates (most secure) | One unique cert per server | +| **Scenario 2** | Per-role certificates (simplified management) | One cert shared per role | +| **Scenario 3** | Single wildcard certificate (simplest) | One cert for everything | + +--- + +## Scenario 1: Per-Host Certificates (Current - Most Secure) + +**Certificate Structure:** +``` +certificates/ +├── mongodb/ +│ ├── mongo_host1.ec2.internal.pem +│ ├── mongo_host2.ec2.internal.pem +│ ├── mongo_host3.ec2.internal.pem +│ └── ca-bundle.crt +├── platform/ +│ ├── platform_host1.ec2.internal.crt +│ ├── platform_host1.ec2.internal.key +│ ├── platform_host2.ec2.internal.crt +│ ├── platform_host2.ec2.internal.key +│ └── ca-bundle.crt +└── ... +``` + +**Inventory Configuration:** +```yaml +# MongoDB +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates/mongodb" + # Default: mongodb_tls_server_cert_filename: "{{ inventory_hostname }}.pem" + # No override needed - this is the default + +# Platform +platform: + vars: + platform_https_pki_src_dir: "{{ playbook_dir }}/certificates/platform" + # Default: platform_https_cert_filename: "{{ inventory_hostname }}.crt" + # Default: platform_https_key_filename: "{{ inventory_hostname }}.key" + # No override needed + +# Redis +redis: + vars: + redis_pki_src_dir: "{{ playbook_dir }}/certificates/redis" + # Default: redis_tls_cert_filename: "{{ inventory_hostname }}.crt" + # Default: redis_tls_key_filename: "{{ inventory_hostname }}.key" + # No override needed + +# Gateway +gateway: + vars: + gateway_pki_src_dir: "{{ playbook_dir }}/certificates/gateway" + # Default: gateway_https_cert_filename: "{{ inventory_hostname }}.crt" + # Default: gateway_https_key_filename: "{{ inventory_hostname }}.key" + # No override needed +``` + +**Pros:** +- ✅ Most secure (compromise of one server doesn't affect others) +- ✅ Easy to rotate individual server certificates +- ✅ Clear audit trail (which cert on which server) + +**Cons:** +- ❌ More certificates to manage +- ❌ More certificate generation overhead + +--- + +## Scenario 2: Per-Role Certificates (Simplified Management) + +**Certificate Structure:** +``` +certificates/ +├── mongodb/ +│ ├── mongodb.pem ← Shared by all MongoDB servers +│ ├── ca-bundle.crt +│ └── replica.key +├── platform/ +│ ├── platform.crt ← Shared by all Platform servers +│ ├── platform.key +│ ├── client.pem +│ ├── mongodb-client.key +│ └── ca-bundle.crt +├── redis/ +│ ├── redis.crt ← Shared by all Redis servers +│ ├── redis.key +│ └── ca-bundle.crt +└── gateway/ + ├── gateway.crt ← Shared by all Gateway servers + ├── gateway.key + └── ca-bundle.crt +``` + +**Inventory Configuration:** +```yaml +# MongoDB - All servers use mongodb.pem +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates/mongodb" + mongodb_tls_server_cert_filename: "mongodb.pem" + +# Platform - All servers use platform.crt/key +platform: + vars: + platform_https_pki_src_dir: "{{ playbook_dir }}/certificates/platform" + platform_https_cert_filename: "platform.crt" + platform_https_key_filename: "platform.key" + +# Redis - All servers use redis.crt/key +redis: + vars: + redis_pki_src_dir: "{{ playbook_dir }}/certificates/redis" + redis_tls_cert_filename: "redis.crt" + redis_tls_key_filename: "redis.key" + +# Gateway - All servers use gateway.crt/key +gateway: + vars: + gateway_pki_src_dir: "{{ playbook_dir }}/certificates/gateway" + gateway_https_cert_filename: "gateway.crt" + gateway_https_key_filename: "gateway.key" +``` + +**Certificate Requirements:** +- Subject Alternative Names (SANs) must include all server hostnames/IPs for each role +- Example MongoDB cert SANs: `DNS:mongo_host1.ec2.internal, DNS:mongo_host2.ec2.internal, DNS:mongo_host3.ec2.internal` + +**Pros:** +- ✅ Fewer certificates to manage +- ✅ Simpler certificate generation (one per role) +- ✅ Easy to deploy new servers (just copy same cert) + +**Cons:** +- ❌ Certificate compromise affects all servers in that role +- ❌ Certificate rotation requires updating all servers +- ❌ Larger certificate files (many SANs) + +--- + +## Scenario 3: Single Wildcard Certificate (Simplest) + +**Certificate Structure:** +``` +certificates/ +├── wildcard.crt ← One cert for everything +├── wildcard.key +└── ca-bundle.crt +``` + +**Inventory Configuration:** +```yaml +# MongoDB +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates" + mongodb_tls_server_cert_filename: "wildcard.pem" + +# Platform +platform: + vars: + platform_https_pki_src_dir: "{{ playbook_dir }}/certificates" + platform_mongodb_pki_src_dir: "{{ playbook_dir }}/certificates" + platform_https_cert_filename: "wildcard.crt" + platform_https_key_filename: "wildcard.key" + +# Redis +redis: + vars: + redis_pki_src_dir: "{{ playbook_dir }}/certificates" + redis_tls_cert_filename: "wildcard.crt" + redis_tls_key_filename: "wildcard.key" + +# Gateway +gateway: + vars: + gateway_pki_src_dir: "{{ playbook_dir }}/certificates" + gateway_https_cert_filename: "wildcard.crt" + gateway_https_key_filename: "wildcard.key" +``` + +**Certificate Requirements:** +- Wildcard certificate covering all hostnames: `*.ec2.internal` or `*.example.com` +- OR certificate with SANs for ALL servers across ALL roles + +**Note for MongoDB:** +- Need to create `wildcard.pem` (combined cert+key): + ```bash + cat wildcard.crt wildcard.key > wildcard.pem + chmod 600 wildcard.pem + ``` + +**Pros:** +- ✅ Simplest to manage (one certificate) +- ✅ Easy to deploy anywhere +- ✅ Fast certificate rotation (update once, deploy everywhere) + +**Cons:** +- ❌ Least secure (compromise affects everything) +- ❌ Single point of failure +- ❌ Wildcard certificates may not be allowed by security policy +- ❌ Very large SAN list if not using wildcard + +--- + +## Comparison Matrix + +| Feature | Scenario 1
(Per-Host) | Scenario 2
(Per-Role) | Scenario 3
(Wildcard) | +|---------|--------------------------|--------------------------|--------------------------| +| **Certificates to manage** | High | Medium | Low (1) | +| **Security level** | Highest | Medium | Lowest | +| **Certificate generation** | Complex | Moderate | Simple | +| **Rotation complexity** | Low (per server) | Medium (per role) | High (everything at once) | +| **New server deployment** | Need new cert | Copy role cert | Copy same cert | +| **SAN requirements** | Single hostname | Multiple hostnames | All hostnames or wildcard | +| **Blast radius if compromised** | One server | One role | Everything | + +--- + +## Migration Between Scenarios + +### From Scenario 1 → Scenario 2 + +**Step 1:** Generate role-level certificates with SANs +```bash +# Example: MongoDB cert with all MongoDB server SANs +openssl req -new -x509 -days 365 -key mongodb.key -out mongodb.crt \ + -subj "/CN=mongodb" \ + -addext "subjectAltName=DNS:mongo_host1.ec2.internal,DNS:mongo_host2.ec2.internal,DNS:mongo_host3.ec2.internal" +``` + +**Step 2:** Update inventory to use role filenames +```yaml +mongodb: + vars: + mongodb_tls_server_cert_filename: "mongodb.pem" # Changed +``` + +**Step 3:** Update certificates directory structure +```bash +# Old structure: certificates/mongodb/mongo_host1.ec2.internal.pem +# New structure: certificates/mongodb/mongodb.pem +``` + +### From Scenario 2 → Scenario 3 + +**Step 1:** Generate wildcard or multi-SAN certificate covering all servers + +**Step 2:** Update inventory to use wildcard filenames +```yaml +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates" # Single directory + mongodb_tls_server_cert_filename: "wildcard.pem" +``` + +--- + +## Recommendations by Environment + +### Development/Testing +- **Use:** Scenario 3 (Wildcard) +- **Why:** Simplest, fastest to set up, easy to regenerate + +### Staging +- **Use:** Scenario 2 (Per-Role) +- **Why:** Balance of simplicity and security, mirrors production patterns + +### Production +- **Use:** Scenario 1 (Per-Host) +- **Why:** Best security, compliance requirements, limited blast radius + +--- + +## Quick Reference - Variable Override Locations + +All filename variables can be overridden in your inventory: + +**MongoDB:** +- `mongodb_tls_server_cert_filename` +- `mongodb_tls_ca_cert_filename` +- `mongodb_replica_keyfile_filename` + +**Platform:** +- `platform_https_cert_filename` +- `platform_https_key_filename` +- `platform_https_ca_filename` +- `platform_mongodb_ca_filename` +- `platform_mongodb_client_cert_filename` +- `platform_mongodb_client_key_filename` + +**Redis:** +- `redis_tls_cert_filename` +- `redis_tls_key_filename` +- `redis_tls_ca_cert_filename` + +**Gateway:** +- `gateway_https_cert_filename` +- `gateway_https_key_filename` +- `gateway_https_ca_filename` + +--- + +## Example: Mixed Scenario (Advanced) + +You can even mix scenarios per role: + +```yaml +# MongoDB: Per-host (most critical) +mongodb: + vars: + mongodb_tls_server_cert_filename: "{{ inventory_hostname }}.pem" + +# Platform: Per-host (user-facing) +platform: + vars: + platform_https_cert_filename: "{{ inventory_hostname }}.crt" + platform_https_key_filename: "{{ inventory_hostname }}.key" + +# Redis: Per-role (internal, less critical) +redis: + vars: + redis_tls_cert_filename: "redis.crt" + redis_tls_key_filename: "redis.key" + +# Gateway: Per-role (behind load balancer) +gateway: + vars: + gateway_https_cert_filename: "gateway.crt" + gateway_https_key_filename: "gateway.key" +``` + +--- + +## Key Takeaway + +**The deployer is flexible!** You don't need code changes - just configure the filename variables in your inventory to match your certificate structure. The `{{ inventory_hostname }}` default supports Scenario 1, but you can override it for Scenarios 2 and 3. \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/meta/runtime.yml b/.ansible/collections/ansible_collections/itential/deployer/meta/runtime.yml new file mode 100644 index 00000000..ef61b759 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/meta/runtime.yml @@ -0,0 +1,52 @@ +--- +# Collections must specify a minimum required ansible version to upload +# to galaxy +requires_ansible: '>=2.11.0' + +# Content that Ansible needs to load from another location or that has +# been deprecated/removed +# plugin_routing: +# action: +# redirected_plugin_name: +# redirect: ns.col.new_location +# deprecated_plugin_name: +# deprecation: +# removal_version: "4.0.0" +# warning_text: | +# See the porting guide on how to update your playbook to +# use ns.col.another_plugin instead. +# removed_plugin_name: +# tombstone: +# removal_version: "2.0.0" +# warning_text: | +# See the porting guide on how to update your playbook to +# use ns.col.another_plugin instead. +# become: +# cache: +# callback: +# cliconf: +# connection: +# doc_fragments: +# filter: +# httpapi: +# inventory: +# lookup: +# module_utils: +# modules: +# netconf: +# shell: +# strategy: +# terminal: +# test: +# vars: + +# Python import statements that Ansible needs to load from another location +# import_redirection: +# ansible_collections.ns.col.plugins.module_utils.old_location: +# redirect: ansible_collections.ns.col.plugins.module_utils.new_location + +# Groups of actions/modules that take a common set of options +# action_groups: +# group_name: +# - module1 +# - module2 diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_gateway.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_gateway.yml new file mode 100644 index 00000000..ea89f709 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_gateway.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Gateway packages + hosts: gateway + become: true + vars: + offline_install_enabled: false + roles: + - role: itential.deployer.common + - role: itential.deployer.offline + tasks: + - name: Download Gateway packages # noqa run-once + ansible.builtin.import_role: + name: itential.deployer.gateway + tasks_from: download-packages + run_once: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_gateway_site.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_gateway_site.yml new file mode 100644 index 00000000..4b969e1c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_gateway_site.yml @@ -0,0 +1,6 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Gateway packages + import_playbook: itential.deployer.download_packages_gateway + tags: download_gateway_packages diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_mongodb.yml new file mode 100644 index 00000000..d8432b42 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_mongodb.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download MongoDB packages + hosts: mongodb + become: true + vars: + offline_install_enabled: false + roles: + - role: itential.deployer.common + - role: itential.deployer.offline + tasks: + - name: Download MongoDB packages # noqa run-once + ansible.builtin.import_role: + name: itential.deployer.mongodb + tasks_from: download-packages + run_once: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_os.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_os.yml new file mode 100644 index 00000000..a9331e35 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_os.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download OS packages + hosts: all + become: true + vars: + offline_install_enabled: false + roles: + - role: itential.deployer.common + - role: itential.deployer.offline + tasks: + - name: Download OS packages # noqa run-once + ansible.builtin.import_role: + name: itential.deployer.os + tasks_from: download-packages + run_once: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_platform.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_platform.yml new file mode 100644 index 00000000..b355cbb6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_platform.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Itential Platform packages + hosts: platform + become: true + vars: + offline_install_enabled: false + validate_platform_encryption_key: false + roles: + - role: itential.deployer.common + - role: itential.deployer.offline + tasks: + - name: Download Itential Platform packages # noqa run-once + ansible.builtin.import_role: + name: itential.deployer.platform + tasks_from: download-packages + run_once: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_platform_site.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_platform_site.yml new file mode 100644 index 00000000..7c589c94 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_platform_site.yml @@ -0,0 +1,11 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Redis packages + import_playbook: itential.deployer.download_packages_redis + +- name: Download MongoDB packages + import_playbook: itential.deployer.download_packages_mongodb + +- name: Download Itential Platform packages + import_playbook: itential.deployer.download_packages_platform diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_redis.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_redis.yml new file mode 100644 index 00000000..1e939472 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_redis.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Redis packages + hosts: redis + become: true + vars: + offline_install_enabled: false + roles: + - role: itential.deployer.common + - role: itential.deployer.offline + tasks: + - name: Download Redis packages # noqa run-once + ansible.builtin.import_role: + name: itential.deployer.redis + tasks_from: download-packages + run_once: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_site.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_site.yml new file mode 100644 index 00000000..6ff93567 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/download_packages_site.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Platform packages + import_playbook: itential.deployer.download_packages_platform_site + +- name: Download Gateway packages + import_playbook: itential.deployer.download_packages_gateway_site diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/gateway.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/gateway.yml new file mode 100644 index 00000000..67afd166 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/gateway.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### IAG +- name: Install IAG + hosts: gateway + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + + # Perform a base installation of IAG + - role: itential.deployer.gateway diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/grafana.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/grafana.yml new file mode 100644 index 00000000..8bd53307 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/grafana.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Grafana + hosts: grafana + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + - role: itential.deployer.grafana + tags: grafana_install diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/install.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/install.yml new file mode 100644 index 00000000..0326e4b0 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/install.yml @@ -0,0 +1,5 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install and configure Itential Platform and Gateway + import_playbook: itential.deployer.site diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/mongodb.yml new file mode 100644 index 00000000..032a5d3c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/mongodb.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### MONGODB +- name: Install MongoDB + hosts: mongodb, mongodb_arbiter + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + # Perform a base installation of MongoDB + # Many of the other component's settings with regard to Itential Platform are stored in MongoDB. + # Run these tasks on any defined arbiters as well. + - role: itential.deployer.mongodb + tags: mongodb diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx.yml new file mode 100644 index 00000000..f2597620 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2025, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install nginx + import_playbook: nginx_install.yml + +- name: Configure nginx + import_playbook: nginx_configure.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx_configure.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx_configure.yml new file mode 100644 index 00000000..549e9b2e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx_configure.yml @@ -0,0 +1,57 @@ +# Copyright (c) 2025, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)--- +--- +- name: Configure nginx + hosts: nginx + become: true + + tasks: + - name: Configure nginx + ansible.builtin.include_role: + name: nginxinc.nginx_config + + # TODO: Use NGINX variables to properly configure SELINUX and remove redundant tasks. + - name: Configure SELinux http_port_t for port {{ nginx_config_http_template[0].config.servers[0].core.listen[0].port }} + community.general.seport: + ports: "{{ nginx_config_http_template[0].config.servers[0].core.listen[0].port }}" + proto: tcp + setype: http_port_t + state: present + + - name: Allow nginx to make network connections + ansible.posix.seboolean: + name: httpd_can_network_connect + state: true + persistent: true + + - name: Allow nginx to modify system files + ansible.posix.seboolean: + name: httpd_setrlimit + state: true + persistent: true + + - name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ nginx_config_http_template[0].config.servers[0].core.listen[0].port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + + - name: Restart nginx after configuration + ansible.builtin.systemd: + name: nginx + state: restarted + enabled: true + daemon_reload: true + + - name: Assert that nginx is running + ansible.builtin.systemd: + name: nginx + register: nginx_status + failed_when: nginx_status.status.ActiveState != "active" + tags: always diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx_install.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx_install.yml new file mode 100644 index 00000000..c07e3d5e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/nginx_install.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2025, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install nginx + hosts: nginx + become: true + + tasks: + - name: Install nginx + ansible.builtin.include_role: + name: nginxinc.nginx + + - name: Ensure nginx is started and enabled + ansible.builtin.systemd: + name: nginx + state: restarted + enabled: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/os.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/os.yml new file mode 100644 index 00000000..c7eca44c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/os.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### OS +- name: Install OS packages + hosts: platform, platform_secondary, redis, redis_secondary, mongodb, mongodb_arbiter, gateway + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + + # Perform a base installation of all packages needed for the application + - role: itential.deployer.os diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/patch_gateway.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/patch_gateway.yml new file mode 100644 index 00000000..b4541fe4 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/patch_gateway.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### IAG +- name: Patch IAG + hosts: gateway + become: true + roles: + - role: itential.deployer.common + tasks: + - name: Patch IAG + ansible.builtin.import_role: + name: itential.deployer.gateway + tasks_from: upgrade-gateway diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/patch_platform.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/patch_platform.yml new file mode 100644 index 00000000..4c2f14b6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/patch_platform.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### Itential Platform +- name: Patch Itential Platform + hosts: platform + become: true + roles: + - role: itential.deployer.common + tasks: + - name: Patch Itential Platform + ansible.builtin.import_role: + name: itential.deployer.platform + tasks_from: upgrade-platform diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/platform.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/platform.yml new file mode 100644 index 00000000..2c9cc548 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/platform.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### Itential Platform +- name: Install Itential Platform + hosts: platform, platform_secondary + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + # Perform a base installation of Itential Platform + - role: itential.deployer.platform + tags: + - platform + - platform_install diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/platform_site.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/platform_site.yml new file mode 100644 index 00000000..97507eb8 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/platform_site.yml @@ -0,0 +1,11 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install and configure Redis + import_playbook: itential.deployer.redis + +- name: Install and configure MongoDB + import_playbook: itential.deployer.mongodb + +- name: Install and configure Itential Platform + import_playbook: itential.deployer.platform diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight.yml new file mode 100644 index 00000000..554dbf12 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight.yml @@ -0,0 +1,25 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Run Redis Preflight checks + hosts: redis, redis_secondary, mongodb, mongodb_secondary, gateway, platform, platform_secondary + become: true + roles: + - role: itential.deployer.common_vars + tags: always + +- name: Include Preflight Redis + import_playbook: itential.deployer.preflight_redis + tags: preflight_redis + +- name: Include Preflight MongoDB + import_playbook: itential.deployer.preflight_mongodb + tags: preflight_mongodb + +- name: Include Preflight Platform + import_playbook: itential.deployer.preflight_platform + tags: preflight_platform + +- name: Include Preflight Gateway + import_playbook: itential.deployer.preflight_gateway + tags: preflight_gateway diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_gateway.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_gateway.yml new file mode 100644 index 00000000..bc64abe2 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_gateway.yml @@ -0,0 +1,45 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Run Redis Preflight checks + hosts: gateway + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common_vars + tags: + - always + tasks: + - name: Preflight + ansible.builtin.import_role: + name: itential.deployer.gateway + tasks_from: preflight + +- name: Read all data and combines and displays results + hosts: localhost + become: false + tags: always + roles: + - role: itential.deployer.common_vars + tasks: + - name: Set results_file + delegate_to: localhost + ansible.builtin.set_fact: + results_file: "{{ preflight_directory }}/Results_Gateway.txt" + + - name: Ensure the destination file exists and is empty + ansible.builtin.file: + path: "{{ results_file }}" + state: absent + + - name: Combine files into the output file + ansible.builtin.shell: | + echo "GATEWAY RESULTS" >> {{ results_file }} + for file in {{ preflight_directory }}/*.txt; do + if [[ $(basename "$file") == gateway*.txt ]]; then + echo ---------------- >> {{ results_file }} + cat "$file" >> {{ results_file }} + echo "" >> {{ results_file }} + fi + done + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_mongodb.yml new file mode 100644 index 00000000..79f517fc --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_mongodb.yml @@ -0,0 +1,46 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Run Redis Preflight checks + hosts: mongodb, mongodb_secondary + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common_vars + tags: + - always + tasks: + - name: Preflight + ansible.builtin.import_role: + name: itential.deployer.mongodb + tasks_from: preflight + +- name: Read all data and combines and displays results + hosts: localhost + become: false + tags: always + roles: + - role: itential.deployer.common_vars + tasks: + - name: Set results_file + delegate_to: localhost + ansible.builtin.set_fact: + results_file: "{{ preflight_directory }}/Results_MongoDB.txt" + + - name: Ensure the destination file exists and is empty + ansible.builtin.file: + path: "{{ results_file }}" + state: absent + + - name: Combine files into the output file + ansible.builtin.shell: | + echo "Mongodb RESULTS" >> {{ results_file }} + for file in {{ preflight_directory }}/*.txt; do + if [[ $(basename "$file") == mongodb*.txt ]]; then + echo ---------------- >> {{ results_file }} + cat "$file" >> {{ results_file }} + echo "" >> {{ results_file }} + fi + done + echo "" >> {{ results_file }} + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_platform.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_platform.yml new file mode 100644 index 00000000..070cc1ba --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_platform.yml @@ -0,0 +1,46 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Run Redis Preflight checks + hosts: platform, platform_secondary + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common_vars + tags: + - always + tasks: + - name: Preflight + ansible.builtin.import_role: + name: itential.deployer.platform + tasks_from: preflight + +- name: Read all data and combines and displays results + hosts: localhost + become: false + tags: always + roles: + - role: itential.deployer.common_vars + tasks: + - name: Set results_file + delegate_to: localhost + ansible.builtin.set_fact: + results_file: "{{ preflight_directory }}/Results_Platform.txt" + + - name: Ensure the destination file exists and is empty + ansible.builtin.file: + path: "{{ results_file }}" + state: absent + + - name: Combine files into the output file + ansible.builtin.shell: | + echo "Platform RESULTS" >> {{ results_file }} + for file in {{ preflight_directory }}/*.txt; do + if [[ $(basename "$file") == platform*.txt ]]; then + echo ---------------- >> {{ results_file }} + cat "$file" >> {{ results_file }} + echo "" >> {{ results_file }} + fi + done + echo "" >> {{ results_file }} + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_redis.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_redis.yml new file mode 100644 index 00000000..b60bd207 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/preflight_redis.yml @@ -0,0 +1,45 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Run Redis Preflight checks + hosts: redis, redis_secondary + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common_vars + tags: + - always + tasks: + - name: Preflight + ansible.builtin.import_role: + name: itential.deployer.redis + tasks_from: preflight + +- name: Read all data and combines and displays results + hosts: localhost + become: false + tags: always + roles: + - role: itential.deployer.common_vars + tasks: + - name: Set results_file + delegate_to: localhost + ansible.builtin.set_fact: + results_file: "{{ preflight_directory }}/Results_Redis.txt" + + - name: Ensure the destination file exists and is empty + ansible.builtin.file: + path: "{{ results_file }}" + state: absent + + - name: Combine files into the output file + ansible.builtin.shell: | + echo "Redis RESULTS" >> {{ results_file }} + for file in {{ preflight_directory }}/*.txt; do + if [[ $(basename "$file") == redis*.txt ]]; then + echo ---------------- >> {{ results_file }} + cat "$file" >> {{ results_file }} + echo "" >> {{ results_file }} + fi + done + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus.yml new file mode 100644 index 00000000..0204f177 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Prometheus + hosts: prometheus + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + - role: itential.deployer.prometheus + tags: prometheus_install diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus_exporters.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus_exporters.yml new file mode 100644 index 00000000..b3b8c6bf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus_exporters.yml @@ -0,0 +1,140 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Redis exporter + hosts: redis* + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + - role: prometheus.prometheus.redis_exporter + vars: + redis_exporter_user: prometheus + tags: redis_exporter_install + tasks: + - name: Make custom configuration changes + tags: redis_exporter_custom_config + block: + - name: Gather service facts + ansible.builtin.service_facts: + + - name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ redis_exporter_web_listen_address.split(':') | last }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +- name: Install MongoDB exporter + hosts: mongodb* + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + - role: prometheus.prometheus.mongodb_exporter + vars: + mongodb_exporter_collectors: all + tags: mongodb_exporter_install + tasks: + - name: Make custom configuration changes + tags: mongodb_exporter_custom_config + block: + + - name: Add MongoDB authentication properties to MongoDB exporter + when: mongodb_exporter_admin_password is defined + notify: Restart mongodb_exporter + block: + + - name: Add the MongoDB user to the systemd service file + ansible.builtin.lineinfile: + path: /etc/systemd/system/mongodb_exporter.service + insertafter: '^\[Service\]' + line: 'Environment="MONGODB_USER=admin"' + + - name: Add the MongoDB password to the systemd service file + ansible.builtin.lineinfile: + path: /etc/systemd/system/mongodb_exporter.service + insertafter: 'Environment="MONGODB_USER=admin"' + line: 'Environment="MONGODB_PASSWORD={{ mongodb_exporter_admin_password }}"' + + - name: Gather service facts + ansible.builtin.service_facts: + + - name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ mongodb_exporter_web_listen_address.split(':') | last }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +- name: Install node exporter + hosts: redis*, mongodb*, platform, gateway + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + - role: prometheus.prometheus.node_exporter + tags: node_exporter_install + tasks: + - name: Make custom configuration changes + tags: node_exporter_custom_config + block: + - name: Gather service facts + ansible.builtin.service_facts: + + - name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ node_exporter_web_listen_address.split(':') | last }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +- name: Install process exporter + hosts: platform, gateway + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + tags: always + + - role: prometheus.prometheus.process_exporter + tags: process_exporter_install + tasks: + - name: Make custom configuration changes + tags: process_exporter_custom_config + block: + - name: Gather service facts + ansible.builtin.service_facts: + + - name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ process_exporter_web_listen_address.split(':') | last }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus_site.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus_site.yml new file mode 100644 index 00000000..0b29a4c4 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/prometheus_site.yml @@ -0,0 +1,11 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Prometheus exporters + import_playbook: itential.deployer.prometheus_exporters + +- name: Install Prometheus + import_playbook: itential.deployer.prometheus + +- name: Install Grafana + import_playbook: itential.deployer.grafana diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/redis.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/redis.yml new file mode 100644 index 00000000..f8ca1d8f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/redis.yml @@ -0,0 +1,23 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +### Redis +- name: Configure Redis data nodes + hosts: redis_master, redis_replica + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + + # Perform a base installation of Redis and optionally configure authorization and replication + - role: itential.deployer.redis + +- name: Configure Redis sentinel nodes + hosts: redis_sentinel + become: true + roles: + # Pull in the common vars + - role: itential.deployer.common + + # Perform a base installation of Redis and optionally configure authorization and replication + - role: itential.deployer.redis diff --git a/.ansible/collections/ansible_collections/itential/deployer/playbooks/site.yml b/.ansible/collections/ansible_collections/itential/deployer/playbooks/site.yml new file mode 100644 index 00000000..67c21e85 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/playbooks/site.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install and configure Itential Platform + import_playbook: itential.deployer.platform_site + +- name: Install and configure Itential Gateway + import_playbook: itential.deployer.gateway diff --git a/.ansible/collections/ansible_collections/itential/deployer/plugins/README.md b/.ansible/collections/ansible_collections/itential/deployer/plugins/README.md new file mode 100644 index 00000000..34cd30a9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/plugins/README.md @@ -0,0 +1,31 @@ +# Collections Plugins Directory + +This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that +is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that +would contain module utils and modules respectively. + +Here is an example directory of the majority of plugins currently supported by Ansible: + +``` +└── plugins + ├── action + ├── become + ├── cache + ├── callback + ├── cliconf + ├── connection + ├── filter + ├── httpapi + ├── inventory + ├── lookup + ├── module_utils + ├── modules + ├── netconf + ├── shell + ├── strategy + ├── terminal + ├── test + └── vars +``` + +A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.14/plugins/plugins.html). diff --git a/.ansible/collections/ansible_collections/itential/deployer/plugins/modules/mongodb_config_state.py b/.ansible/collections/ansible_collections/itential/deployer/plugins/modules/mongodb_config_state.py new file mode 100644 index 00000000..b9de3636 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/plugins/modules/mongodb_config_state.py @@ -0,0 +1,145 @@ +#!/usr/bin/python + +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: mongodb_config_state + +short_description: Report the configuration state of MongoDB. + +# If this is part of a collection, you need to use semantic versioning, +# i.e. the version is of the form "2.5.0" and not "2.4". +version_added: "3.0.0" + +description: This module will inspect the configuration of MongoDB and report back + with simple boolean values the state of the running MongoDB configuration. For + example, it will provide boolean values on the state of replication and on the + state of authorization. + +options: + login_database: + description: The database to login in to. + required: true + type: str + login_host: + description: The host where the database lives. + required: true + type: str + login_port: + description: The port that the database is listening for connections. + required: true + type: int + +author: + - Steven Schattenberg (@steven-schattenberg-itential) +''' + +EXAMPLES = r''' +- name: Determine MongoDB config state + itential.deployer.mongodb_config_state: + login_database: admin + login_host: example.com + login_port: 27017 +''' + +RETURN = r''' +# These are examples of possible return values, and in general should use other names for return values. +replication_enabled: + description: Is replication enabled, true or false + type: bool + returned: always + sample: false +auth_enabled: + description: Is auth enabled, true or false + type: bool + returned: always + sample: false +primary: + description: The name of the primary server + type: str + returned: always + sample: "example.host.com" +members: + description: The list of members in the replica set or empty list + type: arr + returned: always + sample: ["example1.host.com", "example2.host.com", "example3.host.com"] +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.facts.compat import ansible_facts +from pymongo import MongoClient +from pymongo.errors import OperationFailure +from bson.json_util import dumps + +def build_connection_string(args): + return "mongodb://" + args["login_host"] + ":" + str(args["login_port"]) + "/" + args["login_database"] + +def run_module(): + # define available arguments/parameters a user can pass to the module + module_args = dict( + login_database=dict(type='str', required=False, default='admin', no_log=False), + login_host=dict(type='str', required=True, no_log=False), + login_port=dict(type='int', required=False, default=27017, no_log=False) + ) + + # seed the result dict in the object + # we primarily care about changed and state + # changed is if this module effectively modified the target + # state will include any data that you want your module to pass back + # for consumption, for example, in a subsequent task + result = dict( + changed=False, + replication_enabled=False, + auth_enabled=False, + primary="", + members=[] + ) + + # the AnsibleModule object will be our abstraction working with Ansible + # this includes instantiation, a couple of common attr would be the + # args/params passed to the execution, as well as if the module + # supports check mode + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True + ) + + # if the user is working with this module in only check mode we do not + # want to make any changes to the environment, just return the current + # state with no modifications + if module.check_mode: + module.exit_json(**result) + + uri = build_connection_string(module.params) + + client = MongoClient(uri) + database = client.get_database("admin") + hello = database.command("hello") + + if "setName" in hello: + result["replication_enabled"] = True + result["primary"] = hello["primary"].split(":")[0] + result["members"] = hello["hosts"] + + # This MongoDB command requires an authorized user to execute. This module + # is deliberately not authorizing so that we can determine if auth is + # enabled. + try: + user = database.command('usersInfo') + except OperationFailure: + result["auth_enabled"] = True + + # in the event of a successful module execution, you will want to + # simple AnsibleModule.exit_json(), passing the key/value results + module.exit_json(**result) + +def main(): + run_module() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/plugins/modules/os_compatibility.py b/.ansible/collections/ansible_collections/itential/deployer/plugins/modules/os_compatibility.py new file mode 100644 index 00000000..baffbe21 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/plugins/modules/os_compatibility.py @@ -0,0 +1,101 @@ +#!/usr/bin/python + +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: os_compatibility + +short_description: Inspect facts and determine if the host is compatible + +# If this is part of a collection, you need to use semantic versioning, +# i.e. the version is of the form "2.5.0" and not "2.4". +version_added: "3.0.0" + +description: This module will inspect the host facts and determine if the host is compatible for + installation of the Itential stack. The stack requires a dnf package manager and Redhat family + of linux of specific major versions. + +# Specify this value according to your collection +# in format of namespace.collection.doc_fragment_name +# extends_documentation_fragment: +# - my_namespace.my_collection.my_doc_fragment_name + +author: + - Steven Schattenberg (@steven-schattenberg-itential) +''' + +EXAMPLES = r''' +- name: Determine compatibility + itential.deployer.os_compatibility: +''' + +RETURN = r''' +# These are examples of possible return values, and in general should use other names for return values. +compatible: + description: Is this operating system compatible with the Itential platform + type: bool + returned: always + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.facts.compat import ansible_facts + +def run_module(): + # define available arguments/parameters a user can pass to the module + module_args = dict() + + # seed the result dict in the object + # we primarily care about changed and state + # changed is if this module effectively modified the target + # state will include any data that you want your module to pass back + # for consumption, for example, in a subsequent task + result = dict( + changed=False, + compatible=False, + ) + + # the AnsibleModule object will be our abstraction working with Ansible + # this includes instantiation, a couple of common attr would be the + # args/params passed to the execution, as well as if the module + # supports check mode + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True + ) + + # if the user is working with this module in only check mode we do not + # want to make any changes to the environment, just return the current + # state with no modifications + if module.check_mode: + module.exit_json(**result) + + # Get the facts from the host + facts = ansible_facts(module) + + # If its a RedHat family of linux then set compatible to True + if facts["os_family"].lower() == "redhat": + if facts["distribution"].lower() == "redhat" or facts["distribution"].lower() == "rocky": + if int(facts["distribution_major_version"]) >= 8: + result["compatible"] = True + if facts["distribution"].lower() == "amazon": + if int(facts["distribution_major_version"]) >= 2023: + result["compatible"] = True + + # Fail the module if this host is not compatible + if result["compatible"] == False: + module.fail_json(msg='This is not a supported OS family!', **result) + + # in the event of a successful module execution, you will want to + # simple AnsibleModule.exit_json(), passing the key/value results + module.exit_json(**result) + +def main(): + run_module() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/requirements.yml b/.ansible/collections/ansible_collections/itential/deployer/requirements.yml new file mode 100644 index 00000000..2e74a2cd --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/requirements.yml @@ -0,0 +1,2 @@ +collections: + - name: prometheus.prometheus diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/common/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/common/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/common/defaults/main/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/common/defaults/main/main.yml new file mode 100644 index 00000000..3cfcf9dd --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/common/defaults/main/main.yml @@ -0,0 +1,12 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The file containing the installed components and versions +common_itential_release_file: /etc/itential-release + +# Flag to toggle the installation of yum repositories. +# If set to true (default), repositories will be installed in /etc/yum.repos.d. +# If set to false, repositories will not be installed and customers will be +# required to configure them. This will allow customers to use internal +# repositories. +common_install_yum_repos: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/common/defaults/main/offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/common/defaults/main/offline.yml new file mode 100644 index 00000000..99afa208 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/common/defaults/main/offline.yml @@ -0,0 +1,11 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# By default offline mode is off +offline_install_enabled: false + +# Offline directories +offline_target_node_root: /var/tmp +offline_control_node_root: "{{ playbook_dir }}/files" +offline_itential_packages_path: + "itential_packages/{{ ansible_distribution | lower }}_{{ ansible_distribution_major_version }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/common_vars/defaults/main/preflight.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/common_vars/defaults/main/preflight.yml new file mode 100644 index 00000000..bb5ea7ac --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/common_vars/defaults/main/preflight.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +preflight_directory: "/tmp/preflight" + +# default mount to check +preflight_mounts: "/" + +# default env specs to check +preflight_env: dev + +# defaults for running and ignoring the preflight checks +preflight_run_checks: false +preflight_enforce_checks: false diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/gateway.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/gateway.yml new file mode 100644 index 00000000..72c83e24 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/gateway.yml @@ -0,0 +1,54 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# Default feature flags +# Enable everything by default, override in the hosts file if required +gateway_enable_ansible: true +gateway_enable_nornir: true +gateway_enable_netmiko: true +gateway_enable_scripts: true +gateway_enable_netconf: true +gateway_enable_httpreq: true +gateway_enable_python_venv: true +gateway_enable_grpc: true +gateway_enable_git: true + +# Location of IAG assets +gateway_install_dir: /opt/automation-gateway + +# Location of IAG Ansible collections +gateway_ansible_collections_path: "{{ gateway_install_dir }}/ansible/collections" + +# Location of IAG data +gateway_data_dir: /var/lib/automation-gateway + +# Location of IAG logs +gateway_log_dir: /var/log/automation-gateway + +# Default port +gateway_port: 8083 + +# location of IAG config file +gateway_properties_location: /etc/automation-gateway + +gateway_user: itential +gateway_group: itential +gateway_user_home_dir: "/home/{{ gateway_user }}" +gateway_user_shell_rc_file: "{{ gateway_user_home_dir }}/.bashrc" + +# Default HTTPS/SSL settings +gateway_https: true +gateway_https_port: 8443 + +# Flag to enable copying the Gateway SSL certificates +gateway_ssl_copy_certs: true + +gateway_tlsv1_2: false + +# The number of http server threads for handling requests +gateway_http_server_threads: "{{ ansible_processor_cores * 4 }}" + +# Python virtual environment settings +gateway_venv_name: venv +gateway_python_venv: "{{ gateway_install_dir }}/{{ gateway_venv_name }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/offline.yml new file mode 100644 index 00000000..32178779 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/offline.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Base directories +gateway_offline_packages_root: "{{ offline_itential_packages_path }}/{{ gateway_release }}/gateway" +gateway_target_node_root: "{{ offline_target_node_root }}/{{ gateway_offline_packages_root }}" +gateway_control_node_root: "{{ offline_control_node_root }}/{{ gateway_offline_packages_root }}" + +# Target node download directories +gateway_offline_target_node_rpms_dir: "{{ gateway_target_node_root }}/rpms" +gateway_offline_target_node_wheels_dir: "{{ gateway_target_node_root }}/wheels" +gateway_offline_target_node_collections_dir: "{{ gateway_target_node_root }}/collections" + +# Control node download directories +gateway_offline_control_node_rpms_dir: "{{ gateway_control_node_root }}/rpms" +gateway_offline_control_node_wheels_dir: "{{ gateway_control_node_root }}/wheels" +gateway_offline_control_node_collections_dir: "{{ gateway_control_node_root }}/collections" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/pki.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/pki.yml new file mode 100644 index 00000000..7196f32f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/defaults/main/pki.yml @@ -0,0 +1,101 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Gateway PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +gateway_pki_base_dir: /etc/pki/automation-gateway + +# Subdirectory names - customize the layout +gateway_pki_private_subdir: private +gateway_pki_https_subdir: https + +# Derived subdirectory paths - built from base + subdir name +gateway_pki_private_dir: "{{ gateway_pki_base_dir }}/{{ gateway_pki_private_subdir }}" +gateway_pki_https_dir: "{{ gateway_pki_base_dir }}/{{ gateway_pki_https_subdir }}" + +# ============================================================================ +# Certificate and Key Filenames - Customize naming +# ============================================================================ + +# HTTPS server certificate filename +gateway_https_cert_filename: "{{ inventory_hostname }}.crt" + +# HTTPS server private key filename +gateway_https_key_filename: "{{ inventory_hostname }}.key" + +# HTTPS CA bundle filename +gateway_https_ca_filename: ca-bundle.crt + +# ============================================================================ +# Full Certificate Paths - Built from components +# ============================================================================ + +# HTTPS server certificate path +gateway_https_cert_file: "{{ gateway_pki_https_dir }}/{{ gateway_https_cert_filename }}" + +# HTTPS server private key path +gateway_https_key_file: "{{ gateway_pki_private_dir }}/{{ gateway_https_key_filename }}" + +# HTTPS CA bundle path +gateway_https_ca_file: "{{ gateway_pki_https_dir }}/{{ gateway_https_ca_filename }}" + +# ============================================================================ +# Source Directory - Define in inventory +# ============================================================================ + +# Source directory for certificate files (on Ansible controller) +gateway_pki_src_dir: "" + +# ============================================================================ +# Source File Paths - Built from source directory + filename +# ============================================================================ + +# HTTPS source paths - auto-build from source dir + filename +gateway_https_cert_source: "{{ gateway_pki_src_dir }}/{{ gateway_https_cert_filename }}" +gateway_https_key_source: "{{ gateway_pki_src_dir }}/{{ gateway_https_key_filename }}" +gateway_https_ca_source: "{{ gateway_pki_src_dir }}/{{ gateway_https_ca_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI directories and files +gateway_pki_owner: "{{ gateway_user }}" + +# Group for PKI directories and files +gateway_pki_group: "{{ gateway_group }}" + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +gateway_pki_base_dir_mode: "0750" + +# Subdirectory permissions +gateway_pki_subdir_mode: "0750" + +# Private directory permissions +gateway_pki_private_dir_mode: "0700" + +# HTTPS certificate permissions +gateway_https_cert_mode: "0644" + +# HTTPS private key permissions +gateway_https_key_mode: "0600" + +# HTTPS CA bundle permissions +gateway_https_ca_mode: "0644" + +# ============================================================================ +# Backward Compatibility - Legacy Variable Names +# These maintain compatibility with existing templates +# ============================================================================ + +# Legacy variables for templates (point to new paths) +gateway_ssl_cert_dest: "{{ gateway_https_cert_file }}" +gateway_ssl_key_dest: "{{ gateway_https_key_file }}" +gateway_ssl_rootca_dest: "{{ gateway_https_ca_file }}" \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/files/scripts/verify-iag-environment.py b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/files/scripts/verify-iag-environment.py new file mode 100644 index 00000000..da109a16 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/files/scripts/verify-iag-environment.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +# This script will inspect various parts of the IAG environment returning +# some troubleshooting data. It is intended to be a simple test to verify the +# installation. + +import os +import subprocess + +# Get the list of user's environment variables +print("Gathering environment data...") +print(str(dict(os.environ, width=1))) + +# Get the python configuration +print("Gathering python data...") +print(subprocess.run(["which","python3"], text=True, capture_output=True).stdout) +print(subprocess.run(["python3","--version"], text=True, capture_output=True).stdout) + +# Get the ansible configuration +print("Gathering ansible data...") +print(subprocess.run(["ansible","--version"], text=True, capture_output=True).stdout) +print(subprocess.run(["ansible-galaxy","collection","list"], text=True, capture_output=True).stdout) + +exit(0) diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/handlers/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/handlers/main.yml new file mode 100644 index 00000000..c9a31cf6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/handlers/main.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Restart automation-gateway + ansible.builtin.service: + name: automation-gateway + state: restarted + listen: restart automation-gateway diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/configure-gateway-https.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/configure-gateway-https.yml new file mode 100644 index 00000000..c2294db0 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/configure-gateway-https.yml @@ -0,0 +1,88 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create Gateway PKI base directory + ansible.builtin.file: + path: "{{ gateway_pki_base_dir }}" + state: directory + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_pki_base_dir_mode }}" + tags: + - gateway + - gateway_certificates + - certificates + +- name: Create Gateway PKI subdirectories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_pki_subdir_mode }}" + loop: + - "{{ gateway_pki_https_dir }}" + tags: + - gateway + - gateway_certificates + - certificates + +- name: Create Gateway private directory + ansible.builtin.file: + path: "{{ gateway_pki_private_dir }}" + state: directory + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_pki_private_dir_mode }}" + tags: + - gateway + - gateway_certificates + - certificates + +- name: Copy Gateway HTTPS certificate + ansible.builtin.copy: + src: "{{ gateway_https_cert_source }}" + dest: "{{ gateway_https_cert_file }}" + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_https_cert_mode }}" + when: + - gateway_ssl_copy_certs | bool + - gateway_https_cert_source | length > 0 + notify: restart automation-gateway + tags: + - gateway + - gateway_certificates + - certificates + +- name: Copy Gateway HTTPS private key + ansible.builtin.copy: + src: "{{ gateway_https_key_source }}" + dest: "{{ gateway_https_key_file }}" + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_https_key_mode }}" + when: + - gateway_ssl_copy_certs | bool + - gateway_https_key_source | length > 0 + notify: restart automation-gateway + tags: + - gateway + - gateway_certificates + - certificates + +- name: Copy Gateway CA bundle + ansible.builtin.copy: + src: "{{ gateway_https_ca_source }}" + dest: "{{ gateway_https_ca_file }}" + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_https_ca_mode }}" + when: + - gateway_ssl_copy_certs | bool + - gateway_https_ca_source | length > 0 + notify: restart automation-gateway + tags: + - gateway + - gateway_certificates + - certificates diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/copy-certs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/copy-certs.yml new file mode 100644 index 00000000..0955b7e5 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/copy-certs.yml @@ -0,0 +1,27 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +- name: Copy the cert file + ansible.builtin.copy: + src: "{{ gateway_ssl_cert_src }}" + dest: "{{ gateway_ssl_cert_dest }}" + mode: "0400" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + +- name: Copy the key file + ansible.builtin.copy: + src: "{{ gateway_ssl_key_src }}" + dest: "{{ gateway_ssl_key_dest }}" + mode: "0400" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + +- name: Copy the root CA file + ansible.builtin.copy: + src: "{{ gateway_ssl_rootca_src }}" + dest: "{{ gateway_ssl_rootca_dest }}" + mode: "0400" + group: "{{ gateway_group }}" + owner: "{{ gateway_user }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/create-gateway-archive.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/create-gateway-archive.yml new file mode 100644 index 00000000..e10aa6b7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/create-gateway-archive.yml @@ -0,0 +1,90 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# The owner and group are intentially unset throughout in order to use the current user. +# +# From the Ansible documentation: +# group - When left unspecified, it uses the current group of the current user unless you are root, +# in which case it can preserve the previous ownership. +# owner - When left unspecified, it uses the current user unless you are root, in which case it can +# preserve the previous ownership. + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: gateway_pkgs_temp_dir + +- name: Setup Python virtual environment + ansible.builtin.command: + chdir: "{{ gateway_pkgs_temp_dir.path }}" + cmd: /usr/local/bin/python3 -m venv offline_install + changed_when: true + +- name: Install Python Dependencies + ansible.builtin.pip: + name: "{{ gateway_python_app_dependencies }}" + state: present + virtualenv: "{{ gateway_pkgs_temp_dir.path }}/offline_install" + +- name: Copy IAG wheel file to target node + ansible.builtin.copy: + src: "{{ gateway_whl_file }}" + dest: "{{ gateway_pkgs_temp_dir.path }}" + mode: '0644' + +- name: Install IAG + ansible.builtin.pip: + name: "{{ gateway_pkgs_temp_dir.path }}/{{ gateway_whl_file }}" + virtualenv: "{{ gateway_pkgs_temp_dir.path }}/offline_install" + +- name: Uninstall IAG + ansible.builtin.pip: + name: "{{ gateway_pkgs_temp_dir.path }}/{{ gateway_whl_file }}" + state: absent + virtualenv: "{{ gateway_pkgs_temp_dir.path }}/offline_install" + +- name: Create requirements file + ansible.builtin.shell: + chdir: "{{ gateway_pkgs_temp_dir.path }}" + cmd: offline_install/bin/pip3 freeze > requirements.txt + changed_when: true + +- name: Create package directory + ansible.builtin.file: + name: "{{ gateway_pkgs_temp_dir }}/gateway_pkgs" + mode: '0775' + state: directory + changed_when: true + +- name: Download wheel files + ansible.builtin.command: + cmd: offline_install/bin/pip3 download -r requirements.txt -d gateway_pkgs + args: + chdir: "{{ gateway_pkgs_temp_dir.path }}" + changed_when: true + +- name: Copy requirements file to package directory + ansible.builtin.copy: + remote_src: true + src: "{{ gateway_pkgs_temp_dir.path }}/requirements.txt" + dest: "{{ gateway_pkgs_temp_dir.path }}/gateway_pkgs" + mode: '0644' + +- name: Create download directory + ansible.builtin.file: + path: "{{ gateway_pkgs_download_dir_target_node }}" + state: directory + mode: '0755' + +- name: Create IAG archive + community.general.archive: # noqa risky-file-permissions + path: "{{ gateway_pkgs_temp_dir.path }}/gateway_pkgs/*" + dest: "{{ gateway_pkgs_download_dir_target_node }}/gateway_pkgs.tar.gz" + format: gz + force_archive: true + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ gateway_pkgs_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-ansible-collections.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-ansible-collections.yml new file mode 100644 index 00000000..9a47794c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-ansible-collections.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create Ansible collections download directory + ansible.builtin.file: + path: "{{ gateway_offline_target_node_collections_dir }}" + state: directory + mode: '0755' + +- name: Download Ansible collections + ansible.builtin.command: + chdir: "{{ gateway_target_node_root }}" + cmd: "{{ gateway_pkgs_temp_dir.path }}/offline_install/bin/ansible-galaxy + collection download {{ item }}" + with_items: "{{ gateway_ansible_collections }}" + changed_when: true + +- name: Copy Ansible collections to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ gateway_offline_target_node_collections_dir }}" + offline_dest_dir: "{{ gateway_offline_control_node_collections_dir }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-build-rpms.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-build-rpms.yml new file mode 100644 index 00000000..dce977fa --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-build-rpms.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Gateway build packages + ansible.builtin.dnf: + name: "{{ item }}" + state: present + with_items: "{{ gateway_build_packages }}" + register: gateway_build_packages_installed + when: + - gateway_build_packages is defined + - gateway_build_packages is iterable + - gateway_build_packages | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-dependency-rpms.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-dependency-rpms.yml new file mode 100644 index 00000000..26624cde --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-dependency-rpms.yml @@ -0,0 +1,30 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Gateway dependency RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ gateway_packages }}" + offline_download_dir: "{{ gateway_offline_target_node_rpms_dir }}/dependencies" + +- name: Copy Gateway dependency RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ gateway_offline_target_node_rpms_dir }}/dependencies" + offline_dest_dir: "{{ gateway_offline_control_node_rpms_dir }}/dependencies" + +- name: Install Gateway dependency packages + ansible.builtin.dnf: + name: "{{ item }}" + state: present + with_items: "{{ gateway_packages }}" + register: gateway_packages_installed + when: + - gateway_packages is defined + - gateway_packages is iterable + - gateway_packages | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-dependency-wheels.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-dependency-wheels.yml new file mode 100644 index 00000000..bc23ff40 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-dependency-wheels.yml @@ -0,0 +1,118 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# The owner and group are intentionally unset throughout in order to use the current user. +# +# From the Ansible documentation: +# group - When left unspecified, it uses the current group of the current user unless you are root, +# in which case it can preserve the previous ownership. +# owner - When left unspecified, it uses the current user unless you are root, in which case it can +# preserve the previous ownership. + +- name: Download base Python wheels + ansible.builtin.import_role: + name: offline + tasks_from: download-wheels + vars: + offline_wheel_files: "{{ gateway_python_base_dependencies }}" + offline_download_dir: "{{ gateway_offline_target_node_wheels_dir }}/base" + offline_pip_executable: "{{ gateway_pip_executable }}" + when: + - gateway_python_base_dependencies is defined + - gateway_python_base_dependencies | length > 0 + +- name: Copy base Python dependencies to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ gateway_offline_target_node_wheels_dir }}/base" + offline_dest_dir: "{{ gateway_offline_control_node_wheels_dir }}/base" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: gateway_pkgs_temp_dir + +- name: Setup Python virtual environment + ansible.builtin.command: + chdir: "{{ gateway_pkgs_temp_dir.path }}" + cmd: "{{ gateway_python_executable }} -m venv offline_download" + changed_when: true + +- name: Install base Python dependencies + ansible.builtin.pip: + name: "{{ gateway_python_base_dependencies }}" + state: present + virtualenv: "{{ gateway_pkgs_temp_dir.path }}/offline_download" + extra_args: --log /var/log/pip.log + when: + - gateway_python_base_dependencies is defined + - gateway_python_base_dependencies is iterable + - gateway_python_base_dependencies | length > 0 + +- name: Install IAG Python dependencies + ansible.builtin.pip: + name: "{{ gateway_python_app_dependencies }}" + state: present + virtualenv: "{{ gateway_pkgs_temp_dir.path }}/offline_download" + extra_args: --log /var/log/pip.log + when: + - gateway_python_app_dependencies is defined + - gateway_python_app_dependencies is iterable + - gateway_python_app_dependencies | length > 0 + +- name: Download Ansible collections + ansible.builtin.include_tasks: + file: download-ansible-collections.yml + when: + - gateway_ansible_collections is defined + - gateway_ansible_collections is iterable + - gateway_ansible_collections | length > 0 + +- name: Build wheels from source distributions + ansible.builtin.command: + cmd: > + offline_download/bin/pip3 wheel + {{ item }} + -w {{ gateway_offline_target_node_wheels_dir }}/app + --no-deps + args: + chdir: "{{ gateway_pkgs_temp_dir.path }}" + loop: "{{ gateway_python_wheel_build_dependencies }}" + changed_when: true + +- name: Download automation-gateway and remaining dependencies + ansible.builtin.command: + cmd: > + offline_download/bin/pip3 download {{ gateway_wheel_download.files[0].path }} + -d {{ gateway_offline_target_node_wheels_dir }}/app + args: + chdir: "{{ gateway_pkgs_temp_dir.path }}" + changed_when: true + +- name: Find source distributions after building wheels + ansible.builtin.find: + paths: "{{ gateway_offline_target_node_wheels_dir }}/app" + patterns: "*.tar.gz" + register: gateway_source_dists + +- name: Delete source distributions + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + loop: "{{ gateway_source_dists.files }}" + +- name: Copy IAG Python dependencies to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ gateway_offline_target_node_wheels_dir }}/app" + offline_dest_dir: "{{ gateway_offline_control_node_wheels_dir }}/app" + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ gateway_pkgs_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-gateway-wheel.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-gateway-wheel.yml new file mode 100644 index 00000000..98390f0b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-gateway-wheel.yml @@ -0,0 +1,56 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Copy IAG archive from local + ansible.builtin.copy: + src: "{{ gateway_whl_file }}" + dest: "{{ gateway_offline_target_node_wheels_dir }}/gateway/" + mode: '0644' + when: + - gateway_whl_file is defined + - gateway_archive_download_url is not defined + +- name: Download IAG archive from repository + when: + - gateway_archive_download_url is defined + - gateway_whl_file is not defined + block: + - name: Create Gateway wheel directory + ansible.builtin.file: + path: "{{ gateway_offline_target_node_wheels_dir }}/gateway" + state: directory + mode: '0755' + + - name: Download IAG archive from repository + ansible.builtin.get_url: + url: "{{ gateway_archive_download_url }}" + dest: "{{ gateway_offline_target_node_wheels_dir }}/gateway/" + mode: '0644' + # Sets the appropriate header based on the repository type: + # - For JFrog: Uses the "X-JFrog-Art-Api" header with the API key if "repository_api_key" + # is defined and "jfrog" is part of the download URL. + # - For Nexus: Uses a default header ("Accept: application/octet-stream") since Nexus + # doesn't support API key authentication. + headers: >- + {%- if repository_api_key is defined and gateway_archive_download_url is search("jfrog") -%} + {"X-JFrog-Art-Api": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- else -%} + {"Accept": "application/octet-stream"} + {%- endif -%} + url_username: "{{ repository_username | default(omit) }}" + url_password: "{{ repository_password | default(omit) }}" + validate_certs: true + +- name: Copy Gateway to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ gateway_offline_target_node_wheels_dir }}/gateway" + offline_dest_dir: "{{ gateway_offline_control_node_wheels_dir }}/gateway" + +- name: Find downloaded Gateway wheel file + ansible.builtin.find: + paths: "{{ gateway_offline_target_node_wheels_dir }}/gateway/" + patterns: "*.whl" + register: gateway_wheel_download diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-packages.yml new file mode 100644 index 00000000..72d51176 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-packages.yml @@ -0,0 +1,86 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download packages + block: + - name: Validation steps + tags: always + block: + - name: Validate offline_install_enabled variable + ansible.builtin.fail: + msg: offline_install_enabled must be set to false for download + when: + - offline_install_enabled is defined + - offline_install_enabled + + - name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "gateway-release-{{ gateway_release }}.yml" # Prefer this new format + - "{{ gateway_release }}-{{ ansible_distribution + | lower }}-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + + - name: Check for valid IAG release + ansible.builtin.fail: + msg: "Deployer does not support installing Gateway version {{ gateway_release }} + on {{ ansible_distribution }}-{{ ansible_distribution_major_version }}" + when: gateway_invalid_release is defined + + - name: Download Python RPMs + ansible.builtin.include_tasks: + file: download-python-rpms.yml + + - name: Download Gateway dependency RPMs + ansible.builtin.include_tasks: + file: download-dependency-rpms.yml + + - name: Download Gateway build RPMs + ansible.builtin.include_tasks: + file: download-build-rpms.yml + + - name: Download Gateway wheel + ansible.builtin.include_tasks: + file: download-gateway-wheel.yml + + - name: Download Gateway dependency wheels + ansible.builtin.include_tasks: + file: download-dependency-wheels.yml + + always: + - name: Uninstall Python RPMs + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + with_items: "{{ python_install_result.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" + when: + - python_install_result is defined + - python_install_result.results is defined + - python_install_result.results | length > 0 + + - name: Uninstall Gateway dependency RPMs + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + with_items: "{{ gateway_packages_installed.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" + when: + - gateway_packages_installed is defined + - gateway_packages_installed.results is defined + - gateway_packages_installed.results | length > 0 + + - name: Uninstall Gateway build RPMs + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + with_items: "{{ gateway_build_packages_installed.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" + when: + - gateway_build_packages_installed is defined + - gateway_build_packages_installed.results is defined + - gateway_build_packages_installed.results | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-python-rpms.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-python-rpms.yml new file mode 100644 index 00000000..b9f29b40 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/download-python-rpms.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +- name: Download Gateway Python RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ gateway_python_packages }}" + offline_download_dir: "{{ gateway_offline_target_node_rpms_dir }}/python" + tags: download_gateway_python_packages + +- name: Copy Gateway Python RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ gateway_offline_target_node_rpms_dir }}/python" + offline_dest_dir: "{{ gateway_offline_control_node_rpms_dir }}/python" + +- name: Install Python + ansible.builtin.include_role: + name: python + tags: install_python + vars: + python_packages: "{{ gateway_python_packages }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-ansible-collections-offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-ansible-collections-offline.yml new file mode 100644 index 00000000..23ef6526 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-ansible-collections-offline.yml @@ -0,0 +1,34 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: install_collections_temp_dir + +- name: Copy collections to target node + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ install_collections_temp_dir.path }}/{{ item | basename }}" + mode: '0644' + with_fileglob: + - "{{ gateway_offline_control_node_collections_dir }}/*.tar.gz" + - "{{ gateway_offline_control_node_collections_dir }}/requirements.yml" + register: copy_result + +- name: Install collections + ansible.builtin.command: + cmd: "{{ gateway_python_venv }}/bin/ansible-galaxy collection install -p {{ gateway_ansible_collections_path }} + -r requirements.yml" + chdir: "{{ install_collections_temp_dir.path }}" + register: install_result + changed_when: '"Nothing to do" not in install_result.stdout' + failed_when: install_result.failed + when: + - copy_result.changed + - not copy_result.skipped + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ install_collections_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-python-dependencies.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-python-dependencies.yml new file mode 100644 index 00000000..684c36cc --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-python-dependencies.yml @@ -0,0 +1,32 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Python dependencies + ansible.builtin.include_role: + name: python + tasks_from: install-dependencies + tags: install_python + when: not offline_install_enabled + vars: + python_venv: "{{ gateway_python_venv }}" + python_base_dependencies: "{{ gateway_python_base_dependencies }}" + python_app_dependencies: "{{ gateway_python_app_dependencies }}" + +- name: Install Python dependencies (offline) + when: offline_install_enabled + block: + - name: Install base Python dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-wheels + vars: + offline_wheels_dir: "{{ gateway_offline_control_node_wheels_dir }}/base" + offline_python_venv: "{{ gateway_python_venv }}" + + - name: Install application Python dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-wheels + vars: + offline_wheels_dir: "{{ gateway_offline_control_node_wheels_dir }}/app" + offline_python_venv: "{{ gateway_python_venv }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-python.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-python.yml new file mode 100644 index 00000000..f88c61e3 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/install-python.yml @@ -0,0 +1,40 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Python + tags: install_python + block: + - name: Install Python + ansible.builtin.include_role: + name: python + vars: + python_packages: "{{ gateway_python_packages }}" + when: not offline_install_enabled | bool + + - name: Install Python (offline) + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ gateway_offline_control_node_rpms_dir }}/python" + when: offline_install_enabled | bool + + - name: Setup Python virtual environment + ansible.builtin.command: + chdir: "{{ gateway_install_dir }}" + cmd: "{{ gateway_python_executable }} -m venv {{ gateway_venv_name }}" + changed_when: true + + - name: Configure gateway user to activate the virtual environment at login + ansible.builtin.blockinfile: + path: "{{ gateway_user_shell_rc_file }}" + block: | + # Auto-activate Gateway Python virtual environment + if [ -f {{ gateway_python_venv }}/bin/activate ]; then + source {{ gateway_python_venv }}/bin/activate + fi + marker: "# {mark} ANSIBLE MANAGED - Gateway Python venv" + create: true + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0644" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/main.yml new file mode 100644 index 00000000..c1b4b8aa --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/main.yml @@ -0,0 +1,389 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Gateway + block: + - name: Validation steps + tags: always + block: + - name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "gateway-release-{{ gateway_release }}.yml" # Prefer this new format + - "{{ gateway_release }}-{{ ansible_distribution + | lower }}-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + + - name: Check for valid IAG release + ansible.builtin.fail: + msg: "Deployer does not support installing Gateway version {{ gateway_release }} + on {{ ansible_distribution }}-{{ ansible_distribution_major_version }}" + when: gateway_invalid_release is defined + + - name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: gateway_workingdir + + - name: Install Gateway dependency packages + ansible.builtin.dnf: + name: "{{ item }}" + state: present + with_items: "{{ gateway_packages }}" + when: + - not offline_install_enabled | bool + - gateway_packages is defined + - gateway_packages is iterable + - gateway_packages | length > 0 + tags: install_gateway_packages + + - name: Install Gateway dependency packages (offline) + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ gateway_offline_control_node_rpms_dir }}/dependencies" + when: offline_install_enabled | bool + tags: install_gateway_packages + + - name: Create itential group + ansible.builtin.group: + name: "{{ gateway_group }}" + + - name: Create itential user + ansible.builtin.user: + name: "{{ gateway_user }}" + group: "{{ gateway_group }}" + groups: wheel + generate_ssh_key: true + state: present + + - name: Create working directories + ansible.builtin.file: + name: "{{ item }}" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0775" + state: directory + with_items: + - /etc/ansible + - "{{ gateway_log_dir }}" + - "{{ gateway_properties_location }}" + - "{{ gateway_data_dir }}" + - "{{ gateway_install_dir }}" + - "{{ gateway_ansible_collections_path }}" + - "{{ gateway_install_dir }}/ansible/inventory" + - "{{ gateway_install_dir }}/ansible/modules" + - "{{ gateway_install_dir }}/ansible/roles" + - "{{ gateway_install_dir }}/ansible/playbooks" + - "{{ gateway_install_dir }}/ansible/plugins/modules" + - "{{ gateway_install_dir }}/ansible/scripts" + - "{{ gateway_install_dir }}/conf" + - "{{ gateway_install_dir }}/conf/certs" + - "{{ gateway_install_dir }}/nornir/conf" + - "{{ gateway_install_dir }}/nornir/inventory" + - "{{ gateway_install_dir }}/nornir/modules" + - "{{ gateway_install_dir }}/repos" + - "{{ gateway_install_dir }}/scripts" + - "{{ gateway_install_dir }}/ssh" + + - name: Create Python venv directory + ansible.builtin.file: + name: "{{ gateway_install_dir }}/python-venvs" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0775" + state: directory + when: gateway_enable_python_venv | bool + + - name: Configure Gateway HTTPS + ansible.builtin.include_tasks: configure-gateway-https.yml + when: gateway_https | bool + tags: + - gateway + - gateway_certificates + - certificates + + - name: Install Python + tags: install_python + block: + - name: Install Python + ansible.builtin.include_tasks: + file: install-python.yml + + - name: Install Gateway build packages + tags: install_gateway_build_packages + block: + - name: Install Gateway build packages + ansible.builtin.dnf: + name: "{{ item }}" + state: present + register: gateway_build_packages_result + with_items: "{{ gateway_build_packages }}" + when: + - not offline_install_enabled | bool + - gateway_build_packages is defined + - gateway_build_packages is iterable + - gateway_build_packages | length > 0 + + - name: Install Python dependencies + tags: install_python_dependencies + block: + - name: Install Python dependencies + ansible.builtin.include_tasks: + file: install-python-dependencies.yml + + # Need to install ansible within the virtual environment + - name: Configure Ansible + tags: configure_ansible + when: gateway_enable_ansible | bool + block: + - name: Install Ansible collections + when: not offline_install_enabled | bool + block: + - name: Install collections + ansible.builtin.command: + argv: + - "{{ gateway_install_dir }}/venv/bin/ansible-galaxy" + - collection + - install + - -p + - "{{ gateway_ansible_collections_path }}" + - "{{ gateway_ansible_collections | join(' ') }}" + register: gateway_install_collection_result + changed_when: '"Nothing to do" not in gateway_install_collection_result.stdout' + failed_when: gateway_install_collection_result.failed + when: + - gateway_ansible_collections is defined + - gateway_ansible_collections is iterable + - gateway_ansible_collections | length > 0 + + - name: Install Ansible collections (offline) + ansible.builtin.include_tasks: + file: install-ansible-collections-offline.yml + when: offline_install_enabled | bool + + - name: Create Ansible config file + ansible.builtin.template: + src: ansible.cfg.j2 + dest: /etc/ansible/ansible.cfg + mode: "0644" + backup: true + + - name: Create empty ansible inventory files + ansible.builtin.file: + name: "{{ gateway_install_dir }}/ansible/inventory/hosts" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0660" + state: touch + + - name: Create empty ansible vault file + ansible.builtin.file: + name: "{{ gateway_install_dir }}/conf/.vault_password_file" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0400" + state: touch + + - name: Check if Automation Gateway is already installed + ansible.builtin.stat: + path: "{{ gateway_install_dir }}/venv/automation-gateway" + register: gateway_installed + + - name: Propagate IAG archive + when: + - not gateway_installed.stat.exists + - not offline_install_enabled | bool + block: + - name: Copy IAG archive from local + ansible.builtin.copy: + src: "{{ gateway_whl_file }}" + dest: "{{ gateway_workingdir.path }}/{{ gateway_whl_file | basename }}" + mode: '0644' + when: + - not gateway_installed.stat.exists + - gateway_whl_file is defined + - gateway_archive_download_url is not defined + + - name: Download IAG archive from repository + when: + - not gateway_installed.stat.exists + - gateway_archive_download_url is defined + - gateway_whl_file is not defined + block: + - name: Download IAG archive from repository + ansible.builtin.get_url: + url: "{{ gateway_archive_download_url }}" + dest: "{{ gateway_workingdir.path }}/" + mode: '0644' + # Sets the appropriate header based on the repository type: + # - For JFrog: Uses the "X-JFrog-Art-Api" header with the API key if "repository_api_key" + # is defined and "jfrog" is part of the download URL. + # - For Nexus: Uses a default header ("Accept: application/octet-stream") since Nexus + # doesn't support API key authentication. + headers: >- + {%- if repository_api_key is defined and gateway_archive_download_url is search("jfrog") -%} + {"X-JFrog-Art-Api": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- else -%} + {"Accept": "application/octet-stream"} + {%- endif -%} + url_username: "{{ repository_username | default(omit) }}" + url_password: "{{ repository_password | default(omit) }}" + validate_certs: true + register: gateway_download_result + + - name: Set gateway_whl_file destination from download + ansible.builtin.set_fact: + gateway_whl_file: "{{ gateway_download_result.dest }}" + + - name: Install IAG + ansible.builtin.pip: + name: "{{ gateway_workingdir.path }}/{{ gateway_whl_file | basename }}" + virtualenv: "{{ gateway_install_dir }}/venv" + when: not offline_install_enabled | bool + + - name: Set ownership/permissions and create properties.yml + when: not gateway_installed.stat.exists + block: + # Using chown and chmod is a faster way to enforce the file ownership and + # permissions. The file module in ansible checks each and every file/dir + # in the tree, 'chown -R ' does not, it just sets it. + - name: Set appropriate ownership on all gateway files + ansible.builtin.command: + cmd: "chown -R {{ gateway_user }}:{{ gateway_group }} {{ gateway_install_dir }}/venv" + changed_when: true + + - name: Set appropriate permissions on all gateway files + ansible.builtin.command: + cmd: "chmod -R 775 {{ gateway_install_dir }}/venv" + changed_when: true + + - name: Create properties.yml using template based on the version + ansible.builtin.template: + src: "properties.{{ gateway_release }}.yml.j2" + dest: "{{ gateway_properties_location }}/properties.yml" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0600" + + - name: Create Nornir files + when: gateway_enable_nornir | bool + block: + - name: Create Nornir inventory files (empty) + ansible.builtin.file: + name: "{{ item }}" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0660" + state: touch + with_items: + - "{{ gateway_install_dir }}/nornir/inventory/defaults.yml" + - "{{ gateway_install_dir }}/nornir/inventory/groups.yml" + - "{{ gateway_install_dir }}/nornir/inventory/hosts.yml" + + - name: Create Nornir config file + ansible.builtin.template: + src: nornir.config.yml.j2 + dest: "{{ gateway_install_dir }}/nornir/config.yml" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0660" + + - name: Write automation-gateway.service to host + ansible.builtin.template: + src: automation-gateway.service.j2 + dest: /etc/systemd/system/automation-gateway.service + mode: "0644" + backup: true + + # Check if firewalld is running, if it is then open the appropriate ports + - name: Gather service facts + ansible.builtin.service_facts: + + - name: Configure HTTP Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ gateway_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - not (gateway_https | bool) + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + + - name: Configure HTTPS Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ gateway_https_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - gateway_https | bool + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + + - name: Allow IAG to listen on tcp port {{ gateway_port }} + community.general.seport: + ports: "{{ gateway_port }}" + proto: tcp + setype: http_port_t + state: present + when: ansible_selinux.status == "enabled" + + - name: Add test scripts + ansible.builtin.copy: + src: scripts + dest: "{{ gateway_install_dir }}/" + owner: "{{ gateway_user }}" + group: "{{ gateway_group }}" + mode: "0775" + directory_mode: "0775" + + - name: Start Automation Gateway service + ansible.builtin.systemd: + name: automation-gateway + enabled: true + state: restarted + daemon_reload: true + + - name: Update release file + ansible.builtin.include_tasks: + file: update-release-file.yml + + - name: Remove temporary working directory + ansible.builtin.file: + path: "{{ gateway_workingdir.path }}" + state: absent + + always: + - name: Uninstall Gateway build packages + tags: uninstall_gateway_build_packages + block: + - name: Uninstall Gateway build packages + ansible.builtin.dnf: + name: "{{ item }}" + allowerasing: true + autoremove: true + state: absent + with_items: "{{ gateway_build_packages_result.results + | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" + when: + - not offline_install_enabled | bool + - gateway_build_packages_result is defined + - gateway_build_packages_result.results is defined + - gateway_build_packages_result.results is iterable + - gateway_build_packages_result.results | length > 0 + + - name: Assert that Gateway is running + ansible.builtin.systemd: + name: automation-gateway + register: gateway_status + failed_when: gateway_status.status.ActiveState != "active" + tags: always diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/preflight.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/preflight.yml new file mode 100644 index 00000000..0238487d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/preflight.yml @@ -0,0 +1,58 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "gateway-release-{{ gateway_release }}.yml" # Prefer this new format + - "{{ gateway_release }}-{{ ansible_distribution + | lower }}-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + +- name: Run common checks + ansible.builtin.include_role: + name: preflight + vars: + preflight_url_checks: + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: workingdir + +- name: Set pass to true if all conditions pass + ansible.builtin.set_fact: + results: '{{ results | combine({"pass": true}) }}' + when: + - results.cpuCores >= gateway_cpu_cores + - results.get(mountvarname, 0) >= gateway_free_disk_space + - results.memory >= gateway_ram + - results.url_status.values() | unique | length == 1 and + results.url_status.values() | unique | first == 200 + +- name: Create Gateway preflight results + ansible.builtin.template: + src: "gateway.preflight.j2" + dest: "{{ workingdir.path }}/preflightResults.txt" + mode: '0777' + +- name: Fetch Gateway results + ansible.builtin.fetch: + src: "{{ workingdir.path }}/preflightResults.txt" + dest: "{{ preflight_directory }}/gateway_{{ inventory_hostname }}_results.txt" + flat: true + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent + +- name: Check if host passed preflight checks. + ansible.builtin.assert: + that: results["pass"] == true + fail_msg: "Platform host did not pass the preflight checks" + success_msg: "Platform host passed the preflight checks" + when: + - preflight_enforce_checks is defined + - preflight_enforce_checks diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/update-release-file.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/update-release-file.yml new file mode 100644 index 00000000..c387bb6b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/update-release-file.yml @@ -0,0 +1,68 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Update release file with IAG version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + line: "GATEWAY={{ gateway_release }}" + mode: "0666" + create: true + changed_when: true + +- name: Capture Python version + ansible.builtin.command: + cmd: "{{ gateway_python_venv }}/bin/python3 -V" + register: python_installed_version + changed_when: false + +- name: Update release file with Python version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + line: "PYTHON={{ python_installed_version.stdout }}" + mode: "0666" + create: true + changed_when: true + +- name: Capture Pip version + ansible.builtin.command: + cmd: "{{ gateway_python_venv }}/bin/pip3 -V" + register: pip_installed_version + changed_when: false + +- name: Update release file with Pip version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + line: "PIP={{ pip_installed_version.stdout }}" + mode: "0666" + create: true + changed_when: true + +- name: Update release file with Ansible version + when: gateway_enable_ansible | bool + block: + - name: Get Ansible version from automation-gateway venv + ansible.builtin.command: + cmd: "{{ gateway_python_venv }}/bin/ansible --version" + register: gateway_ansible_venv_version + changed_when: false + + - name: Extract version + ansible.builtin.set_fact: + gateway_ansible_version: "{{ gateway_ansible_venv_version.stdout_lines[0] | regex_search('\\d+\\.\\d+\\.\\d+') }}" + + - name: Update release file with Ansible version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + line: "ANSIBLE={{ gateway_ansible_version }}" + mode: "0666" + create: true + changed_when: true + +- name: Update release file with Nornir version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + line: "NORNIR=true" + mode: "0666" + create: true + when: gateway_enable_nornir | bool + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/upgrade-gateway.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/upgrade-gateway.yml new file mode 100644 index 00000000..73043783 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/tasks/upgrade-gateway.yml @@ -0,0 +1,84 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: workingdir + +- name: Copy IAG archive from local + ansible.builtin.copy: + src: "{{ gateway_whl_file }}" + dest: "{{ workingdir.path }}/{{ gateway_whl_file | basename }}" + mode: '0644' + when: + - gateway_whl_file is defined + - gateway_archive_download_url is not defined + +- name: Download IAG archive from repository + when: + - gateway_archive_download_url is defined + - gateway_whl_file is not defined + block: + - name: Download IAG archive from repository + ansible.builtin.get_url: + url: "{{ gateway_archive_download_url }}" + dest: "{{ workingdir.path }}/" + mode: '0644' + # Sets the appropriate header based on the repository type: + # - For JFrog: Uses the "X-JFrog-Art-Api" header with the API key if "repository_api_key" is defined and "jfrog" is part of the download URL. + # - For Nexus: Uses a default header ("Accept: application/octet-stream") since Nexus doesn't support API key authentication. + headers: >- + {%- if repository_api_key is defined and gateway_archive_download_url is search("jfrog") -%} + {"X-JFrog-Art-Api": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- else -%} + {"Accept": "application/octet-stream"} + {%- endif -%} + url_username: "{{ repository_username | default(omit) }}" + url_password: "{{ repository_password | default(omit) }}" + validate_certs: true + register: download_result + + - name: Set gateway_whl_file destination from download + ansible.builtin.set_fact: + gateway_whl_file: "{{ download_result.dest }}" + +- name: Upgrade IAG + ansible.builtin.pip: + name: "{{ workingdir.path }}/{{ gateway_whl_file | basename }}" + virtualenv: "{{ gateway_install_dir }}/venv" + +# Using chown and chmod is a faster way to enforce the file ownership and +# permissions. The file module in ansible checks each and every file/dir +# in the tree, 'chown -R ' does not, it just sets it. +- name: Set appropriate ownership on all gateway files + ansible.builtin.command: + cmd: "chown -R {{ gateway_user }}:{{ gateway_group }} {{ gateway_install_dir }}/venv" + register: chown_output + changed_when: chown_output.rc == 0 + failed_when: chown_output.rc != 0 + +- name: Set appropriate permissions on all gateway files + ansible.builtin.command: + cmd: "chmod -R 775 {{ gateway_install_dir }}/venv" + register: chmod_output + changed_when: chmod_output.rc == 0 + failed_when: chmod_output.rc != 0 + +- name: Start Automation Gateway service + ansible.builtin.systemd: + name: automation-gateway + enabled: true + state: restarted + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent + +- name: Assert that Gateway is running + ansible.builtin.systemd: + name: automation-gateway + register: gateway_status + failed_when: gateway_status.status.ActiveState != "active" + tags: always diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/ansible.cfg.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/ansible.cfg.j2 new file mode 100644 index 00000000..0e5ec714 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/ansible.cfg.j2 @@ -0,0 +1,2 @@ +[defaults] +collections_path={{ gateway_ansible_collections_path }}:/usr/share/ansible/collections diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/automation-gateway.service.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/automation-gateway.service.j2 new file mode 100644 index 00000000..d4bbc61f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/automation-gateway.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Itential Automation Gateway +After=network.target + +[Service] +User=itential +Restart=always +Type=simple +ExecStart={{ gateway_python_venv }}/bin/automation-gateway --properties-file={{ gateway_properties_location }}/properties.yml +WorkingDirectory=/tmp +Environment=MAX_EVENT_RES=15000000 +Environment=PATH={{ gateway_python_venv }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +Environment=ANSIBLE_PYTHON_INTERPRETER={{ gateway_python_venv }}/bin/python + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/gateway.preflight.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/gateway.preflight.j2 new file mode 100644 index 00000000..2bda982f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/gateway.preflight.j2 @@ -0,0 +1,18 @@ +Name: {{results['name']}} +Role: Gateway +Pass: {{results['pass']}} + + +SELinux | {{results['SELinux']}} +http_proxy | {{ 'Yes' if results['http_proxy'] else 'None'}} +https_proxy | {{ 'Yes' if results['https_proxy'] else 'None'}} +IPv6 | {{ 'Enabled' if results['ipv6'] else 'Disabled'}} + +CPU | {{ 'Pass' if results['cpuCores'] >= gateway_cpu_cores else 'FAIL'}} | Cores: {{results['cpuCores']}} Req: {{gateway_cpu_cores}} +HDD | {{ 'Pass' if results['/_sizeAvailable'] >= gateway_free_disk_space else 'FAIL'}} | Free: {{results['/_sizeAvailable']}} on {{results['mount']}} Req: {{gateway_free_disk_space}} +Memory | {{ 'Pass' if results['memory'] >= gateway_ram else 'FAIL'}} | Free: {{results['memory']}} Req: {{gateway_ram}} + +URL | Status +{% for key, value in results['url_status'].items() %} +{{key}} | {{value}} +{% endfor %} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/nornir.config.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/nornir.config.yml.j2 new file mode 100644 index 00000000..1203eaf7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/nornir.config.yml.j2 @@ -0,0 +1,14 @@ +--- +logging: + enabled: False + +inventory: + plugin: SimpleInventory + options: + host_file: "{{ gateway_install_dir }}/nornir/inventory/hosts.yml" + group_file: "{{ gateway_install_dir }}/nornir/inventory/groups.yml" + defaults_file: "{{ gateway_install_dir }}/nornir/inventory/defaults.yml" +runner: + plugin: threaded + options: + num_workers: 100 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2021.1.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2021.1.yml.j2 new file mode 100644 index 00000000..8c498334 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2021.1.yml.j2 @@ -0,0 +1,251 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.com/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, etc. + +########## +# System # +########## + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +port: {{ gateway_port }} + +# The IP addresses to bind the web application to. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: false + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# This must remain true for testing, production but may be disabled if it is +# helpful while still developing/decorating custom content. +strict_args: true + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway.db" + +# A flag which determines whether or not audit logging is enabled. +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxillary Automation Gateway sqlite database file for audit logs. +audit_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db" + +# Path to the auxillary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db" + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "{{ gateway_install_dir }}/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External inventory. +#inventory_file: "{{ gateway_install_dir }}/ansible/inventory/hosts" + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to Ansible's execution environment. +# All non-collection paths (see Ansible 2.10 notes below) known to Ansible are already included and do not need to be specified. +# Additionally, this parameter needs to be configured if the path reported by 'ansible --version' is incorrect +# or you would like to customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules/network" + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and exclusively used in Ansible's execution environment. +# Due to differences in collections before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible_collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/roles" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=true if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +#nornir_config_file: "{{ gateway_install_dir }}/nornir/config.yml" + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - "{{ gateway_install_dir }}/nornir/modules" + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +############# +# Terraform # +############# +# Terraform was removed due to HashiCorp adopting the +# Business Source License (BSL) for their core products + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: false + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending reqests to the Hashicorp +# Vault Server. (default=true if absent/misconfigured) +#vault_cert_verification: true + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2021.2.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2021.2.yml.j2 new file mode 100644 index 00000000..7aa0271e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2021.2.yml.j2 @@ -0,0 +1,269 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, etc. + +########## +# System # +########## + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +port: {{ gateway_port }} + +# The IP addresses to bind the web application to. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: true + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "commands", etc. +strict_args: true + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway.db" + +# A flag which determines whether or not audit logging is enabled. (default=true if absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxillary Automation Gateway sqlite database file for audit logs. +audit_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db" + +# Path to the auxillary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db" + +######### +# Repos # +######### + +# A boolean flag that enables Git repository (repos) support (default=true if absent/misconfigured). +repos_enabled: true + +# Path to the location where repository clones should be stored for use by Automation Gateway. +repos_path: "{{ gateway_install_dir }}/repos" + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or playbooks. +# Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "{{ gateway_install_dir }}/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External inventory. +inventory_file: "{{ gateway_install_dir }}/ansible/inventory/hosts" + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to Ansible's execution environment. +# All non-collection paths (see Ansible 2.10 notes below) known to Ansible are already included and do not need to be specified. +# Additionally, this parameter needs to be configured if the path reported by 'ansible --version' is incorrect +# or you would like to customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules/network" + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and exclusively used in Ansible's execution environment. +# Due to differences in collections before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible_collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, i.e., itential_cli, itential_get_config. +#extended_device_role_path: + #This is a sample path to roles that extend device support + #- "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/extensible_device_roles" + + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=true if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: "{{ gateway_install_dir }}/nornir/config.yml" + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - "{{ gateway_install_dir }}/nornir/modules" + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +############# +# Terraform # +############# +# Terraform was removed due to HashiCorp adopting the +# Business Source License (BSL) for their core products + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: false + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending reqests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2022.1.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2022.1.yml.j2 new file mode 100644 index 00000000..03948bc6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2022.1.yml.j2 @@ -0,0 +1,268 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, etc. + +########## +# System # +########## + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +port: {{ gateway_port }} + +# The IP addresses to bind the web application to. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: true + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "commands", etc. +strict_args: true + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway.db" + +# A flag which determines whether or not audit logging is enabled. (default=true if absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxillary Automation Gateway sqlite database file for audit logs. +audit_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db" + +# Path to the auxillary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db" + +######### +# Repos # +######### + +# A boolean flag that enables Git repository (repos) support (default=true if absent/misconfigured). +repos_enabled: true + +# Path to the location where repository clones should be stored for use by Automation Gateway. +repos_path: "{{ gateway_install_dir }}/repos" + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or playbooks. +# Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "{{ gateway_install_dir }}/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External inventory. +inventory_file: "{{ gateway_install_dir }}/ansible/inventory/hosts" + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to Ansible's execution environment. +# All non-collection paths (see Ansible 2.10 notes below) known to Ansible are already included and do not need to be specified. +# Additionally, this parameter needs to be configured if the path reported by 'ansible --version' is incorrect +# or you would like to customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules/network" + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and exclusively used in Ansible's execution environment. +# Due to differences in collections before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible_collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, i.e., itential_cli, itential_get_config. +#extended_device_role_path: + #This is a sample path to roles that extend device support + #- "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/extensible_device_roles" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=true if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: "{{ gateway_install_dir }}/nornir/config.yml" + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - "{{ gateway_install_dir }}/nornir/modules" + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +############# +# Terraform # +############# +# Terraform was removed due to HashiCorp adopting the +# Business Source License (BSL) for their core products + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: false + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending reqests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.1.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.1.yml.j2 new file mode 100644 index 00000000..1dde9850 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.1.yml.j2 @@ -0,0 +1,390 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, etc. + +########## +# System # +########## + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +{% if gateway_https %} +port: {{ gateway_https_port }} +{% else %} +port: {{ gateway_port }} +{% endif %} + +# The IP addresses to bind the web application to. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: true + +# Directory to write global log files to +global_log_directory: '{{ gateway_log_dir }}' + +# Maximum log files kept in rotation +# Valid range of values is 1-100. If value is set to 1, log file will not be limited in size. +max_log_files: 5 + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "commands", etc. +strict_args: true + +################ +# SSL Settings # +################ + +# To start the server using SSL/TLS please fill out the following properties. +{% if gateway_https %} +server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +server_keyfile: "{{ gateway_ssl_key_dest }}" + +server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% else %} +#server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +#server_keyfile: "{{ gateway_ssl_key_dest }}" + +# server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% endif %} + +# TLSv1_2 +{% if gateway_https and gateway_tlsv1_2 %} +server_ssl_version: "TLSv1_2" +{% else %} +#server_ssl_version: "TLSv1_2" +{% endif %} + +# You may also set custom SSL Ciphers. +# +# https://docs.gunicorn.org/en/20.x/settings.html#ciphers +# +{% if server_ssl_ciphers is defined %} +server_ssl_ciphers: "{{ server_ssl_ciphers }}" +{% else %} +# server_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:..."" +{% endif %} + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway.db" + +# A flag which determines whether or not audit logging is enabled. (default=true if absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxillary Automation Gateway sqlite database file for audit logs. +audit_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db" + +# Path to the auxillary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db" + +####################### +# LDAP Authentication # +####################### + +# +# LDAP Basic SETTINGS +# + +# Enable LDAP authentication globally +ldap_auth_enabled: False + +# LDAP server hostname or IP address +ldap_server: 'ldap.example.com' + +# LDAP BASE DN +ldap_base_dn: 'DC=example,DC=com' + +# LDAP BIND Username +ldap_bind_user_dn: 'CN=admin,CN=users,DC=example,DC=com' + +# LDAP BIND Password +ldap_bind_user_password: '' + +# +# LDAP Securitry +# + +# Enable LDAPS +ldap_secure_enabled: False + +# Validate the servers TLS certificate +ldap_secure_validation_enabled: True + +# TLS version to use when connection to LDAP server (default: TLSv1.2) +# Options ["1", "1.1", "1.2"] +ldap_secure_validation_tls_version: '1.2' + +# Location of local CA certificate file for server validation +ldap_ca_certs_file: '/etc/ssl/certs/ca.crt' + +# +# LDAP User Search +# + +# Search LDAP for the username before doing a bind +ldap_always_search_bind: True + +# LDAP user search filter +ldap_user_search_filter: '(objectclass=person)' + +# LDAP user search scope +# Options "LEVEL" or "SUBTREE" +ldap_user_search_scope: 'SUBTREE' + +# User login attribute +ldap_user_login_attr: 'sAMAccountName' + +# User login RDN (relative directory name) attribute +# uid=testuser,ou=users,dc=example,dc=com = 'uid' +# cn=testuser,ou=users,dc=example,dc=com = 'cn' +ldap_user_rdn_attr: 'cn' + +# LDAP user DN used to be prepended to the base DN to limit the scope when searching for users +ldap_user_dn : '' # OU=users + +# +# LDAP GROUP OPTIONS +# + +# Group search filter +ldap_group_search_filter: '(objectClass=group)' + +# Group search scope +# Options "LEVEL" or "SUBTREE" +ldap_group_search_scope: 'SUBTREE' + +# Group members attribute +ldap_group_members_attr: 'member' + +# LDAP group DN used to be prepended to the base DN to limit the scope when searching for groups +ldap_group_dn : '' # OU=groups + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or playbooks. +# Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "{{ gateway_install_dir }}/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External inventory. +inventory_file: "{{ gateway_install_dir }}/ansible/inventory/hosts" + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to Ansible's execution environment. +# All non-collection paths (see Ansible 2.10 notes below) known to Ansible are already included and do not need to be specified. +# Additionally, this parameter needs to be configured if the path reported by 'ansible --version' is incorrect +# or you would like to customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/ansible/modules" + - "{{ gateway_install_dir }}/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and exclusively used in Ansible's execution environment. +# Due to differences in collections before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/roles" + - "{{ gateway_install_dir }}/ansible/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, i.e., itential_cli, itential_get_config. +#extended_device_role_path: + #This is a sample path to roles that extend device support + #- "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/extensible_device_roles" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python3.9/site-packages/automation_gateway/integrations/playbooks" + - "{{ gateway_install_dir }}/ansible/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=true if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: "{{ gateway_install_dir }}/nornir/config.yml" + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - "{{ gateway_install_dir }}/nornir/modules" + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +############# +# Terraform # +############# +# Terraform was removed due to HashiCorp adopting the +# Business Source License (BSL) for their core products + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: false + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending reqests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.2.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.2.yml.j2 new file mode 100644 index 00000000..7e6b7e65 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.2.yml.j2 @@ -0,0 +1,408 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, etc. + +########## +# System # +########## + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +{% if gateway_https %} +port: {{ gateway_https_port }} +{% else %} +port: {{ gateway_port }} +{% endif %} + +# The IP addresses to bind the web application to. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: true + +# Directory to write global log files to +global_log_directory: '{{ gateway_log_dir }}' + +# Maximum log files kept in rotation +# Valid range of values is 1-100. If value is set to 1, log file will not be limited in size. +max_log_files: 5 + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "commands", etc. +strict_args: true + +################ +# SSL Settings # +################ + +# To start the server using SSL/TLS please fill out the following properties. +{% if gateway_https %} +server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +server_keyfile: "{{ gateway_ssl_key_dest }}" + +server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% else %} +#server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +#server_keyfile: "{{ gateway_ssl_key_dest }}" + +# server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% endif %} + +# TLSv1_2 +{% if gateway_https and gateway_tlsv1_2 %} +server_ssl_version: "TLSv1_2" +{% else %} +#server_ssl_version: "TLSv1_2" +{% endif %} + +# You may also set custom SSL Ciphers. +# +# https://docs.gunicorn.org/en/20.x/settings.html#ciphers +# +{% if server_ssl_ciphers is defined %} +server_ssl_ciphers: "{{ server_ssl_ciphers }}" +{% else %} +# server_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:..."" +{% endif %} + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway.db" + +# A flag which determines whether or not audit logging is enabled. (default=true if absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxiliary Automation Gateway sqlite database file for audit logs. +audit_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db" + +# Path to the auxiliary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: "sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db" + +####################### +# LDAP Authentication # +####################### + +# +# LDAP Basic SETTINGS +# + +# Enable LDAP authentication globally +ldap_auth_enabled: False + +# LDAP server hostname or IP address +ldap_server: 'ldap.example.com' + +# LDAP BASE DN +ldap_base_dn: 'DC=example,DC=com' + +# LDAP BIND Username +ldap_bind_user_dn: 'CN=admin,CN=users,DC=example,DC=com' + +# LDAP BIND Password +ldap_bind_user_password: '' + +# +# LDAP Security +# + +# Enable LDAPS +ldap_secure_enabled: False + +# Validate the servers TLS certificate +ldap_secure_validation_enabled: True + +# TLS version to use when connection to LDAP server (default: TLSv1.2) +# Options ["1", "1.1", "1.2"] +ldap_secure_validation_tls_version: '1.2' + +# Location of local CA certificate file for server validation +ldap_ca_certs_file: '/etc/ssl/certs/ca.crt' + +# +# LDAP User Search +# + +# Search LDAP for the username before doing a bind +ldap_always_search_bind: True + +# LDAP user search filter +ldap_user_search_filter: '(objectclass=person)' + +# LDAP user search scope +# Options "LEVEL" or "SUBTREE" +ldap_user_search_scope: 'SUBTREE' + +# User login attribute +ldap_user_login_attr: 'sAMAccountName' + +# User login RDN (relative directory name) attribute +# uid=testuser,ou=users,dc=example,dc=com = 'uid' +# cn=testuser,ou=users,dc=example,dc=com = 'cn' +ldap_user_rdn_attr: 'cn' + +# LDAP user DN used to be prepended to the base DN to limit the scope when searching for users +ldap_user_dn : '' # OU=users + +# +# LDAP GROUP OPTIONS +# + +# Group search filter +ldap_group_search_filter: '(objectClass=group)' + +# Group search scope +# Options "LEVEL" or "SUBTREE" +ldap_group_search_scope: 'SUBTREE' + +# Group members attribute +ldap_group_members_attr: 'member' + +# LDAP group DN used to be prepended to the base DN to limit the scope when searching for groups +ldap_group_dn : '' # OU=groups + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or playbooks. +# Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "{{ gateway_install_dir }}/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External inventory. +inventory_file: "{{ gateway_install_dir }}/ansible/inventory/hosts" + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to Ansible's execution environment. +# All non-collection paths (see Ansible 2.10 notes below) known to Ansible are already included and do not need to be specified. +# Additionally, this parameter needs to be configured if the path reported by 'ansible --version' is incorrect +# or you would like to customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/ansible/modules" + - "{{ gateway_install_dir }}/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and exclusively used in Ansible's execution environment. +# Due to differences in collections before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/roles" + - "{{ gateway_install_dir }}/ansible/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, i.e., itential_cli, itential_get_config. +#extended_device_role_path: + #This is a sample path to roles that extend device support + #- "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/extensible_device_roles" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/playbooks" + - "{{ gateway_install_dir }}/ansible/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=true if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: "{{ gateway_install_dir }}/nornir/config.yml" + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - "{{ gateway_install_dir }}/nornir/modules" + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +################ +# Python Venvs # +################ + +# Enable python venv support +python_venv_enabled: {{ gateway_enable_python_venv }} + +# Paths to python venvs for use in scripts +python_venv_paths: + - "{{ gateway_install_dir }}/python-venvs/" + +################## +# GRPC gNMI/gNOI # +################## + +# Grpc requires grpcio and pygnmi to be installed +grpc_enabled: {{ gateway_enable_grpc }} + +############# +# Terraform # +############# +# Terraform was removed due to HashiCorp adopting the +# Business Source License (BSL) for their core products + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: false + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending requests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.3.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.3.yml.j2 new file mode 100644 index 00000000..d5b7e4c7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.2023.3.yml.j2 @@ -0,0 +1,452 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, +# etc. + +########## +# System # +########## + +# INVENTORY ENCRYPTION +# Set the Fernet encryption key to have IAG encrypt device variables['password'] +# ANYONE THAT HAS THIS KEY CAN DECRYPT YOUR PASSWORDS - PROTECT IT! +# WHICH ALSO MEANS PROTECT YOUR properties.yml file `chmod 600 properties.yml` +# and validate the file's ownership. +#fernet_key: "" + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +{% if gateway_https %} +port: {{ gateway_https_port }} +{% else %} +port: {{ gateway_port }} +{% endif %} + +# The gunicorn bind_address string.. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +# +# You can also bind to a linux socket using "unix://" +# if you want to front-end automation-gateway with nginx or another proxy server. +# +# bind_address: "unix:///tmp/gunicorn.sock" +# bind_address: "[::]" +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: false + +# Directory to write global log files to +global_log_directory: '{{ gateway_log_dir }}' + +# Maximum log files kept in rotation +# Valid range of values is 1-100. If value is set to 1, log file will not be limited in size. +max_log_files: 5 + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "{% raw %}{{commands}}{% endraw %}", etc. +strict_args: true + +################ +# SSL Settings # +################ + +# To start the server using SSL/TLS please fill out the following properties. +{% if gateway_https %} +server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +server_keyfile: "{{ gateway_ssl_key_dest }}" + +server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% else %} +#server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +#server_keyfile: "{{ gateway_ssl_key_dest }}" + +# server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% endif %} + +# TLSv1_2 +{% if gateway_https and gateway_tlsv1_2 %} +server_ssl_version: "TLSv1_2" +{% else %} +#server_ssl_version: "TLSv1_2" +{% endif %} + +# You may also set custom SSL Ciphers. +# +# https://docs.gunicorn.org/en/20.x/settings.html#ciphers +# +{% if server_ssl_ciphers is defined %} +server_ssl_ciphers: "{{ server_ssl_ciphers }}" +{% else %} +# server_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:..."" +{% endif %} + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway.db' + +# A flag which determines whether or not audit logging is enabled. (default=true if +# absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxiliary Automation Gateway sqlite database file for audit logs. +audit_db_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db' + +# Path to the auxiliary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db' + +####################### +# LDAP Authentication # +####################### + +# +# LDAP Basic SETTINGS +# + +# Enable LDAP authentication globally +ldap_auth_enabled: false + +# LDAP server hostname or IP address +ldap_server: 'ldap.example.com' + +# LDAP BASE DN +ldap_base_dn: 'DC=example,DC=com' + +# LDAP BIND Username +ldap_bind_user_dn: 'CN=admin,CN=users,DC=example,DC=com' + +# LDAP BIND Password +ldap_bind_user_password: '' + +# +# LDAP Security +# + +# Enable LDAPS +ldap_secure_enabled: false + +# Validate the servers TLS certificate +ldap_secure_validation_enabled: true + +# TLS version to use when connection to LDAP server (default: TLSv1.2) +# Options ["1", "1.1", "1.2"] +ldap_secure_validation_tls_version: '1.2' + +# Location of local CA certificate file for server validation +ldap_ca_certs_file: '/etc/ssl/certs/ca.crt' + +# +# LDAP User Search +# CN=SvcLveINA,OU=Service Accounts,OU=Protected Accounts,OU=SEC,DC=mid,DC=dom + +# Search LDAP for the username before doing a bind +ldap_always_search_bind: true + +# LDAP user search filter +ldap_user_search_filter: '(objectclass=person)' + +# LDAP user search scope +# Options "LEVEL" or "SUBTREE" +ldap_user_search_scope: 'SUBTREE' + +# User login attribute +ldap_user_login_attr: 'sAMAccountName' + +# User login RDN (relative directory name) attribute +# uid=testuser,ou=users,dc=example,dc=com = 'uid' +# cn=testuser,ou=users,dc=example,dc=com = 'cn' +ldap_user_rdn_attr: 'cn' + +# LDAP user DN used to be prepended to the base DN to limit the scope when searching for users +ldap_user_dn : '' # OU=users + +# +# LDAP GROUP OPTIONS +# + +# Group search filter +ldap_group_search_filter: '(objectClass=group)' + +# Group search scope +# Options "LEVEL" or "SUBTREE" +ldap_group_search_scope: 'SUBTREE' + +# Group members attribute +ldap_group_members_attr: 'member' + +# LDAP group DN used to be prepended to the base DN to limit the scope when searching for groups +ldap_group_dn : '' # OU=groups + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or +# playbooks. Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "/opt/automation-gateway/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External +# inventory. +inventory_file: '{{ gateway_install_dir }}/ansible/inventory/hosts' + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. All non-collection paths (see Ansible 2.10 notes below) known to +# Ansible are already included and do not need to be specified. # Additionally, this parameter needs +# to be configured if the path reported by 'ansible --version' is incorrect or you would like to +# customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes +# below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/ansible/modules" + - "{{ gateway_install_dir }}/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and +# exclusively used in Ansible's execution environment. Due to differences in collections +# before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/roles" + - "{{ gateway_install_dir }}/ansible/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, +# i.e., itential_cli, itential_get_config. +extended_device_role_path: + # This path will enable connecting to devices that use Netmiko + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/extensible_device_roles/ansible_netmiko" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/playbooks" + - "{{ gateway_install_dir }}/ansible/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=false if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: '{{ gateway_install_dir }}/nornir/config.yml' + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - '{{ gateway_install_dir }}/nornir/modules' + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +################ +# Python Venvs # +################ + +# Enable python venv support +python_venv_enabled: {{ gateway_enable_python_venv }} + +# Paths to python venvs for use in scripts +python_venv_paths: + - "{{ gateway_install_dir }}/venvs/" + +################## +# GRPC gNMI/gNOI # +################## + +# Grpc requires grpcio and pygnmi to be installed +grpc_enabled: {{ gateway_enable_grpc }} + +############# +# Terraform # +############# + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: true + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + # Default location for custom content per the setup script + - '/usr/share/automation-gateway/terraform' + # Legacy path for backwards compatibility + - '/usr/share/automation-gateway/terraform/scripts' + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending requests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" + +################### +# Git Integration # +################### + +git_enabled: {{ gateway_enable_git }} + +# The parent folder to use for ssh key storage. +git_key_path: {{ gateway_install_dir }}/ssh/ + +# The parent path for all git repositories added via Git Integration +git_repo_path: {{ gateway_install_dir }}/repos/ + +# If you do not specify a git_exec path we will look for the first +# git executable in the environment. +# git_exec: /usr/local/bin/git + +# Strict host key checking +# +git_strict_host_check: false \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.4.2.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.4.2.yml.j2 new file mode 100644 index 00000000..d5b7e4c7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.4.2.yml.j2 @@ -0,0 +1,452 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, +# etc. + +########## +# System # +########## + +# INVENTORY ENCRYPTION +# Set the Fernet encryption key to have IAG encrypt device variables['password'] +# ANYONE THAT HAS THIS KEY CAN DECRYPT YOUR PASSWORDS - PROTECT IT! +# WHICH ALSO MEANS PROTECT YOUR properties.yml file `chmod 600 properties.yml` +# and validate the file's ownership. +#fernet_key: "" + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +{% if gateway_https %} +port: {{ gateway_https_port }} +{% else %} +port: {{ gateway_port }} +{% endif %} + +# The gunicorn bind_address string.. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +# +# You can also bind to a linux socket using "unix://" +# if you want to front-end automation-gateway with nginx or another proxy server. +# +# bind_address: "unix:///tmp/gunicorn.sock" +# bind_address: "[::]" +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: false + +# Directory to write global log files to +global_log_directory: '{{ gateway_log_dir }}' + +# Maximum log files kept in rotation +# Valid range of values is 1-100. If value is set to 1, log file will not be limited in size. +max_log_files: 5 + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "{% raw %}{{commands}}{% endraw %}", etc. +strict_args: true + +################ +# SSL Settings # +################ + +# To start the server using SSL/TLS please fill out the following properties. +{% if gateway_https %} +server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +server_keyfile: "{{ gateway_ssl_key_dest }}" + +server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% else %} +#server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +#server_keyfile: "{{ gateway_ssl_key_dest }}" + +# server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% endif %} + +# TLSv1_2 +{% if gateway_https and gateway_tlsv1_2 %} +server_ssl_version: "TLSv1_2" +{% else %} +#server_ssl_version: "TLSv1_2" +{% endif %} + +# You may also set custom SSL Ciphers. +# +# https://docs.gunicorn.org/en/20.x/settings.html#ciphers +# +{% if server_ssl_ciphers is defined %} +server_ssl_ciphers: "{{ server_ssl_ciphers }}" +{% else %} +# server_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:..."" +{% endif %} + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway.db' + +# A flag which determines whether or not audit logging is enabled. (default=true if +# absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxiliary Automation Gateway sqlite database file for audit logs. +audit_db_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db' + +# Path to the auxiliary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db' + +####################### +# LDAP Authentication # +####################### + +# +# LDAP Basic SETTINGS +# + +# Enable LDAP authentication globally +ldap_auth_enabled: false + +# LDAP server hostname or IP address +ldap_server: 'ldap.example.com' + +# LDAP BASE DN +ldap_base_dn: 'DC=example,DC=com' + +# LDAP BIND Username +ldap_bind_user_dn: 'CN=admin,CN=users,DC=example,DC=com' + +# LDAP BIND Password +ldap_bind_user_password: '' + +# +# LDAP Security +# + +# Enable LDAPS +ldap_secure_enabled: false + +# Validate the servers TLS certificate +ldap_secure_validation_enabled: true + +# TLS version to use when connection to LDAP server (default: TLSv1.2) +# Options ["1", "1.1", "1.2"] +ldap_secure_validation_tls_version: '1.2' + +# Location of local CA certificate file for server validation +ldap_ca_certs_file: '/etc/ssl/certs/ca.crt' + +# +# LDAP User Search +# CN=SvcLveINA,OU=Service Accounts,OU=Protected Accounts,OU=SEC,DC=mid,DC=dom + +# Search LDAP for the username before doing a bind +ldap_always_search_bind: true + +# LDAP user search filter +ldap_user_search_filter: '(objectclass=person)' + +# LDAP user search scope +# Options "LEVEL" or "SUBTREE" +ldap_user_search_scope: 'SUBTREE' + +# User login attribute +ldap_user_login_attr: 'sAMAccountName' + +# User login RDN (relative directory name) attribute +# uid=testuser,ou=users,dc=example,dc=com = 'uid' +# cn=testuser,ou=users,dc=example,dc=com = 'cn' +ldap_user_rdn_attr: 'cn' + +# LDAP user DN used to be prepended to the base DN to limit the scope when searching for users +ldap_user_dn : '' # OU=users + +# +# LDAP GROUP OPTIONS +# + +# Group search filter +ldap_group_search_filter: '(objectClass=group)' + +# Group search scope +# Options "LEVEL" or "SUBTREE" +ldap_group_search_scope: 'SUBTREE' + +# Group members attribute +ldap_group_members_attr: 'member' + +# LDAP group DN used to be prepended to the base DN to limit the scope when searching for groups +ldap_group_dn : '' # OU=groups + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or +# playbooks. Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "/opt/automation-gateway/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External +# inventory. +inventory_file: '{{ gateway_install_dir }}/ansible/inventory/hosts' + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. All non-collection paths (see Ansible 2.10 notes below) known to +# Ansible are already included and do not need to be specified. # Additionally, this parameter needs +# to be configured if the path reported by 'ansible --version' is incorrect or you would like to +# customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes +# below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/ansible/modules" + - "{{ gateway_install_dir }}/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and +# exclusively used in Ansible's execution environment. Due to differences in collections +# before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/roles" + - "{{ gateway_install_dir }}/ansible/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, +# i.e., itential_cli, itential_get_config. +extended_device_role_path: + # This path will enable connecting to devices that use Netmiko + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/extensible_device_roles/ansible_netmiko" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/playbooks" + - "{{ gateway_install_dir }}/ansible/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=false if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: '{{ gateway_install_dir }}/nornir/config.yml' + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - '{{ gateway_install_dir }}/nornir/modules' + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +################ +# Python Venvs # +################ + +# Enable python venv support +python_venv_enabled: {{ gateway_enable_python_venv }} + +# Paths to python venvs for use in scripts +python_venv_paths: + - "{{ gateway_install_dir }}/venvs/" + +################## +# GRPC gNMI/gNOI # +################## + +# Grpc requires grpcio and pygnmi to be installed +grpc_enabled: {{ gateway_enable_grpc }} + +############# +# Terraform # +############# + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: true + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + # Default location for custom content per the setup script + - '/usr/share/automation-gateway/terraform' + # Legacy path for backwards compatibility + - '/usr/share/automation-gateway/terraform/scripts' + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending requests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" + +################### +# Git Integration # +################### + +git_enabled: {{ gateway_enable_git }} + +# The parent folder to use for ssh key storage. +git_key_path: {{ gateway_install_dir }}/ssh/ + +# The parent path for all git repositories added via Git Integration +git_repo_path: {{ gateway_install_dir }}/repos/ + +# If you do not specify a git_exec path we will look for the first +# git executable in the environment. +# git_exec: /usr/local/bin/git + +# Strict host key checking +# +git_strict_host_check: false \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.4.3.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.4.3.yml.j2 new file mode 100644 index 00000000..0979f3e8 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/templates/properties.4.3.yml.j2 @@ -0,0 +1,456 @@ +--- +# Notes: +# +# While many customizations can be made based on your environment and which integrations you +# would like enabled, this file is meant to mimic the installation process found at +# https://docs.itential.io/ as closely as possible so the user can use as many defaults as possible. +# +# This configuration file accepts any valid YAML syntax including the bash-like syntax for lists, +# etc. + +########## +# System # +########## + +# INVENTORY ENCRYPTION +# Set the Fernet encryption key to have IAG encrypt device variables['password'] +# ANYONE THAT HAS THIS KEY CAN DECRYPT YOUR PASSWORDS - PROTECT IT! +# WHICH ALSO MEANS PROTECT YOUR properties.yml file `chmod 600 properties.yml` +# and validate the file's ownership. +#fernet_key: "" + +# The port on which Automation Gateway server will listen for requests. +# Mutually exclusive with bind_list +{% if gateway_https %} +port: {{ gateway_https_port }} +{% else %} +port: {{ gateway_port }} +{% endif %} + +# The gunicorn bind_address string.. +# For ipv4 only use "0.0.0.0", for ipv6 and ipv4 use "[::]" +# Mutually exclusive with bind_list +# +# You can also bind to a linux socket using "unix://" +# if you want to front-end automation-gateway with nginx or another proxy server. +# +# bind_address: "unix:///tmp/gunicorn.sock" +# bind_address: "[::]" +bind_address: {{ inventory_hostname }} + +# List of addresses and ports to bind to. +# This setting will override both 'port' and 'bind_address' +#bind_list: +# - "{{ inventory_hostname }}:{{ gateway_port }}" + +# Base of url for external proxy, used for generating redirects: +# external_address: 'http://automation-gateway.example.com:8080' + +# The number of http server threads for handling requests. +# It is recommended to set this to 4 x NUM_CORES. +# E.g. for a 16 core machine, the value should be set to 64. +http_server_threads: {{ gateway_http_server_threads }} + +# A flag that determines whether authentication is disabled or not. +# Warning: only disable authentication for temporary, non production testing. +authentication_disabled: false + +# The maximum number of concurrent sessions allowed. +authentication_max_sessions: 5000 + +# The idle timeout of each session (in seconds). +authentication_idle_timeout: 600 + +# A boolean flag that enables password reset support (default=false if absent/misconfigured). +password_reset_enabled: false + +# Directory to write global log files to +global_log_directory: '{{ gateway_log_dir }}' + +# Maximum log files kept in rotation +# Valid range of values is 1-100. If value is set to 1, log file will not be limited in size. +max_log_files: 5 + +# NOTE: Log levels for Automation Gateway Server are as follows. +# In order of ascending severity: DEBUG, INFO, WARNING, ERROR, or CRITICAL. +# Log messages of equal and greater severity will be displayed in the relevant log. +# Example: logging_level INFO will display log messages with a severity of INFO -> CRITICAL. +# (default=INFO if absent/misconfigured) + +# Automation Gateway Server Logging Level +logging_level: INFO + +# Automation Gateway HTTP Server Logging Level +# NOTE: request details are DEBUG level log messages, it may be useful to set this to DEBUG +http_logging_level: INFO + +# A flag that enables/disables parameter schema validation for content decorations. +# Generally enabled when using multiple types per parameter, or when testing decorations. +# Example: "commands" could be a literal list of commands, or a string representing a jinja +# variable from your host's variables "{% raw %}{{commands}}{% endraw %}", etc. +strict_args: true + +# Enabling this property masks the device variables "password" and "ansible_password" in any GET +# request response for any device type. +mask_device_passwords: true + +################ +# SSL Settings # +################ + +# To start the server using SSL/TLS please fill out the following properties. +{% if gateway_https %} +server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +server_keyfile: "{{ gateway_ssl_key_dest }}" + +server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% else %} +#server_certfile: "{{ gateway_ssl_cert_dest }}" + +# Note: gunicorn does not currently support encrypted key files. +#server_keyfile: "{{ gateway_ssl_key_dest }}" + +# server_cabundle: "{{ gateway_ssl_rootca_dest }}" +{% endif %} + +# TLSv1_2 +{% if gateway_https and gateway_tlsv1_2 %} +server_ssl_version: "TLSv1_2" +{% else %} +#server_ssl_version: "TLSv1_2" +{% endif %} + +# You may also set custom SSL Ciphers. +# +# https://docs.gunicorn.org/en/20.x/settings.html#ciphers +# +{% if server_ssl_ciphers is defined %} +server_ssl_ciphers: "{{ server_ssl_ciphers }}" +{% else %} +# server_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:..."" +{% endif %} + +############# +# Databases # +############# + +# Path to the main Automation Gateway sqlite database file. +data_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway.db' + +# A flag which determines whether or not audit logging is enabled. (default=true if +# absent/misconfigured) +audit: true + +# The number of days (days >= 0) worth of data to retain in the audit log database +# Records earlier than the specified days will be deleted. (default=None if absent/misconfigured) +audit_retention_days: 30 + +# Path to the auxiliary Automation Gateway sqlite database file for audit logs. +audit_db_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway_audit.db' + +# Path to the auxiliary Automation Gateway sqlite database file for execution logs. +exec_history_db_file: 'sqlite:///{{ gateway_data_dir }}/automation-gateway_exec_history.db' + +####################### +# LDAP Authentication # +####################### + +# +# LDAP Basic SETTINGS +# + +# Enable LDAP authentication globally +ldap_auth_enabled: false + +# LDAP server hostname or IP address +ldap_server: 'ldap.example.com' + +# LDAP BASE DN +ldap_base_dn: 'DC=example,DC=com' + +# LDAP BIND Username +ldap_bind_user_dn: 'CN=admin,CN=users,DC=example,DC=com' + +# LDAP BIND Password +ldap_bind_user_password: '' + +# +# LDAP Security +# + +# Enable LDAPS +ldap_secure_enabled: false + +# Validate the servers TLS certificate +ldap_secure_validation_enabled: true + +# TLS version to use when connection to LDAP server (default: TLSv1.2) +# Options ["1", "1.1", "1.2"] +ldap_secure_validation_tls_version: '1.2' + +# Location of local CA certificate file for server validation +ldap_ca_certs_file: '/etc/ssl/certs/ca.crt' + +# +# LDAP User Search +# CN=SvcLveINA,OU=Service Accounts,OU=Protected Accounts,OU=SEC,DC=mid,DC=dom + +# Search LDAP for the username before doing a bind +ldap_always_search_bind: true + +# LDAP user search filter +ldap_user_search_filter: '(objectclass=person)' + +# LDAP user search scope +# Options "LEVEL" or "SUBTREE" +ldap_user_search_scope: 'SUBTREE' + +# User login attribute +ldap_user_login_attr: 'sAMAccountName' + +# User login RDN (relative directory name) attribute +# uid=testuser,ou=users,dc=example,dc=com = 'uid' +# cn=testuser,ou=users,dc=example,dc=com = 'cn' +ldap_user_rdn_attr: 'cn' + +# LDAP user DN used to be prepended to the base DN to limit the scope when searching for users +ldap_user_dn : '' # OU=users + +# +# LDAP GROUP OPTIONS +# + +# Group search filter +ldap_group_search_filter: '(objectClass=group)' + +# Group search scope +# Options "LEVEL" or "SUBTREE" +ldap_group_search_scope: 'SUBTREE' + +# Group members attribute +ldap_group_members_attr: 'member' + +# LDAP group DN used to be prepended to the base DN to limit the scope when searching for groups +ldap_group_dn : '' # OU=groups + +########### +# Ansible # +########### + +# A boolean flag that enables Ansible support (default=true if absent/misconfigured). +ansible_enabled: {{ gateway_enable_ansible }} + +# A boolean which logs additional debug messages when executing Ansible modules, roles, or +# playbooks. Set the ansible_debug property to true to log additional debug messages when +# executing Ansible modules, roles, or playbooks. (default=false if absent/misconfigured) +ansible_debug: false + +# A flag to prevent deletion of the temporary files generated by executing +# Ansible content (modules, collections, roles, playbooks). (default=false if absent/misconfigured) +no_cleanup: false + +# Path of the file that contains a password used by ansible-vault to encrypt sensitive data. +# Uncomment this property if you will be using Ansible vault encrypted variables. +# Be sure to secure this file with permissions of 0200 or 0400. +#vault_password_file: "/opt/automation-gateway/conf/.vault_password_file" + +# Path to the Ansible external inventory file (folders not valid). +# A valid file will disable Ansible Internal inventory and instead use only this Ansible External +# inventory. +inventory_file: '{{ gateway_install_dir }}/ansible/inventory/hosts' + +# Path(s) to the Ansible modules that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. All non-collection paths (see Ansible 2.10 notes below) known to +# Ansible are already included and do not need to be specified. # Additionally, this parameter needs +# to be configured if the path reported by 'ansible --version' is incorrect or you would like to +# customize/trim down the set of Ansible modules that will be discovered (see Ansible<=2.9 notes +# below). +# Trim example for ansible 2.9: "/usr/local/lib/python3.9/site-packages/ansible/modules/network" +# NOTE: Use only the site-packages paths you need for your installation to avoid +# cross environment issues in the case where multiple of these paths exist +module_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/ansible/modules" + - "{{ gateway_install_dir }}/ansible/modules" + +# Path(s) to the Ansible collections that should be discovered by Automation Gateway and +# exclusively used in Ansible's execution environment. Due to differences in collections +# before/after Ansible 2.9, these will be the only paths relevant during discovery AND execution. +collection_path: + - "{{ gateway_install_dir }}/ansible/collections" + +# Path(s) to the Ansible roles that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. +role_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/roles" + - "{{ gateway_install_dir }}/ansible/roles" + +# Path(s) to customized roles that extend device support of the Itential roles found in the release, +# i.e., itential_cli, itential_get_config. +extended_device_role_path: + # This path will enable connecting to devices that use Netmiko + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/extensible_device_roles/ansible_netmiko" + +# Discovery behavior for Ansible playbooks. Determines whether or not to +# recursively search the directories found in the 'playbook_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +playbook_recursive: true + +# Path(s) to the Ansible playbooks that should be discovered by Automation Gateway and appended to +# Ansible's execution environment. +playbook_path: + - "{{ gateway_install_dir }}/venv/lib/python{{ gateway_python_version }}/site-packages/automation_gateway/integrations/playbooks" + - "{{ gateway_install_dir }}/ansible/playbooks" + +################# +# HTTP_Requests # +################# + +# A boolean flag that enables HTTP_Requests support (default=true if absent/misconfigured). +http_requests_enabled: {{ gateway_enable_httpreq }} + +########### +# NETCONF # +########### + +# A boolean flag that enables Netconf support (default=false if absent/misconfigured). +netconf_enabled: {{ gateway_enable_netconf }} + +########### +# Netmiko # +########### + +# A boolean flag that enables Netmiko support (default=false if absent/misconfigured). +netmiko_enabled: {{ gateway_enable_netmiko }} + +########## +# Nornir # +########## + +# A boolean flag that enables Nornir support (default=false if absent/misconfigured). +nornir_enabled: {{ gateway_enable_nornir }} + +# Path to the Nornir configuration file. +# A valid file will allows the use of Nornir External inventory. +nornir_config_file: '{{ gateway_install_dir }}/nornir/config.yml' + +# Discovery behavior for Nornir modules. Determines whether or not to +# recursively search the directories found in the 'nornir_module_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +nornir_module_recursive: true + +# Path(s) to the Nornir modules that should be discovered by Automation Gateway. +nornir_module_path: + # Default location for custom content per the setup script + - '{{ gateway_install_dir }}/nornir/modules' + +########### +# Scripts # +########### + +# A boolean flag that enables Scripts support (default=true if absent/misconfigured). +scripts_enabled: {{ gateway_enable_scripts }} + +# Discovery behavior for standalone scripts. Determines whether or not to +# recursively search the directories found in the 'script_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +script_recursive: true + +# Path(s) to the standalone scripts that should be discovered by Automation Gateway. +script_path: + - "{{ gateway_install_dir }}/scripts" + +################ +# Python Venvs # +################ + +# Enable python venv support +python_venv_enabled: {{ gateway_enable_python_venv }} + +# Paths to python venvs for use in scripts +python_venv_paths: + - "{{ gateway_install_dir }}/venvs/" + +################## +# GRPC gNMI/gNOI # +################## + +# Grpc requires grpcio and pygnmi to be installed +grpc_enabled: {{ gateway_enable_grpc }} + +############# +# Terraform # +############# + +# A boolean flag that enables Terraform support (default=false if absent/misconfigured). +terraform_enabled: false + +# Discovery behavior for Terraform modules. Determines whether or not to +# recursively search the directories found in the 'terraform_path' parameter, or +# to only search those directories and no deeper. (default=true if absent/misconfigured) +terraform_recursive: true + +# Path(s) to the Terraform modules that should be discovered by Automation Gateway. +terraform_path: + # Default location for custom content per the setup script + - '/usr/share/automation-gateway/terraform' + # Legacy path for backwards compatibility + - '/usr/share/automation-gateway/terraform/scripts' + +################### +# Hashicorp Vault # +################### + +# A flag that enables Hashicorp Vault support. (default=false if absent/misconfigured) +vault_enabled: false + +# The URL to the Hashicorp Vault server. +#vault_server: "https://localhost:8200" + +# The mount point on which the Hashicorp Vault KV-V2 secret engine is enabled. +#vault_mount_point: secret + +# The path to a file containing the vault access token used by the AG Server for +# Hashicorp Vault operations. The file should be secured with 0400 permissions. +#vault_access_token: "{{ gateway_install_dir }}/conf/.vault_token_file" + +# A flag that enables TLS certificate verification when sending requests to the Hashicorp +# Vault Server. (default=false if absent/misconfigured) +#vault_cert_verification: false + +# The path to a CA (Certificate Authority) file. This file is used to perform TLS certificate +# verification when sending requests to a Hashicorp Vault Server configured with a self-signed +# certificate. This parameter is not required when sending requests to a Hashicorp Vault Server +# configured with a certificate signed by a trusted authority. +#vault_ca_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client certificate PEM file used for performing TLS authentication of the AG +# vault client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_cert_file: "{{ gateway_install_dir }}/conf/certs/cert.pem" + +# The path to a client key PEM file used for performing TLS authentication of the AG vault +# client with the Hashicorp Vault Server. Both a client certificate file and a key file +# must be configured for TLS authentication to be utilized. +#vault_client_key_file: "{{ gateway_install_dir }}/conf/certs/key.pem" + +################### +# Git Integration # +################### + +git_enabled: {{ gateway_enable_git }} + +# The parent folder to use for ssh key storage. +git_key_path: {{ gateway_install_dir }}/ssh/ + +# The parent path for all git repositories added via Git Integration +git_repo_path: {{ gateway_install_dir }}/repos/ + +# If you do not specify a git_exec path we will look for the first +# git executable in the environment. +# git_exec: /usr/local/bin/git + +# Strict host key checking +# +git_strict_host_check: false \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/gateway-release-4.2.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/gateway-release-4.2.yml new file mode 100644 index 00000000..dbf49e11 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/gateway-release-4.2.yml @@ -0,0 +1,64 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +gateway_packages: + - selinux-policy + - selinux-policy-targeted + +gateway_build_packages_map: + "8": + - gcc-c++ + - libssh-devel + - make + - pkgconf-pkg-config + - python39-devel + "9": + - gcc-c++ + - libssh-devel + - make + - pkgconf-pkg-config + - python3-devel + "2023": + - gcc-c++ + - libssh-devel + - make + - pkgconf-pkg-config + - python3-devel + +# Backwards compatible variable name references the appropriate list from the map +gateway_build_packages: "{{ gateway_build_packages_map[ansible_distribution_major_version] }}" + +gateway_python_version: 3.9 +gateway_python_executable: "/usr/bin/python{{ gateway_python_version }}" +gateway_pip_executable: "/usr/bin/pip{{ gateway_python_version }}" + +gateway_python_packages_map: + "8": + - python39 + - python39-pip + "9": + - python3 + - python3-pip + "2023": + - python3 + - python3-pip + +# Backwards compatible variable name references the appropriate list from the map +gateway_python_packages: "{{ gateway_python_packages_map[ansible_distribution_major_version] }}" + +gateway_python_base_dependencies: + - pip==24.0 + - setuptools==69.0.3 + - wheel==0.42.0 + +# Python modules that require a build. For offline installs, these will be built using 'pip wheel'. +gateway_python_wheel_build_dependencies: + - ansible-pylibssh==1.3.0 + - mypy_extensions==0.4.4 + - ncclient==0.6.10 + - netifaces==0.10.9 + - pygnmi==0.8.9 + +# These Python modules are pinned here because we are using 'pip download' and not 'pip install' +# for offline installs. +gateway_python_app_dependencies: diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/gateway-release-4.3.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/gateway-release-4.3.yml new file mode 100644 index 00000000..40884e61 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/gateway-release-4.3.yml @@ -0,0 +1,65 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +gateway_packages: + - selinux-policy + - selinux-policy-targeted + +gateway_build_packages_map: + "8": + - gcc-c++ + - libssh-devel + - make + - pkgconf-pkg-config + - python39-devel + "9": + - gcc-c++ + - libssh-devel + - make + - pkgconf-pkg-config + - python3-devel + "2023": + - gcc-c++ + - libssh-devel + - make + - pkgconf-pkg-config + - python3-devel + +# Backwards compatible variable name references the appropriate list from the map +gateway_build_packages: "{{ gateway_build_packages_map[ansible_distribution_major_version] }}" + +gateway_python_version: 3.9 +gateway_python_executable: "/usr/bin/python{{ gateway_python_version }}" +gateway_pip_executable: "/usr/bin/pip{{ gateway_python_version }}" + +gateway_python_packages_map: + "8": + - python39 + - python39-pip + "9": + - python3 + - python3-pip + "2023": + - python3 + - python3-pip + +# Backwards compatible variable name references the appropriate list from the map +gateway_python_packages: "{{ gateway_python_packages_map[ansible_distribution_major_version] }}" + +gateway_python_base_dependencies: + - pip==24.0 + - setuptools==78.1.1 + - wheel==0.43.0 + +# Python modules that require a build. For offline installs, these will be built using 'pip wheel' +gateway_python_wheel_build_dependencies: + - ansible-pylibssh==1.3.0 + - mypy_extensions==0.4.4 + - ncclient==0.6.19 + - netifaces==0.10.9 + - pygnmi==0.8.9 + +# These Python modules are pinned here because we are using 'pip download' and not 'pip install' +gateway_python_app_dependencies: + - importlib-metadata==4.13.0 + - grpcio-tools==1.53.0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/release-undefined.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/release-undefined.yml new file mode 100644 index 00000000..ff31477c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/gateway/vars/release-undefined.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +gateway_invalid_release: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/defaults/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/defaults/main.yml new file mode 100644 index 00000000..0d04e5bf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/defaults/main.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Grafana user and group +grafana_user: grafana +grafana_group: grafana + +# Grafana server settings +grafana_port: 3000 +grafana_repo_url: https://rpm.grafana.com +grafana_gpg_key: https://rpm.grafana.com/gpg.key +grafana_install_dir: /etc/grafana +grafana_dashboard_dir: "{{ grafana_install_dir }}/provisioning/dashboards" +grafana_allow_ui_updates: false diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_iap.json b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_iap.json new file mode 100644 index 00000000..dd7ac9fb --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_iap.json @@ -0,0 +1,7072 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": false, + "iconColor": "#e0752d", + "limit": 100, + "matchAny": true, + "name": "PMM Annotations", + "showIn": 0, + "tags": [ + "pmm_annotation", + "$node_name" + ], + "type": "tags" + }, + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "#6ed0e0", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "tags": [], + "type": "dashboard" + } + ] + }, + "description": "Provides insights about processes running on Linux host, such as Per Process CPU and Memory Usage, Disk IO, Process status etc \n\nTo be used with Percona Monitoring and Management v2 (PMM2)", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 14239, + "graphTooltip": 1, + "id": 6, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The parameter shows how long a system has been “up” and running without a shut down or restart.", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 300 + }, + { + "color": "rgba(50, 172, 45, 0.97)", + "value": 3600 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 19, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "calculatedInterval": "10m", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((node_time_seconds{node_name=~\"$node_name\"} - node_boot_time_seconds{node_name=~\"$node_name\"}) or (time() - node_boot_time_seconds{node_name=~\"$node_name\"}))", + "format": "time_series", + "hide": false, + "interval": "5m", + "intervalFactor": 1, + "legendFormat": "", + "metric": "", + "refId": "A", + "step": 300 + } + ], + "title": "System Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 25, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "(count(node_cpu_seconds_total{node_name=~\"$node_name\",mode=~\"user\"}) or (1-absent(node_cpu_seconds_total{node_name=~\"$node_name\",mode=~\"user\"}))) + sum(rdsosmetrics_General_numVCPUs{node_name=~\"$node_name\"} or up * 0)", + "format": "time_series", + "interval": "5m", + "intervalFactor": 1, + "refId": "A", + "step": 300 + } + ], + "title": "Virtual CPUs", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The system load is a measurement of the computational work the system is performing. Each running process either using or waiting for CPU resources adds 1 to the load.", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#299c46", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "#d44a3a", + "value": 20 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 57, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg_over_time(node_load1{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_load1{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Load Average", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "RAM (Random Access Memory) is the hardware in a computing device where the operating system, application programs and data in current use are kept so they can be quickly reached by the device's processor.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 26, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (node_memory_MemTotal_bytes{node_name=~\"$node_name\"})", + "format": "time_series", + "interval": "5m", + "intervalFactor": 1, + "refId": "A", + "step": 300 + } + ], + "title": "RAM", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Percent of Memory Available\nNote: on Modern Linux Kernels amount of Memory Available for application is not the same as Free+Cached+Buffers", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d44a3a", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "#299c46", + "value": 20 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 55, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (((node_memory_MemAvailable_bytes{node_name=~\"$node_name\"} or (node_memory_MemFree_bytes{node_name=~\"$node_name\"} + node_memory_Buffers_bytes{node_name=~\"$node_name\"} + node_memory_Cached_bytes{node_name=~\"$node_name\"})) / node_memory_MemTotal_bytes{node_name=~\"$node_name\"}) * 100)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Memory Available", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "RAM + SWAP", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 37, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((node_memory_MemTotal_bytes{node_name=~\"$node_name\"} + node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}))", + "format": "time_series", + "interval": "5m", + "intervalFactor": 1, + "refId": "A", + "step": 300 + } + ], + "title": "Virtual Memory", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of active IAP user sessions.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+__name__=\"iap_active_sessions\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Active Sessions" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_active_sessions", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "IAP Active User Sessions", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of active jobs at a given moment. \"Active\" includes running and errored jobs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+__name__=\"iap_active_jobs\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Active Jobs" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_active_jobs", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "IAP Active Jobs", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 1001, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process CPU Usage", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The CPU time is measured in clock ticks or seconds. It is useful to measure CPU time as a percentage of the CPU's capacity, which is called the CPU usage.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "CPU Utilization Details - ${__field.labels.node_name}", + "url": "/graph/d/node-cpu/cpu-utilization-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Max Core Utilization" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "nice" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1F78C1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "softirq" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFFFFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "steal" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8F3BB8", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "system" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "user" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max Core Utilization" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.pointSize", + "value": 4 + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "steal" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name,mode) (clamp_max(((avg by (mode,node_name) ( (clamp_max(rate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\"}[$interval]),1)) or (clamp_max(irate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\"}[5m]),1)) ))*100 or (avg_over_time(node_cpu_average{node_name=~\"$node_name\", mode!=\"total\", mode!=\"idle\"}[$interval]) or avg_over_time(node_cpu_average{node_name=~\"$node_name\", mode!=\"total\", mode!=\"idle\"}[5m]))),100))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{ mode }}", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "clamp_max(max by (node_name) (sum by (cpu,node_name) ( (clamp_max(rate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[$interval]),1)) or (clamp_max(irate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[5m]),1)) )),1)", + "format": "time_series", + "hide": true, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Max Core Utilization", + "refId": "C" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "When a system is running with maximum CPU utilization, the transmitting and receiving threads must all share the available CPU. This will cause data to be queued more frequently to cope with the lack of CPU. CPU Saturation may be measured as the length of a wait queue, or the time spent waiting on the queue.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "CPU Utilization Details - ${__field.labels.node_name}", + "url": "/graph/d/node-cpu/cpu-utilization-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Allocated" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#64B0C8", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "IO Load " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1F78C1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max CPU Core Utilization" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max Core Usage" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Normalized CPU Load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max CPU Core Utilization" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.pointSize", + "value": 4 + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "max", + "value": 1 + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((avg_over_time(node_procs_running{node_name=~\"$node_name\"}[$interval])-1) / scalar(count(node_cpu_seconds_total{mode=\"user\", node_name=~\"$node_name\"})) or (avg_over_time(node_procs_running{node_name=~\"$node_name\"}[5m])-1) / scalar(count(node_cpu_seconds_total{mode=\"user\", node_name=~\"$node_name\"})))", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Normalized CPU Load", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "clamp_max(max by (node_name) (sum by (cpu,node_name) ( (clamp_max(rate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[$interval]),1)) or (clamp_max(irate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[5m]),1)) )),1)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Max CPU Core Utilization", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (aws_rds_cpu_credit_usage_average{node_name=~\"$node_name\"})", + "hide": false, + "interval": "$interval", + "legendFormat": "CPU Credits Usage", + "refId": "C" + } + ], + "title": "CPU Saturation and Max Core Usage", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 1066, + "panels": [], + "title": "IAP Processes Memory Usage", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The percentage of the heap memory in use", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "dashed" + } + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+__name__=\"iap_memory_heap_used_size\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Heap Used" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+__name__=\"iap_total_memory_heap_size\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Total Heap Size" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_memory_heap_used_size", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_total_memory_heap_size", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "IAP Heap used percentage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn Jst Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "JST Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn TemplateBuilder Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Template Builder Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn AGManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "AGManager Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn MOP Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "MOP Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn AutomationStudio Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Automation Studio Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 44 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn core\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Pronghorn Core Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 52 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn NSOManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "NSO Manager Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 52 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn OperationsManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Operations Manager Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 60 + }, + "id": 1067, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn WorkFlowEngine Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Workflow Engine Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 60 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn JsonForms Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "JSON Forms Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 68 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn Search Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Search Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 68 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn ConfigurationManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Configuration Manager Memory", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 76 + }, + "id": 1003, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Memory Usage", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1f78c1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1f78c1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 77 + }, + "id": 29, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Free", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Buffers", + "metric": "", + "refId": "D", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "clamp_min(avg by (node_name) (((avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[5m])) - ((avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[5m]))+ \n(avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[5m])) + \n(avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\"}[5m]))))),0)", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Used", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg(avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\",job=~\"rds.*|node.*\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\",job=~\"rds.*|node.*\"}[5m])) without (job))", + "interval": "$interval", + "legendFormat": "Cache", + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629e51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 77 + }, + "id": 6, + "links": [ + { + "targetBlank": true, + "title": "Memory Overview", + "url": "/graph/d/node-memory/memory-details?$__url_time_range&$__all_variables" + } + ], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[5m])) + \n(avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[5m])))", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "metric": "", + "refId": "C", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (\n(avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[5m])) + ((avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[5m])) or\n((avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[5m]))))\n)", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Available", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (\n((avg_over_time(node_memory_MemTotal_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=\"$node_name\"}[5m])) +\n(avg_over_time(node_memory_SwapTotal_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapTotal_bytes{node_name=\"$node_name\"}[5m]))) -\n((avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[5m])) + ((avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[5m])) or\n((avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[5m])))))\n)", + "interval": "$interval", + "legendFormat": "Used", + "refId": "D" + } + ], + "title": "Virtual Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7eb26d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#f2c96d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 85 + }, + "id": 1063, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[5m])) -\n(avg_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[5m])))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Used", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (max_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Free", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (max_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "Swap Space", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Swap Activity is memory management that involves swapping sections of memory to and from physical storage.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Swap out (-) / Swap in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap Out (Writes)" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 85 + }, + "id": 1065, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_vmstat_pswpin{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpin{node_name=~\"$node_name\"}[5m]) * 4096)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Swap In (Reads)", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_vmstat_pswpout{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpout{node_name=~\"$node_name\"}[5m]) * 4096)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Swap Out (Writes)", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((rate(node_vmstat_pswpin{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpin{node_name=~\"$node_name\"}[5m]) * 4096) + (rate(node_vmstat_pswpout{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpout{node_name=~\"$node_name\"}[5m]) * 4096))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "Swap Activity", + "type": "timeseries" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 93 + }, + "id": 1005, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Disk I/O includes read or write or input/output operations involving a physical disk. It is the speed with which the data transfer takes place between the hard disk drive and RAM.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Page Out (-) / Page In (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Disk Details - ${__field.labels.node_name}", + "url": "/graph/d/node-disk/disk-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Disk Writes (Page Out)" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 78 + }, + "id": 31, + "links": [ + { + "targetBlank": true, + "title": "Disk Performance", + "url": "/graph/d/node-disk/disk-details?$__url_time_range&$__all_variables" + } + ], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[5m]) * 1024 or\n(max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[5m])) * 1024)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Disk Reads (Page In)", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((rate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[5m]) * 1024) or\n(max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[5m])) * 1024)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Disk Writes (Page Out)", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((rate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[5m]) * 1024 ) + (rate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[5m]) * 1024) or\n((max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[5m])) +\n(max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[5m])))* 1024)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "I/O Activity", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Shows average latency for Reads and Writes IO Devices. Higher than typical latency for highly loaded storage indicates saturation (overload) and is frequent cause of performance problems. Higher than normal latency also can indicate internal storage problems.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Disk Details - ${__field.labels.node_name}", + "url": "/graph/d/node-disk/disk-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Read Latency" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1f78c1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Write Latency" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e24d42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg Read Latency (1h)" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "custom.showPoints", + "value": "never" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg Write Latency (1h)" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.lineWidth", + "value": 1 + }, + { + "id": "custom.showPoints", + "value": "never" + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 78 + }, + "id": 61, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_read_time_seconds_total{node_name=~\"$node_name\"}[$interval])) / sum by (node_name) (rate(node_disk_reads_completed_total{node_name=~\"$node_name\"}[$interval]) > 0 )) or (sum by (node_name) (irate(node_disk_read_time_seconds_total{node_name=~\"$node_name\"}[5m])) / \nsum by (node_name) (irate(node_disk_reads_completed_total{node_name=~\"$node_name\"}[5m]) > 0 ))\nor avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[5m])/1000 or\navg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[5m])/1000)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Read Latency", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_write_time_seconds_total{node_name=~\"$node_name\"}[$interval])) / sum by (node_name) (rate(node_disk_writes_completed_total{node_name=~\"$node_name\"}[$interval]) > 0 )) or (sum by (node_name) (irate(node_disk_write_time_seconds_total{node_name=~\"$node_name\"}[5m])) / \nsum by (node_name) (irate(node_disk_writes_completed_total{node_name=~\"$node_name\"}[5m]) > 0 ))\nor (avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[5m])/1000) or\n(avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[$interval]) or avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[5m]))/1000)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Write Latency", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_read_time_seconds_total{node_name=~\"$node_name\"}[1h])) / sum by (node_name) (rate(node_disk_reads_completed_total{node_name=~\"$node_name\"}[1h]) > 0 ))\nor avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[1h])/1000 or avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[1h])/1000 or\navg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[1h])/1000 or avg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[1h])/1000)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Avg Read Latency (1h)", + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_write_time_seconds_total{node_name=~\"$node_name\"}[1h])) / sum by (node_name) (rate(node_disk_writes_completed_total{node_name=~\"$node_name\"}[1h]) > 0 )) \nor (avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[1h])/1000) or\n(avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[1h])/1000))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Avg Write Latency (1h)", + "refId": "D" + } + ], + "title": "Disk IO Latency", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Disk IO Usage", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 94 + }, + "id": 1007, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 79 + }, + "id": 1037, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,max_over_time(namedprocess_namegroup_num_procs{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]))", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "metric": "process_namegroup_num_procs", + "refId": "A", + "step": 10 + } + ], + "title": "Top processes by number of processes instances", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 79 + }, + "id": 1039, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,max_over_time(namedprocess_namegroup_num_threads{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]) )", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "title": "Top processes by number of threads", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process and Thread Counts", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 95 + }, + "id": 1009, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "\nInterrupt is an input signal to the processor indicating an event that needs immediate attention. An interrupt signal alerts the processor and serves as a request for the processor to interrupt the currently executing code, so that the event can be processed in a timely manner.\n\nContext switch is the process of storing the state of a process or thread, so that it can be restored and resume execution at a later point. This allows multiple processes to share a single CPU, and is an essential feature of a multitasking operating system.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "CPU Utilization Details - ${__field.labels.node_name}", + "url": "/graph/d/node-cpu/cpu-utilization-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Context Switches per Virtual CPU" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 80 + }, + "id": 27, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2m", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_context_switches_total{node_name=~\"$node_name\"}[$interval]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Context Switches", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((rate(node_context_switches_total{node_name=~\"$node_name\"}[$interval])) / scalar(count(node_cpu_seconds_total{mode=\"user\", node_name=~\"$node_name\"})))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Context Switches per Virtual CPU", + "refId": "B", + "step": 60 + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (rate(node_intr_total{node_name=~\"$node_name\"}[$interval]) )", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Interrupts", + "refId": "C" + } + ], + "title": "Interrupts and Context Switches", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Context Switches", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 96 + }, + "id": 1011, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Disk Details - ${__field.labels.node_name}", + "url": "/graph/d/node-disk/disk-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Allocated" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 81 + }, + "id": 32, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (max_over_time(node_filefd_maximum{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_filefd_maximum{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Limit", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (max_over_time(node_filefd_allocated{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_filefd_allocated{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Allocated", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + } + ], + "title": "Global File Descriptors Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 88 + }, + "id": 1045, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,max_over_time(namedprocess_namegroup_open_filedesc{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]))", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "title": "Top processes by Open File Descriptors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 88 + }, + "id": 1047, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,\nmax_over_time(namedprocess_namegroup_worst_fd_ratio{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]))*100", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "title": "Top processes by File Descriptor Usage Percent", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process File Descriptors", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 97 + }, + "id": 1015, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Blocked Processes" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e24d42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Created Processes (Forks)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e0752d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Forks" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#f9934e", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Interrupts" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1f78c1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Runnable Processes" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ed0e0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Created Processes (Forks)" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "custom.pointSize", + "value": 4 + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "unit", + "value": "ops" + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 82 + }, + "id": 43, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (clamp_min((avg_over_time(node_procs_running{node_name=~\"$node_name\"}[$interval]) - 1) or (avg_over_time(node_procs_running{node_name=~\"$node_name\"}[5m]) -1),0))", + "interval": "$interval", + "legendFormat": "Runnable Processes", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg_over_time(node_procs_blocked{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_procs_blocked{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Blocked Processes", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (rate(node_forks_total{node_name=~\"$node_name\"}[$interval]) or irate(node_forks_total{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Created Processes (Forks)", + "refId": "C" + } + ], + "title": "Processes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 89 + }, + "id": 1053, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,\nmax_over_time(namedprocess_namegroup_states{node_name=\"$node_name\", groupname=~\"$processes\", state=\"Running\"}[$interval]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "title": "Top running processes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 89 + }, + "id": 1055, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,\nmax_over_time(namedprocess_namegroup_states{node_name=\"$node_name\", groupname=~\"$processes\", state=\"Waiting\"}[$interval]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "title": "Top of processes waiting on IO", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Statuses", + "type": "row" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 98 + }, + "id": 1019, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Uptime", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "displayName", + "value": "Uptime" + }, + { + "id": "unit", + "value": "s" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "instance" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "job" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "groupname" + }, + "properties": [ + { + "id": "displayName", + "value": "Processes" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 99 + }, + "id": 1061, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "time()-(namedprocess_namegroup_oldest_start_time_seconds{node_name=\"$node_name\"}>0)", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Processes by uptime", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Time", + "Value", + "groupname" + ] + } + } + }, + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + } + ], + "refresh": "10s", + "schemaVersion": 39, + "tags": [ + "OS", + "IAP" + ], + "templating": { + "list": [ + { + "allFormat": "glob", + "auto": true, + "auto_count": 200, + "auto_min": "1s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "datasource": "Metrics", + "hide": 0, + "includeAll": false, + "label": "Interval", + "multi": false, + "multiFormat": "glob", + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1s", + "value": "1s" + }, + { + "selected": false, + "text": "5s", + "value": "5s" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "1s,5s,1m,5m,1h,6h,1d", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "allFormat": "glob", + "current": { + "isNone": true, + "selected": false, + "text": "None", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(namedprocess_namegroup_cpu_seconds_total, node_name)", + "hide": 0, + "includeAll": false, + "label": "Node Name", + "multi": false, + "multiFormat": "regex values", + "name": "node_name", + "options": [], + "query": "label_values(namedprocess_namegroup_cpu_seconds_total, node_name)", + "refresh": 2, + "refresh_on_load": false, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_name)", + "hide": 2, + "includeAll": true, + "label": "Service Name", + "multi": true, + "name": "service_name", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_name)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, environment)", + "hide": 2, + "includeAll": true, + "label": "Environment", + "multi": true, + "name": "environment", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, environment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, cluster)", + "hide": 2, + "includeAll": true, + "label": "Cluster", + "multi": true, + "name": "cluster", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, cluster)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, replication_set)", + "hide": 2, + "includeAll": true, + "label": "Replication Set", + "multi": true, + "name": "replication_set", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, replication_set)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(pg_stat_database_tup_fetched{service_name=~\"$service_name\",datname!~\"template.*|postgres\"},datname)", + "hide": 2, + "includeAll": true, + "label": "Database", + "multi": true, + "name": "database", + "options": [], + "query": "label_values(pg_stat_database_tup_fetched{service_name=~\"$service_name\",datname!~\"template.*|postgres\"},datname)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, node_type)", + "hide": 2, + "includeAll": true, + "label": "Type", + "multi": true, + "name": "node_type", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, node_type)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_type)", + "hide": 2, + "includeAll": true, + "label": "Type", + "multi": true, + "name": "service_type", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_type)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(mysql_info_schema_user_statistics_connected_time_seconds_total{service_name=\"$service_name\"},user)", + "hide": 2, + "includeAll": true, + "label": "Username", + "multi": true, + "name": "username", + "options": [], + "query": "label_values(mysql_info_schema_user_statistics_connected_time_seconds_total{service_name=\"$service_name\"},user)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, schema)", + "hide": 2, + "includeAll": true, + "label": "Schema", + "multi": true, + "name": "schema", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, schema)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allFormat": "glob", + "current": { + "isNone": true, + "selected": false, + "text": "None", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(up{node_name=~\"$node_name\"}, node_id)", + "hide": 2, + "includeAll": false, + "label": "Node ID", + "multi": false, + "multiFormat": "regex values", + "name": "node_id", + "options": [], + "query": "label_values(up{node_name=~\"$node_name\"}, node_id)", + "refresh": 2, + "refresh_on_load": false, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(namedprocess_namegroup_num_procs{node_name=~\"$node_name\"},groupname)", + "hide": 0, + "includeAll": true, + "label": "Processes", + "multi": true, + "name": "processes", + "options": [], + "query": "label_values(namedprocess_namegroup_num_procs{node_name=~\"$node_name\"},groupname)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "collapse": false, + "enable": true, + "hidden": false, + "notice": false, + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "status": "Stable", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ], + "type": "timepicker" + }, + "timezone": "browser", + "title": "Itential Automation Platform", + "uid": "fdr5qg92u7v9ca", + "version": 3, + "weekStart": "" +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_iap2.json b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_iap2.json new file mode 100644 index 00000000..dfd4d45b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_iap2.json @@ -0,0 +1,6943 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": false, + "iconColor": "#e0752d", + "limit": 100, + "matchAny": true, + "name": "PMM Annotations", + "showIn": 0, + "tags": [ + "pmm_annotation", + "$node_name" + ], + "type": "tags" + }, + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "#6ed0e0", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "tags": [], + "type": "dashboard" + } + ] + }, + "description": "Provides insights about processes running on Linux host, such as Per Process CPU and Memory Usage, Disk IO, Process status etc \n\nTo be used with Percona Monitoring and Management v2 (PMM2)", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 14239, + "graphTooltip": 1, + "id": 1, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The parameter shows how long a system has been “up” and running without a shut down or restart.", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 300 + }, + { + "color": "rgba(50, 172, 45, 0.97)", + "value": 3600 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 19, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "calculatedInterval": "10m", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((node_time_seconds{node_name=~\"$node_name\"} - node_boot_time_seconds{node_name=~\"$node_name\"}) or (time() - node_boot_time_seconds{node_name=~\"$node_name\"}))", + "format": "time_series", + "hide": false, + "interval": "5m", + "intervalFactor": 1, + "legendFormat": "", + "metric": "", + "refId": "A", + "step": 300 + } + ], + "title": "System Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 25, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "(count(node_cpu_seconds_total{node_name=~\"$node_name\",mode=~\"user\"}) or (1-absent(node_cpu_seconds_total{node_name=~\"$node_name\",mode=~\"user\"}))) + sum(rdsosmetrics_General_numVCPUs{node_name=~\"$node_name\"} or up * 0)", + "format": "time_series", + "interval": "5m", + "intervalFactor": 1, + "refId": "A", + "step": 300 + } + ], + "title": "Virtual CPUs", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The system load is a measurement of the computational work the system is performing. Each running process either using or waiting for CPU resources adds 1 to the load.", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#299c46", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "#d44a3a", + "value": 20 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 57, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg_over_time(node_load1{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_load1{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Load Average", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "RAM (Random Access Memory) is the hardware in a computing device where the operating system, application programs and data in current use are kept so they can be quickly reached by the device's processor.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 26, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (node_memory_MemTotal_bytes{node_name=~\"$node_name\"})", + "format": "time_series", + "interval": "5m", + "intervalFactor": 1, + "refId": "A", + "step": 300 + } + ], + "title": "RAM", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Percent of Memory Available\nNote: on Modern Linux Kernels amount of Memory Available for application is not the same as Free+Cached+Buffers", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d44a3a", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "#299c46", + "value": 20 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 55, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (((node_memory_MemAvailable_bytes{node_name=~\"$node_name\"} or (node_memory_MemFree_bytes{node_name=~\"$node_name\"} + node_memory_Buffers_bytes{node_name=~\"$node_name\"} + node_memory_Cached_bytes{node_name=~\"$node_name\"})) / node_memory_MemTotal_bytes{node_name=~\"$node_name\"}) * 100)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Memory Available", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "RAM + SWAP", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 37, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((node_memory_MemTotal_bytes{node_name=~\"$node_name\"} + node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}))", + "format": "time_series", + "interval": "5m", + "intervalFactor": 1, + "refId": "A", + "step": 300 + } + ], + "title": "Virtual Memory", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of active IAP user sessions.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_active_sessions", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "IAP Active User Sessions", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of active jobs at a given moment. \"Active\" includes running and errored jobs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_active_jobs", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "IAP Active Jobs", + "type": "timeseries" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 1001, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The CPU time is measured in clock ticks or seconds. It is useful to measure CPU time as a percentage of the CPU's capacity, which is called the CPU usage.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "CPU Utilization Details - ${__field.labels.node_name}", + "url": "/graph/d/node-cpu/cpu-utilization-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Max Core Utilization" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "nice" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1F78C1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "softirq" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFFFFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "steal" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8F3BB8", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "system" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "user" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max Core Utilization" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.pointSize", + "value": 4 + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "steal" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name,mode) (clamp_max(((avg by (mode,node_name) ( (clamp_max(rate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\"}[$interval]),1)) or (clamp_max(irate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\"}[5m]),1)) ))*100 or (avg_over_time(node_cpu_average{node_name=~\"$node_name\", mode!=\"total\", mode!=\"idle\"}[$interval]) or avg_over_time(node_cpu_average{node_name=~\"$node_name\", mode!=\"total\", mode!=\"idle\"}[5m]))),100))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{ mode }}", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "clamp_max(max by (node_name) (sum by (cpu,node_name) ( (clamp_max(rate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[$interval]),1)) or (clamp_max(irate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[5m]),1)) )),1)", + "format": "time_series", + "hide": true, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Max Core Utilization", + "refId": "C" + } + ], + "title": "CPU Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "When a system is running with maximum CPU utilization, the transmitting and receiving threads must all share the available CPU. This will cause data to be queued more frequently to cope with the lack of CPU. CPU Saturation may be measured as the length of a wait queue, or the time spent waiting on the queue.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "CPU Utilization Details - ${__field.labels.node_name}", + "url": "/graph/d/node-cpu/cpu-utilization-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Allocated" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "CPU Load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#64B0C8", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "IO Load " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1F78C1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max CPU Core Utilization" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max Core Usage" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Normalized CPU Load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Max CPU Core Utilization" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.pointSize", + "value": 4 + }, + { + "id": "custom.showPoints", + "value": "always" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "max", + "value": 1 + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((avg_over_time(node_procs_running{node_name=~\"$node_name\"}[$interval])-1) / scalar(count(node_cpu_seconds_total{mode=\"user\", node_name=~\"$node_name\"})) or (avg_over_time(node_procs_running{node_name=~\"$node_name\"}[5m])-1) / scalar(count(node_cpu_seconds_total{mode=\"user\", node_name=~\"$node_name\"})))", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Normalized CPU Load", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "clamp_max(max by (node_name) (sum by (cpu,node_name) ( (clamp_max(rate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[$interval]),1)) or (clamp_max(irate(node_cpu_seconds_total{node_name=~\"$node_name\",mode!=\"idle\",mode!=\"iowait\"}[5m]),1)) )),1)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Max CPU Core Utilization", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (aws_rds_cpu_credit_usage_average{node_name=~\"$node_name\"})", + "hide": false, + "interval": "$interval", + "legendFormat": "CPU Credits Usage", + "refId": "C" + } + ], + "title": "CPU Saturation and Max Core Usage", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process CPU Usage", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 1066, + "panels": [], + "title": "IAP Processes Memory Usage", + "type": "row" + }, + { + "description": "The percentage of the heap memory in use", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_memory_heap_used_size", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "iap_total_memory_heap_size", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "IAP Heap used percentage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn core\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Pronghorn Core Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 1067, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn WorkFlowEngine Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Workflow Engine Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn Jst Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "JST Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn TemplateBuilder Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Template Builder Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn OperationsManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Operations Manager Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn AutomationStudio Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Automation Studio Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn AGManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "AGManager Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 44 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn MOP Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "MOP Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 52 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn NSOManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "NSO Manager Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 52 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn JsonForms Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "JSON Forms Memory", + "type": "timeseries" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 1003, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1f78c1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#1f78c1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#A352CC", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 61 + }, + "id": 29, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Free", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Buffers", + "metric": "", + "refId": "D", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "clamp_min(avg by (node_name) (((avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[5m])) - ((avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=~\"$node_name\"}[5m]))+ \n(avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=~\"$node_name\"}[5m])) + \n(avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\"}[5m]))))),0)", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Used", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg(avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\",job=~\"rds.*|node.*\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=~\"$node_name\",job=~\"rds.*|node.*\"}[5m])) without (job))", + "interval": "$interval", + "legendFormat": "Cache", + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629e51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#eab839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 61 + }, + "id": 6, + "links": [ + { + "targetBlank": true, + "title": "Memory Overview", + "url": "/graph/d/node-memory/memory-details?$__url_time_range&$__all_variables" + } + ], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=~\"$node_name\"}[5m])) + \n(avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[5m])))", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "metric": "", + "refId": "C", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (\n(avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[5m])) + ((avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[5m])) or\n((avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[5m]))))\n)", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Available", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (\n((avg_over_time(node_memory_MemTotal_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemTotal_bytes{node_name=\"$node_name\"}[5m])) +\n(avg_over_time(node_memory_SwapTotal_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapTotal_bytes{node_name=\"$node_name\"}[5m]))) -\n((avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapFree_bytes{node_name=\"$node_name\"}[5m])) + ((avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemAvailable_bytes{node_name=\"$node_name\"}[5m])) or\n((avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_MemFree_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Buffers_bytes{node_name=\"$node_name\"}[5m]))+\n(avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[$interval]) or avg_over_time(node_memory_Cached_bytes{node_name=\"$node_name\"}[5m])))))\n)", + "interval": "$interval", + "legendFormat": "Used", + "refId": "D" + } + ], + "title": "Virtual Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7eb26d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#f2c96d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 69 + }, + "id": 1063, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[5m])) -\n(avg_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[5m])))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Used", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (max_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_memory_SwapFree_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Free", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (max_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_memory_SwapTotal_bytes{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "Swap Space", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Swap Activity is memory management that involves swapping sections of memory to and from physical storage.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Swap out (-) / Swap in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "links": [ + { + "targetBlank": true, + "title": "Memory Details - ${__field.labels.node_name}", + "url": "/graph/d/node-memory/memory-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total " + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap Out (Writes)" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 69 + }, + "id": 1065, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_vmstat_pswpin{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpin{node_name=~\"$node_name\"}[5m]) * 4096)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Swap In (Reads)", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_vmstat_pswpout{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpout{node_name=~\"$node_name\"}[5m]) * 4096)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Swap Out (Writes)", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((rate(node_vmstat_pswpin{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpin{node_name=~\"$node_name\"}[5m]) * 4096) + (rate(node_vmstat_pswpout{node_name=~\"$node_name\"}[$interval]) * 4096 or irate(node_vmstat_pswpout{node_name=~\"$node_name\"}[5m]) * 4096))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "title": "Swap Activity", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Memory Usage", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 1005, + "panels": [ + { + "aliasColors": { + "Total": "#bf1b00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "description": "Disk I/O includes read or write or input/output operations involving a physical disk. It is the speed with which the data transfer takes place between the hard disk drive and RAM.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [ + { + "targetBlank": true, + "title": "Disk Details - ${__field.labels.node_name}", + "url": "/graph/d/node-disk/disk-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ] + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 31, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + { + "targetBlank": true, + "title": "Disk Performance", + "url": "/graph/d/node-disk/disk-details?$__url_time_range&$__all_variables" + } + ], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Disk Writes (Page Out)", + "transform": "negative-Y" + }, + { + "alias": "Total", + "legend": false, + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[5m]) * 1024 or\n(max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[5m])) * 1024)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Disk Reads (Page In)", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) ((rate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[5m]) * 1024) or\n(max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[5m])) * 1024)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Disk Writes (Page Out)", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((rate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgin{node_name=~\"$node_name\"}[5m]) * 1024 ) + (rate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[$interval]) * 1024 or irate(node_vmstat_pgpgout{node_name=~\"$node_name\"}[5m]) * 1024) or\n((max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_writeKbPS{node_name=~\"$node_name\"}[5m])) +\n(max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[$interval]) or max_over_time(rdsosmetrics_diskIO_readKbPS{node_name=~\"$node_name\"}[5m])))* 1024)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Total", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "I/O Activity", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 5, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "Bps", + "label": "Page Out (-) / Page In (+)", + "logBase": 1, + "show": true + }, + { + "format": "bytes", + "logBase": 1, + "min": 0, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": { + "Read Latency": "#1f78c1", + "Write Latency": "#e24d42" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "description": "Shows average latency for Reads and Writes IO Devices. Higher than typical latency for highly loaded storage indicates saturation (overload) and is frequent cause of performance problems. Higher than normal latency also can indicate internal storage problems.", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [ + { + "targetBlank": true, + "title": "Disk Details - ${__field.labels.node_name}", + "url": "/graph/d/node-disk/disk-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ] + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 61, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Avg Read Latency (1h)", + "fill": 0, + "lines": true, + "linewidth": 1, + "points": false + }, + { + "alias": "Avg Write Latency (1h)", + "fill": 0, + "lines": true, + "linewidth": 1, + "points": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_read_time_seconds_total{node_name=~\"$node_name\"}[$interval])) / sum by (node_name) (rate(node_disk_reads_completed_total{node_name=~\"$node_name\"}[$interval]) > 0 )) or (sum by (node_name) (irate(node_disk_read_time_seconds_total{node_name=~\"$node_name\"}[5m])) / \nsum by (node_name) (irate(node_disk_reads_completed_total{node_name=~\"$node_name\"}[5m]) > 0 ))\nor avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[5m])/1000 or\navg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[5m])/1000)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Read Latency", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_write_time_seconds_total{node_name=~\"$node_name\"}[$interval])) / sum by (node_name) (rate(node_disk_writes_completed_total{node_name=~\"$node_name\"}[$interval]) > 0 )) or (sum by (node_name) (irate(node_disk_write_time_seconds_total{node_name=~\"$node_name\"}[5m])) / \nsum by (node_name) (irate(node_disk_writes_completed_total{node_name=~\"$node_name\"}[5m]) > 0 ))\nor (avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[5m])/1000) or\n(avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[$interval]) or avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[5m]))/1000)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Write Latency", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_read_time_seconds_total{node_name=~\"$node_name\"}[1h])) / sum by (node_name) (rate(node_disk_reads_completed_total{node_name=~\"$node_name\"}[1h]) > 0 ))\nor avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[1h])/1000 or avg_over_time(aws_rds_read_latency_average{node_name=~\"$node_name\"}[1h])/1000 or\navg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[1h])/1000 or avg_over_time(rdsosmetrics_diskIO_readLatency{node_name=~\"$node_name\"}[1h])/1000)", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Avg Read Latency (1h)", + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((sum by (node_name) (rate(node_disk_write_time_seconds_total{node_name=~\"$node_name\"}[1h])) / sum by (node_name) (rate(node_disk_writes_completed_total{node_name=~\"$node_name\"}[1h]) > 0 )) \nor (avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(aws_rds_write_latency_average{node_name=~\"$node_name\"}[1h])/1000) or\n(avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[$interval])/1000 or avg_over_time(rdsosmetrics_diskIO_writeLatency{node_name=~\"$node_name\"}[1h])/1000))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Avg Write Latency (1h)", + "refId": "D" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Disk IO Latency", + "tooltip": { + "shared": true, + "sort": 5, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "s", + "logBase": 2, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Disk IO Usage", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 62 + }, + "id": 1007, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 1037, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,max_over_time(namedprocess_namegroup_num_procs{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]))", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "metric": "process_namegroup_num_procs", + "refId": "A", + "step": 10 + } + ], + "title": "Top processes by number of processes instances", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "points", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 63 + }, + "id": 1039, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.3.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,max_over_time(namedprocess_namegroup_num_threads{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]) )", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "title": "Top processes by number of threads", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process and Thread Counts", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 63 + }, + "id": 1009, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "description": "\nInterrupt is an input signal to the processor indicating an event that needs immediate attention. An interrupt signal alerts the processor and serves as a request for the processor to interrupt the currently executing code, so that the event can be processed in a timely manner.\n\nContext switch is the process of storing the state of a process or thread, so that it can be restored and resume execution at a later point. This allows multiple processes to share a single CPU, and is an essential feature of a multitasking operating system.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [ + { + "targetBlank": true, + "title": "CPU Utilization Details - ${__field.labels.node_name}", + "url": "/graph/d/node-cpu/cpu-utilization-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ] + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 26 + }, + "hiddenSeries": false, + "id": 27, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Context Switches per Virtual CPU", + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "calculatedInterval": "2m", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (rate(node_context_switches_total{node_name=~\"$node_name\"}[$interval]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Context Switches", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) ((rate(node_context_switches_total{node_name=~\"$node_name\"}[$interval])) / scalar(count(node_cpu_seconds_total{mode=\"user\", node_name=~\"$node_name\"})))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Context Switches per Virtual CPU", + "refId": "B", + "step": 60 + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (rate(node_intr_total{node_name=~\"$node_name\"}[$interval]) )", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Interrupts", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Interrupts and Context Switches", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 5, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "short", + "label": "", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": 0, + "show": false + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Context Switches", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 64 + }, + "id": 1011, + "panels": [ + { + "aliasColors": { + "Allocated": "#E0752D", + "Limit": "#bf1b00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [ + { + "targetBlank": true, + "title": "Disk Details - ${__field.labels.node_name}", + "url": "/graph/d/node-disk/disk-details?var-node_name=${__field.labels.node_name}&$__url_time_range" + } + ] + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Limit", + "fill": 0 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (max_over_time(node_filefd_maximum{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_filefd_maximum{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Limit", + "metric": "", + "refId": "B", + "step": 300, + "target": "" + }, + { + "calculatedInterval": "2s", + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "datasourceErrors": {}, + "errors": {}, + "expr": "avg by (node_name) (max_over_time(node_filefd_allocated{node_name=~\"$node_name\"}[$interval]) or max_over_time(node_filefd_allocated{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Allocated", + "metric": "", + "refId": "A", + "step": 300, + "target": "" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Global File Descriptors Usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 5, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "short", + "label": "", + "logBase": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": 0, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 34 + }, + "hiddenSeries": false, + "id": 1045, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,max_over_time(namedprocess_namegroup_open_filedesc{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]))", + "format": "time_series", + "hide": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Top processes by Open File Descriptors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 34 + }, + "hiddenSeries": false, + "id": 1047, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "max", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,\nmax_over_time(namedprocess_namegroup_worst_fd_ratio{groupname=~\"$processes\",node_name=\"$node_name\"}[$interval]))*100", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Top processes by File Descriptor Usage Percent", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process File Descriptors", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 65 + }, + "id": 1015, + "panels": [ + { + "aliasColors": { + "Blocked Processes": "#e24d42", + "Created Processes (Forks)": "#e0752d", + "Forks": "#f9934e", + "Interrupts": "#1f78c1", + "Runnable Processes": "#6ed0e0" + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 29 + }, + "hiddenSeries": false, + "id": 43, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Created Processes (Forks)", + "bars": false, + "pointradius": 1, + "points": true, + "stack": false, + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (clamp_min((avg_over_time(node_procs_running{node_name=~\"$node_name\"}[$interval]) - 1) or (avg_over_time(node_procs_running{node_name=~\"$node_name\"}[5m]) -1),0))", + "interval": "$interval", + "legendFormat": "Runnable Processes", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (avg_over_time(node_procs_blocked{node_name=~\"$node_name\"}[$interval]) or avg_over_time(node_procs_blocked{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Blocked Processes", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "avg by (node_name) (rate(node_forks_total{node_name=~\"$node_name\"}[$interval]) or irate(node_forks_total{node_name=~\"$node_name\"}[5m]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "Created Processes (Forks)", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Processes", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 5, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "short", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "decimals": 2, + "format": "ops", + "logBase": 1, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "description": "", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 36 + }, + "hiddenSeries": false, + "id": 1053, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,\nmax_over_time(namedprocess_namegroup_states{node_name=\"$node_name\", groupname=~\"$processes\", state=\"Running\"}[$interval]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Top running processes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "decimals": 2, + "description": "", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 36 + }, + "hiddenSeries": false, + "id": 1055, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.3.7", + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "topk(5,\nmax_over_time(namedprocess_namegroup_states{node_name=\"$node_name\", groupname=~\"$processes\", state=\"Waiting\"}[$interval]))", + "format": "time_series", + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{groupname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Top of processes waiting on IO", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": false + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Statuses", + "type": "row" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 66 + }, + "id": 1019, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "refId": "A" + } + ], + "title": "Process Uptime", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "displayName", + "value": "Uptime" + }, + { + "id": "unit", + "value": "s" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "instance" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "job" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.hidden", + "value": true + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "groupname" + }, + "properties": [ + { + "id": "displayName", + "value": "Processes" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 67 + }, + "id": 1061, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "time()-(namedprocess_namegroup_oldest_start_time_seconds{node_name=\"$node_name\"}>0)", + "format": "table", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Processes by uptime", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Time", + "Value", + "groupname" + ] + } + } + }, + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 77 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn Search Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Search Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalResident\".+$/" + }, + "properties": [ + { + "id": "mappings", + "value": [] + }, + { + "id": "displayName", + "value": "Proportional Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"proportionalSwapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Proportional Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"resident\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Resident" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"swapped\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Swapped" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^.+memtype=\"virtual\".+$/" + }, + "properties": [ + { + "id": "displayName", + "value": "Virtual" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 77 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "namedprocess_namegroup_memory_bytes{groupname=\"Pronghorn ConfigurationManager Application\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "OS", + "IAP" + ], + "templating": { + "list": [ + { + "allFormat": "glob", + "auto": true, + "auto_count": 200, + "auto_min": "1s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "datasource": "Metrics", + "hide": 0, + "includeAll": false, + "label": "Interval", + "multi": false, + "multiFormat": "glob", + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1s", + "value": "1s" + }, + { + "selected": false, + "text": "5s", + "value": "5s" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "1s,5s,1m,5m,1h,6h,1d", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "allFormat": "glob", + "current": { + "isNone": true, + "selected": false, + "text": "None", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(namedprocess_namegroup_cpu_seconds_total, node_name)", + "hide": 0, + "includeAll": false, + "label": "Node Name", + "multi": false, + "multiFormat": "regex values", + "name": "node_name", + "options": [], + "query": "label_values(namedprocess_namegroup_cpu_seconds_total, node_name)", + "refresh": 2, + "refresh_on_load": false, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_name)", + "hide": 2, + "includeAll": true, + "label": "Service Name", + "multi": true, + "name": "service_name", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_name)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, environment)", + "hide": 2, + "includeAll": true, + "label": "Environment", + "multi": true, + "name": "environment", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, environment)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, cluster)", + "hide": 2, + "includeAll": true, + "label": "Cluster", + "multi": true, + "name": "cluster", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, cluster)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, replication_set)", + "hide": 2, + "includeAll": true, + "label": "Replication Set", + "multi": true, + "name": "replication_set", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, replication_set)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(pg_stat_database_tup_fetched{service_name=~\"$service_name\",datname!~\"template.*|postgres\"},datname)", + "hide": 2, + "includeAll": true, + "label": "Database", + "multi": true, + "name": "database", + "options": [], + "query": "label_values(pg_stat_database_tup_fetched{service_name=~\"$service_name\",datname!~\"template.*|postgres\"},datname)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, node_type)", + "hide": 2, + "includeAll": true, + "label": "Type", + "multi": true, + "name": "node_type", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, node_type)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_type)", + "hide": 2, + "includeAll": true, + "label": "Type", + "multi": true, + "name": "service_type", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, service_type)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(mysql_info_schema_user_statistics_connected_time_seconds_total{service_name=\"$service_name\"},user)", + "hide": 2, + "includeAll": true, + "label": "Username", + "multi": true, + "name": "username", + "options": [], + "query": "label_values(mysql_info_schema_user_statistics_connected_time_seconds_total{service_name=\"$service_name\"},user)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, schema)", + "hide": 2, + "includeAll": true, + "label": "Schema", + "multi": true, + "name": "schema", + "options": [], + "query": "label_values({__name__=~\"pg_up|mysql_up|mongodb_up|proxysql_mysql_status_active_transactions\"}, schema)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allFormat": "glob", + "current": { + "isNone": true, + "selected": false, + "text": "None", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(up{node_name=~\"$node_name\"}, node_id)", + "hide": 2, + "includeAll": false, + "label": "Node ID", + "multi": false, + "multiFormat": "regex values", + "name": "node_id", + "options": [], + "query": "label_values(up{node_name=~\"$node_name\"}, node_id)", + "refresh": 2, + "refresh_on_load": false, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(namedprocess_namegroup_num_procs{node_name=~\"$node_name\"},groupname)", + "hide": 0, + "includeAll": true, + "label": "Processes", + "multi": true, + "name": "processes", + "options": [], + "query": "label_values(namedprocess_namegroup_num_procs{node_name=~\"$node_name\"},groupname)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "collapse": false, + "enable": true, + "hidden": false, + "notice": false, + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "status": "Stable", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ], + "type": "timepicker" + }, + "timezone": "browser", + "title": "Itential Automation Platform", + "uid": "fdr5qg92u7v9ca", + "version": 12, + "weekStart": "" +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_mongo.json b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_mongo.json new file mode 100644 index 00000000..13cf8631 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_mongo.json @@ -0,0 +1,2929 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS.INTERNAL-ODMONT.COM", + "label": "prometheus.internal-odmont.com", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": [], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.5.3" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "iteration": 1655913813644, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 49, + "panels": [], + "title": "Cluster Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "dark-red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + }, + "unit": "bool_yes_no" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_up{env=~\"$env\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "MongoService UP", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Mongodb Service Uptime in hours", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#65882d", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 3, + "y": 1 + }, + "id": 18, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 15, + "valueSize": 15 + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_members_uptime{env=~\"$env\", member_state=\"PRIMARY\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Mongodb Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of incoming connections from clients to the database server. This number includes the current shell session. Consider the value of connections.available to add more context to this datum.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 20, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 15, + "valueSize": 15 + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_ss_connections{env=\"$env\", conn_type=\"current\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Current Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Count of all incoming connections created to the server. This number includes connections that have since closed.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 22, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 15, + "valueSize": 15 + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_ss_connections{env=\"$env\", conn_type=\"totalCreated\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Total Created Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of unused incoming connections available. Consider this value in combination with the value of connections.current to understand the connection load on the database, and the UNIX ulimit Settings document for more information about system thresholds on available connections.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 21, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 15, + "valueSize": 15 + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_ss_connections{env=\"$env\", conn_type=\"available\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Available Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The number of active client connections to the server. Active client connections refers to client connections that currently have operations in progress.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 23, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 15, + "valueSize": 15 + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_ss_connections{env=\"$env\", conn_type=\"available\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Active Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 25, + "options": { + "content": "A document that reports on database operations by type since the mongod instance last started. These numbers will grow over time until next restart. Analyze these values over time to track database utilization.", + "mode": "markdown" + }, + "pluginVersion": "8.5.3", + "title": "opcounters", + "type": "text" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The total number of insert operations received since the mongod instance last started.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 11 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(mongodb_ss_opcounters{env=\"$env\", legacy_op_type=\"insert\"}[$__interval])", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Received Insert Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The total number of update operations received since the mongod instance last started.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 11 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(mongodb_ss_opcounters{env=\"$env\", legacy_op_type=\"update\"}[$__interval])", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Received Update Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The total number of commands issued to the database since the mongod instance last started.\n\nopcounters.command counts all commands except the write commands: insert, update, and delete.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 11 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(mongodb_ss_opcounters{env=\"$env\", legacy_op_type=\"command\"}[$__interval])", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Received Command Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The total number of queries received since the mongod instance last started.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 6, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 19 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(mongodb_ss_opcounters{env=\"$env\", legacy_op_type=\"query\"}[$__interval])", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Received Queries", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The total number of delete operations since the mongod instance last started.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 19 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(mongodb_ss_opcounters{env=\"$env\", legacy_op_type=\"delete\"}[$__interval])", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Received Delete Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The total number of getMore operations since the mongod instance last started. This counter can be high even if the query count is low. Secondary nodes send getMore operations as part of the replication process.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 19 + }, + "id": 31, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(mongodb_ss_opcounters{env=\"$env\", legacy_op_type=\"getmore\"}[$__interval])", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Received getMore Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Number of collections in the database.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 27 + }, + "id": 33, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "mergeValues": true, + "rowHeight": 0.93, + "showValue": "always", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_dbstats_collections{env=\"$env\", instance=\"$instance\"}", + "legendFormat": "{{database}}", + "range": true, + "refId": "A" + } + ], + "title": "Total Collections/DB", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Total number of indexes across all collections in the database.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 27 + }, + "id": 34, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "mergeValues": true, + "rowHeight": 0.93, + "showValue": "always", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_dbstats_indexes{env=\"$env\", instance=\"$instance\"}", + "legendFormat": "{{database}}", + "range": true, + "refId": "A" + } + ], + "title": "Total Indexs/DB", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Number of views in the database.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 60, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 27 + }, + "id": 35, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "mergeValues": true, + "rowHeight": 0.93, + "showValue": "always", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_dbstats_views{env=\"$env\", instance=\"$instance\"}", + "legendFormat": "{{database}}", + "range": true, + "refId": "A" + } + ], + "title": "Total Views/DB", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Sum of the space allocated to all collections in the database for document storage, including free space.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 37, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_dbstats_storageSize{env=\"$env\", instance=\"$instance\"}", + "legendFormat": "{{database}} ", + "range": true, + "refId": "A" + } + ], + "title": "Allocated Storage to Collections in DB", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Sum of the space allocated to all indexes in the database, including free index space.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 38, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_dbstats_indexSize{env=\"$env\", instance=\"$instance\"}", + "legendFormat": "{{database}}", + "range": true, + "refId": "A" + } + ], + "title": "Allocated Storage to Indexs in DB", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 14, + "panels": [], + "title": "Replication Set Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 7, + "x": 0, + "y": 44 + }, + "id": 42, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "valueSize": 30 + }, + "textMode": "name" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_rs_members_id{env=\"$env\", member_state=\"PRIMARY\", instance=\"$instance\"}", + "legendFormat": "{{member_state}} - {{instance}}", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "This metric can show a correlation with the replication lag value.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 7, + "y": 44 + }, + "id": 47, + "options": { + "legend": { + "calcs": [ + "last" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_rs_members_pingMs{env=\"$env\", instance=\"$instance\"}", + "legendFormat": "{{member_state}} - {{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Max Member Ping Time - $instance", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "The oplog (operations log) is a special capped collection that keeps a rolling record of all operations that modify the data stored in your databases.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 14, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-yellow", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "172.31.11.244:9216" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 9, + "x": 15, + "y": 44 + }, + "id": 40, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_oplog_stats_size{env=\"$env\", instance=\"$instance\", rs_nm=\"$rs\"}", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "OPLog Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 48 + }, + "id": 43, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "name" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_rs_members_id{env=\"$env\", member_state=\"SECONDARY\", instance=\"$instance\"}", + "legendFormat": "{{member_state}} - {{instance}}", + "range": true, + "refId": "A" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "MongoDB replication lag occurs when the secondary node cannot replicate data fast enough to keep up with the rate that data is being written to the primary node. It could be caused by something as simple as network latency, packet loss within your network, or a routing issue.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 22, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "{cl_id=\"62961a7e162f952813b8d646\", env=\"DEV\", instance=\"172.31.11.244:9216\", job=\"mongodb_exporter\", member_idx=\"172.31.11.244:27017\", member_state=\"SECONDARY\", rs_nm=\"repl\", rs_state=\"2\"}" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 20, + "x": 0, + "y": 53 + }, + "id": 53, + "options": { + "legend": { + "calcs": [ + "last", + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_rs_members_optimeDate{env=\"$env\", instance=\"$instance\", rs_nm=\"$rs\"} - mongodb_rs_members_optimeDate{env=\"$env\", instance=\"$instance\", rs_nm=\"$rs\"}", + "legendFormat": "{{member_state}}", + "range": true, + "refId": "A" + } + ], + "title": "Replication Lag", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "This shows the time since the last election.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-green", + "value": null + } + ] + }, + "unit": "dateTimeAsLocal" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 20, + "y": 53 + }, + "id": 45, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "mongodb_electionCandidateMetrics_lastElectionDate{env=\"$env\"}", + "refId": "A" + } + ], + "title": "ReplSet Last Election", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 62 + }, + "id": 2, + "panels": [], + "title": "Cursor Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Cursor is a pointer, and using this pointer we can access the document. cursor.timeOut property was updated incrementally, and connections that died without closing the cursor. The consequence is that it will remain open on the server and consume memory unless it is reaped by the default MongoDB setting.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 9, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 55, + "options": { + "legend": { + "calcs": [ + "last", + "mean", + "max" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_ss_metrics_cursor_timedOut{env=\"$env\", rs_nm=\"$rs\"}", + "legendFormat": "{{instance}} - {{rs_nm}}", + "range": true, + "refId": "A" + } + ], + "title": "Cursor Timeout", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "description": "Number of cursors currently opened by MongoDB for clients", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 63 + }, + "id": 56, + "options": { + "legend": { + "calcs": [ + "last", + "mean", + "max" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "mongodb_ss_metrics_cursor_totalOpened{env=\"$env\", rs_nm=\"$rs\"}", + "legendFormat": "{{instance}} - {{rs_nm}}", + "range": true, + "refId": "A" + } + ], + "title": "Cursor totalOpened", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 71 + }, + "id": 51, + "panels": [], + "title": "Server Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 72 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "avg(rate(node_cpu_seconds_total{env=\"$env\", mode=\"system\"}[$interval])) by (instance) *100", + "hide": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU% Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 72 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "mean", + "sum" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "node_memory_MemTotal_bytes{env=\"$env\", job=\"$nodeJob\"} - node_memory_MemFree_bytes{env=\"$env\", job=\"$nodeJob\"} - (node_memory_Cached_bytes{env=\"$env\", job=\"$nodeJob\"} + node_memory_Buffers_bytes{env=\"$env\", job=\"$nodeJob\"})", + "hide": false, + "legendFormat": "{{instance}} - RAM Used", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "node_memory_Cached_bytes{env=\"$env\", job=\"$nodeJob\"} + node_memory_Buffers_bytes{env=\"$env\", job=\"$nodeJob\"} + node_memory_SReclaimable_bytes{env=\"$env\", job=\"$nodeJob\"}", + "hide": false, + "legendFormat": "{{instance}} - Buffer Mem", + "range": true, + "refId": "B" + } + ], + "title": "Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 80 + }, + "id": 12, + "options": { + "legend": { + "calcs": [ + "mean", + "min", + "max" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "irate(node_network_receive_bytes_total{env=\"$env\", job=\"$nodeJob\"}[5m])", + "legendFormat": "{{instance}}-{{device}} - Receives", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "irate(node_network_transmit_bytes_total{env=\"$env\", job=\"$nodeJob\"}[5m])", + "hide": false, + "legendFormat": "{{instance}}-{{device}} - Transmit", + "range": true, + "refId": "B" + } + ], + "title": "Network I/O", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 21, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 80 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean" + ], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(node_disk_read_bytes_total{env=\"$env\", job=\"$nodeJob\",device=~\"$device\"}[$interval])", + "legendFormat": "{{instance}}-{{device}} - Reads", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "rate(node_disk_written_bytes_total{env=\"$env\", job=\"$nodeJob\",device=~\"$device\"}[$interval])", + "hide": false, + "legendFormat": "{{instance}}-{{device}} - Write", + "range": true, + "refId": "B" + } + ], + "title": "Disk I/O", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 88 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "editorMode": "code", + "expr": "100 - ((node_filesystem_avail_bytes{env=\"$env\", job=\"$nodeJob\",device!~'rootfs'} * 100) / node_filesystem_size_bytes{env=\"$env\", job=\"$nodeJob\",device!~'rootfs'})", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Disk Space Utilization", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 36, + "style": "dark", + "tags": ["MongoDB"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "prometheus.internal-odmont.com", + "value": "prometheus.internal-odmont.com" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(mongodb_up, env)", + "hide": 0, + "includeAll": false, + "label": "env", + "multi": false, + "name": "env", + "options": [], + "query": { + "query": "label_values(mongodb_up, env)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(mongodb_up{env=\"$env\"}, job)", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "mongoJob", + "options": [], + "query": { + "query": "label_values(mongodb_up{env=\"$env\"}, job)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(node_uname_info, nodename)", + "hide": 2, + "includeAll": false, + "label": "Hostname", + "multi": false, + "name": "hostname", + "options": [], + "query": { + "query": "label_values(node_uname_info, nodename)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(mongodb_up{env=\"$env\"}, instance)", + "hide": 0, + "includeAll": false, + "label": "Instance", + "multi": false, + "name": "instance", + "options": [], + "query": { + "query": "label_values(mongodb_up{env=\"$env\"}, instance)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "30s", + "value": "30s" + }, + "hide": 2, + "name": "interval", + "options": [ + { + "selected": true, + "text": "30s", + "value": "30s" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "2m", + "value": "2m" + }, + { + "selected": false, + "text": "3m", + "value": "3m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + } + ], + "query": "30s,1m,2m,3m,5m,10m,30m", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(node_uname_info, job)", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "nodeJob", + "options": [], + "query": { + "query": "label_values(node_uname_info, job)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(node_filesystem_size_bytes, mountpoint)", + "hide": 0, + "includeAll": false, + "label": "Mountpoints", + "multi": false, + "name": "mountpoint", + "options": [], + "query": { + "query": "label_values(node_filesystem_size_bytes, mountpoint)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(node_disk_reads_completed_total, device)", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "device", + "options": [], + "query": { + "query": "label_values(node_disk_reads_completed_total, device)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(mongodb_rs_ok{env=\"$env\"}, rs_nm)", + "hide": 0, + "includeAll": false, + "label": "ReplicaSet", + "multi": false, + "name": "rs", + "options": [], + "query": { + "query": "label_values(mongodb_rs_ok{env=\"$env\"}, rs_nm)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "MongoDB", + "uid": "SsEeTs97k", + "version": 37, + "weekStart": "", + "gnetId": 16490, + "description": "MongoDB Dashboard with Cluster, Replication, cursor, and server metrics using Mongodb Exporter by percona" +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_node.json b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_node.json new file mode 100644 index 00000000..fc4a51c5 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_node.json @@ -0,0 +1,23899 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.4.3" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:1058", + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 1860, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "GitHub", + "type": "link", + "url": "https://github.com/rfmoz/grafana-dashboards" + }, + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "Grafana", + "type": "link", + "url": "https://grafana.com/grafana/dashboards/1860" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 261, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Quick CPU / Mem / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Resource pressure via PSI", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "links": [], + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "dark-yellow", + "value": 70 + }, + { + "color": "dark-red", + "value": 90 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 323, + "links": [], + "options": { + "displayMode": "basic", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": {} + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "irate(node_pressure_cpu_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "legendFormat": "CPU", + "range": false, + "refId": "CPU some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "irate(node_pressure_memory_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "Mem", + "range": false, + "refId": "Memory some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "irate(node_pressure_io_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "I/O", + "range": false, + "refId": "I/O some", + "step": 240 + } + ], + "title": "Pressure", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Busy state of all CPU cores together", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 20, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "100 * (1 - avg(rate(node_cpu_seconds_total{mode=\"idle\", instance=\"$node\"}[$__rate_interval])))", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "", + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "CPU Busy", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "System load over all CPU cores together", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 85 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 155, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "scalar(node_load1{instance=\"$node\",job=\"$job\"}) * 100 / count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu))", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Sys Load", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Non available RAM memory", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 9, + "y": 1 + }, + "hideTimeOverride": false, + "id": 16, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "((node_memory_MemTotal_bytes{instance=\"$node\", job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\", job=\"$job\"}) / node_memory_MemTotal_bytes{instance=\"$node\", job=\"$job\"}) * 100", + "format": "time_series", + "hide": true, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "(1 - (node_memory_MemAvailable_bytes{instance=\"$node\", job=\"$job\"} / node_memory_MemTotal_bytes{instance=\"$node\", job=\"$job\"})) * 100", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "B", + "step": 240 + } + ], + "title": "RAM Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Used Swap", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 25 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 1 + }, + "id": 21, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "((node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"}) / (node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"})) * 100", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "SWAP Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Used Root FS", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 1 + }, + "id": 154, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "100 - ((node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"} * 100) / node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Root FS Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Total number of CPU cores", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 18, + "y": 1 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu))", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "CPU Cores", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "System uptime", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 20, + "y": 1 + }, + "hideTimeOverride": true, + "id": 15, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_time_seconds{instance=\"$node\",job=\"$job\"} - node_boot_time_seconds{instance=\"$node\",job=\"$job\"}", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Total RootFS", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 70 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 18, + "y": 3 + }, + "id": 23, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",mountpoint=\"/\",fstype!=\"rootfs\"}", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "RootFS Total", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Total RAM", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 20, + "y": 3 + }, + "id": 75, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "RAM Total", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Total SWAP", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 2, + "x": 22, + "y": 3 + }, + "id": 18, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"}", + "instant": true, + "intervalFactor": 1, + "range": false, + "refId": "A", + "step": 240 + } + ], + "title": "SWAP Total", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 263, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Basic CPU / Mem / Net / Disk", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Basic CPU info", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Busy Iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy Iowait" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Idle" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy System" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy User" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Busy Other" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 77, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"system\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "Busy System", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Busy User", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"iowait\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy Iowait", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=~\".*irq\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy IRQs", + "range": true, + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode!='idle',mode!='user',mode!='system',mode!='iowait',mode!='irq',mode!='softirq'}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Busy Other", + "range": true, + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"idle\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Idle", + "range": true, + "refId": "F", + "step": 240 + } + ], + "title": "CPU Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Basic memory usage", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SWAP Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Cache + Buffer" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DEDAF7", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 78, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "RAM Total", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"} - (node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} + node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} + node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "RAM Used", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} + node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} + node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "RAM Cache + Buffer", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "RAM Free", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SWAP Used", + "refId": "E", + "step": 240 + } + ], + "title": "Memory Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Basic network info per interface", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Recv_bytes_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_drop_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_errs_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Recv_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CCA300", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_bytes_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_drop_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_errs_eth2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Trans_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CCA300", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_drop_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#967302", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_errs_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "recv_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_bytes_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_bytes_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_drop_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_drop_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#967302", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_errs_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "trans_errs_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 74, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "recv {{device}}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "trans {{device}} ", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Basic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Disk space used of all filesystems mounted", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 152, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "100 - ((node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'} * 100) / node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}}", + "refId": "A", + "step": 240 + } + ], + "title": "Disk Space Used Basic", + "type": "timeseries" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 265, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "percentage", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Idle - Waiting for something to happen" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Iowait - Waiting for I/O to complete" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Irq - Servicing interrupts" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Nice - Niced processes executing in user mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Softirq - Servicing softirqs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Steal - Time spent in other operating systems when running in a virtualized environment" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCE2DE", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "System - Processes executing in kernel mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "User - Normal processes executing in user mode" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5195CE", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 3, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"system\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "System - Processes executing in kernel mode", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "User - Normal processes executing in user mode", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"nice\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Nice - Niced processes executing in user mode", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"iowait\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Iowait - Waiting for I/O to complete", + "range": true, + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"irq\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Irq - Servicing interrupts", + "range": true, + "refId": "F", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"softirq\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Softirq - Servicing softirqs", + "range": true, + "refId": "G", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"steal\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Steal - Time spent in other operating systems when running in a virtualized environment", + "range": true, + "refId": "H", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum(irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\", mode=\"idle\"}[$__rate_interval])) / scalar(count(count(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}) by (cpu)))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Idle - Waiting for something to happen", + "range": true, + "refId": "J", + "step": 240 + } + ], + "title": "CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap - Swap memory usage" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused - Free memory unassigned" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Hardware Corrupted - *./" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 24, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_MemTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"} - node_memory_Slab_bytes{instance=\"$node\",job=\"$job\"} - node_memory_PageTables_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapCached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Apps - Memory used by user-space applications", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_PageTables_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "PageTables - Memory used to map between virtual and physical memory addresses", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_SwapCached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SwapCache - Memory that keeps track of pages that have been fetched from swap but not yet been modified", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Slab_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Slab - Memory used by the kernel to cache data structures for its own use (caches like inode, dentry, etc)", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Cached_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Cache - Parked file data (file content) cache", + "refId": "E", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Buffers_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Buffers - Block device (e.g. harddisk) cache", + "refId": "F", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_MemFree_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Unused - Free memory unassigned", + "refId": "G", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "(node_memory_SwapTotal_bytes{instance=\"$node\",job=\"$job\"} - node_memory_SwapFree_bytes{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Swap - Swap space used", + "refId": "H", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_HardwareCorrupted_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working", + "refId": "I", + "step": 240 + } + ], + "title": "Memory Stack", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bits out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "receive_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "receive_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 84, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])*8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 33 + }, + "id": 156, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'} - node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}}", + "refId": "A", + "step": 240 + } + ], + "title": "Disk Space Used", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IO read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 229, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "intervalFactor": 4, + "legendFormat": "{{device}} - Reads completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Writes completed", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "io time" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*read*./" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 42, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_read_bytes_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Successfully read bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_written_bytes_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Successfully written bytes", + "refId": "B", + "step": 240 + } + ], + "title": "I/O Usage Read / Write", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "%util", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "io time" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 127, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_io_time_seconds_total{instance=\"$node\",job=\"$job\",device=~\"$diskdevices\"} [$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}}", + "refId": "A", + "step": 240 + } + ], + "title": "I/O Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "percentage", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 3, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^Guest - /" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5195ce", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^GuestNice - /" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#c15c17", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 319, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_guest_seconds_total{instance=\"$node\",job=\"$job\", mode=\"user\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[1m])))", + "hide": false, + "legendFormat": "Guest - Time spent running a virtual CPU for a guest operating system", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "sum by(instance) (irate(node_cpu_guest_seconds_total{instance=\"$node\",job=\"$job\", mode=\"nice\"}[1m])) / on(instance) group_left sum by (instance)((irate(node_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[1m])))", + "hide": false, + "legendFormat": "GuestNice - Time spent running a niced guest (virtual CPU for guest operating system)", + "range": true, + "refId": "B" + } + ], + "title": "CPU spent seconds in guests (VMs)", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "CPU / Memory / Net / Disk", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 266, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 54 + }, + "id": 136, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Inactive_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Inactive - Memory which has been less recently used. It is more eligible to be reclaimed for other purposes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Active_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Active - Memory that has been used more recently and usually not reclaimed unless absolutely necessary", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Active / Inactive", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*CommitLimit - *./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 54 + }, + "id": 135, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Committed_AS_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Committed_AS - Amount of memory presently allocated on the system", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_CommitLimit_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CommitLimit - Amount of memory currently available to be allocated on the system", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Committed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 64 + }, + "id": 191, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Inactive_file_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inactive_file - File-backed memory on inactive LRU list", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Inactive_anon_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inactive_anon - Anonymous and swap cache on inactive LRU list, including tmpfs (shmem)", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Active_file_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Active_file - File-backed memory on active LRU list", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Active_anon_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Active_anon - Anonymous and swap cache on active least-recently-used (LRU) list, including tmpfs", + "refId": "D", + "step": 240 + } + ], + "title": "Memory Active / Inactive Detail", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 64 + }, + "id": 130, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Writeback_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Writeback - Memory which is actively being written back to disk", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_WritebackTmp_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "WritebackTmp - Memory used by FUSE for temporary writeback buffers", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Dirty_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Dirty - Memory which is waiting to get written back to the disk", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Writeback and Dirty", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 74 + }, + "id": 138, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Mapped_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Mapped - Used memory in mapped pages files which have been mapped, such as libraries", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Shmem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Shmem - Used shared memory (shared between several processes, thus including RAM disks)", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_ShmemHugePages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ShmemHugePages - Memory used by shared memory (shmem) and tmpfs allocated with huge pages", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_ShmemPmdMapped_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ShmemPmdMapped - Amount of shared (shmem/tmpfs) memory backed by huge pages", + "refId": "D", + "step": 240 + } + ], + "title": "Memory Shared and Mapped", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 74 + }, + "id": 131, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_SUnreclaim_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SUnreclaim - Part of Slab, that cannot be reclaimed on memory pressure", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_SReclaimable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SReclaimable - Part of Slab, that might be reclaimed, such as caches", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Slab", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 84 + }, + "id": 70, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_VmallocChunk_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocChunk - Largest contiguous block of vmalloc area which is free", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_VmallocTotal_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocTotal - Total size of vmalloc memory area", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_VmallocUsed_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "VmallocUsed - Amount of vmalloc area which is used", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Vmalloc", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 84 + }, + "id": 159, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Bounce_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Bounce - Memory used for block device bounce buffers", + "refId": "A", + "step": 240 + } + ], + "title": "Memory Bounce", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Inactive *./" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 94 + }, + "id": 129, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_AnonHugePages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "AnonHugePages - Memory in anonymous huge pages", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_AnonPages_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "AnonPages - Memory in user pages not backed by files", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Anonymous", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 94 + }, + "id": 160, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_KernelStack_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "KernelStack - Kernel memory stack. This is not reclaimable", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Percpu_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PerCPU - Per CPU memory allocated dynamically by loadable modules", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Kernel / CPU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 140, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_HugePages_Free{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Free - Huge pages in the pool that are not yet allocated", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_HugePages_Rsvd{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Rsvd - Huge pages for which a commitment to allocate from the pool has been made, but no allocation has yet been made", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_HugePages_Surp{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages_Surp - Huge pages in the pool above the value in /proc/sys/vm/nr_hugepages", + "refId": "C", + "step": 240 + } + ], + "title": "Memory HugePages Counter", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 71, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_HugePages_Total{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "HugePages - Total size of the pool of huge pages", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Hugepagesize_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Hugepagesize - Huge Page size", + "refId": "B", + "step": 240 + } + ], + "title": "Memory HugePages Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 114 + }, + "id": 128, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_DirectMap1G_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "DirectMap1G - Amount of pages mapped as this size", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_DirectMap2M_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "DirectMap2M - Amount of pages mapped as this size", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_DirectMap4k_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "DirectMap4K - Amount of pages mapped as this size", + "refId": "C", + "step": 240 + } + ], + "title": "Memory DirectMap", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 114 + }, + "id": 137, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Unevictable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unevictable - Amount of unevictable memory that can't be swapped out for a variety of reasons", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_Mlocked_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "MLocked - Size of pages locked to memory using the mlock() system call", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Unevictable and MLocked", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 124 + }, + "id": 132, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_memory_NFS_Unstable_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NFS Unstable - Memory in NFS pages sent to the server, but not yet committed to the storage", + "refId": "A", + "step": 240 + } + ], + "title": "Memory NFS", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Memory Meminfo", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 267, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*out/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 41 + }, + "id": 176, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pgpgin{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pagesin - Page in operations", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pgpgout{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pagesout - Page out operations", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Pages In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "pages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*out/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 41 + }, + "id": 22, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pswpin{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pswpin - Pages swapped in", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pswpout{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pswpout - Pages swapped out", + "refId": "B", + "step": 240 + } + ], + "title": "Memory Pages Swap In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "faults", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Apps" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#629E51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A437C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Hardware Corrupted - Amount of RAM that the kernel identified as corrupted / not working" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CFFAFF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "RAM_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806EB7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2F575E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Unused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pgfault - Page major and minor fault operations" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.stacking", + "value": { + "group": false, + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 51 + }, + "id": 175, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 350 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pgfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgfault - Page major and minor fault operations", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pgmajfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgmajfault - Major page fault operations", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_pgfault{instance=\"$node\",job=\"$job\"}[$__rate_interval]) - irate(node_vmstat_pgmajfault{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pgminfault - Minor page fault operations", + "refId": "C", + "step": 240 + } + ], + "title": "Memory Page Faults", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#99440A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Buffers" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#58140C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6D1F62", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cached" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Committed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#508642", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dirty" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Free" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B7DBAB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Mapped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PageTables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Page_Tables" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Slab_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Swap_Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C15C17", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#511749", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total RAM + Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#052B51", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Swap" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "VmallocUsed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 51 + }, + "id": 307, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_vmstat_oom_kill{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "oom killer invocations ", + "refId": "A", + "step": 240 + } + ], + "title": "OOM Killer", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Memory Vmstat", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 293, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Variation*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 260, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_estimated_error_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Estimated error in seconds", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_offset_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Time offset in between local system and reference clock", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_maxerror_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum error in seconds", + "refId": "C", + "step": 240 + } + ], + "title": "Time Synchronized Drift", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 24 + }, + "id": 291, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_loop_time_constant{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Phase-locked loop time adjust", + "refId": "A", + "step": 240 + } + ], + "title": "Time PLL Adjust", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Variation*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 34 + }, + "id": 168, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_sync_status{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Is clock synchronized to a reliable server (1 = yes, 0 = no)", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_frequency_adjustment_ratio{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Local clock frequency adjustment", + "refId": "B", + "step": 240 + } + ], + "title": "Time Synchronized Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 34 + }, + "id": 294, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_tick_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Seconds between clock ticks", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_timex_tai_offset_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "International Atomic Time (TAI) offset", + "refId": "B", + "step": 240 + } + ], + "title": "Time Misc", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "System Timesync", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 312, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 73 + }, + "id": 62, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_procs_blocked{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processes blocked waiting for I/O to complete", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_procs_running{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processes in runnable state", + "refId": "B", + "step": 240 + } + ], + "title": "Processes Status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Enable with --collector.processes argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 73 + }, + "id": 315, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_processes_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ state }}", + "refId": "A", + "step": 240 + } + ], + "title": "Processes State", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "forks / sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 83 + }, + "id": 148, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_forks_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Processes forks second", + "refId": "A", + "step": 240 + } + ], + "title": "Processes Forks", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max.*/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 83 + }, + "id": 149, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(process_virtual_memory_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Processes virtual memory size in bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "process_resident_memory_max_bytes{instance=\"$node\",job=\"$job\"}", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum amount of virtual memory available in bytes", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(process_virtual_memory_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Processes virtual memory size in bytes", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(process_virtual_memory_max_bytes{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum amount of virtual memory available in bytes", + "refId": "D", + "step": 240 + } + ], + "title": "Processes Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Enable with --collector.processes argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PIDs limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 93 + }, + "id": 313, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_processes_pids{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Number of PIDs", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_processes_max_processes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PIDs limit", + "refId": "B", + "step": 240 + } + ], + "title": "PIDs Number and Limit", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*waiting.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 93 + }, + "id": 305, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_schedstat_running_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }} - seconds spent running a process", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_schedstat_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }} - seconds spent by processing waiting for this CPU", + "refId": "B", + "step": 240 + } + ], + "title": "Process schedule stats Running / Waiting", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Enable with --collector.processes argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Threads limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 103 + }, + "id": 314, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_processes_threads{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Allocated threads", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_processes_max_threads{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Threads limit", + "refId": "B", + "step": 240 + } + ], + "title": "Threads Number and Limit", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "System Processes", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 269, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_context_switches_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Context switches", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_intr_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Interrupts", + "refId": "B", + "step": 240 + } + ], + "title": "Context Switches / Interrupts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 7, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_load1{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 1m", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_load5{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 5m", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_load15{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Load 15m", + "refId": "C", + "step": 240 + } + ], + "title": "System Load", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "hertz" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Max" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 10 + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": false, + "viz": false + } + }, + { + "id": "custom.fillBelowTo", + "value": "Min" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Min" + }, + "properties": [ + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + }, + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": false, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 321, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "node_cpu_scaling_frequency_hertz{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }}", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "avg(node_cpu_scaling_frequency_max_hertz{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Max", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "avg(node_cpu_scaling_frequency_min_hertz{instance=\"$node\",job=\"$job\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Min", + "range": true, + "refId": "C", + "step": 240 + } + ], + "title": "CPU Frequency Scaling", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "https://docs.kernel.org/accounting/psi.html", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Memory some" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Memory full" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "I/O some" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "I/O full" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 322, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "rate(node_pressure_cpu_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CPU some", + "range": true, + "refId": "CPU some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "rate(node_pressure_memory_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Memory some", + "range": true, + "refId": "Memory some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "rate(node_pressure_memory_stalled_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Memory full", + "range": true, + "refId": "Memory full", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "rate(node_pressure_io_waiting_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "I/O some", + "range": true, + "refId": "I/O some", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "rate(node_pressure_io_stalled_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "I/O full", + "range": true, + "refId": "I/O full", + "step": 240 + } + ], + "title": "Pressure Stall Information", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Enable with --collector.interrupts argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Critical*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 259, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_interrupts_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ type }} - {{ info }}", + "refId": "A", + "step": 240 + } + ], + "title": "Interrupts Detail", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 306, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_schedstat_timeslices_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{ cpu }}", + "refId": "A", + "step": 240 + } + ], + "title": "Schedule timeslices executed by each cpu", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 56 + }, + "id": 151, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_entropy_available_bits{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Entropy available to random number generators", + "refId": "A", + "step": 240 + } + ], + "title": "Entropy", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 56 + }, + "id": 308, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(process_cpu_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Time spent", + "refId": "A", + "step": 240 + } + ], + "title": "CPU time spent in user and system contexts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 64, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "process_max_fds{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Maximum open file descriptors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "process_open_fds{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Open file descriptors", + "refId": "B", + "step": 240 + } + ], + "title": "File Descriptors", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "System Misc", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 304, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "temperature", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "celsius" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Critical*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 158, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_hwmon_temp_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} temp", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_hwmon_temp_crit_alarm_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Critical Alarm", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_hwmon_temp_crit_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Critical", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_hwmon_temp_crit_hyst_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Critical Historical", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_hwmon_temp_max_celsius{instance=\"$node\",job=\"$job\"} * on(chip) group_left(chip_name) node_hwmon_chip_names{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ chip_name }} {{ sensor }} Max", + "refId": "E", + "step": 240 + } + ], + "title": "Hardware temperature monitor", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Max*./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 300, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_cooling_device_cur_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Current {{ name }} in {{ type }}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_cooling_device_max_state{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Max {{ name }} in {{ type }}", + "refId": "B", + "step": 240 + } + ], + "title": "Throttle cooling device", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 69 + }, + "id": 302, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_power_supply_online{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ power_supply }} online", + "refId": "A", + "step": 240 + } + ], + "title": "Power supply", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Hardware Misc", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 296, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 297, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_systemd_socket_accepted_connections_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ name }} Connections", + "refId": "A", + "step": 240 + } + ], + "title": "Systemd Sockets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Inactive" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Active" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Deactivating" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFCB7D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Activating" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C8F2C2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 46 + }, + "id": 298, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"activating\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Activating", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"active\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Active", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"deactivating\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Deactivating", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"failed\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Failed", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_systemd_units{instance=\"$node\",job=\"$job\",state=\"inactive\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Inactive", + "refId": "E", + "step": 240 + } + ], + "title": "Systemd Units State", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Systemd", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 270, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The number (after merges) of I/O requests completed per second for the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IO read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 9, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 4, + "legendFormat": "{{device}} - Reads completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Writes completed", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps Completed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The number of bytes read from or written to the device per second", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 33, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_read_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "{{device}} - Read bytes", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_written_bytes_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Written bytes", + "refId": "B", + "step": 240 + } + ], + "title": "Disk R/W Data", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The average time for requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "time. read (-) / write (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 37, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_read_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]) / irate(node_disk_reads_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - Read wait time avg", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_write_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval]) / irate(node_disk_writes_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Write wait time avg", + "refId": "B", + "step": 240 + } + ], + "title": "Disk Average Wait Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The average queue length of the requests that were issued to the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "aqu-sz", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 35, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_io_time_weighted_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}}", + "refId": "A", + "step": 240 + } + ], + "title": "Average Queue Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The number of read and write requests merged per second that were queued to the device", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "I/Os", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Read.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 67 + }, + "id": 133, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_reads_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Read merged", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_writes_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "intervalFactor": 1, + "legendFormat": "{{device}} - Write merged", + "refId": "B", + "step": 240 + } + ], + "title": "Disk R/W Merged", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100% for devices serving requests serially. But for devices serving requests in parallel, such as RAID arrays and modern SSDs, this number does not reflect their performance limits.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "%util", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 67 + }, + "id": 36, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_io_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - IO", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_discard_time_seconds_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - discard", + "refId": "B", + "step": 240 + } + ], + "title": "Time Spent Doing I/Os", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "The number of outstanding requests at the instant the sample was taken. Incremented as requests are given to appropriate struct request_queue and decremented as they finish.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Outstanding req.", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 77 + }, + "id": 34, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_disk_io_now{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - IO now", + "refId": "A", + "step": 240 + } + ], + "title": "Instantaneous Queue Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "IOs", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EAB839", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#6ED0E0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EF843C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#584477", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda2_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BA43A9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sda3_.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F4D598", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#0A50A1", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdb3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0752D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#962D82", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#614D93", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdc3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#9AC48A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#65C5DB", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9934E", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#EA6460", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde1.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0F9D7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sdd2.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FCEACA", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*sde3.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F9E2D2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 77 + }, + "id": 301, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_discards_completed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 4, + "legendFormat": "{{device}} - Discards completed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_disk_discards_merged_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Discards merged", + "refId": "B", + "step": 240 + } + ], + "title": "Disk IOps Discards completed / merged", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Storage Disk", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 271, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 43, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_avail_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Available", + "metric": "", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_free_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Free", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_size_bytes{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Size", + "refId": "C", + "step": 240 + } + ], + "title": "Filesystem space available", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "file nodes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 62 + }, + "id": 41, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_files_free{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Free file nodes", + "refId": "A", + "step": 240 + } + ], + "title": "File Nodes Free", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "files", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 72 + }, + "id": 28, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filefd_maximum{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 4, + "legendFormat": "Max open files", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filefd_allocated{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Open files", + "refId": "B", + "step": 240 + } + ], + "title": "File Descriptor", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "file Nodes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 72 + }, + "id": 219, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_files{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - File nodes total", + "refId": "A", + "step": 240 + } + ], + "title": "File Nodes Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "/ ReadOnly" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 82 + }, + "id": 44, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_readonly{instance=\"$node\",job=\"$job\",device!~'rootfs'}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - ReadOnly", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_filesystem_device_error{instance=\"$node\",job=\"$job\",device!~'rootfs',fstype!~'tmpfs'}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{mountpoint}} - Device error", + "refId": "B", + "step": 240 + } + ], + "title": "Filesystem in ReadOnly / Error", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Storage Filesystem", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 272, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "receive_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "receive_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_eth0" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7EB26D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "transmit_packets_lo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E24D42", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 60, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_packets_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_packets_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic by Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 142, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_errs_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive errors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_errs_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit errors", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 57 + }, + "id": 143, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_drop_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive drop", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_drop_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit drop", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Drop", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 57 + }, + "id": 141, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_compressed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive compressed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_compressed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit compressed", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Compressed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 67 + }, + "id": 146, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_multicast_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive multicast", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Multicast", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 67 + }, + "id": 144, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_fifo_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive fifo", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_fifo_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit fifo", + "refId": "B", + "step": 240 + } + ], + "title": "Network Traffic Fifo", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 77 + }, + "id": 145, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_receive_frame_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{device}} - Receive frame", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Frame", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 77 + }, + "id": 231, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_carrier_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Statistic transmit_carrier", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Carrier", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Trans.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 232, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_network_transmit_colls_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{device}} - Transmit colls", + "refId": "A", + "step": 240 + } + ], + "title": "Network Traffic Colls", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "entries", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NF conntrack limit" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 61, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_nf_conntrack_entries{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NF conntrack entries", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_nf_conntrack_entries_limit{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "NF conntrack limit", + "refId": "B", + "step": 240 + } + ], + "title": "NF Conntrack", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Entries", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 97 + }, + "id": 230, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_arp_entries{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - ARP entries", + "refId": "A", + "step": 240 + } + ], + "title": "ARP Entries", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 97 + }, + "id": 288, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_network_mtu_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Bytes", + "refId": "A", + "step": 240 + } + ], + "title": "MTU", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 107 + }, + "id": 280, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_network_speed_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Speed", + "refId": "A", + "step": 240 + } + ], + "title": "Speed", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packets", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 107 + }, + "id": 289, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_network_transmit_queue_length{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ device }} - Interface transmit queue length", + "refId": "A", + "step": 240 + } + ], + "title": "Queue Length", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "packetes drop (-) / process (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Dropped.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 117 + }, + "id": 290, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_softnet_processed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Processed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_softnet_dropped_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Dropped", + "refId": "B", + "step": 240 + } + ], + "title": "Softnet Packets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 117 + }, + "id": 310, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_softnet_times_squeezed_total{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "CPU {{cpu}} - Squeezed", + "refId": "A", + "step": 240 + } + ], + "title": "Softnet Out of Quota", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 127 + }, + "id": 309, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_network_up{operstate=\"up\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{interface}} - Operational state UP", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_network_carrier{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{device}} - Physical link state", + "refId": "B" + } + ], + "title": "Network Operational Status", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Network Traffic", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 273, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 63, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_TCP_alloc{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_alloc - Allocated sockets", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_TCP_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_inuse - Tcp sockets currently in use", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_TCP_mem{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_mem - Used memory for tcp", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_TCP_orphan{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_orphan - Orphan sockets", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_TCP_tw{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCP_tw - Sockets waiting close", + "refId": "E", + "step": 240 + } + ], + "title": "Sockstat TCP", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 124, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_UDPLITE_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDPLITE_inuse - Udplite sockets currently in use", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_UDP_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDP_inuse - Udp sockets currently in use", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_UDP_mem{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "UDP_mem - Used memory for udp", + "refId": "C", + "step": 240 + } + ], + "title": "Sockstat UDP", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 125, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_FRAG_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "FRAG_inuse - Frag sockets currently in use", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_RAW_inuse{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "RAW_inuse - Raw sockets currently in use", + "refId": "C", + "step": 240 + } + ], + "title": "Sockstat FRAG / RAW", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 58 + }, + "id": 220, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_TCP_mem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "mem_bytes - TCP sockets in that state", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_UDP_mem_bytes{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "mem_bytes - UDP sockets in that state", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_FRAG_memory{instance=\"$node\",job=\"$job\"}", + "interval": "", + "intervalFactor": 1, + "legendFormat": "FRAG_memory - Used memory for frag", + "refId": "C" + } + ], + "title": "Sockstat Memory Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "sockets", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 68 + }, + "id": 126, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_sockstat_sockets_used{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Sockets_used - Sockets currently in use", + "refId": "A", + "step": 240 + } + ], + "title": "Sockstat Used", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Network Sockstat", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 274, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "octets out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 221, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_IpExt_InOctets{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InOctets - Received octets", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_IpExt_OutOctets{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "OutOctets - Sent octets", + "refId": "B", + "step": 240 + } + ], + "title": "Netstat IP In / Out Octets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 33 + }, + "id": 81, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "width": 300 + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Ip_Forwarding{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Forwarding - IP forwarding", + "refId": "A", + "step": 240 + } + ], + "title": "Netstat IP Forwarding", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "messages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 115, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Icmp_InMsgs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InMsgs - Messages which the entity received. Note that this counter includes all those counted by icmpInErrors", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Icmp_OutMsgs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutMsgs - Messages which this entity attempted to send. Note that this counter includes all those counted by icmpOutErrors", + "refId": "B", + "step": 240 + } + ], + "title": "ICMP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "messages out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 43 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Icmp_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InErrors - Messages which the entity received but determined as having ICMP-specific errors (bad ICMP checksums, bad length, etc.)", + "refId": "A", + "step": 240 + } + ], + "title": "ICMP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Snd.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 55, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Udp_InDatagrams{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InDatagrams - Datagrams received", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Udp_OutDatagrams{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutDatagrams - Datagrams sent", + "refId": "B", + "step": 240 + } + ], + "title": "UDP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 109, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Udp_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "InErrors - UDP Datagrams that could not be delivered to an application", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Udp_NoPorts{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "NoPorts - UDP Datagrams received on a port with no listener", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_UdpLite_InErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "InErrors Lite - UDPLite Datagrams that could not be delivered to an application", + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Udp_RcvbufErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "RcvbufErrors - UDP buffer errors received", + "refId": "D", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Udp_SndbufErrors{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "SndbufErrors - UDP buffer errors send", + "refId": "E", + "step": 240 + } + ], + "title": "UDP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "datagrams out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Out.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*Snd.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 63 + }, + "id": 299, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_InSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "InSegs - Segments received, including those received in error. This count includes segments received on currently established connections", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_OutSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "OutSegs - Segments sent, including those on current connections but excluding those containing only retransmitted octets", + "refId": "B", + "step": 240 + } + ], + "title": "TCP In / Out", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 63 + }, + "id": 104, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_TcpExt_ListenOverflows{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "ListenOverflows - Times the listen queue of a socket overflowed", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_TcpExt_ListenDrops{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "ListenDrops - SYNs to LISTEN sockets ignored", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_TcpExt_TCPSynRetrans{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "TCPSynRetrans - SYN-SYN/ACK retransmits to break down retransmissions in SYN, fast/timeout retransmits", + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_RetransSegs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "RetransSegs - Segments retransmitted - that is, the number of TCP segments transmitted containing one or more previously transmitted octets", + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_InErrs{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "InErrs - Segments received in error (e.g., bad TCP checksums)", + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_OutRsts{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "interval": "", + "legendFormat": "OutRsts - Segments sent with RST flag", + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "irate(node_netstat_TcpExt_TCPRcvQDrop{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "legendFormat": "TCPRcvQDrop - Packets meant to be queued in rcv queue but dropped because socket rcvbuf limit hit", + "range": true, + "refId": "G" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "irate(node_netstat_TcpExt_TCPOFOQueue{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "hide": false, + "interval": "", + "legendFormat": "TCPOFOQueue - TCP layer receives an out of order packet and has enough memory to queue it", + "range": true, + "refId": "H" + } + ], + "title": "TCP Errors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*MaxConn *./" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 73 + }, + "id": 85, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_netstat_Tcp_CurrEstab{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "CurrEstab - TCP connections for which the current state is either ESTABLISHED or CLOSE- WAIT", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_netstat_Tcp_MaxConn{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "MaxConn - Limit on the total number of TCP connections the entity can support (Dynamic is \"-1\")", + "refId": "B", + "step": 240 + } + ], + "title": "TCP Connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter out (-) / in (+)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*Sent.*/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 73 + }, + "id": 91, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesFailed{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesFailed - Invalid SYN cookies received", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesRecv{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesRecv - SYN cookies received", + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_TcpExt_SyncookiesSent{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "SyncookiesSent - SYN cookies sent", + "refId": "C", + "step": 240 + } + ], + "title": "TCP SynCookie", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 83 + }, + "id": 82, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_ActiveOpens{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "ActiveOpens - TCP connections that have made a direct transition to the SYN-SENT state from the CLOSED state", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "irate(node_netstat_Tcp_PassiveOpens{instance=\"$node\",job=\"$job\"}[$__rate_interval])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "PassiveOpens - TCP connections that have made a direct transition to the SYN-RCVD state from the LISTEN state", + "refId": "B", + "step": 240 + } + ], + "title": "TCP Direct Transition", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "Enable with --collector.tcpstat argument on node-exporter", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "connections", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 83 + }, + "id": 320, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"established\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "established - TCP sockets in established state", + "range": true, + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"fin_wait2\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "fin_wait2 - TCP sockets in fin_wait2 state", + "range": true, + "refId": "B", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"listen\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "listen - TCP sockets in listen state", + "range": true, + "refId": "C", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "editorMode": "code", + "expr": "node_tcp_connection_states{state=\"time_wait\",instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "time_wait - TCP sockets in time_wait state", + "range": true, + "refId": "D", + "step": 240 + } + ], + "title": "TCP Stat", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Network Netstat", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 33 + }, + "id": 279, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "seconds", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 40, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_scrape_collector_duration_seconds{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape duration", + "refId": "A", + "step": 240 + } + ], + "title": "Node Exporter Scrape Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "counter", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*error.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + }, + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 66 + }, + "id": 157, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "9.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_scrape_collector_success{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape success", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "expr": "node_textfile_scrape_error{instance=\"$node\",job=\"$job\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{collector}} - Scrape textfile error (1 = true)", + "refId": "B", + "step": 240 + } + ], + "title": "Node Exporter Scrape", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "000000001" + }, + "refId": "A" + } + ], + "title": "Node Exporter", + "type": "row" + } + ], + "refresh": "1m", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "Linux" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Job", + "multi": false, + "name": "job", + "options": [], + "query": { + "query": "label_values(node_uname_info, job)", + "refId": "Prometheus-job-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${datasource}" + }, + "definition": "label_values(node_uname_info{job=\"$job\"}, instance)", + "hide": 0, + "includeAll": false, + "label": "Host", + "multi": false, + "name": "node", + "options": [], + "query": { + "query": "label_values(node_uname_info{job=\"$job\"}, instance)", + "refId": "Prometheus-node-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "value": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+" + }, + "hide": 2, + "includeAll": false, + "multi": false, + "name": "diskdevices", + "options": [ + { + "selected": true, + "text": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "value": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+" + } + ], + "query": "[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Server & System", + "uid": "rYdddlPWk", + "version": 92, + "weekStart": "" +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_redis.json b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_redis.json new file mode 100644 index 00000000..b06018d8 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/files/definitions/default/grafana_dashboard_definition_redis.json @@ -0,0 +1,1625 @@ +{ + "__inputs": [ + { + "name": "DS_PROM", + "label": "prom", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.3.3" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Redis Dashboard for Prometheus Redis Exporter 1.x", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 763, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 0, + "y": 0 + }, + "id": 9, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "max(max_over_time(redis_uptime_in_seconds{instance=~\"$instance\"}[$__interval]))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "", + "metric": "", + "refId": "A", + "step": 1800 + } + ], + "title": "Max Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 2, + "x": 3, + "y": 0 + }, + "hideTimeOverride": true, + "id": 12, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(redis_connected_clients{instance=~\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "metric": "", + "refId": "A", + "step": 2 + } + ], + "timeFrom": "1m", + "title": "Clients", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percent", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 5, + "y": 0 + }, + "hideTimeOverride": true, + "id": 11, + "links": [], + "maxDataPoints": 100, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(100 * (redis_memory_used_bytes{instance=~\"$instance\"} / redis_memory_max_bytes{instance=~\"$instance\"}))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "metric": "", + "refId": "A", + "step": 2 + } + ], + "timeFrom": "1m", + "title": "Memory Usage", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 18, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(rate(redis_commands_total{instance=~\"$instance\"} [1m])) by (cmd)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ cmd }}", + "metric": "redis_command_calls_total", + "refId": "A", + "step": 240 + } + ], + "title": "Total Commands / sec", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 1, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "irate(redis_keyspace_hits_total{instance=~\"$instance\"}[5m])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "hits, {{ instance }}", + "metric": "", + "refId": "A", + "step": 240, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "irate(redis_keyspace_misses_total{instance=~\"$instance\"}[5m])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "misses, {{ instance }}", + "metric": "", + "refId": "B", + "step": 240, + "target": "" + } + ], + "title": "Hits / Misses per Sec", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#BF1B00", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 7, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "redis_memory_used_bytes{instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "used, {{ instance }}", + "metric": "", + "refId": "A", + "step": 240, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "redis_memory_max_bytes{instance=~\"$instance\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "max, {{ instance }}", + "refId": "B", + "step": 240 + } + ], + "title": "Total Memory Usage", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 10, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(rate(redis_net_input_bytes_total{instance=~\"$instance\"}[5m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ input }}", + "refId": "A", + "step": 240 + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(rate(redis_net_output_bytes_total{instance=~\"$instance\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ output }}", + "refId": "B", + "step": 240 + } + ], + "title": "Network I/O", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 5, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum (redis_db_keys{instance=~\"$instance\"}) by (db, instance)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ db }}, {{ instance }}", + "refId": "A", + "step": 240, + "target": "" + } + ], + "title": "Total Items per DB", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 70, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 13, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum (redis_db_keys{instance=~\"$instance\"}) by (instance) - sum (redis_db_keys_expiring{instance=~\"$instance\"}) by (instance)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "not expiring, {{ instance }}", + "refId": "A", + "step": 240, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum (redis_db_keys_expiring{instance=~\"$instance\"}) by (instance)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "expiring, {{ instance }}", + "metric": "", + "refId": "B", + "step": 240 + } + ], + "title": "Expiring vs Not-Expiring Keys", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "evicts" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "memcached_items_evicted_total{instance=\"172.17.0.1:9150\",job=\"prometheus\"}" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#890F02", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "reclaims" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#3F6833", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(rate(redis_expired_keys_total{instance=~\"$instance\"}[5m])) by (instance)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "expired, {{ instance }}", + "metric": "", + "refId": "A", + "step": 240, + "target": "" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(rate(redis_evicted_keys_total{instance=~\"$instance\"}[5m])) by (instance)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "evicted, {{ instance }}", + "refId": "B", + "step": 240 + } + ], + "title": "Expired/Evicted Keys", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 16, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(redis_connected_clients{instance=~\"$instance\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "connected", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(redis_blocked_clients{instance=~\"$instance\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "blocked", + "refId": "B" + } + ], + "title": "Connected/Blocked Clients", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 20, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(irate(redis_commands_duration_seconds_total{instance =~ \"$instance\"}[1m])) by (cmd)\n /\nsum(irate(redis_commands_total{instance =~ \"$instance\"}[1m])) by (cmd)\n", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ cmd }}", + "metric": "redis_command_calls_total", + "refId": "A", + "step": 240 + } + ], + "title": "Average Time Spent by Command / sec", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 14, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.3.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "expr": "sum(irate(redis_commands_duration_seconds_total{instance=~\"$instance\"}[1m])) by (cmd) != 0", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{ cmd }}", + "metric": "redis_command_calls_total", + "refId": "A", + "step": 240 + } + ], + "title": "Total Time Spent by Command / sec", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [ + "Redis" + ], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(redis_up, namespace)", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(redis_up, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "P0147FA0CB911A4EC" + }, + "definition": "label_values(redis_up{namespace=~\"$namespace\"}, instance)", + "hide": 0, + "includeAll": false, + "multi": true, + "name": "instance", + "options": [], + "query": "label_values(redis_up{namespace=~\"$namespace\"}, instance)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Redis", + "uid": "e008bc3f-81a2-40f9-baf2-a33fd8dec7ec", + "version": 2, + "weekStart": "" +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/tasks/main.yml new file mode 100644 index 00000000..a37cd960 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/tasks/main.yml @@ -0,0 +1,87 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create grafana group + ansible.builtin.group: + name: "{{ grafana_group }}" + state: present + +- name: Create grafana user + ansible.builtin.user: + name: "{{ grafana_user }}" + group: "{{ grafana_group }}" + state: present + +- name: Install Grafana repo + ansible.builtin.yum_repository: + name: "grafana" + description: Grafana Repository + baseurl: "{{ grafana_repo_url }}" + enabled: true + gpgcheck: true + gpgkey: "{{ grafana_gpg_key }}" + when: common_install_yum_repos | bool + +# Install grafana with yum +- name: Install Grafana + ansible.builtin.dnf: + name: "{{ item }}" + state: present + with_items: + - grafana + - chkconfig + +# Add default datasources +- name: Create grafana datasources file + ansible.builtin.template: + src: grafana_datasources.yml.j2 + dest: "{{ grafana_install_dir }}/provisioning/datasources/datasources.yml" + owner: "{{ grafana_user }}" + group: "{{ grafana_group }}" + mode: "0644" + lstrip_blocks: true + +- name: Upload grafana dashboard config + ansible.builtin.template: + src: grafana_dashboard_config_iap.yml.j2 + dest: "{{ grafana_install_dir }}/provisioning/dashboards/grafana_dashboard_config_iap.yml" + group: "{{ grafana_group }}" + owner: "{{ grafana_user }}" + mode: "0644" + +- name: Upload grafana dashboard default definitions + ansible.builtin.copy: + src: definitions/default/ + dest: "{{ grafana_install_dir }}/provisioning/dashboards/definitions/" + directory_mode: "0755" + group: "{{ grafana_group }}" + owner: "{{ grafana_user }}" + mode: "0644" + +- name: Gather service facts + ansible.builtin.service_facts: + +- name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ grafana_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +- name: Start Grafana + ansible.builtin.systemd: + name: grafana-server + state: restarted + enabled: true + +- name: Assert that Grafana is running + ansible.builtin.systemd: + name: grafana-server + register: grafana_status + failed_when: grafana_status.status.ActiveState != "active" + tags: always diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/templates/grafana_dashboard_config_iap.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/templates/grafana_dashboard_config_iap.yml.j2 new file mode 100644 index 00000000..b31b009d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/templates/grafana_dashboard_config_iap.yml.j2 @@ -0,0 +1,25 @@ +# # config file version +apiVersion: 1 + +providers: + # an unique provider name. Required + - name: 'default' + # Org id. Default to 1 + orgId: 1 + # name of the dashboard folder. + folder: '' + # folder UID. will be automatically generated if not specified + folderUid: '' + # provider type. Default to 'file' + type: file + # disable dashboard deletion + disableDeletion: false + # how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 + # allow updating provisioned dashboards from the UI + allowUiUpdates: {{ grafana_allow_ui_updates }} + options: + # path to dashboard files on disk. Required when using the 'file' type + path: {{ grafana_dashboard_dir }} + # use folder names from filesystem to create folders in Grafana + foldersFromFilesStructure: false \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/templates/grafana_datasources.yml.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/templates/grafana_datasources.yml.j2 new file mode 100644 index 00000000..c25480c5 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/templates/grafana_datasources.yml.j2 @@ -0,0 +1,53 @@ +{%- set prometheus_host = groups.prometheus | first -%} +# config file version +apiVersion: 1 + +# list of datasources that should be deleted from the database +deleteDatasources: + +# list of datasources to insert/update depending +# whats available in the database +datasources: + # name of the datasource. Required +- name: Prometheus IAP + # datasource type. Required + type: prometheus + # access mode. direct or proxy. Required + access: proxy + # org id. will default to orgId 1 if not specified + orgId: 1 + # url + {% if 'prometheus_web_listen_address' in hostvars[prometheus_host] %} + url: http://{{ hostvars[prometheus_host].prometheus_web_listen_address }} + {% else %} + url: http://{{ prometheus_host }}:{{ grafana_prometheus_web_listen_port }} + {% endif %} + # database password, if used + password: + # database user, if used + user: + # database name, if used + database: + # enable/disable basic auth + basicAuth: false + # basic auth username + basicAuthUser: admin + # basic auth password + basicAuthPassword: foobar + # enable/disable with credentials headers + withCredentials: + # mark as default datasource. Max one per org + isDefault: + # fields that will be converted to json and stored in json_data + jsonData: + graphiteVersion: "1.1" + tlsAuth: false + tlsAuthWithCACert: false + # json object of data that will be encrypted. + secureJsonData: + tlsCACert: "..." + tlsClientCert: "..." + tlsClientKey: "..." + version: 1 + # allow users to edit datasources from the UI. + editable: true \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/vars/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/vars/main.yml new file mode 100644 index 00000000..9e6b5524 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/grafana/vars/main.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +grafana_prometheus_web_listen_port: 9090 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/install.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/install.yml new file mode 100644 index 00000000..d8b46c46 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/install.yml @@ -0,0 +1,26 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +mongodb_release_url: + "https://repo.mongodb.org/yum/{% if ansible_distribution_file_variety == 'OracleLinux' %}redhat{% else %}{{ ansible_distribution_file_variety | lower }}{% endif %}/{{ ansible_distribution_major_version }}/mongodb-org/{{ mongodb_version }}/{{ ansible_architecture }}/" + +# The mongodb role uses the system python3 executables. +mongodb_python_executable: /usr/bin/python3 +mongodb_pip_executable: /usr/bin/pip3 +mongodb_python_base_dependencies: + - pip +mongodb_python_app_dependencies: + - pymongo + +# To isolate Python, a virtual environment is used. +mongodb_python_venv_root: /var/tmp +mongodb_python_venv_name: mongodb_venv +mongodb_python_venv: "{{ mongodb_python_venv_root }}/{{ mongodb_python_venv_name }}" + +# Mongod service settings +mongodb_mongod_service_retries: 5 +mongodb_mongod_service_delay: 10 + +# MongoDB status settings +mongodb_status_poll: 3 +mongodb_status_interval: 10 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/kernel_params.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/kernel_params.yml new file mode 100644 index 00000000..4f533571 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/kernel_params.yml @@ -0,0 +1,10 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Kernel parameters +mongodb_sysctl_file: /etc/sysctl.d/98-mongodb.conf +mongodb_net_ipv4_tcp_keepalive_time: 300 +mongodb_net_core_somaxconn: 65535 +mongodb_vm_zone_reclaim_mode: 0 +mongodb_vm_swappiness: 1 +mongodb_vm_max_map_count: 262144 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/mongodb.yml new file mode 100644 index 00000000..4d6bf787 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/mongodb.yml @@ -0,0 +1,60 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Location of mongo conf file +mongodb_conf_file: /etc/mongod.conf + +# Directory that stores mongodb data files +mongodb_data_dir: /var/lib/mongo + +# Target path for writing mongodb log files +mongodb_log_dir: /var/log/mongodb + +# Directory that stores the mongodb pid file +mongodb_pid_dir: /var/run/mongodb + +# The Mongo user and group +mongodb_owner: mongod +mongodb_group: mongod + +# The default admin database name +mongodb_admin_db_name: admin + +# Flag to enable/disable IPv6 +mongodb_bind_ipv6: true + +# The hostnames and/or IP addresses and/or full Unix domain socket paths on +# which mongos or mongod should listen for client connections. You may attach +# mongos or mongod to any interface. To bind to multiple addresses, enter a +# list of comma-separated values. +# +# The inventory_hostname will be automatically added to mongodb_bind_addrs. +# +# If mongodb_bind_ipv6 is set to true, '::1' will be added to mongodb_bind_addrs. +mongodb_bind_addrs: 127.0.0.1 + +# The TCP port on which the MongoDB instance listens for client connections. +mongodb_port: "{{ mongodb_port_default }}" + +# Default Itential database name in MongoDB +mongodb_itential_db_name: itential + +# Feature flags that can be overridden in the hosts file +# Essentially, a default installation will not have replication, authorization, +# or TLS settings applied. +mongodb_replication_enabled: false +mongodb_auth_enabled: true +mongodb_tls_enabled: true + +# Default mongo user names +mongodb_user_admin: admin +mongodb_user_itential: itential + +# Default mongo user passwords +# These are meant to be changed by the customer. By default they are meant to +# be predictable and simple. +mongodb_user_admin_password: admin +mongodb_user_itential_password: itential + +# The name of the mongo replica set +mongodb_replset_name: "{{ mongodb_replset_name_default }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/offline.yml new file mode 100644 index 00000000..c87df11a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/offline.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Base directories +mongodb_offline_packages_root: "{{ offline_itential_packages_path }}/{{ platform_release }}/mongodb" +mongodb_offline_target_node_root: + "{{ offline_target_node_root }}/{{ mongodb_offline_packages_root }}" +mongodb_offline_control_node_root: + "{{ offline_control_node_root }}/{{ mongodb_offline_packages_root }}" + +# Target node download directories +mongodb_offline_target_node_rpms_dir: "{{ mongodb_offline_target_node_root }}/rpms" +mongodb_offline_target_node_wheels_dir: "{{ mongodb_offline_target_node_root }}/wheels" + +# Control node download directories +mongodb_offline_control_node_rpms_dir: "{{ mongodb_offline_control_node_root }}/rpms" +mongodb_offline_control_node_wheels_dir: "{{ mongodb_offline_control_node_root }}/wheels" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/pki.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/pki.yml new file mode 100644 index 00000000..13fba653 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/defaults/main/pki.yml @@ -0,0 +1,85 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# MongoDB PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +mongodb_pki_base_dir: /etc/pki/mongodb + +# Subdirectory names - customize the layout +mongodb_pki_private_subdir: private + +# Derived subdirectory paths - built from base + subdir name +mongodb_pki_private_dir: "{{ mongodb_pki_base_dir }}/{{ mongodb_pki_private_subdir }}" + +# ============================================================================ +# Certificate and Key Filenames - Customize naming +# ============================================================================ + +# TLS server certificate filename (combined cert + key PEM) +mongodb_tls_server_cert_filename: "{{ inventory_hostname }}.pem" + +# CA certificate filename +mongodb_tls_ca_cert_filename: ca-bundle.crt + +# Replica set authentication keyfile filename +mongodb_replica_keyfile_filename: replica.key + +# ============================================================================ +# Full Certificate Paths - Built from components, but can be overridden +# ============================================================================ + +# TLS server certificate path (used by mongod for TLS connections) +mongodb_cert_keyfile_destination: "{{ mongodb_pki_base_dir }}/{{ mongodb_tls_server_cert_filename }}" + +# CA certificate path (used to validate client certificates) +mongodb_root_ca_file_destination: "{{ mongodb_pki_base_dir }}/{{ mongodb_tls_ca_cert_filename }}" + +# Replica set keyfile path (used for internal authentication) +mongodb_auth_keyfile_destination: "{{ mongodb_pki_private_dir }}/{{ mongodb_replica_keyfile_filename }}" + +# ============================================================================ +# Source Directory and File Paths - Define source directory in inventory +# ============================================================================ + +# Source directory for certificate files (on Ansible controller) +# Set this in your inventory to point to your certificate directory +mongodb_pki_src_dir: "" + +mongodb_ssl_root_dir: "{{ mongodb_pki_base_dir }}" +# Source paths - built from source directory + filename +# These auto-build from mongodb_pki_src_dir, but can be overridden individually +mongodb_cert_keyfile_source: "{{ mongodb_pki_src_dir }}/{{ mongodb_tls_server_cert_filename }}" +mongodb_root_ca_file_source: "{{ mongodb_pki_src_dir }}/{{ mongodb_tls_ca_cert_filename }}" +mongodb_auth_keyfile_source: "{{ mongodb_pki_src_dir }}/{{ mongodb_replica_keyfile_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI directories and files +mongodb_pki_owner: "{{ mongodb_owner }}" + +# Group for PKI directories and files +mongodb_pki_group: "{{ mongodb_group }}" + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +mongodb_pki_base_dir_mode: "0750" + +# Private subdirectory permissions +mongodb_pki_private_dir_mode: "0700" + +# TLS server certificate permissions +mongodb_tls_server_cert_mode: "0640" + +# CA certificate permissions +mongodb_tls_ca_cert_mode: "0644" + +# Replica keyfile permissions +mongodb_replica_keyfile_mode: "0400" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_cgroup_memory.te b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_cgroup_memory.te new file mode 100644 index 00000000..cca488cb --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_cgroup_memory.te @@ -0,0 +1,12 @@ +module itential_mongodb_cgroup_memory 1.0; + +require { + type cgroup_t; + type mongod_t; + class dir search; + class file { getattr open read }; +} + +#============= mongod_t ============== +allow mongod_t cgroup_t:dir search; +allow mongod_t cgroup_t:file { getattr open read }; diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_proc_net.te b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_proc_net.te new file mode 100644 index 00000000..8804fa2b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_proc_net.te @@ -0,0 +1,10 @@ +module itential_mongodb_proc_net 1.0; + +require { + type proc_net_t; + type mongod_t; + class file { open read }; +} + +#============= mongod_t ============== +allow mongod_t proc_net_t:file { open read }; diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_sysctl_fs.te b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_sysctl_fs.te new file mode 100644 index 00000000..3577b876 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_sysctl_fs.te @@ -0,0 +1,12 @@ +module itential_mongodb_sysctl_fs 1.0; + +require { + type sysctl_fs_t; + type mongod_t; + class dir search; + class file { open read }; +} + +#============= mongod_t ============== +allow mongod_t sysctl_fs_t:dir search; +allow mongod_t sysctl_fs_t:file { open read }; diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_sysctl_net.te b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_sysctl_net.te new file mode 100644 index 00000000..512a699c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_sysctl_net.te @@ -0,0 +1,12 @@ +module itential_mongodb_sysctl_net 1.0; + +require { + type sysctl_net_t; + type mongod_t; + class dir search; + class file { getattr read open }; +} + +#============= mongod_t ============== +allow mongod_t sysctl_net_t:dir search; +allow mongod_t sysctl_net_t:file { getattr read open }; \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_var_lib_nfs.te b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_var_lib_nfs.te new file mode 100644 index 00000000..6135885d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/files/itential_mongodb_var_lib_nfs.te @@ -0,0 +1,10 @@ +module itential_mongodb_var_lib_nfs 1.0; + +require { + type var_lib_nfs_t; + type mongod_t; + class dir search; +} + +#============= mongod_t ============== +allow mongod_t var_lib_nfs_t:dir search; \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/handlers/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/handlers/main.yml new file mode 100644 index 00000000..766d3ba0 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/handlers/main.yml @@ -0,0 +1,6 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Update Itential release file + ansible.builtin.include_tasks: + file: update-release-file.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/adjust-kernel-params.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/adjust-kernel-params.yml new file mode 100644 index 00000000..7db5bc70 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/adjust-kernel-params.yml @@ -0,0 +1,55 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Tune Kernel parameters + +# If you experience network timeouts or socket errors in communication between clients and +# servers, or between members of a sharded cluster or replica set, check the TCP keepalive +# value for the affected systems. +# +# Many operating systems set this value to 7200 seconds (two hours) by default. For MongoDB, +# you will generally experience better results with a shorter keepalive value, on the order +# of 120 seconds (two minutes). +# +# If your MongoDB deployment experiences keepalive-related issues, you must alter the +# keepalive value on all affected systems. This includes all machines running mongod or +# mongos processes and all machines hosting client processes that connect to MongoDB. +- name: Adjust keepalive + ansible.posix.sysctl: + name: net.ipv4.tcp_keepalive_time + value: "{{ mongodb_net_ipv4_tcp_keepalive_time }}" + state: present + sysctl_file: "{{ mongodb_sysctl_file }}" + reload: true + +- name: Increase throughput settings + ansible.posix.sysctl: + name: net.core.somaxconn + value: "{{ mongodb_net_core_somaxconn }}" + state: present + sysctl_file: "{{ mongodb_sysctl_file }}" + reload: true + +- name: Disable zone reclaim mode + ansible.posix.sysctl: + name: vm.zone_reclaim_mode + value: "{{ mongodb_vm_zone_reclaim_mode }}" + state: present + sysctl_file: "{{ mongodb_sysctl_file }}" + reload: true + +- name: Set vm swappiness + ansible.posix.sysctl: + name: vm.swappiness + value: "{{ mongodb_vm_swappiness }}" + state: present + sysctl_file: "{{ mongodb_sysctl_file }}" + reload: true + +- name: Set vm max_map_count + ansible.posix.sysctl: + name: vm.max_map_count + value: "{{ mongodb_vm_max_map_count }}" + state: present + sysctl_file: "{{ mongodb_sysctl_file }}" + reload: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-auth.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-auth.yml new file mode 100644 index 00000000..0cf0e97b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-auth.yml @@ -0,0 +1,90 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# When authorization is enabled in mongo using a replica set, the members of a +# replica set will be required to authenticate to each other. This is accomplished +# with a keyFile or x509 certificate. The following block will create this key file, +# distribute it to each node, and set the appropriate ownership and permissions. +- name: Create replica set keyfile + when: mongodb_replication_enabled | bool + block: + + - name: Ensure PKI base directory exists + ansible.builtin.file: + state: directory + path: "{{ mongodb_pki_base_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_base_dir_mode }}" + + - name: Ensure PKI private directory exists for keyfile + ansible.builtin.file: + state: directory + path: "{{ mongodb_pki_private_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_private_dir_mode }}" + + - name: Check if replica set key exists on the primary node + ansible.builtin.stat: + path: "{{ mongodb_auth_keyfile_destination }}" + when: inventory_hostname == groups['mongodb'][0] + register: keyfile_stat + + # Use openssl to generate a key file on primary mongo node. The primary is the + # first node defined in the host file. The key file is created here once and then + # distributed to each of the other nodes in the replset. They must all have the + # same key file. + - name: Generate a new replica set key with OpenSSL + ansible.builtin.shell: + cmd: openssl rand -base64 756 > "{{ mongodb_auth_keyfile_destination }}" + args: + creates: "{{ mongodb_auth_keyfile_destination }}" + when: + - inventory_hostname == groups['mongodb'][0] + - not keyfile_stat.stat.exists + + - name: Get the key from the primary node + ansible.builtin.slurp: + src: '{{ mongodb_auth_keyfile_destination }}' + register: keyfile + delegate_to: "{{ groups['mongodb'][0] }}" + when: inventory_hostname != groups['mongodb'][0] + + - name: Copy the key file to the secondary nodes + ansible.builtin.copy: + dest: "{{ mongodb_auth_keyfile_destination }}" + content: "{{ keyfile.content | b64decode }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_replica_keyfile_mode }}" + when: inventory_hostname != groups['mongodb'][0] + + - name: Set the key file ownership and permissions + ansible.builtin.file: + path: "{{ mongodb_auth_keyfile_destination }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_replica_keyfile_mode }}" + +# Execute the template to apply changes to the mongo.conf for auth +- name: Create MongoDB config file (auth) + ansible.builtin.template: + src: mongod.conf.j2 + dest: "{{ mongodb_conf_file }}" + owner: "{{ mongodb_owner }}" + group: "{{ mongodb_group }}" + mode: "0644" + vars: + stage: "auth" + +- name: Start mongo (auth) + ansible.builtin.service: + name: mongod + state: restarted + enabled: true + register: mongod_service_result + until: mongod_service_result.status.ActiveState == "active" + retries: "{{ mongodb_mongod_service_retries }}" + delay: "{{ mongodb_mongod_service_delay }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-logrotate.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-logrotate.yml new file mode 100644 index 00000000..c7532a82 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-logrotate.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2025, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: "Insert logRotate: reopen under systemLog in mongod.conf (backward compatibility)" + tags: configure_logrotate + ansible.builtin.lineinfile: + path: "{{ mongodb_conf_file }}" + regexp: '^\\s*logRotate:' + line: ' logRotate: reopen' + insertafter: '^systemLog:' + state: present + +- name: "Deploy logrotate configuration for MongoDB" + tags: configure_logrotate + ansible.builtin.template: + src: mongod.logrotate.j2 + dest: /etc/logrotate.d/mongod + owner: root + group: root + mode: '0644' diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-replicaset.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-replicaset.yml new file mode 100644 index 00000000..14f7698f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-replicaset.yml @@ -0,0 +1,163 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# Check the state of the MongoDB servers. This might or might not be a replicaset. +# This might or might not have authorization enabled. This module returns an +# object that looks like this: +# { +# "auth_enabled": true, +# "changed": false, +# "failed": false, +# "members": [ +# "example1.host.com:27017", +# "example2.host.com:27017", +# "example3.host.com:27017" +# ], +# "primary": "ip-10-0-0-28.ec2.internal:27017", +# "replication_enabled": true +# } +- name: Discover MongoDB configuration state + itential.deployer.mongodb_config_state: + login_database: admin + login_host: "{{ inventory_hostname }}" + login_port: "{{ mongodb_port }}" + register: mongodb_state + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + +- name: Print MongoDB configuration state + ansible.builtin.debug: + msg: "{{ mongodb_state }}" + +# Execute the template to apply changes to the mongo.conf for replication +- name: Create MongoDB config file (replicaset) + ansible.builtin.template: + src: mongod.conf.j2 + dest: "{{ mongodb_conf_file }}" + owner: "{{ mongodb_owner }}" + group: "{{ mongodb_group }}" + mode: "0644" + when: not mongodb_state.replication_enabled + vars: + stage: "replication" + +- name: Start mongo (replicaset) + ansible.builtin.service: + name: mongod + state: restarted + enabled: true + register: mongod_service_result + until: mongod_service_result.status.ActiveState == "active" + retries: "{{ mongodb_mongod_service_retries }}" + delay: "{{ mongodb_mongod_service_delay }}" + when: not mongodb_state.replication_enabled + +- name: Set empty array of mongo servers + ansible.builtin.set_fact: + mongodb_servers: [] + when: not mongodb_state.replication_enabled + +# This task should always run, arbiter or not +- name: Create the replicaset members list (no arbiter) + ansible.builtin.set_fact: + mongodb_servers: "{{ mongodb_servers + [item + ':' + mongodb_port | string] }}" + with_items: "{{ groups.mongodb }}" + when: + - not mongodb_state.replication_enabled + - inventory_hostname in groups.mongodb + - groups.mongodb.index(inventory_hostname) == 0 + +# This task will only run when there is an arbiter defined in the hosts file +- name: Add the arbiter to the list of servers when there is one + ansible.builtin.set_fact: + mongodb_servers: "{{ mongodb_servers + [item + ':' + mongodb_port | string] }}" + with_items: "{{ groups.mongodb_arbiter }}" + when: + - not mongodb_state.replication_enabled + - inventory_hostname in groups.mongodb + - groups.mongodb.index(inventory_hostname) == 0 + - groups.mongodb_arbiter is defined + +- name: Create the replicaset + community.mongodb.mongodb_replicaset: + arbiter_at_index: "{{ (groups.mongodb_arbiter | default([]) | length > 0) | ternary(mongodb_servers | length - 1, omit) }}" + auth_mechanism: "SCRAM-SHA-256" + login_user: "{{ (mongodb_state.auth_enabled | bool) | ternary(mongodb_user_admin, omit) }}" + login_password: "{{ (mongodb_state.auth_enabled | bool) | ternary(mongodb_user_admin_password, omit) }}" + login_port: "{{ mongodb_port }}" + login_database: admin + login_host: "{{ inventory_hostname }}" + members: "{{ mongodb_servers }}" + replica_set: "{{ mongodb_replset_name }}" + validate: true + when: + - not mongodb_state.replication_enabled + - inventory_hostname in groups.mongodb + - groups.mongodb.index(inventory_hostname) == 0 + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + +- name: Ensure replicaset is stable before continuing + community.mongodb.mongodb_status: + login_user: "{{ mongodb_state.auth_enabled | ternary(mongodb_user_admin, omit) }}" + login_password: "{{ mongodb_state.auth_enabled | ternary(mongodb_user_admin_password, omit) }}" + login_port: "{{ mongodb_port }}" + login_database: admin + login_host: "{{ inventory_hostname }}" + replica_set: "{{ mongodb_replset_name }}" + poll: "{{ mongodb_status_poll }}" + interval: "{{ mongodb_status_interval }}" + validate: minimal + register: rs + failed_when: + - "'Unable to determine if auth is enabled' not in rs.msg" + - "'replicaset is in a converged state' not in rs.msg" + when: + - not mongodb_state.replication_enabled + - inventory_hostname in groups.mongodb + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + +# Starting in MongoDB 5.0, the implicit default write concern is w: majority. +# However, special considerations are made for deployments containing arbiters: +# The voting majority of a replica set is 1 plus half the number of voting +# members, rounded down. If the number of data-bearing voting members is not +# greater than the voting majority, the default write concern is { w: 1 }. +# In all other scenarios, the default write concern is { w: "majority" }. +# Specifically, MongoDB uses the following formula to determine the default +# write concern: +# +# if [ (#arbiters > 0) AND (#non-arbiters <= majority(#voting-nodes)) ] +# defaultWriteConcern = { w: 1 } +# else +# defaultWriteConcern = { w: "majority" } +# +# When there are 2 non-arbiters and 1 arbiter for a total of 3 voting nodes, +# the majority of voting nodes (1 plus half of 3, rounded down) is 2. Therefore +# The number of non-arbiters (2) is equal to the majority of voting nodes (2), +# resulting in an implicit write concern of { w: 1 }. When there are 4 +# non-arbiters and 1 arbiter for a total of 5 voting nodes, the majority of +# voting nodes (1 plus half of 5, rounded down) is 3. The number of non-arbiters +# (4) is greater than the majority of voting nodes (3), resulting in an implicit +# write concern of { w: "majority" }. +# +# Thus, conditionally run the following command to force the appropriate +# writeConcern when there is 1 arbiter and 2 non-arbiters. +- name: Adjust the default writeConcern if there are arbiters + community.mongodb.mongodb_shell: + mongo_cmd: auto + login_user: "{{ mongodb_state.auth_enabled | ternary(mongodb_user_admin, omit) }}" + login_password: "{{ mongodb_state.auth_enabled | ternary(mongodb_user_admin_password, omit) }}" + login_port: "{{ mongodb_port }}" + login_database: admin + login_host: "{{ inventory_hostname }}" + eval: db.adminCommand({"setDefaultRWConcern":1,"defaultWriteConcern":{"w":1}}) + when: + - not mongodb_state.replication_enabled + - inventory_hostname in groups.mongodb + - inventory_hostname == mongodb_state.primary + - groups.mongodb | length < 3 + - groups.mongodb_arbiter | default([]) | length > 0 + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-tls.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-tls.yml new file mode 100644 index 00000000..adb4f0b0 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb-tls.yml @@ -0,0 +1,73 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create MongoDB PKI base directory + ansible.builtin.file: + state: directory + path: "{{ mongodb_pki_base_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_base_dir_mode }}" + tags: + - mongodb + - mongodb_certificates + - certificates + +- name: Create MongoDB private directory + ansible.builtin.file: + state: directory + path: "{{ mongodb_pki_private_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_private_dir_mode }}" + tags: + - mongodb + - mongodb_certificates + - certificates + +- name: Copy certificate to MongoDB host if TLS enabled + ansible.builtin.copy: + src: "{{ mongodb_cert_keyfile_source }}" + dest: "{{ mongodb_cert_keyfile_destination }}" + mode: "{{ mongodb_tls_server_cert_mode }}" + group: "{{ mongodb_pki_group }}" + owner: "{{ mongodb_pki_owner }}" + notify: restart mongod + tags: + - mongodb + - mongodb_certificates + - certificates + +- name: Copy CA certificate to MongoDB host if TLS enabled + ansible.builtin.copy: + src: "{{ mongodb_root_ca_file_source }}" + dest: "{{ mongodb_root_ca_file_destination }}" + mode: "{{ mongodb_tls_ca_cert_mode }}" + group: "{{ mongodb_pki_group }}" + owner: "{{ mongodb_pki_owner }}" + notify: restart mongod + tags: + - mongodb + - mongodb_certificates + - certificates + +- name: Create MongoDB config file (TLS) + ansible.builtin.template: + src: mongod.conf.j2 + dest: "{{ mongodb_conf_file }}" + owner: "{{ mongodb_owner }}" + group: "{{ mongodb_group }}" + mode: "0644" + vars: + stage: "tls" + notify: restart mongod + tags: + - mongodb + - mongodb_config + +- name: Flush handlers to restart mongod with TLS config + ansible.builtin.meta: flush_handlers + tags: + - mongodb + - mongodb_certificates + - certificates diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb.yml new file mode 100644 index 00000000..24b9abae --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-mongodb.yml @@ -0,0 +1,23 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# Initialize the replicaset. This requires MongoDB to be in a running state. +# Initiating a replicaset can only happen when authentication is NOT running. +# This step must happen first. +- name: Configure MongoDB replica set + ansible.builtin.include_tasks: + file: configure-mongodb-replicaset.yml + when: mongodb_replication_enabled | bool + +# Configure auth +- name: Configure MongoDB Auth + ansible.builtin.include_tasks: + file: configure-mongodb-auth.yml + when: mongodb_auth_enabled | bool + +# Configure TLS +- name: Configure MongoDB TLS + ansible.builtin.include_tasks: + file: configure-mongodb-tls.yml + when: mongodb_tls_enabled | bool diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-selinux.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-selinux.yml new file mode 100644 index 00000000..ebdde2e7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/configure-selinux.yml @@ -0,0 +1,47 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Configure SELinux + tags: configure_selinux + when: ansible_selinux.status == "enabled" + block: + - name: SELinux - Install custom profiles + ansible.builtin.include_role: + name: selinux + when: > + (mongodb_data_dir != "/var/lib/mongo") or + (mongodb_log_dir != "/var/log/mongodb") + + - name: SELinux - Configure port when using non-standard MongoDB port + community.general.seport: + ports: "{{ mongodb_port }}" + proto: tcp + setype: mongod_port_t + state: present + when: mongodb_port != 27017 + + # If MongoDB is configured to use non-default paths for its data and log + # directories then we need to update the SELinux policy to allow the + # mongod service to use the new directory, it’s worth to note that we + # need to make sure to include the .* at the end of the directory. Then, + # update the SELinux user policy for the new directory. Finally, apply + # the updated SELinux policies to the directory. Do this for data and logs. + - name: SELinux - Configure file context when using non-standard data directory + ansible.builtin.include_role: + name: selinux + tasks_from: configure-context + vars: + selinux_target: "{{ mongodb_data_dir }}.*" + selinux_setype: mongod_var_lib_t + selinux_path: "{{ mongodb_data_dir }}" + when: mongodb_data_dir != "/var/lib/mongo" + + - name: SELinux - Configure file context when using non-standard log directory + ansible.builtin.include_role: + name: selinux + tasks_from: configure-context + vars: + selinux_target: "{{ mongodb_log_dir }}.*" + selinux_setype: mongod_log_t + selinux_path: "{{ mongodb_log_dir }}" + when: mongodb_log_dir != "/var/log/mongodb" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/disable-thp.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/disable-thp.yml new file mode 100644 index 00000000..2de7c2be --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/disable-thp.yml @@ -0,0 +1,90 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# MongoDB 7 and below! +# +# Transparent Huge Pages (THP) is a Linux memory management system that reduces the overhead +# of Translation Lookaside Buffer (TLB) lookups on machines with large amounts of memory by +# using larger memory pages. +# +# However, database workloads often perform poorly with THP enabled, because they tend to +# have sparse rather than contiguous memory access patterns. When running MongoDB on Linux, +# THP should be disabled for best performance. +# +# To ensure that THP is disabled before mongod starts, you should create a service file for +# your platform's initialization system that disables THP at boot. Instructions are provided +# below for both the systemd and the System V init initialization systems. +# +# Additionally, for RHEL / CentOS systems that make use of ktune and tuned performance +# profiles, you must create a custom tuned profile as well. + +# Check if its already disabled +- name: Ensure THP is enabled never + ansible.builtin.lineinfile: + name: /sys/kernel/mm/transparent_hugepage/enabled + line: "always madvise [never]" + state: present + check_mode: true + register: thp_enable_conf + +- name: Ensure THP is defrag never + ansible.builtin.lineinfile: + name: /sys/kernel/mm/transparent_hugepage/defrag + line: "always defer defer+madvise madvise [never]" + state: present + check_mode: true + register: thp_defrag_conf + +# Disable Transparent Huge Pages (THP) if it has not been already +- name: Disable Transparent Huge Pages (THP) + when: + - thp_enable_conf.changed + - thp_defrag_conf.changed + block: + - name: Create systemd unit file + ansible.builtin.template: + src: thp.service.j2 + dest: "/etc/systemd/system/disable-transparent-huge-pages.service" + owner: root + group: root + mode: "0644" + vars: + description: Disable Transparent Hugepages (THP) + command: /bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null && echo never | tee /sys/kernel/mm/transparent_hugepage/defrag > /dev/null' + + - name: Start THP service + ansible.builtin.systemd: + name: disable-transparent-huge-pages.service + state: started + enabled: true + daemon_reload: true + + - name: Install and configure tuned + when: ansible_distribution_file_variety == "RedHat" + block: + - name: Create custom tuned profile directory + ansible.builtin.file: + state: directory + path: "/etc/tuned/virtual-guest-no-thp" + owner: root + group: root + mode: "0755" + + - name: Ensure tuned does not re-enable THP + ansible.builtin.template: + src: tuned.conf.j2 + dest: "/etc/tuned/virtual-guest-no-thp/tuned.conf" + owner: root + group: root + mode: "0644" + vars: + tuned_action: never + + - name: Enable tuned profile + ansible.builtin.command: + cmd: tuned-adm profile virtual-guest-no-thp + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/download-packages-python.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/download-packages-python.yml new file mode 100644 index 00000000..750562bb --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/download-packages-python.yml @@ -0,0 +1,59 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Python RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ mongodb_python_packages }}" + offline_download_dir: "{{ mongodb_offline_target_node_rpms_dir }}" + +- name: Copy RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ mongodb_offline_target_node_rpms_dir }}" + offline_dest_dir: "{{ mongodb_offline_control_node_rpms_dir }}" + +- name: Install Python + ansible.builtin.include_role: + name: python + tags: install_python + vars: + python_packages: "{{ mongodb_python_packages }}" + +- name: Download base Python dependencies + ansible.builtin.import_role: + name: offline + tasks_from: download-wheels + vars: + offline_wheel_files: "{{ mongodb_python_base_dependencies }}" + offline_download_dir: "{{ mongodb_offline_target_node_wheels_dir }}/base" + offline_pip_executable: "{{ mongodb_pip_executable }}" + when: + - mongodb_python_base_dependencies is defined + - mongodb_python_base_dependencies | length > 0 + +- name: Download MongoDB Python dependencies + ansible.builtin.import_role: + name: offline + tasks_from: download-wheels + vars: + offline_with_deps: true + offline_wheel_files: "{{ mongodb_python_app_dependencies }}" + offline_download_dir: "{{ mongodb_offline_target_node_wheels_dir }}/app" + offline_pip_executable: "{{ mongodb_pip_executable }}" + when: + - mongodb_python_app_dependencies is defined + - mongodb_python_app_dependencies | length > 0 + +- name: Uninstall Python RPMs + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + with_items: "{{ python_install_result.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/download-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/download-packages.yml new file mode 100644 index 00000000..2579daa7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/download-packages.yml @@ -0,0 +1,68 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include tasks to validate variables + ansible.builtin.include_tasks: + file: validate-vars.yml + tags: always + +- name: Download MongoDB RPMs + tags: download_mongodb_packages + block: + - name: Install MongoDB repo + ansible.builtin.yum_repository: + name: mongodb + description: MongoDB Repository + baseurl: "{{ mongodb_release_url }}" + enabled: true + gpgcheck: true + gpgkey: "{{ mongodb_gpgkey_url }}" + when: common_install_yum_repos | bool + + - name: Download MongoDB RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ mongodb_packages + mongodb_package_dependencies }}" + offline_download_dir: "{{ mongodb_offline_target_node_rpms_dir }}" + + - name: Copy RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ mongodb_offline_target_node_rpms_dir }}" + offline_dest_dir: "{{ mongodb_offline_control_node_rpms_dir }}" + +- name: Download Python packages + tags: download_python_packages + block: + - name: Download Python packages + ansible.builtin.include_tasks: + file: download-packages-python.yml + + - name: Copy RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ mongodb_offline_target_node_rpms_dir }}" + offline_dest_dir: "{{ mongodb_offline_control_node_rpms_dir }}" + + - name: Copy base Python dependencies to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ mongodb_offline_target_node_wheels_dir }}/base" + offline_dest_dir: "{{ mongodb_offline_control_node_wheels_dir }}/base" + + - name: Copy MongoDB Python dependencies to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ mongodb_offline_target_node_wheels_dir }}/app" + offline_dest_dir: "{{ mongodb_offline_control_node_wheels_dir }}/app" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/enable-thp.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/enable-thp.yml new file mode 100644 index 00000000..38fceb6b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/enable-thp.yml @@ -0,0 +1,80 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Transparent Hugepages (THP) is a Linux memory management system that reduces the overhead +# of Translation Lookaside Buffer (TLB) lookups. THP achieves this by combining small pages +# and making them appear as larger memory pages to the application. +# +# In MongoDB 8.0 and later, ensure that THP is enabled before mongod starts by creating a +# service file for your platform's initialization system. +# +# Additionally, for RHEL and CentOS systems that use ktune and tuned performance profiles, +# you must also create a custom tuned profile. +# +# Check if its already enabled +- name: Ensure THP is enabled always + ansible.builtin.lineinfile: + name: /sys/kernel/mm/transparent_hugepage/enabled + line: "[always] madvise never" + state: present + check_mode: true + register: thp_enable_conf + +- name: Ensure THP is defrag always + ansible.builtin.lineinfile: + name: /sys/kernel/mm/transparent_hugepage/defrag + line: "always defer [defer+madvise] madvise never" + state: present + check_mode: true + register: thp_defrag_conf + +- name: Enable Transparent Huge Pages (THP) + when: thp_enable_conf.changed or thp_defrag_conf.changed + block: + - name: Create systemd unit file + ansible.builtin.template: + src: thp.service.j2 + dest: "/etc/systemd/system/enable-transparent-huge-pages.service" + owner: root + group: root + mode: "0644" + vars: + description: Enable Transparent Hugepages (THP) + command: /bin/sh -c 'echo always | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null && echo defer+madvise | tee /sys/kernel/mm/transparent_hugepage/defrag > /dev/null && echo 0 | tee /sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none > /dev/null && echo 1 | tee /proc/sys/vm/overcommit_memory > /dev/null' + + - name: Start THP service + ansible.builtin.systemd: + name: enable-transparent-huge-pages.service + state: started + enabled: true + daemon_reload: true + + - name: Install and configure tuned + when: ansible_distribution_file_variety == "RedHat" + block: + - name: Create custom tuned profile directory + ansible.builtin.file: + state: directory + path: "/etc/tuned/virtual-guest-no-thp" + owner: root + group: root + mode: "0755" + + - name: Ensure tuned does not re-enable THP + ansible.builtin.template: + src: tuned.conf.j2 + dest: "/etc/tuned/virtual-guest-no-thp/tuned.conf" + owner: root + group: root + mode: "0644" + vars: + tuned_action: always + + - name: Enable tuned profile + ansible.builtin.command: + cmd: tuned-adm profile virtual-guest-no-thp + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb-offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb-offline.yml new file mode 100644 index 00000000..2e06844a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb-offline.yml @@ -0,0 +1,15 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Allow yum to update MongoDB packages + ansible.builtin.lineinfile: + path: /etc/yum.conf + line: exclude=mongodb-org* + state: absent + +- name: Install MongoDB RPMs (offline) + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ mongodb_offline_control_node_rpms_dir }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb-online.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb-online.yml new file mode 100644 index 00000000..6065ab46 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb-online.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Mongo dependency packages + ansible.builtin.dnf: + name: "{{ mongodb_package_dependencies }}" + state: present + update_cache: true + +# Install the mongodb repo if mongodb is not already installed +- name: Install MongoDB repo + ansible.builtin.yum_repository: + name: "mongodb" + description: MongoDB Repository + baseurl: "{{ mongodb_release_url }}" + enabled: true + gpgcheck: true + gpgkey: "{{ mongodb_gpgkey_url }}" + when: + - common_install_yum_repos | bool + - "'mongodb-org' not in ansible_facts.packages" + +# Install mongodb if mongodb is not already installed +- name: Install MongoDB packages + ansible.builtin.dnf: + name: "{{ mongodb_packages }}" + state: present + when: "'mongodb-org' not in ansible_facts.packages" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb.yml new file mode 100644 index 00000000..d2d1784b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-mongodb.yml @@ -0,0 +1,170 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install MongoDB packages + tags: install_mongodb_packages + block: + - name: Get the list of installed packages + ansible.builtin.package_facts: + manager: "auto" + + - name: Install MongoDB packages + ansible.builtin.include_tasks: + file: install-mongodb-online.yml + when: not offline_install_enabled + + - name: Install MongoDB packages (offline) + ansible.builtin.include_tasks: + file: install-mongodb-offline.yml + when: offline_install_enabled + +# Update dnf config to prevent mongodb from getting updated by dnf updates +- name: Prevent dnf from updating mongo + ansible.builtin.lineinfile: + path: /etc/dnf/dnf.conf + line: exclude=mongodb-org* + +- name: Create MongoDB log, data, pid directories + ansible.builtin.file: + state: directory + path: "{{ item }}" + owner: "{{ mongodb_owner }}" + group: "{{ mongodb_group }}" + mode: "0755" + loop: + - "{{ mongodb_data_dir }}" + - "{{ mongodb_log_dir }}" + - "{{ mongodb_pid_dir }}" + +- name: Install Python + ansible.builtin.include_tasks: + file: install-python.yml + tags: install_python + +- name: Disable Transparent Huge Pages (THP) and configure tuned when mongodb version < 8.0 + ansible.builtin.import_tasks: + file: disable-thp.yml + when: mongodb_version | float < 8.0 + +- name: Enable Transparent Huge Pages (THP) and configure tuned when mongodb version >= 8.0 + ansible.builtin.import_tasks: + file: enable-thp.yml + when: mongodb_version | float >= 8.0 + +- name: Adjust Kernel parameters + ansible.builtin.import_tasks: + file: adjust-kernel-params.yml + +- name: Configure SELinux + ansible.builtin.include_tasks: + file: configure-selinux.yml + tags: configure_selinux + when: + - ansible_facts.selinux.status == 'enabled' + - ansible_facts.selinux.mode == 'enforcing' + +- name: Configure logrotate for MongoDB + ansible.builtin.include_tasks: + file: configure-mongodb-logrotate.yml + tags: configure_logrotate + +# Check if firewalld is running, if it is then open the appropriate ports +- name: Gather service facts + ansible.builtin.service_facts: + +- name: Open Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ mongodb_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +# The config file will be generated a few times as we go through the process +# of configuring MongoDB. This first time we will ignore any of the auth, TLS, +# and replication settings. The reason is so that we can create the database +# users. That can not be done if all of these features are enabled. The +# variable "stage" is used to provide this template context. When stage is +# "initialize" the template will be forced to create a simple config. +- name: Create MongoDB config file (initial) + ansible.builtin.template: + src: mongod.conf.j2 + dest: "{{ mongodb_conf_file }}" + owner: "{{ mongodb_owner }}" + group: "{{ mongodb_group }}" + mode: "0644" + vars: + stage: initialize + tags: initialize_mongo_config + +- name: Start mongo (initial) + ansible.builtin.service: + name: mongod + state: restarted + enabled: true + register: mongod_service_result + until: mongod_service_result.status.ActiveState == "active" + retries: "{{ mongodb_mongod_service_retries }}" + delay: "{{ mongodb_mongod_service_delay }}" + tags: initialize_mongo_config + +- name: Discover MongoDB configuration state + tags: create_mongo_users + itential.deployer.mongodb_config_state: + login_database: admin + login_host: "{{ inventory_hostname }}" + login_port: "{{ mongodb_port }}" + register: mongodb_state + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + +- name: Print MongoDB configuration state + tags: create_mongo_users + ansible.builtin.debug: + msg: "{{ mongodb_state }}" + +- name: Add users to database + when: inventory_hostname == groups['mongodb'][0] + tags: create_mongo_users + block: + # The tasks in this file should only run on one host if configuring a replica set + # This creates the admin user that has root access to the database. + - name: Add admin user to database + community.mongodb.mongodb_user: + login_user: "{{ mongodb_user_admin if mongodb_state.auth_enabled else omit }}" + login_password: "{{ mongodb_user_admin_password if mongodb_state.auth_enabled else omit }}" + login_port: "{{ mongodb_port }}" + login_host: "{{ mongodb_state.primary if mongodb_state.replication_enabled else groups['mongodb'][0] }}" + database: "{{ mongodb_admin_db_name }}" + name: "{{ mongodb_user_admin }}" + password: "{{ mongodb_user_admin_password }}" + state: present + roles: + - db: "{{ mongodb_admin_db_name }}" + role: root + update_password: always + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" + + # This creates the itential user that only has read & write access to the + # itential database. It is used by Itential Platform to connect to the db. + - name: Add itential user to database + community.mongodb.mongodb_user: + login_user: "{{ mongodb_user_admin if mongodb_state.auth_enabled else omit }}" + login_password: "{{ mongodb_user_admin_password if mongodb_state.auth_enabled else omit }}" + login_port: "{{ mongodb_port }}" + login_host: "{{ mongodb_state.primary if mongodb_state.replication_enabled else groups['mongodb'][0] }}" + database: "{{ mongodb_itential_db_name }}" + user: "{{ mongodb_user_itential }}" + password: "{{ mongodb_user_itential_password }}" + state: present + roles: + - db: "{{ mongodb_itential_db_name }}" + role: readWrite + update_password: always + vars: + ansible_python_interpreter: "{{ mongodb_python_venv }}/bin/python3" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-python.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-python.yml new file mode 100644 index 00000000..34a9e334 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/install-python.yml @@ -0,0 +1,55 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Python and its dependencies + tags: install_python + block: + + - name: Install Python + ansible.builtin.include_role: + name: python + vars: + python_executable: "{{ mongodb_python_executable }}" + python_packages: "{{ mongodb_python_packages }}" + + - name: Check if python virtual environment already exists + ansible.builtin.stat: + path: "{{ mongodb_python_venv }}" + register: mongodb_python_venv_check + + - name: Setup python virtual environment + ansible.builtin.command: + chdir: "{{ mongodb_python_venv_root }}" + cmd: "{{ mongodb_python_executable }} -m venv {{ mongodb_python_venv_name }}" + register: mongodb_python_venv_result + changed_when: mongodb_python_venv_result.changed + when: not mongodb_python_venv_check.stat.exists + + - name: Install Python dependencies + ansible.builtin.include_role: + name: python + tasks_from: install-dependencies + vars: + python_venv: "{{ mongodb_python_venv }}" + python_base_dependencies: "{{ mongodb_python_base_dependencies }}" + python_app_dependencies: "{{ mongodb_python_app_dependencies }}" + when: not offline_install_enabled + + - name: Install Python dependencies (offline) + when: offline_install_enabled + block: + - name: Install base Python dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-wheels + vars: + offline_wheels_dir: "{{ mongodb_offline_control_node_wheels_dir }}/base" + offline_python_venv: "{{ mongodb_python_venv }}" + + - name: Install application Python dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-wheels + vars: + offline_wheels_dir: "{{ mongodb_offline_control_node_wheels_dir }}/app" + offline_python_venv: "{{ mongodb_python_venv }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/main.yml new file mode 100644 index 00000000..da67a34d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/main.yml @@ -0,0 +1,31 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include tasks to validate variables + ansible.builtin.include_tasks: + file: validate-vars.yml + tags: always + +# Installs all the necessary components and dependencies for MongoDB. +# This will start the server with the simplest config. +- name: Install MongoDB and all necessary components + ansible.builtin.import_tasks: + file: install-mongodb.yml + notify: Update Itential release file + tags: install_mongodb + +# This will configure MongoDB according to the variables defined in the +# hosts file. If auth, tls, nor replication are enabled then this can be +# safely skipped. +- name: Configure MongoDB according to host file variables + ansible.builtin.import_tasks: + file: configure-mongodb.yml + tags: configure_mongodb + when: mongodb_auth_enabled | bool or mongodb_tls_enabled | bool or mongodb_replication_enabled | bool + +- name: Assert that MongoDB is running + ansible.builtin.systemd: + name: mongod + register: mongodb_status + failed_when: mongodb_status.status.ActiveState != "active" + tags: always diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/preflight.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/preflight.yml new file mode 100644 index 00000000..59dc05f9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/preflight.yml @@ -0,0 +1,73 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "{{ iap_release }}-{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + tags: always + + +- name: Run common checks + ansible.builtin.include_role: + name: preflight + vars: + preflight_url_checks: + - "{{ mongodb_release_url }}" + - "{{ mongodb_gpgkey_url }}" + +- name: Get avx cpu info + ansible.builtin.command: grep avx /proc/cpuinfo + register: avx_cpuinfo + changed_when: true + +- name: Set avx variable + ansible.builtin.set_fact: + avx: "{{ 'supported' if ('avx' in avx_cpuinfo['stdout']) else 'not supported' }}" + +- name: Set avx + ansible.builtin.set_fact: + results: '{{ results | combine({"avx": avx}) }}' + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: workingdir + +- name: Set pass to true if all conditions pass + ansible.builtin.set_fact: + results: '{{ results | combine({"pass": true}) }}' + when: + - results.cpuCores >= mongodb_cpu_cores + - results.get(mountvarname, 0) >= mongodb_free_disk_space + - results.memory >= mongodb_ram + - results.url_status.values() | unique | length == 1 and results.url_status.values() | unique | first == 200 + - results.avx == 'supported' + +- name: Create MongoDB preflight results + ansible.builtin.template: + src: "mongodb.preflight.j2" + dest: "{{ workingdir.path }}/mongodbPreflightResults.txt" + mode: '0777' + +- name: Fetch MongoDB results + ansible.builtin.fetch: + src: "{{ workingdir.path }}/mongodbPreflightResults.txt" + dest: "{{ preflight_directory }}/mongodb_{{ inventory_hostname }}_results.txt" + flat: true + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent + +- name: Check if host passed preflight checks. + ansible.builtin.assert: + that: results["pass"] == true + fail_msg: "MongoDB host did not pass the preflight checks" + success_msg: "MongoDB host passed the preflight checks" + when: + - preflight_enforce_checks is defined + - preflight_enforce_checks diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/update-release-file.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/update-release-file.yml new file mode 100644 index 00000000..e91f25f1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/update-release-file.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Determine MongoDB version + ansible.builtin.shell: + cmd: set -o pipefail && mongod --version | grep "db version" | cut -d" " -f3 + register: result + check_mode: false + changed_when: false + failed_when: result.rc != 0 and result.rc != 127 + +- name: Write MongoDB release information + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: '^MONGODB=' + line: "MONGODB={{ result.stdout }}" + create: true + mode: "0644" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/validate-vars.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/validate-vars.yml new file mode 100644 index 00000000..f6fd378e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/tasks/validate-vars.yml @@ -0,0 +1,79 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate and set installation variables + tags: always + block: + - name: Validate an installation variable is set + ansible.builtin.assert: + that: > + (platform_release is defined) or + (mongodb_version is defined and + mongodb_packages is defined and + mongodb_python_packages is defined) + fail_msg: >- + platform_release must be defined OR + mongodb_version, mongodb_packages, and mongodb_python_packages must be defined + + - name: Validate installation variables when not using platform_release + ansible.builtin.assert: + that: + - mongodb_version is defined + - mongodb_packages is defined + - mongodb_python_packages is defined + fail_msg: >- + mongodb_version, mongodb_packages, and mongodb_python_packages + must be defined when platform_release is not defined + when: platform_release is not defined + + - name: Set installation variables when using Itential Platform release defaults + when: platform_release is defined + block: + - name: Load Itential Platform release default variables + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "platform-release-{{ platform_release }}.yml" + - "platform-release-{{ platform_release | string | split('.') | first }}.yml" + - "platform-release-undefined.yml" + + - name: Check for valid MongoDB release + ansible.builtin.assert: + that: mongodb_invalid_platform_release is not defined + fail_msg: >- + Deployer does not support installing MongoDB + for Itential Platform release {{ platform_release }} + + - name: Set mongodb_version to the default value when not defined in inventory + ansible.builtin.set_fact: + mongodb_version: "{{ mongodb_version_default[ansible_distribution_major_version] }}" + when: mongodb_version is not defined + + - name: Set mongodb_packages to the default value when not defined in inventory + ansible.builtin.set_fact: + mongodb_packages: "{{ mongodb_packages_default[ansible_distribution_major_version] }}" + when: mongodb_packages is not defined + + - name: Set mongodb_python_packages to the default value when not defined in inventory + ansible.builtin.set_fact: + mongodb_python_packages: "{{ mongodb_python_packages_default[ansible_distribution_major_version] }}" + when: mongodb_python_packages is not defined + + - name: Set mongodb_gpgkey_url to the default value when not defined in inventory + ansible.builtin.set_fact: + mongodb_gpgkey_url: "{{ mongodb_gpgkey_url_default[ansible_distribution_major_version] }}" + when: mongodb_gpgkey_url is not defined + + - name: Set mongodb_package_dependencies to the default value when not defined in inventory + ansible.builtin.set_fact: + mongodb_package_dependencies: "{{ mongodb_package_dependencies_default[ansible_distribution_major_version] }}" + when: mongodb_package_dependencies is not defined + + - name: Print MongoDB installation details + ansible.builtin.debug: + msg: + - "MongoDB version: {{ mongodb_version }}" + - "MongoDB packages: {{ mongodb_packages }}" + - "MongoDB dependency packages: {{ mongodb_package_dependencies }}" + - "Python packages: {{ mongodb_python_packages }}" + when: not offline_install_enabled diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongod.conf.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongod.conf.j2 new file mode 100644 index 00000000..4ba4e58d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongod.conf.j2 @@ -0,0 +1,107 @@ +{%- set authMode = "disabled" %} +{%- set tlsMode = "disabled" %} +{%- if (stage != "initialize" and stage != "replication") and mongodb_auth_enabled | bool %} + {%- set authMode = "enabled" %} +{%- endif %} +{%- if stage == "tls" and mongodb_tls_enabled | bool %} + {%- set tlsMode = "requireTLS" %} +{%- endif %} +# mongod.conf + +# For documentation of all options, see: +# http://docs.mongodb.org/manual/reference/configuration-options/ + +# Where to write logging data. +systemLog: + destination: file + logAppend: true + # Required for external log rotation (logrotate). + logRotate: reopen + path: {{ mongodb_log_dir }}/mongod.log + +# Where and how to store data. +storage: + # The directory where the mongod instance stores its data. + dbPath: {{ mongodb_data_dir }} +{% if (mongodb_version is not defined) or (mongodb_version | float < 7.0) -%} + # Enable or disable the durability journal to ensure data files remain + # valid and recoverable. + journal: + enabled: true +{%- endif %} + # The storage engine for the mongod database. + engine: wiredTiger + +{% if (mongodb_version is not defined) or (mongodb_version | float < 5.0) -%} +# How the process runs +processManagement: + fork: true + pidFilePath: /var/run/mongodb/mongod.pid +{%- endif -%} + +# Security +security: + authorization: {{ authMode }} +{% if (stage != "initialize" and stage != "replication") and mongodb_auth_enabled | bool and mongodb_replication_enabled | bool %} + # The path to a key file that stores the shared secret that MongoDB + # instances use to authenticate to each other in a sharded cluster + # or replica set. Not required for standalone instance. + keyFile: {{ mongodb_auth_keyfile_destination }} +{% endif %} + +# Network Interfaces & TLS Settings +net: + # The TCP port on which the MongoDB instance listens for client connections. + port: {{ mongodb_port }} + ipv6: {{ mongodb_bind_ipv6 | to_nice_json }} + + # The hostnames and/or IP addresses and/or full Unix domain socket paths on + # which mongos or mongod should listen for client connections. You may attach + # mongos or mongod to any interface. To bind to multiple addresses, enter a + # list of comma-separated values. + bindIp: {{ mongodb_bind_ipv6 | ternary('::1, ', None) }}{{ mongodb_bind_addrs }}, {{ inventory_hostname }} + + # Specifies the default compressor(s) to use for communication between this + # mongod or mongos instance and other members of the deployment if the + # instance is part of a replica set or a sharded cluster, mongosh, drivers + # that support the OP_COMPRESSED message format. MongoDB supports the following + # compressors: snappy, zlib, zstd. To disable network compression, set the + # value to disabled. + compression: + compressors: disabled + + tls: + mode: {{ tlsMode }} + +{% if stage == "tls" and mongodb_tls_enabled | bool %} + # The .pem file that contains both the TLS certificate and key. + certificateKeyFile: {{ mongodb_cert_keyfile_destination }} + + # The .pem file that contains the root certificate chain from the + # Certificate Authority. Specify the file name of the .pem file + # using relative or absolute paths. + CAFile: {{ mongodb_root_ca_file_destination }} + + # For clients that do not present certificates, mongod bypasses + # TLS/SSL certificate validation when establishing the connection. + allowConnectionsWithoutCertificates: true + + # Enable or disable the validation checks for TLS certificates on + # other servers in the cluster and allows the use of invalid + # certificates to connect. + allowInvalidCertificates: true + + # When net.tls.allowInvalidHostnames is true, MongoDB disables the + # validation of the hostnames in TLS certificates, allowing mongod + # to connect to MongoDB instances if the hostname their certificates + # do not match the specified hostname. + allowInvalidHostnames: true +{% endif %} + +{% if stage != "initialize" and mongodb_replication_enabled | bool %} +# Replication Settings +replication: + # The name of the replica set that the mongod is part of. All hosts + # in the replica set must have the same set name. + replSetName: {{ mongodb_replset_name }} +{% endif %} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongod.logrotate.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongod.logrotate.j2 new file mode 100644 index 00000000..bba9a93f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongod.logrotate.j2 @@ -0,0 +1,37 @@ +# Logrotate configuration for MongoDB logs +# ----------------------------------------------------- +# This file is managed by Ansible. +# Safe to edit, but if you re-run automation, it may be overwritten. +# +# To customize retention, compression, or post-rotate actions, edit below. +# You can change values such as 'rotate', 'daily', or the 'create' directive +# as needed for your environment. + +{{ mongodb_log_dir }}/mongod.log { + # How often to rotate (change to weekly/monthly if desired) + daily + + # How many rotations to keep (increase/decrease as needed) + rotate 7 + + # Enable compression for old logs (can comment to disable) + compress + delaycompress + + # Don't complain if log is missing or empty + missingok + notifempty + + # File permissions & ownership for new logs + create 0640 {{ mongodb_owner }} {{ mongodb_group }} + + # Ensures only one rotation at a time if multiple logs exist + sharedscripts + + # What to do after rotation (do not remove HUP unless you know what you are doing) + postrotate + /bin/kill -USR1 $(/usr/bin/pgrep -xo mongod) >/dev/null 2>&1 || true + endscript +} + +# For further options, see 'man logrotate' or consult Ansible role documentation. \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongodb.preflight.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongodb.preflight.j2 new file mode 100644 index 00000000..c7b0e8bf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/mongodb.preflight.j2 @@ -0,0 +1,19 @@ +Name: {{results['name']}} +Role: MongoDB +Pass: {{results['pass']}} + + +SELinux | {{results['SELinux']}} +avx | {{results['avx']}} +http_proxy | {{ 'Yes' if results['http_proxy'] else 'None'}} +https_proxy | {{ 'Yes' if results['https_proxy'] else 'None'}} +IPv6 | {{ 'Enabled' if results['ipv6'] else 'Disabled'}} + +CPU | {{ 'Pass' if results['cpuCores'] >= mongodb_cpu_cores else 'FAIL'}} | Cores: {{results['cpuCores']}} Req: {{mongodb_cpu_cores}} +HDD | {{ 'Pass' if results['/_sizeAvailable'] >= mongodb_free_disk_space else 'FAIL'}} | Free: {{results['/_sizeAvailable']}} on {{results['mount']}} Req: {{mongodb_free_disk_space}} +Memory | {{ 'Pass' if results['memory'] >= mongodb_ram else 'FAIL'}} | Free: {{results['memory']}} Req: {{mongodb_ram}} + +URL | Status +{% for key, value in results['url_status'].items() %} +{{key}} | {{value}} +{% endfor %} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/thp.service.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/thp.service.j2 new file mode 100644 index 00000000..5dd3733a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/thp.service.j2 @@ -0,0 +1,12 @@ +[Unit] +Description={{ description }} +DefaultDependencies=no +After=sysinit.target local-fs.target +Before=mongod.service + +[Service] +Type=oneshot +ExecStart={{ command }} + +[Install] +WantedBy=basic.target \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/tuned.conf.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/tuned.conf.j2 new file mode 100644 index 00000000..638b8772 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/templates/tuned.conf.j2 @@ -0,0 +1,5 @@ +[main] +include=virtual-guest + +[vm] +transparent_hugepages={{ tuned_action }} diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/main.yml new file mode 100644 index 00000000..3aa723a3 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/main.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The default port +mongodb_port_default: 27017 + +# The name of the mongo replica set +mongodb_replset_name_default: rs0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/platform-release-6.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/platform-release-6.yml new file mode 100644 index 00000000..861664c9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/platform-release-6.yml @@ -0,0 +1,52 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +mongodb_version_default: + "8": 8.0 + "9": 8.0 + "2023": 8.0 + +mongodb_packages_default: + "8": + - mongodb-org + "9": + - mongodb-org + "2023": + - mongodb-org + - mongodb-mongosh-shared-openssl3 + +mongodb_package_dependencies_default: + "8": + - selinux-policy + - selinux-policy-targeted + - audit + - tuned + "9": + - selinux-policy + - selinux-policy-targeted + - audit + - tuned + "2023": + - selinux-policy + - selinux-policy-targeted + - audit + +# MongoDB doesn't require python, pip, or pymongo but the community.mongodb collection does. +mongodb_python_packages_default: + "8": + - python39 + - python39-pip + "9": + - python3 + - python3-pip + "2023": + - python3 + - python3-pip + +mongodb_gpgkey_url_default: + "8": + - https://www.mongodb.org/static/pgp/server-{{ mongodb_version }}.asc + "9": + - https://www.mongodb.org/static/pgp/server-{{ mongodb_version }}.asc + "2023": + - https://pgp.mongodb.com/server-{{ mongodb_version }}.asc diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/platform-release-undefined.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/platform-release-undefined.yml new file mode 100644 index 00000000..0f19135e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/mongodb/vars/platform-release-undefined.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +mongodb_invalid_platform_release: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-adapter.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-adapter.yml new file mode 100644 index 00000000..c5128a58 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-adapter.yml @@ -0,0 +1,81 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_download_dir is set + ansible.builtin.assert: + that: offline_download_dir is defined + msg: "offline_download_dir must be set" + +- name: Validate offline_adapter is set + ansible.builtin.assert: + that: offline_adapter is defined + msg: "offline_adapter must be set" + +- name: Parse adapter name + ansible.builtin.set_fact: + adapter_name: "{{ offline_adapter | basename | split('.') | first }}" + +- name: Git clone adapter # noqa: latest (always clone the latest) + ansible.builtin.git: + repo: "{{ offline_adapter }}" + dest: "{{ offline_download_dir }}/{{ adapter_name }}" + force: true + when: (offline_adapter | basename | split('.') | last) == "git" + +- name: Unzip {{ offline_adapter }} + ansible.builtin.unarchive: + src: "{{ offline_adapter }}" + dest: "{{ offline_download_dir }}" + when: (offline_adapter | basename | split('.') | last) == "zip" + +- name: Delete package-lock.json file + ansible.builtin.file: + path: "{{ offline_download_dir }}/{{ adapter_name }}/package-lock.json" + state: absent + when: platform_delete_package_lock_file + +- name: Install {{ adapter_name }} + ansible.builtin.command: + cmd: npm install + args: + chdir: "{{ offline_download_dir }}/{{ adapter_name }}" + changed_when: true + +# The bundleDependencies defines an array of package names that will be bundled +# when publishing the package. This really should be defined in the package.json +# when it's downloaded. If it is not already defined, set it to true. A value of true +# will bundle all dependencies. +- name: Check if dependencies is already defined in package.json + ansible.builtin.lineinfile: + state: absent + path: "{{ offline_download_dir }}/{{ adapter_name }}/package.json" + regexp: '"dependencies":' + check_mode: true + changed_when: false + register: dependencies_check + +- name: Check if bundleDependencies is already defined in package.json + ansible.builtin.lineinfile: + state: absent + path: "{{ offline_download_dir }}/{{ adapter_name }}/package.json" + regexp: '"bundleDependencies":' + check_mode: true + changed_when: false + register: bundle_dependencies_check + +- name: Define bundleDependencies if undefined + ansible.builtin.lineinfile: + state: present + path: "{{ offline_download_dir }}/{{ adapter_name }}/package.json" + line: ' "bundleDependencies": true,' + insertbefore: '^\s*"dependencies"\s*:\s*{' + when: + - dependencies_check.found == 1 + - bundle_dependencies_check.found == 0 + +- name: Re-pack {{ adapter_name }} + ansible.builtin.command: + cmd: npm pack "{{ adapter_name }}/" + args: + chdir: "{{ offline_download_dir }}" + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-adapters.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-adapters.yml new file mode 100644 index 00000000..60ffde76 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-adapters.yml @@ -0,0 +1,25 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_download_dir is set + ansible.builtin.assert: + that: offline_download_dir is defined + msg: "offline_download_dir must be set" + +- name: Validate offline_adapters is set + ansible.builtin.assert: + that: offline_adapters is defined + msg: "offline_adapters must be set" + +- name: Create download directory + ansible.builtin.file: + path: "{{ offline_download_dir }}" + state: directory + mode: '0755' + +- name: Download adapter + ansible.builtin.include_tasks: + file: download-adapter.yml + loop: "{{ offline_adapters }}" + loop_control: + loop_var: offline_adapter diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-rpms.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-rpms.yml new file mode 100644 index 00000000..a067a2e5 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-rpms.yml @@ -0,0 +1,104 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate required variables are set + ansible.builtin.assert: + that: + - offline_download_dir is defined + - offline_download_method is defined + - offline_download_packages is defined + msg: offline_download_dir, offline_download_method and offline_download_packages must be set + +- name: Validate offline_download_method method + ansible.builtin.assert: + that: offline_download_method in + ['yum_module', 'yum_install', 'yum_reinstall', 'repotrack', 'yumdownloader', 'get_url'] + msg: invalid download method + +- name: Download packages + when: + - offline_download_packages is defined + - offline_download_packages is iterable + - offline_download_packages | length > 0 + block: + - name: Create download directory + ansible.builtin.file: + path: "{{ offline_download_dir }}" + state: directory + mode: '0755' + + - name: Download packages (ansible dnf module) + ansible.builtin.dnf: + name: "{{ offline_download_packages }}" + state: present + download_only: true + download_dir: "{{ offline_download_dir }}" + when: offline_download_method == "yum_module" + + - name: Download packages (yum install) # noqa command-instead-of-module + ansible.builtin.command: + cmd: "yum install --downloadonly --downloaddir {{ offline_download_dir }} + -y {{ offline_download_packages }}" + changed_when: true + when: offline_download_method == "yum_install" + + - name: Download packages (yum reinstall) # noqa command-instead-of-module + ansible.builtin.command: + cmd: "yum reinstall --downloadonly --downloaddir {{ offline_download_dir }} + -y {{ offline_download_packages }}" + changed_when: true + when: offline_download_method == "yum_reinstall" + + - name: Download packages (repotrack) + ansible.builtin.command: + cmd: "repotrack {{ offline_download_packages | join(' ') }}" + args: + chdir: "{{ offline_download_dir }}" + changed_when: true + when: offline_download_method == "repotrack" + + - name: Use yumdownloader + when: offline_download_method == "yumdownloader" + block: + - name: Install Yum utils + ansible.builtin.dnf: + name: yum-utils + state: present + + - name: Download packages (yumdownloader) + ansible.builtin.command: + cmd: "yumdownloader --resolve --downloaddir {{ offline_download_dir }} + {{ offline_download_packages | join(' ') }}" + changed_when: true + failed_when: false + + - name: Download packages (get_url) + ansible.builtin.get_url: + url: "{{ package }}" + dest: "{{ offline_download_dir }}" + mode: '0755' + # Sets the appropriate header based on the repository type: + # - For JFrog: Uses the "X-JFrog-Art-Api" header with the API key if + # "repository_api_key" is defined and "jfrog" is part of the download URL. + # - For Gitlab: Uses the "PRIVATE-TOKEN" header with the API key if + # "repository_api_key" is defined and "gitlab" is part of the download URL. + # - For Nexus: Uses a default header ("Accept: application/octet-stream") since + # Nexus doesn't support API key authentication. + headers: >- + {%- if repository_api_key is defined and package is search("jfrog") -%} + {"X-JFrog-Art-Api": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- elif repository_api_key is defined and package is search("gitlab") -%} + {"PRIVATE-TOKEN": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- else -%} + {"Accept": "application/octet-stream"} + {%- endif -%} + url_username: "{{ repository_username | default(omit) }}" + url_password: "{{ repository_password | default(omit) }}" + validate_certs: true + loop: "{{ offline_download_packages }}" + loop_control: + loop_var: package + when: + - offline_download_method == "get_url" + - "'http' in package" + - package.endswith('.rpm') diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-wheels.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-wheels.yml new file mode 100644 index 00000000..8a082337 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/download-wheels.yml @@ -0,0 +1,43 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_download_dir is set + ansible.builtin.assert: + that: offline_download_dir is defined + msg: "offline_download_dir must be set" + +- name: Validate offline_pip_executable is set + ansible.builtin.assert: + that: offline_pip_executable is defined + msg: "offline_pip_executable must be set" + +- name: Validate offline_wheel_files is set + ansible.builtin.assert: + that: offline_wheel_files is defined + msg: "offline_wheel_files must be set" + +- name: Create download directory + ansible.builtin.file: + path: "{{ offline_download_dir }}" + state: directory + mode: '0755' + +# When the --no-deps option is used, package dependencies will not be downloaded. +- name: Download wheel files (no deps) + ansible.builtin.command: + cmd: "{{ offline_pip_executable }} download --no-deps {{ offline_wheel_files | join(' ') }}" + args: + chdir: "{{ offline_download_dir }}" + changed_when: true + when: offline_with_deps is not defined or not offline_with_deps | bool + +# Package dependencies will be downloaded. +- name: Download wheel files (with deps) + ansible.builtin.command: + cmd: "{{ offline_pip_executable }} download {{ offline_wheel_files | join(' ') }}" + args: + chdir: "{{ offline_download_dir }}" + changed_when: true + when: + - offline_with_deps is defined + - offline_with_deps | bool diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/fetch-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/fetch-packages.yml new file mode 100644 index 00000000..0fc6a8c1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/fetch-packages.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_src_dir is set + ansible.builtin.assert: + that: offline_src_dir is defined + msg: "offline_src_dir must be set" + +- name: Validate offline_dest_dir is set + ansible.builtin.assert: + that: offline_dest_dir is defined + msg: "offline_dest_dir must be set" + +- name: Find downloaded packages + ansible.builtin.find: + paths: "{{ offline_src_dir }}" + register: packages + +- name: Copy packages to control node + ansible.builtin.fetch: + src: "{{ item.path }}" + dest: "{{ offline_dest_dir }}/" + flat: true + with_items: "{{ packages.files }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-adapter.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-adapter.yml new file mode 100644 index 00000000..9febdf59 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-adapter.yml @@ -0,0 +1,65 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_src_adapters_path is set + ansible.builtin.assert: + that: offline_src_adapters_path is defined + msg: "offline_src_adapters_path must be set" + +- name: Validate offline_dest_adapters_path is set + ansible.builtin.assert: + that: offline_dest_adapters_path is defined + msg: "offline_dest_adapters_path must be set" + +- name: Validate adapter_name is set + ansible.builtin.assert: + that: adapter_name is defined + msg: "adapter_name must be set" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: install_adapters_temp_dir + +- name: Copy adapter to target node + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ install_adapters_temp_dir.path }}" + mode: '0644' + with_fileglob: "{{ offline_src_adapters_path }}/*{{ adapter_name }}-*.tgz" + +- name: Find adapter on target node + ansible.builtin.find: + paths: "{{ install_adapters_temp_dir.path }}" + patterns: "*{{ adapter_name }}-*.tgz" + register: adapter_list + +- name: Validate adapter exists + ansible.builtin.fail: + msg: "{{ adapter_name }} does not exist in {{ offline_src_adapters_path }}, re-run download" + when: adapter_list.files | length == 0 + +- name: Create adapter destination + ansible.builtin.file: + name: "{{ offline_dest_adapters_path }}/{{ adapter_name }}" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: '0775' + state: directory + +# The --transform option will transform (rename) files and directories. +# In our case, we need to rename the root directory of the adapter from +# 'package' to the name of the adapter name. +- name: Extract adapter + ansible.builtin.unarchive: + src: "{{ adapter_list.files[0].path }}" + dest: "{{ offline_dest_adapters_path }}/" + remote_src: true + extra_opts: + - --transform + - "s/^package/{{ adapter_name }}/" + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ install_adapters_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-rpms.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-rpms.yml new file mode 100644 index 00000000..6bf1a7b8 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-rpms.yml @@ -0,0 +1,60 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_rpms_path is set + ansible.builtin.assert: + that: offline_rpms_path is defined + msg: "offline_rpms_path must be set" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: install_packages_temp_dir + +- name: Copy RPMs to target node + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ install_packages_temp_dir.path }}/{{ item | basename }}" + mode: '0644' + with_fileglob: "{{ offline_rpms_path }}/*.rpm" + +- name: Find RPMs on target node + ansible.builtin.find: + paths: "{{ install_packages_temp_dir.path }}" + patterns: "*.rpm" + register: rpm_list + +- name: Rebuild RPM database + ansible.builtin.command: rpmdb --rebuilddb + changed_when: false + +- name: Get list of yum repos (to disable temporarily) # noqa command-instead-of-module + ansible.builtin.command: yum -q repolist + register: repolist_result + changed_when: false + +- name: Install RPMs (ansible dnf module) + ansible.builtin.dnf: + name: "{{ rpm_list.files | map(attribute='path') | list | sort }}" + state: present + disable_gpg_check: true + cacheonly: true + install_weak_deps: false + enablerepo: [] + disablerepo: "{{ repolist_result.stdout_lines[1:] | map('split', ' ') | map('first') | list }}" + when: offline_use_rpm_cmd is not defined or not offline_use_rpm_cmd | bool + +- name: Install RPMs (rpm) # noqa command-instead-of-module + ansible.builtin.command: + cmd: "rpm -i {{ offline_rpm_cmd_opts }} + {{ rpm_list.files | map(attribute='path') | list | sort | join(' ') }}" + register: install_result + changed_when: install_result.rc == 0 + when: + - offline_use_rpm_cmd is defined + - offline_use_rpm_cmd | bool + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ install_packages_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels-archive.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels-archive.yml new file mode 100644 index 00000000..39f79652 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels-archive.yml @@ -0,0 +1,35 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_wheels_archive is set + ansible.builtin.assert: + that: offline_wheels_archive is defined + msg: "offline_wheels_archive must be set" + +- name: Validate offline_virtual_env or offline_python_pip_executable is set + ansible.builtin.assert: + that: offline_virtual_env is defined or offline_python_pip_executable is defined + msg: "offline_virtual_env or offline_python_pip_executable must be set" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: install_wheel_archive_temp_dir + +- name: Extract wheel archive + ansible.builtin.unarchive: + src: "{{ offline_wheels_archive.path }}" + dest: "{{ install_wheel_archive_temp_dir.path }}" + remote_src: true + +- name: Install wheels using requirements file + ansible.builtin.pip: + executable: "{{ virtual_env is defined | ternary(omit, python_pip_executable) }}" + virtualenv: "{{ virtual_env is defined | ternary(virtual_env, omit) }}" + requirements: "{{ install_wheel_archive_temp_dir.path }}/requirements.txt" + extra_args: "--no-index --find-links=file:///{{ install_wheel_archive_temp_dir.path }}" + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ install_wheel_archive_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels-archives.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels-archives.yml new file mode 100644 index 00000000..7d7a8618 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels-archives.yml @@ -0,0 +1,41 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_wheels_path is set + ansible.builtin.assert: + that: offline_wheels_path is defined + msg: "offline_wheels_path must be set" + +- name: Validate offline_wheels_archive is set + ansible.builtin.assert: + that: offline_wheels_archive is defined + msg: "offline_wheels_archive must be set" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: install_wheels_temp_dir + +- name: Copy wheel archives to target node + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ install_wheels_temp_dir.path }}/{{ item | basename }}" + mode: '0644' + with_fileglob: "{{ offline_wheels_path }}/*.tar.gz" + +- name: Find wheel archives on target node + ansible.builtin.find: + paths: "{{ install_wheels_temp_dir.path }}" + patterns: "*.tar.gz" + register: wheel_archive_list + +- name: Install wheel archive + ansible.builtin.include_tasks: "install-wheels-archive.yml" + loop: "{{ wheel_archive_list.files }}" + loop_control: + loop_var: offline_wheels_archive + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ install_wheels_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels.yml new file mode 100644 index 00000000..c0f69d5a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/offline/tasks/install-wheels.yml @@ -0,0 +1,54 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_pip_executable or offline_python_venv is set + ansible.builtin.assert: + that: offline_pip_executable is defined or offline_python_venv is defined + msg: "offline_pip_executable or offline_python_venv must be set" + +- name: Validate offline_wheels_dir is set + ansible.builtin.assert: + that: offline_wheels_dir is defined + msg: "offline_wheels_dir must be set" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: install_wheels_temp_dir + +- name: Copy wheel files to target node + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ install_wheels_temp_dir.path }}/{{ item | basename }}" + mode: '0644' + with_fileglob: + - "{{ offline_wheels_dir }}/*.whl" + - "{{ offline_wheels_dir }}/*.tar.gz" + +- name: Find wheel files on target node + ansible.builtin.find: + paths: "{{ install_wheels_temp_dir.path }}" + patterns: + - "*.whl" + - "*.tar.gz" + register: wheel_list + +- name: Install wheel files in virtual env + ansible.builtin.pip: + name: "{{ wheel_list.files | map(attribute='path') | list | sort }}" + virtualenv: "{{ offline_python_venv }}" + extra_args: --no-index + when: offline_python_venv is defined + +- name: Install wheel files using pip executable + ansible.builtin.pip: + name: "{{ wheel_list.files | map(attribute='path') | list | sort }}" + executable: "{{ offline_pip_executable }}" + umask: "0022" + extra_args: --no-index + when: offline_python_venv is not defined + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ install_wheels_temp_dir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/os/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/defaults/main/offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/defaults/main/offline.yml new file mode 100644 index 00000000..f7745145 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/defaults/main/offline.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Base directories +os_offline_packages_root: "{{ offline_itential_packages_path }}/{{ platform_release }}/os" +os_offline_target_node_root: "{{ offline_target_node_root }}/{{ os_offline_packages_root }}" +os_offline_control_node_root: + "{{ offline_control_node_root }}/{{ os_offline_packages_root }}" + +# Target node download directories +os_offline_target_node_rpms_dir: "{{ os_offline_target_node_root }}/rpms" + +# Control node download directories +os_offline_control_node_rpms_dir: "{{ os_offline_control_node_root }}/rpms" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/download-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/download-packages.yml new file mode 100644 index 00000000..9e717e33 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/download-packages.yml @@ -0,0 +1,65 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline_install_enabled variable + ansible.builtin.fail: + msg: offline_install_enabled must be set to false for download + when: + - offline_install_enabled is defined + - offline_install_enabled + +- name: Check for supported OS family + ansible.builtin.fail: + msg: "itential.installer does not support distribution '{{ ansible_os_family.lower() }}'" + when: ansible_os_family.lower() not in ('redhat',) + +- name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "release-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + +- name: Check supported OS + ansible.builtin.fail: + msg: "Deployer does not support installing on {{ ansible_distribution }} {{ ansible_distribution_major_version }}!" + when: invalid_os_release is defined + +- name: Download OS RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ os_packages }}" + offline_download_dir: "{{ os_offline_target_node_rpms_dir }}" + +- name: Download security RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ security_packages }}" + offline_download_dir: "{{ os_offline_target_node_rpms_dir }}" + +- name: Download operations RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ operational_packages }}" + offline_download_dir: "{{ os_offline_target_node_rpms_dir }}" + +- name: Copy RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ os_offline_target_node_rpms_dir }}" + offline_dest_dir: "{{ os_offline_control_node_rpms_dir }}" + +- name: Set OS packages downloaded flag + ansible.builtin.set_fact: + os_packages_downloaded: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/main.yml new file mode 100644 index 00000000..5384a0d1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/main.yml @@ -0,0 +1,16 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Check release file + ansible.builtin.stat: + path: "{{ common_itential_release_file }}" + register: release_file + +- name: Check for supported os family + ansible.builtin.fail: + msg: "itential.installer does not support distribution '{{ ansible_os_family.lower() }}'" + when: ansible_os_family.lower() not in ('redhat',) + +- name: Include OS specific tasks + ansible.builtin.include_tasks: "{{ ansible_os_family.lower() }}.yml" + when: not release_file.stat.exists diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat-offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat-offline.yml new file mode 100644 index 00000000..07032fcb --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat-offline.yml @@ -0,0 +1,9 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install OS rpms + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ os_offline_control_node_rpms_dir }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat-online.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat-online.yml new file mode 100644 index 00000000..dc3c29f1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat-online.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install OS Packages + ansible.builtin.dnf: + name: "{{ os_packages }}" + state: present + validate_certs: false + skip_broken: true + update_cache: true + +- name: Install Security Packages + ansible.builtin.dnf: + name: "{{ security_packages }}" + state: present + +- name: Install Operations Packages + ansible.builtin.dnf: + name: "{{ operational_packages }}" + state: present diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat.yml new file mode 100644 index 00000000..80801785 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/tasks/redhat.yml @@ -0,0 +1,26 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "release-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + +- name: Check supported OS + ansible.builtin.fail: + msg: "Deployer does not support installing on OS version {{ ansible_distribution_major_version }}!" + when: invalid_os_release is defined + +- name: Include OS specific tasks + ansible.builtin.include_tasks: "{{ ansible_os_family.lower() }}-online.yml" + when: + - not release_file.stat.exists + - not offline_install_enabled + +- name: Include OS specific tasks (offline) + ansible.builtin.include_tasks: "{{ ansible_os_family.lower() }}-offline.yml" + when: + - not release_file.stat.exists + - offline_install_enabled diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-8.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-8.yml new file mode 100644 index 00000000..fb53dac7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-8.yml @@ -0,0 +1,33 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +os_packages: + - coreutils + - openssl + +security_packages: + - checkpolicy + - libselinux + - libselinux-utils + - policycoreutils + - policycoreutils-python-utils + - selinux-policy-mls + +operational_packages: + - bind-utils + - curl + - dos2unix + - git + - gzip + - jq + - man + - rsyslog + - sudo + - sysstat + - tar + - tcpdump + - telnet + - unzip + - wget + - which + - zip diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-9.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-9.yml new file mode 100644 index 00000000..fb53dac7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-9.yml @@ -0,0 +1,33 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +os_packages: + - coreutils + - openssl + +security_packages: + - checkpolicy + - libselinux + - libselinux-utils + - policycoreutils + - policycoreutils-python-utils + - selinux-policy-mls + +operational_packages: + - bind-utils + - curl + - dos2unix + - git + - gzip + - jq + - man + - rsyslog + - sudo + - sysstat + - tar + - tcpdump + - telnet + - unzip + - wget + - which + - zip diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-undefined.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-undefined.yml new file mode 100644 index 00000000..5ce1d151 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/os/vars/release-undefined.yml @@ -0,0 +1,3 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +invalid_os_release: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/authentication.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/authentication.yml new file mode 100644 index 00000000..3903dbfc --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/authentication.yml @@ -0,0 +1,27 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# If true, logs out existing sessions for a user when they log in with a new session. +platform_auth_unique_sessions_enabled: false + +# Members of these groups will be implicitly assigned with admin permissions. +platform_auth_admin_groups: + # - { "provenance": "Local AAA", "group": "pronghorn_admin" } + +# Enables a AAA adapter to custom build the principal object for a user with a "buildPrincipal" method. +platform_auth_broker_principal_enabled: false + +# The name of the cookie used for a user session. +platform_auth_session_cookie_name: token + +# The time in minutes before a user session expires. +platform_auth_session_ttl: 60 + +# Enables a default user to be used for login when SSO is not configured and no AAA Adapter exists. +platform_default_user_enabled: true + +# The username of the default user. +platform_default_user_username: "admin" + +# The password of the default user. +platform_default_user_password: "admin" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/brokers.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/brokers.yml new file mode 100644 index 00000000..d5e29d84 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/brokers.yml @@ -0,0 +1,12 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# A list of adapter types that manages the devices. +platform_device_broker_default_adapter_priority: + +# Runs a command on a device. +platform_device_broker_run_command_adapter_preference: + +# If true, the platform will perform strict JSON Schema validation on messages into the brokers and +# coming back to the broker layer from adapters. +platform_broker_validation_enabled: false diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/gateway_manager.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/gateway_manager.yml new file mode 100644 index 00000000..a1ab1cbc --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/gateway_manager.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +platform_gateway_manager_websocket_port: 8080 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/integration_worker.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/integration_worker.yml new file mode 100644 index 00000000..9becdd88 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/integration_worker.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The number of threads available for API requests. +platform_integration_thread_count: 5 + +# The number of milliseconds until an integration request times out. +platform_integration_timeout: 15000 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/logging.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/logging.yml new file mode 100644 index 00000000..362a8cc8 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/logging.yml @@ -0,0 +1,59 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The maximum number of each log file to keep as rotation occurs. +platform_log_max_files: 100 + +# The maximum file size in bytes of each log file before rotation occurs. +platform_log_max_file_size: 1048576 + +# The minimum log level to display in the log file. +platform_log_level: info + +# The absolute directory path where log files are written. +platform_log_dir: "{{ platform_log_dir_default }}" + +# The name of the primary platform log file. +platform_log_filename: platform.log + +# The minimum log level to display in the console (stdout). +platform_log_level_console: warn + +# The absolute directory path where webserver log files are written. +platform_webserver_log_directory: "{{ platform_log_dir }}" + +# The name of the webserver log file. +platform_webserver_log_filename: webserver.log + +# The minimum log level to send to the syslog server. +platform_log_level_syslog: warning + +# The hostname or IP address of the syslog server. +platform_syslog_host: localhost + +# The port number of the syslog server. +platform_syslog_port: 514 + +# The protocol to use when sending logs to the syslog server. +platform_syslog_protocol: udp4 + +# The syslog facility to use when sending logs to the syslog server. +platform_syslog_facility: local0 + +# The syslog message format to use when sending logs to the syslog server. +platform_syslog_type: BSD + +# The path to the syslog server file. +platform_syslog_path: /dev/log + +# The process property to include as the process id in the syslog message. +platform_syslog_pid: process.pid + +# The hostname to include in the syslog message. +platform_syslog_localhost: localhost + +# The process property to include as the application name in the syslog message. +platform_syslog_app_name: process.title + +# The end of line character to include in the syslog message. +platform_syslog_eol: diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/mongodb.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/mongodb.yml new file mode 100644 index 00000000..029789c4 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/mongodb.yml @@ -0,0 +1,35 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Instructs the MongoDB driver to use the configured username/password when connecting to MongoDB. +platform_mongo_auth_enabled: true + +# The username to use when connecting to MongoDB. +platform_mongo_user: itential + +# The password to use when connecting to MongoDB. +platform_mongo_password: itential + +# The name of the database that the MongoDB user must authenticate against. +platform_mongo_auth_db: + +# If true, the server will not check if it is connecting to a compatible MongoDB version. +platform_mongo_bypass_version_check: false + +# The name of the MongoDB logical database to connect to. +platform_mongo_db_name: itential + +# The MongoDB connection string. For a replica set this will include all members of the replica set. +# For Mongo Atlas this will be the SRV connection format. +platform_mongo_url: mongodb://localhost:27017 + +# Instruct the MongoDB driver to use TLS protocols when connecting to the database. +platform_mongo_tls_enabled: true + +# If true, disables the validation checks for TLS certificates on other servers in the cluster +# and allows the use of invalid or self-signed certificates to connect. +platform_mongo_tls_allow_invalid_certificates: false + +# The maximum number of connections in a connection pool. +# Each application/adapter has its own connection pool. +platform_mongo_max_pool_size: diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/offline.yml new file mode 100644 index 00000000..ac30c376 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/offline.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Base directories +platform_offline_packages_root: + "{{ offline_itential_packages_path }}/{{ platform_release }}/platform" +platform_offline_target_node_root: + "{{ offline_target_node_root }}/{{ platform_offline_packages_root }}" +platform_offline_control_node_root: + "{{ offline_control_node_root }}/{{ platform_offline_packages_root }}" + +# Target node download directories +platform_offline_target_node_rpms_dir: "{{ platform_offline_target_node_root }}/rpms" +platform_offline_target_node_wheels_dir: "{{ platform_offline_target_node_root }}/wheels" +platform_offline_target_node_adapters_dir: "{{ platform_offline_target_node_root }}/adapters" + +# Control node download directories +platform_offline_control_node_rpms_dir: "{{ platform_offline_control_node_root }}/rpms" +platform_offline_control_node_wheels_dir: "{{ platform_offline_control_node_root }}/wheels" +platform_offline_control_node_adapters_dir: "{{ platform_offline_control_node_root }}/adapters" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/pki.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/pki.yml new file mode 100644 index 00000000..53ab5a06 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/pki.yml @@ -0,0 +1,143 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Platform PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +platform_pki_base_dir: /etc/pki/itential-platform + +# Subdirectory names - customize the layout +platform_pki_private_subdir: private +platform_pki_https_subdir: https +platform_pki_mongodb_subdir: mongodb + +# Derived subdirectory paths - built from base + subdir name +platform_pki_private_dir: "{{ platform_pki_base_dir }}/{{ platform_pki_private_subdir }}" +platform_pki_https_dir: "{{ platform_pki_base_dir }}/{{ platform_pki_https_subdir }}" +platform_pki_mongodb_dir: "{{ platform_pki_base_dir }}/{{ platform_pki_mongodb_subdir }}" + +# ============================================================================ +# HTTPS Certificate Filenames - Customize naming +# ============================================================================ + +# HTTPS server certificate filename +platform_https_cert_filename: "{{ inventory_hostname }}.crt" + +# HTTPS private key filename +platform_https_key_filename: "{{ inventory_hostname }}.key" + +# HTTPS CA bundle filename +platform_https_ca_filename: ca-bundle.crt + +# ============================================================================ +# HTTPS Full Certificate Paths - Built from components +# ============================================================================ + +# HTTPS server certificate path +platform_webserver_https_cert: "{{ platform_pki_https_dir }}/{{ platform_https_cert_filename }}" + +# HTTPS private key path +platform_webserver_https_key: "{{ platform_pki_private_dir }}/{{ platform_https_key_filename }}" + +# HTTPS CA bundle path +platform_webserver_https_ca: "{{ platform_pki_https_dir }}/{{ platform_https_ca_filename }}" + +# ============================================================================ +# MongoDB Client Certificate Filenames - Customize naming +# ============================================================================ + +# MongoDB CA certificate filename +platform_mongodb_ca_filename: ca-bundle.crt + +# ============================================================================ +# MongoDB Client Full Certificate Paths - Built from components +# ============================================================================ + +# MongoDB CA certificate path (used to validate MongoDB server) +platform_mongodb_root_ca_file_destination: "{{ platform_pki_mongodb_dir }}/{{ platform_mongodb_ca_filename }}" + +# ============================================================================ +# Application Configuration Mappings +# These map to the paths expected by Platform's properties.json +# ============================================================================ + +# MongoDB CA file for application properties.json +# This variable is used in templates and needs to point to the destination path +platform_mongo_tls_ca_file: "{{ platform_mongodb_root_ca_file_destination }}" + +# ============================================================================ +# Source Directories - Define in inventory +# ============================================================================ + +# Source directory for HTTPS certificates (on Ansible controller) +platform_https_pki_src_dir: "/Users/ananth.munagala/deployer_checkins/PE-1386/certificates/platform" + +# Source directory for MongoDB certificates (on Ansible controller) +platform_mongodb_pki_src_dir: "/Users/ananth.munagala/deployer_checkins/PE-1386/certificates/platform" + +# ============================================================================ +# Source File Paths - Built from source directory + filename +# ============================================================================ + +# HTTPS source paths - auto-build from source dir + filename +platform_certfile_source: "{{ platform_https_pki_src_dir }}/{{ platform_https_cert_filename }}" +platform_keyfile_source: "{{ platform_https_pki_src_dir }}/{{ platform_https_key_filename }}" +platform_https_ca_source: "{{ platform_https_pki_src_dir }}/{{ platform_https_ca_filename }}" + +# MongoDB client source paths - auto-build from source dir + filename +platform_mongodb_root_ca_file_source: "{{ platform_mongodb_pki_src_dir }}/{{ platform_mongodb_ca_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI base directory +platform_pki_base_owner: root + +# Group for PKI base directory +platform_pki_base_group: itential + +# Owner for private key files +platform_pki_private_owner: root + +# Group for private key files +platform_pki_private_group: itential + +# Owner for certificate files +platform_pki_cert_owner: "{{ platform_user }}" + +# Group for certificate files +platform_pki_cert_group: "{{ platform_group }}" + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +platform_pki_base_dir_mode: "0750" + +# Subdirectory permissions +platform_pki_subdir_mode: "0750" + +# Private directory permissions +platform_pki_private_dir_mode: "0750" + +# HTTPS certificate permissions +platform_https_cert_mode: "0644" + +# HTTPS private key permissions +platform_https_key_mode: "0640" + +# HTTPS CA bundle permissions +platform_https_ca_mode: "0644" + +# MongoDB CA certificate permissions +platform_mongodb_ca_mode: "0644" + +# MongoDB client certificate permissions +platform_mongodb_client_cert_mode: "0640" + +# MongoDB client private key permissions +platform_mongodb_client_key_mode: "0600" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/platform.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/platform.yml new file mode 100644 index 00000000..b12066dc --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/platform.yml @@ -0,0 +1,53 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Itential Platform directories +platform_root_dir: "{{ platform_root_dir_default }}" +platform_config_dir: "{{ platform_config_dir_default }}" +# platform_tls_dir: "{{ platform_tls_dir_default }}" +platform_itential_home_dir: "{{ platform_itential_home_dir_default }}" + +# Destination as referenced by itential user when connecting from itential host. +# This is ultimately stored in the mongo database to be read by Itential Platform, therefore +# this is the location as seen from the Itential Platform host. + +platform_package_dependencies: + - glibc-common + - openldap + - openldap-clients + - openssl + - git + +platform_python_base_dependencies: + - pip + - setuptools + - wheel + +# The python and pip executable locations. +# These will be symlinks to the appropriate executables in /usr/bin. +platform_python_executable: "/usr/bin/python{{ platform_python_version }}" +platform_pip_executable: "/usr/bin/pip{{ platform_python_version }}" + +# The default user that runs the server process +platform_user: itential + +# The default group that runs the server process +platform_group: itential + +# Flag to determine whether to use rsync when uploading artifacts +platform_upload_using_rsync: false + +# Flag to remove the package-lock.json file before running the NPM install +platform_delete_package_lock_file: true + +# Flag to disable Git safe repo check +platform_disable_git_safe_repo_checks: true + +# Flag to prevent the NPM scripts from running when running the NPM install +platform_npm_ignore_scripts: true + +# Flag to install app-artifacts +platform_app_artifacts_enabled: false + +# Flag to determine if the service is started +platform_start_service: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/platform_ui.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/platform_ui.yml new file mode 100644 index 00000000..f078a2e1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/platform_ui.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Path to the layout file extended in pug templates. +platform_ui_layout_file: + +# Path to the HTML file that will be displayed as the home page for the UI. +platform_ui_home_file: "node_modules/@itential/iap-ui/build/index.html" + +# Path to the HTML file that will be displayed as the login page for the UI. +platform_ui_login_file: "node_modules/@itential/iap-ui/build/index.html" + +# Path to the HTML file that will be displayed as the profile page for the UI. +platform_ui_profile_file: "node_modules/@itential/iap-ui/build/index.html" + +# Path to the favicon file that will be displayed in the browser tab. +platform_ui_favicon_file: "ui/img/favicon.ico" + +# Path to the apple touch icon file that will be displayed on iOS devices. +platform_ui_apple_touch_icon_file: "ui/img/apple-touch-icon.png" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/redis.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/redis.yml new file mode 100644 index 00000000..29543329 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/redis.yml @@ -0,0 +1,44 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The Redis keyspace (database number) to use for the connection. +platform_redis_db: 0 + +# Flag to enable Redis authentication. +platform_redis_auth_enabled: true + +# The username to use when connecting to Redis. +platform_redis_username: itential + +# The password to use when connecting to Redis. +platform_redis_password: itential + +# The maximum number of times to retry a request to Redis when the connection is lost. +platform_redis_max_retries_per_request: 20 + +# The maximum number of times to retry writing a heartbeat message to Redis from a service. +platform_redis_max_heartbeat_write_retries: 20 + +# The hostname of the Redis server. Not used when connecting to Redis Sentinels. +platform_redis_host: localhost + +# The port to use when connecting to this Redis instance. +platform_redis_port: 6379 + +# The list of Redis Sentinel servers (hostnames and ports) to use for high availability. +platform_redis_sentinels: + +# The username to use when connecting to Sentinel. +platform_redis_sentinel_username: sentineluser + +# The password to use when connecting to Sentinel. +platform_redis_sentinel_password: sentineluser + +# The Redis primary name. This only has meaning when Redis is running with replication enabled. +# The sentinels will monitor this node and consider it down only when the sentinels agree. +# Note: The primary name should not include special characters other than: .-_ and no whitespaces. +platform_redis_name: itentialmaster + +# Redis TLS configuration options for secure connections. +# Refer to NodeJS TLS library for all supported options. +platform_redis_tls: diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/server.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/server.yml new file mode 100644 index 00000000..843b81d3 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/server.yml @@ -0,0 +1,66 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The name of the profile document to load from the MongoDB where legacy configuration +# properties are stored. +# Not required for installations that are using environment variables or a properties file. +platform_profile_id: + +# The file path to the directory containing additional services (applications and adapters). +# Although the name implies only one service directory can be provisioned, it's actually +# a list. +platform_service_directory: + +# An identifier for the server instance. This is used to uniquely identify the server in a +# multi-server environment. +# If not provided, the server will generate one on startup. +platform_server_id: "{{ inventory_hostname }}" + +# A whitelist of services (applications/adapters) to initialize on startup of the platform. +# If no value is given, all services will be initialized. +platform_services: + +# The service type that will be denied CRUD operation access. +platform_service_blacklist: + +# Indicates whether the platform is using encrypted code files. +platform_encrypted: true + +# The amount of time a service should wait before shutting down, in seconds. +platform_shutdown_timeout: 3 + +# The application/adapter launch delay, in seconds. +platform_service_launch_delay: 1 + +# The application/adapter launch timeout, in seconds. +platform_service_launch_timeout: 600 + +# How often to update service health, measured in seconds. +platform_service_health_check_interval: 5 + +# The number of failed health checks in a row before a service is considered to be “unhealthy”. +platform_service_health_check_unhealthy_threshold: 3 + +# If true, the platform will periodically check for dead processes. +platform_dead_process_check_enabled: false + +# How often to check if application/adapter stopped sending healthcheck pings, in seconds. +platform_dead_process_check_interval: 5 + +# Maximum time period for application/adapter without sending healthcheck ping, in seconds. +platform_dead_process_max_period: 15 + +# Specifies the amount of times services will retry on crash before stopping. +platform_service_crash_recovery_max_retries: 10 + +# Specifies the amount of times between each retry before the count will reset in milliseconds. +platform_service_crash_recovery_reset_retries_after_ms: 60000 + +# The timeout for external API requests, in seconds. +platform_external_request_timeout: 5 + +# The interval for how often IAP polls for the number of devices, in hours. +platform_device_count_polling_interval: 24 + +# If true, the platform will track detailed audit events. +platform_audit_enabled: false diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/snmp.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/snmp.yml new file mode 100644 index 00000000..64e0e0ac --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/snmp.yml @@ -0,0 +1,5 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +platform_snmp_alarm_configs: + - { "ip": "localhost", "community": "public", "type": "trap", "properties": { "port": 161, "retries": 1, "timeout": 5000, "transport": "udp4", "trapPort": 162, "version": "V1" } } # noqa yaml[line-length] diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/vault.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/vault.yml new file mode 100644 index 00000000..d194bb3e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/vault.yml @@ -0,0 +1,51 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Flag to enable/disable configuring Vault in Itential Platform +platform_configure_vault: false + +# The directory to store the vault root key in +platform_vault_token_dir: "{{ platform_server_dir }}/keys" + +# The URL to the Hashicorp Vault server. +platform_vault_url: http://localhost:8200 + +# The authorization method to connect to Hashicorp Vault. Either token or approle. +platform_vault_auth_method: token + +# Hashicorp Vault token +# Must be configured in inventory when platform_vault_auth_method is set to 'token' +platform_vault_token: + +# Hashicorp Vault Role ID +# Must be configured in inventory when platform_vault_auth_method is set to 'approle' +platform_vault_role_id: + +# Hashicorp Vault Secret ID +# Must be configured in inventory when platform_vault_auth_method is set to 'approle' +platform_vault_secret_id: + +# The path where the AppRole was enabled. +platform_vault_approle_path: approle + +# The file path to a token file. The token is used for authentication to access Vault secrets. +platform_vault_token_file: "{{ platform_vault_token_dir }}/vault.token" + +# Reference for the path to secret and name of key in Hashicorp Vault +# Syntax is $SECRET_{path to secret in Vault} $KEY_{name of key in secretPath} +# For example, in perf lab Hashi Vault +# secrets are at Secrets/itential/iap. Hence "$SECRET_iap" +# Key is "redisPassword" for the password value. Hence "$KEY_redisPassword" +platform_redis_password_vault: "$SECRET_iap $KEY_redisPassword" + +platform_mongo_password_vault: "$SECRET_iap $KEY_mongoDb" + +# The file path to the .env file containing Role ID and Secret ID for AppRole authentication. +platform_vault_role_secrets_env_file: "{{ platform_vault_token_dir }}/vault-role-secrets.env" + +# The endpoint for the Secrets Engine that is used. +platform_vault_secrets_endpoint: itential/data + +# If true, only reads secrets from Hashicorp Vault. Otherwise, the platform can write secrets +# to Vault for storage. +platform_vault_read_only: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/webserver.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/webserver.yml new file mode 100644 index 00000000..13ace775 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/webserver.yml @@ -0,0 +1,41 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# A toggle to instruct the webserver to include HTTP cache control headers on the response. +platform_webserver_cache_control_enabled: false + +# Timeout to use for incoming HTTP requests to the platform API, in milliseconds. +platform_webserver_timeout: 300000 + +# The value of the HTTP Access-Control-Allow-Origin header returned to clients. +platform_webserver_response_header_access_control_allow_origin: "*" + +# If true, allows the webserver to respond to insecure HTTP requests. +platform_webserver_http_enabled: true + +# The port on which the webserver listens for HTTP requests. +platform_webserver_http_port: 3000 + +# If true, allows the webserver to respond to secure HTTPS requests. +platform_webserver_https_enabled: true + +# The port on which the webserver listens for HTTPS requests. +platform_webserver_https_port: 3443 + +# The passphrase for the private key used to enable TLS sessions. +platform_webserver_https_passphrase: + +# The set of allowed SSL/TLS protocol versions. +platform_webserver_https_secure_protocol: TLS_method + +# The allowed SSL/TLS cipher suite. +platform_webserver_https_ciphers: "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA" # noqa line-length yaml[line-length] + +# Specifies the number of renegotiations that are allowed in a single HTTPS connection. +platform_webserver_https_client_reneg_limit: 3 + +# Specifies the time renegotiation window in seconds for a single HTTPS connection. +platform_webserver_https_client_reneg_window: 600 + +# The set of allowed HTTP verbs in addition to those defined in the standard HTTP/1.1 protocol. +platform_webserver_http_allowed_optional_verbs: diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/workflow_worker.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/workflow_worker.yml new file mode 100644 index 00000000..8d92d53c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/defaults/main/workflow_worker.yml @@ -0,0 +1,10 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# If true, will start working tasks immediately after the server startup process is complete. +# If false, the task worker must be enabled manually via the UI/API. +platform_task_worker_enabled: true + +# If true, will allow jobs to be started after the server startup process is complete. +# If false, API calls to start Jobs will return an error until enabled manually via the UI/API. +platform_job_worker_enabled: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/handlers/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/handlers/main.yml new file mode 100644 index 00000000..15291cbf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/handlers/main.yml @@ -0,0 +1,15 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Enable and Start Platform + ansible.builtin.systemd: + name: itential-platform + enabled: true + state: restarted + daemon_reload: true + when: platform_start_service | bool + listen: restart itential-platform + +- name: Update Itential release file + ansible.builtin.include_tasks: + file: update-release-file.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-firewalld.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-firewalld.yml new file mode 100644 index 00000000..4e7fc429 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-firewalld.yml @@ -0,0 +1,45 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Check if firewalld is running, if it is then open the appropriate ports +- name: Gather service facts + ansible.builtin.service_facts: + +- name: Open Itential Platform HTTP Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ platform_webserver_http_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + - platform_webserver_http_enabled | bool + +- name: Open Itential Platform HTTPS Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ platform_webserver_https_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + - platform_webserver_https_enabled | bool + +- name: Open Gateway Manager Port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ platform_gateway_manager_websocket_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + - platform_packages | select ('search', 'itential-gateway_manager') | list | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-platform.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-platform.yml new file mode 100644 index 00000000..4133ddff --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-platform.yml @@ -0,0 +1,14 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create systemd file + ansible.builtin.template: + src: itential-platform.service.j2 + dest: /usr/lib/systemd/system/itential-platform.service + owner: root + group: root + mode: "0644" + +- name: Create properties.json file + ansible.builtin.include_tasks: + file: create-properties-file.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-selinux.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-selinux.yml new file mode 100644 index 00000000..894139bc --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-selinux.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Configure SELinux when using custom install directory + when: + - ansible_selinux.status == "enabled" + - platform_server_dir != platform_server_dir_default + block: + - name: Set SELinux to allow systemd to use custom install directory + community.general.sefcontext: + target: "{{ platform_server_dir }}" + setype: bin_t + + - name: Reload SELinux policy + ansible.builtin.command: restorecon -irv "{{ platform_server_dir }}" + register: platform_restorecon_result + changed_when: platform_restorecon_result.rc == 0 + failed_when: + - platform_restorecon_result.rc is defined + - platform_restorecon_result.rc > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-vault.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-vault.yml new file mode 100644 index 00000000..919c4ea9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/configure-vault.yml @@ -0,0 +1,56 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Make the directory to store vault credentials + ansible.builtin.file: + path: "{{ platform_vault_token_dir }}" + state: directory + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: "0770" + +- name: Configure Vault with Token authentication + when: platform_vault_auth_method == "token" + block: + - name: Validate vault token + ansible.builtin.assert: + that: + - platform_vault_token is defined + - platform_vault_token | length > 0 + fail_msg: "platform_vault_token must be provided" + + - name: Create the token file + ansible.builtin.copy: + dest: "{{ platform_vault_token_file }}" + content: "{{ platform_vault_token }}" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: "0400" + no_log: true + +- name: Configure Vault with AppRole authentication + when: platform_vault_auth_method == "approle" + block: + - name: Validate user-provided credentials + ansible.builtin.assert: + that: + - platform_vault_role_id is defined + - platform_vault_role_id | length > 0 + - platform_vault_secret_id is defined + - platform_vault_secret_id | length > 0 + fail_msg: "platform_vault_role_id and platform_vault_secret_id must be provided" + + # Store credentials in .env file instead of directly in systemd service. + # This approach prevents secrets from being visible when running + # 'systemctl show itential-platform | grep -i vault' command. + # The .env file is loaded via EnvironmentFile directive, keeping credentials secure. + - name: Create vault-role-secrets.env file with credentials + ansible.builtin.copy: + dest: "{{ platform_vault_token_dir }}/vault-role-secrets.env" + content: | + ITENTIAL_VAULT_ROLE_ID={{ platform_vault_role_id }} + ITENTIAL_VAULT_SECRET_ID={{ platform_vault_secret_id }} + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: "0400" + no_log: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/copy-certs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/copy-certs.yml new file mode 100644 index 00000000..fda641b2 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/copy-certs.yml @@ -0,0 +1,112 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Create Platform PKI Directory Structure +# ============================================================================ + +- name: Create Platform PKI base directory + ansible.builtin.file: + path: "{{ platform_pki_base_dir }}" + state: directory + owner: "{{ platform_pki_base_owner }}" + group: "{{ platform_pki_base_group }}" + mode: "{{ platform_pki_base_dir_mode }}" + tags: + - platform + - platform_certificates + - certificates + +- name: Create Platform PKI subdirectories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ platform_pki_base_owner }}" + group: "{{ platform_pki_base_group }}" + mode: "{{ platform_pki_subdir_mode }}" + loop: + - "{{ platform_pki_https_dir }}" + - "{{ platform_pki_mongodb_dir }}" + tags: + - platform + - platform_certificates + - certificates + +- name: Create Platform private key directory + ansible.builtin.file: + path: "{{ platform_pki_private_dir }}" + state: directory + owner: "{{ platform_pki_private_owner }}" + group: "{{ platform_pki_private_group }}" + mode: "{{ platform_pki_private_dir_mode }}" + tags: + - platform + - platform_certificates + - certificates + +# ============================================================================ +# HTTPS Certificates +# ============================================================================ + +- name: Copy HTTPS key and cert files + when: platform_webserver_https_enabled | bool + tags: + - platform + - platform_certificates + - platform_https + - certificates + block: + - name: Ensure the HTTPS private key directory exists + ansible.builtin.file: + path: "{{ platform_webserver_https_key | dirname }}" + state: directory + owner: "{{ platform_pki_private_owner }}" + group: "{{ platform_pki_private_group }}" + mode: "{{ platform_pki_private_dir_mode }}" + + - name: Ensure the HTTPS cert directory exists + ansible.builtin.file: + path: "{{ platform_webserver_https_cert | dirname }}" + state: directory + owner: "{{ platform_pki_base_owner }}" + group: "{{ platform_pki_base_group }}" + mode: "{{ platform_pki_subdir_mode }}" + + - name: Put the HTTPS key file in the correct location + ansible.builtin.copy: + src: "{{ platform_keyfile_source }}" + dest: "{{ platform_webserver_https_key }}" + mode: "{{ platform_https_key_mode }}" + owner: "{{ platform_pki_private_owner }}" + group: "{{ platform_pki_private_group }}" + notify: restart itential-platform + + - name: Put the HTTPS cert file in the correct location + ansible.builtin.copy: + src: "{{ platform_certfile_source }}" + dest: "{{ platform_webserver_https_cert }}" + mode: "{{ platform_https_cert_mode }}" + owner: "{{ platform_pki_cert_owner }}" + group: "{{ platform_pki_cert_group }}" + notify: restart itential-platform + +# ============================================================================ +# MongoDB Client Certificates +# ============================================================================ + +- name: Copy MongoDB root CA file to the appropriate location + ansible.builtin.copy: + src: "{{ platform_mongodb_root_ca_file_source }}" + dest: "{{ platform_mongodb_root_ca_file_destination }}" + mode: "{{ platform_mongodb_ca_mode }}" + owner: "{{ platform_pki_cert_owner }}" + group: "{{ platform_pki_cert_group }}" + when: + - platform_mongo_tls_enabled | bool + - platform_mongodb_root_ca_file_source is defined + notify: restart itential-platform + tags: + - platform + - platform_certificates + - platform_mongodb + - certificates \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/create-itential-user.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/create-itential-user.yml new file mode 100644 index 00000000..367dd020 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/create-itential-user.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# TODO: Remove this file once the RPM is creating the directories correctly + +- name: Create itential group + ansible.builtin.group: + name: "{{ platform_group }}" + state: present + +- name: Create itential user + ansible.builtin.user: + name: "{{ platform_user }}" + group: "{{ platform_group }}" + home: "{{ platform_itential_home_dir }}" + state: present diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/create-properties-file.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/create-properties-file.yml new file mode 100644 index 00000000..8305ab91 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/create-properties-file.yml @@ -0,0 +1,56 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# TODO: Do we still need to support the primary/secondary concept? + +- name: Create the platform.properties file + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ platform_config_dir }}/platform.properties" + mode: "0600" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + lstrip_blocks: true + backup: true + with_first_found: + - "{{ platform_release }}-properties.j2" + - "{{ platform_release | string | split('.') | first }}-properties.j2" + vars: + profile_name: Local_AAA + when: groups["platform_secondary"] is not defined or groups["platform_secondary"] | length < 1 + +- name: Create the Itential properties.json files for advanced prod builds + when: groups["platform_secondary"] is defined and groups["platform_secondary"] | length > 0 + block: + - name: Create the platform.properties file for the primary + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ platform_config_dir }}/platform.properties" + mode: "0600" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + lstrip_blocks: true + backup: true + with_first_found: + - "{{ platform_release }}-properties.j2" + - "{{ platform_release | string | split('.') | first }}-properties.j2" + vars: + profile_name: Primary_Local_AAA + when: inventory_hostname in groups['platform'] + + - name: Create the platform.properties file for the secondary + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ platform_config_dir }}/platform.properties" + mode: "0600" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + lstrip_blocks: true + backup: true + with_first_found: + - "{{ platform_release }}-properties.j2" + - "{{ platform_release | string | split('.') | first }}-properties.j2" + vars: + profile_name: Secondary_Local_AAA + when: inventory_hostname in groups['platform_secondary'] diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-adapters.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-adapters.yml new file mode 100644 index 00000000..f169eb04 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-adapters.yml @@ -0,0 +1,64 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install packages required for download + ansible.builtin.dnf: + name: "{{ item }}" + state: present + with_items: + - git + - jq + register: install_result + +- name: Disable safe repository checks + community.general.git_config: + name: safe.directory + scope: global + value: '*' + when: platform_disable_git_safe_repo_checks + +- name: Install NodeJS + ansible.builtin.include_tasks: + file: install-nodejs.yml + +- name: Download and fetch adapters + when: + - platform_adapters is defined + - platform_adapters is iterable + - platform_adapters | length > 0 + block: + - name: Download adapters + ansible.builtin.include_role: + name: offline + tasks_from: download-adapters + vars: + offline_adapters: "{{ platform_adapters }}" + offline_download_dir: "{{ platform_offline_target_node_adapters_dir }}" + + - name: Find all downloaded adapters + ansible.builtin.find: + paths: "{{ platform_offline_target_node_adapters_dir }}" + patterns: "*.tgz" + register: found_adapters + + - name: Copy adapters to control node + ansible.builtin.fetch: + src: "{{ item.path }}" + dest: "{{ platform_offline_control_node_adapters_dir }}/" + flat: true + with_items: "{{ found_adapters.files }}" + +- name: Uninstall packages required for download + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + with_items: "{{ install_result.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" + +- name: Uninstall NodeJS packages # noqa no-handler + ansible.builtin.dnf: + name: "{{ platform_nodejs_package }}" + state: absent + autoremove: true + when: nodejs_install_result.changed diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-nodejs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-nodejs.yml new file mode 100644 index 00000000..68cf14e3 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-nodejs.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install NodeJS repo + ansible.builtin.import_tasks: + file: install-nodejs-repo.yml + when: ansible_distribution == "Amazon" + +- name: Download NodeJS RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ platform_nodejs_package | split }}" + offline_download_dir: "{{ platform_offline_target_node_rpms_dir }}/nodejs" + +- name: Copy RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ platform_offline_target_node_rpms_dir }}/nodejs" + offline_dest_dir: "{{ platform_offline_control_node_rpms_dir }}/nodejs" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-os.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-os.yml new file mode 100644 index 00000000..b056b9cf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-os.yml @@ -0,0 +1,19 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Itential Platform dependency RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ platform_package_dependencies }}" + offline_download_dir: "{{ platform_offline_target_node_rpms_dir }}/dependencies" + +- name: Copy Itential Platform dependency RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ platform_offline_target_node_rpms_dir }}/dependencies" + offline_dest_dir: "{{ platform_offline_control_node_rpms_dir }}/dependencies" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-platform.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-platform.yml new file mode 100644 index 00000000..b5248581 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-platform.yml @@ -0,0 +1,42 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create list of Itential Platform RPM URLs + ansible.builtin.set_fact: + platform_package_urls: "{{ platform_packages | select('match', '^(https?|ftp)://') | list }}" + +- name: Download Itential Platform RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: get_url + offline_download_packages: "{{ platform_package_urls }}" + offline_download_dir: "{{ platform_offline_target_node_rpms_dir }}/platform" + when: + - platform_package_urls is defined + - platform_package_urls is iterable + - platform_package_urls | length > 0 + +- name: Create list of Itential Platform RPMs (non-URLs) + ansible.builtin.set_fact: + platform_package_local_rpms: "{{ platform_packages | reject('match', '^(https?|ftp)://') | list }}" + +- name: Upload Itential Platform RPMs + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ platform_offline_target_node_rpms_dir }}/platform/" + mode: "0775" + loop: "{{ platform_package_local_rpms }}" + when: + - platform_package_local_rpms is defined + - platform_package_local_rpms is iterable + - platform_package_local_rpms | length > 0 + +- name: Copy Itential Platform RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ platform_offline_target_node_rpms_dir }}/platform" + offline_dest_dir: "{{ platform_offline_control_node_rpms_dir }}/platform" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-python.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-python.yml new file mode 100644 index 00000000..1ba4264f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages-python.yml @@ -0,0 +1,73 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download Python RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ platform_python_packages }}" + offline_download_dir: "{{ platform_offline_target_node_rpms_dir }}/python" + +- name: Copy Python RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ platform_offline_target_node_rpms_dir }}/python" + offline_dest_dir: "{{ platform_offline_control_node_rpms_dir }}/python" + +- name: Install Python + ansible.builtin.include_tasks: + file: install-python.yml + tags: install_python + +- name: Download base Python dependencies + ansible.builtin.import_role: + name: offline + tasks_from: download-wheels + vars: + offline_wheel_files: "{{ platform_python_base_dependencies }}" + offline_download_dir: "{{ platform_offline_target_node_wheels_dir }}/base" + offline_pip_executable: "{{ platform_pip_executable }}" + when: + - platform_python_base_dependencies is defined + - platform_python_base_dependencies | length > 0 + +- name: Copy base Python dependencies to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ platform_offline_target_node_wheels_dir }}/base" + offline_dest_dir: "{{ platform_offline_control_node_wheels_dir }}/base" + +- name: Download Itential Platform Python dependencies + ansible.builtin.import_role: + name: offline + tasks_from: download-wheels + vars: + offline_with_deps: true + offline_wheel_files: "{{ platform_python_app_dependencies }}" + offline_download_dir: "{{ platform_offline_target_node_wheels_dir }}/app" + offline_pip_executable: "{{ platform_pip_executable }}" + when: + - platform_python_app_dependencies is defined + - platform_python_app_dependencies | length > 0 + +- name: Copy Itential Platform Python dependencies to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ platform_offline_target_node_wheels_dir }}/app" + offline_dest_dir: "{{ platform_offline_control_node_wheels_dir }}/app" + +- name: Uninstall Python RPMs + ansible.builtin.dnf: + name: "{{ item }}" + state: absent + autoremove: true + with_items: "{{ python_install_result.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages.yml new file mode 100644 index 00000000..34a37ace --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-packages.yml @@ -0,0 +1,52 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate offline and role vars + tags: always + block: + - name: Validate offline_install_enabled variable + ansible.builtin.fail: + msg: offline_install_enabled must be set to false for download + when: + - offline_install_enabled is defined + - offline_install_enabled + + - name: Validate role vars + ansible.builtin.include_tasks: + file: validate-vars.yml + +- name: Download Platform packages + tags: download_platform + block: + - name: Download Platform packages + ansible.builtin.include_tasks: + file: download-packages-platform.yml + +- name: Download Platform dependency packages + tags: download_dependencies + block: + - name: Download Platform dependency packages + ansible.builtin.include_tasks: + file: download-packages-os.yml + +- name: Download NodeJS packages + tags: download_nodejs + block: + - name: Download NodeJS packages + ansible.builtin.include_tasks: + file: download-packages-nodejs.yml + +- name: Download Python packages + tags: download_python + block: + - name: Download Python packages + ansible.builtin.include_tasks: + file: download-packages-python.yml + +- name: Download Adapter packages + tags: download_adapters + block: + - name: Download Adapter packages + ansible.builtin.include_tasks: + file: download-adapters.yml + when: platform_adapters is defined diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-platform-archive-from-repo.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-platform-archive-from-repo.yml new file mode 100644 index 00000000..49eccfc9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/download-platform-archive-from-repo.yml @@ -0,0 +1,28 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Download the Itential Platform artifact from URL + ansible.builtin.get_url: + url: "{{ artifact }}" + dest: "{{ platform_package_temp_download_dir.path }}/" + mode: '0755' + # Sets the appropriate header based on the repository type: + # - For JFrog: Uses the "X-JFrog-Art-Api" header with the API key if "repository_api_key" + # is defined and "jfrog" is part of the download URL. + # - For Gitlab: Uses the "PRIVATE-TOKEN" header with the API key if "repository_api_key" + # is defined and "gitlab" is part of the download URL. + # - For Nexus: Uses a default header ("Accept: application/octet-stream") since Nexus doesn't + # support API key authentication. + headers: >- + {%- if repository_api_key is defined and artifact is search("jfrog") -%} + {"X-JFrog-Art-Api": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- elif repository_api_key is defined and artifact is search("gitlab") -%} + {"PRIVATE-TOKEN": "{{ repository_api_key }}", "Accept": "application/octet-stream"} + {%- else -%} + {"Accept": "application/octet-stream"} + {%- endif -%} + url_username: "{{ repository_username | default(omit) }}" + url_password: "{{ repository_password | default(omit) }}" + validate_certs: true + register: platform_package_download_result + changed_when: false diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/encrypt-passwords.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/encrypt-passwords.yml new file mode 100644 index 00000000..31863ad1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/encrypt-passwords.yml @@ -0,0 +1,47 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Note: Platform's encrypt.js script does not take command line arguments. +# Instead, it prompts the user for input, reads it from stdin, and prints the key on the last line. +# This necessitates the use of the workaround below. +- name: Encrypt default passwords + when: not (platform_configure_vault | bool) + tags: encrypt_default_passwords + no_log: true + notify: Enable and Start Platform + block: + - name: Generate encrypted passwords + ansible.builtin.shell: > + set -o pipefail && + (echo "{{ item.plaintext }}"; sleep 2; echo "{{ platform_encryption_key }}") | + node {{ platform_server_dir }}/utils/encrypt.js 2>&1 | + tail -n 1 + args: + executable: /bin/bash + loop: + - name: platform_redis_password_encrypted + plaintext: "{{ platform_redis_password }}" + - name: platform_redis_sentinel_password_encrypted + plaintext: "{{ platform_redis_sentinel_password }}" + - name: platform_mongo_password_encrypted + plaintext: "{{ platform_mongo_password }}" + - name: platform_default_user_password_encrypted + plaintext: "{{ platform_default_user_password }}" + register: platform_encrypt_results + changed_when: false + failed_when: > + platform_encrypt_results.rc != 0 or + platform_encrypt_results.stdout == "" or + not platform_encrypt_results.stdout.startswith("$ENC") or + (platform_encrypt_results.stdout.split(':') | last | length) != 32 + + - name: Set encrypted passwords + ansible.builtin.set_fact: + "{{ item.item.name }}": "{{ item.stdout }}" + loop: "{{ platform_encrypt_results.results }}" + loop_control: + label: "{{ item.item.name }}" + + - name: Create properties.json file + ansible.builtin.include_tasks: + file: create-properties-file.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-adapters.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-adapters.yml new file mode 100644 index 00000000..67553b57 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-adapters.yml @@ -0,0 +1,179 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install any configured adapters + notify: Enable and Start Platform + when: ( (not offline_install_enabled | bool) and + platform_adapters is defined and + platform_adapters is iterable and + (platform_adapters | default([], true)) | length > 0 ) or + offline_install_enabled | bool + block: + - name: Ensure adapters directory exists + ansible.builtin.file: + path: "{{ platform_services_dir }}" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: '0775' + state: directory + + - name: Find all adapters already installed + ansible.builtin.find: + paths: "{{ platform_services_dir }}" + recurse: false + file_type: directory + patterns: "adapter-*" + register: platform_installed_adapters_find_result + + - name: Create a list of adapters already installed + ansible.builtin.set_fact: + platform_installed_adapters: "{{ platform_installed_adapters | default([]) + [item.path | basename] }}" + loop: "{{ platform_installed_adapters_find_result.files }}" + + - name: Install adapters + when: not offline_install_enabled + block: + - name: Remove the adapters already installed from the list of adapters + ansible.builtin.set_fact: + platform_adapters: "{{ platform_adapters | reject('search', item) }}" + loop: "{{ platform_installed_adapters }}" + when: + - platform_installed_adapters is defined + - platform_installed_adapters is iterable + - platform_installed_adapters | length > 0 + + # From the list of repos/zip files provided, extract the name of the adapter. This name + # will be used in a later step to perform the npm install. + # Examples: + # https://gitlab.com/itentialopensource/adapters/.git + # .zip + - name: Make a list of the adapter names + ansible.builtin.set_fact: + platform_adapter_names: "{{ platform_adapter_names + [item | basename | split('.') | first] }}" + loop: "{{ platform_adapters | default([], true) }}" + vars: + platform_adapter_names: [] + + - name: Disable safe repository checks + community.general.git_config: + name: safe.directory + scope: global + value: '*' + when: platform_disable_git_safe_repo_checks + + - name: Git clone adapter # noqa: latest (always clone the latest) + ansible.builtin.git: + repo: "{{ item }}" + dest: "{{ platform_services_dir }}/{{ platform_adapter_names[i] }}" + force: true + loop: "{{ platform_adapters | default([], true) }}" + loop_control: + index_var: i + when: (item | basename | split('.') | last) == "git" + + - name: Unzip adapter archive + ansible.builtin.unarchive: + src: "{{ item }}" + dest: "{{ platform_services_dir }}" + loop: "{{ platform_adapters | default([], true) }}" + loop_control: + index_var: i + when: (item | basename | split('.') | last) == "zip" + + - name: Delete package-lock.json file + ansible.builtin.file: + path: "{{ platform_services_dir }}/{{ item }}/package-lock.json" + state: absent + loop: "{{ platform_adapter_names }}" + when: platform_delete_package_lock_file + + - name: Run npm install + community.general.npm: + path: "{{ platform_services_dir }}/{{ item }}" + ignore_scripts: "{{ platform_npm_ignore_scripts }}" + loop: "{{ platform_adapter_names }}" + + - name: Install adapters (offline) + when: offline_install_enabled + block: + - name: Find downloaded adapters (offline) + ansible.builtin.find: + paths: "{{ platform_offline_control_node_adapters_dir }}" + patterns: "*.tgz" + register: platform_downloaded_adapters + changed_when: false + delegate_to: localhost + become: false + + # From the list of archives provided, extract the name of the adapter. + # Examples: + # --.tgz + - name: Make a list of the adapter names (offline) + ansible.builtin.set_fact: + platform_adapter_names: "{{ platform_adapter_names + [item.path | + regex_replace('^.*?(adapter-[^-]+(?:[_-][^-]+)*)-\\d.*\\.tgz$', '\\1')] }}" + loop: "{{ platform_downloaded_adapters.files | default([], true) }}" + vars: + platform_adapter_names: [] + when: + - platform_downloaded_adapters is defined + - platform_downloaded_adapters.files is defined + - platform_downloaded_adapters.files is iterable + - platform_downloaded_adapters.files | length > 0 + + - name: Remove the adapters already installed from the list of adapters names (offline) + ansible.builtin.set_fact: + platform_adapter_names: "{{ platform_adapter_names | reject('search', item) }}" + loop: "{{ platform_installed_adapters }}" + when: + - platform_adapter_names is defined + - platform_adapter_names is iterable + - platform_adapter_names | length > 0 + - platform_installed_adapters is defined + - platform_installed_adapters is iterable + - platform_installed_adapters | length > 0 + + - name: Install adapters (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-adapter + vars: + offline_src_adapters_path: "{{ platform_offline_control_node_adapters_dir }}" + offline_dest_adapters_path: "{{ platform_services_dir }}" + loop: "{{ platform_adapter_names }}" + loop_control: + loop_var: adapter_name + when: + - platform_adapter_names is defined + - platform_adapter_names is iterable + - platform_adapter_names | length > 0 + + - name: Set ownership and permissions and update release file + when: + - platform_adapter_names is defined + - platform_adapter_names is iterable + - platform_adapter_names | length > 0 + block: + # Using chown and chmod is a faster way to enforce the file ownership and + # permissions. The file module in ansible checks each and every file/dir + # in the tree, 'chown -R ' does not, it just sets it. + - name: Set appropriate ownership on all itential files + ansible.builtin.command: + cmd: "chown -R {{ platform_user }}:{{ platform_group }} + {{ platform_services_dir }}/{{ item }}" + loop: "{{ platform_adapter_names }}" + changed_when: true + + - name: Set appropriate permissions on all itential files + ansible.builtin.command: + cmd: "chmod -R 775 {{ platform_services_dir }}/{{ item }}" + loop: "{{ platform_adapter_names }}" + changed_when: true + + - name: Write adapter names to release file + ansible.builtin.lineinfile: + path: "/etc/itential-release" + line: "ADAPTER={{ item }}" + create: true + mode: '0644' + loop: "{{ platform_adapter_names }}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-app-artifacts.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-app-artifacts.yml new file mode 100644 index 00000000..9c1a4120 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-app-artifacts.yml @@ -0,0 +1,50 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install App Artifacts + notify: Enable and Start Platform + block: + - name: Make directory for App Artifacts + ansible.builtin.file: + path: "{{ platform_services_dir }}/app-artifacts" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: '0775' + state: directory + register: result + + - name: Install App Artifacts # noqa no-handler + when: result.changed + block: + - name: Unarchive App Artifacts + ansible.builtin.unarchive: + src: "{{ platform_app_artifacts_source_file }}" + dest: "{{ platform_services_dir }}/app-artifacts" + group: "{{ platform_user }}" + owner: "{{ platform_group }}" + extra_opts: --strip-components=1 + + # Using chown and chmod is a faster way to enforce the file ownership and + # permissions. The file module in ansible checks each and every file/dir + # in the tree, 'chown -R ' does not, it just sets it. + - name: Set ownership on App Artifacts + ansible.builtin.command: + argv: + - chown + - -R + - "{{ platform_user }}:{{ platform_group }}" + - "{{ platform_services_dir }}/app-artifacts" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 + + - name: Set permissions on App Artifacts + ansible.builtin.command: + argv: + - chmod + - -R + - u=rwX,g=rX,o=rX + - "{{ platform_services_dir }}/app-artifacts" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-nodejs-repo.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-nodejs-repo.yml new file mode 100644 index 00000000..4e931705 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-nodejs-repo.yml @@ -0,0 +1,22 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create temp working dir + ansible.builtin.tempfile: + state: directory + register: workingdir + +- name: Download NodeJS repo install script + ansible.builtin.get_url: + url: "{{ platform_nodejs_repo_url }}" + dest: "{{ workingdir.path }}/{{ platform_nodejs_repo_url | basename }}" + mode: "0755" + +- name: Install NodeJS yum repo + ansible.builtin.command: "{{ workingdir.path }}/{{ platform_nodejs_repo_url | basename }}" + changed_when: true + +- name: Remove workingdir + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-nodejs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-nodejs.yml new file mode 100644 index 00000000..15298c13 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-nodejs.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +- name: Install NodeJS + ansible.builtin.dnf: + name: "{{ platform_nodejs_package }}" + state: present + register: nodejs_install_result + when: not offline_install_enabled + +- name: Install NodeJS (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ platform_offline_control_node_rpms_dir }}/nodejs" + when: offline_install_enabled diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform-dependency-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform-dependency-packages.yml new file mode 100644 index 00000000..2c16f814 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform-dependency-packages.yml @@ -0,0 +1,16 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Platform dependencies + ansible.builtin.dnf: + name: "{{ platform_package_dependencies }}" + state: present + when: not offline_install_enabled + +- name: Install Platform dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ platform_offline_control_node_rpms_dir }}/dependencies" + when: offline_install_enabled diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform-packages-relocate.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform-packages-relocate.yml new file mode 100644 index 00000000..808dee6b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform-packages-relocate.yml @@ -0,0 +1,55 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# +# The ansible dnf module does not support passing the relocate flag. So the command module must +# be used if the standard install directories are overridden. +# + +# The Platform server package (itential-platform) must be installed first +# The server package supports the following prefixes that can be relocated: +# Prefix: /opt/itential/platform +# Prefix: /var/log/itential +# Prefix: /etc/itential +# Prefix: /home/itential +- name: Install Platform server package # noqa command-instead-of-module + ansible.builtin.command: > + rpm -Uvh + {% for reloc in relocations %} + {% if reloc.old != reloc.new %}--relocate {{ reloc.old }}={{ reloc.new }} {% endif %} + {% endfor %} + {{ item }} + register: platform_package_install_result + changed_when: platform_package_install_result.rc == 0 + failed_when: + - platform_package_install_result.rc != 0 + - platform_package_install_result.stderr is not search("already installed") + vars: + relocations: + - { old: "{{ platform_root_dir_default }}", new: "{{ platform_root_dir }}" } + - { old: "{{ platform_log_dir_default }}", new: "{{ platform_log_dir }}" } + - { old: "{{ platform_config_dir_default }}", new: "{{ platform_config_dir }}" } + - { old: "{{ platform_itential_home_dir_default }}", new: "{{ platform_itential_home_dir }}" } + loop: "{{ platform_packages_find_result.files | map(attribute='path') }}" + when: item is search("itential-platform") + +# The Itential Platform service packages +# The service packages support the following prefix that can be relocated: +# Prefix: /opt/itential/platform/services +- name: Install the Itential Platform service packages # noqa command-instead-of-module + ansible.builtin.command: > + rpm -Uvh + {% for reloc in relocations %} + {% if reloc.old != reloc.new %}--relocate {{ reloc.old }}={{ reloc.new }} {% endif %} + {% endfor %} + {{ item }} + register: platform_package_install_result + changed_when: platform_package_install_result.rc == 0 + failed_when: + - platform_package_install_result.rc != 0 + - platform_package_install_result.stderr is not search("already installed") + vars: + relocations: + - { old: "{{ platform_services_dir_default }}", new: "{{ platform_services_dir }}" } + loop: "{{ platform_packages_find_result.files | map(attribute='path') }}" + when: item is not search("itential-platform") diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform.yml new file mode 100644 index 00000000..5f2f4946 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-platform.yml @@ -0,0 +1,89 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Online install + when: not offline_install_enabled + block: + - name: Create temporary download directory + ansible.builtin.tempfile: + state: directory + register: platform_package_temp_download_dir + changed_when: false + + - name: Upload packages from control node + ansible.builtin.include_tasks: + file: upload-platform-archive-from-local.yml + loop: "{{ platform_packages }}" + loop_control: + loop_var: artifact + when: + - "'http' not in artifact" + - artifact.endswith('.rpm') + + - name: Download packages from repository + ansible.builtin.include_tasks: + file: download-platform-archive-from-repo.yml + loop: "{{ platform_packages }}" + loop_control: + loop_var: artifact + when: + - "'http' in artifact" + - artifact.endswith('.rpm') + + - name: Find downloaded packages + ansible.builtin.find: + paths: "{{ platform_package_temp_download_dir.path }}" + patterns: "*.rpm" + register: platform_packages_find_result + changed_when: false + + - name: Install the Itential Platform packages + when: platform_packages_find_result | length > 0 + block: + - name: Determine if the packages need to be relocated + ansible.builtin.set_fact: + platform_relocate_packages: true + when: > + (platform_root_dir != platform_root_dir_default or + platform_log_dir != platform_log_dir_default or + platform_config_dir != platform_config_dir_default or + platform_itential_home_dir != platform_itential_home_dir_default) + + - name: Install the Itential Platform packages (standard install directories) + ansible.builtin.dnf: + name: "{{ platform_packages_find_result.files | map(attribute='path') | join(',') }}" + disable_gpg_check: true + state: present + when: platform_relocate_packages is not defined + + - name: Install the Itential Platform packages (relocate install directories) + ansible.builtin.include_tasks: + file: install-platform-packages-relocate.yml + when: platform_relocate_packages is defined + + # TODO: Implement installing from a yum repo + # - name: Install the Itential Platform packages (YUM repository) + # ansible.builtin.dnf: + # name: "{{ item.path }}" + # disable_gpg_check: true + # state: present + # loop: "{{ platform_packages }}" + # loop_control: + # loop_var: artifact + # when: + # - "'http' not in artifact" + # - not artifact.endswith('.rpm') + + - name: Remove temporary download directory + ansible.builtin.file: + path: "{{ platform_package_temp_download_dir.path }}" + state: absent + changed_when: false + +- name: Install Platform (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ platform_offline_control_node_rpms_dir }}/platform" + when: offline_install_enabled diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-python.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-python.yml new file mode 100644 index 00000000..55ccfce7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/install-python.yml @@ -0,0 +1,57 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Online install + when: not offline_install_enabled + block: + - name: Install Python + ansible.builtin.include_role: + name: python + tags: install_python + vars: + python_packages: "{{ platform_python_packages }}" + + - name: Create python3 symlinks + ansible.builtin.include_role: + name: python + tasks_from: create-symlinks + tags: install_python + vars: + python_executable: "{{ platform_python_executable }}" + python_pip_executable: "{{ platform_pip_executable }}" + + - name: Install Python dependencies + ansible.builtin.include_role: + name: python + tasks_from: install-dependencies + tags: install_python + vars: + python_pip_executable: "{{ platform_pip_executable }}" + python_base_dependencies: "{{ platform_python_base_dependencies }}" + python_app_dependencies: "{{ platform_python_app_dependencies }}" + +- name: Install Python (offline) + when: offline_install_enabled + block: + - name: Install Python RPMs (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ platform_offline_control_node_rpms_dir }}/python" + + - name: Install base Python dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-wheels + vars: + offline_pip_executable: "{{ platform_pip_executable }}" + offline_wheels_dir: "{{ platform_offline_control_node_wheels_dir }}/base" + + - name: Install application Python dependencies (offline) + ansible.builtin.include_role: + name: offline + tasks_from: install-wheels + vars: + offline_pip_executable: "{{ platform_pip_executable }}" + offline_wheels_dir: "{{ platform_offline_control_node_wheels_dir }}/app" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/main.yml new file mode 100644 index 00000000..00ead95d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/main.yml @@ -0,0 +1,127 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate vars + ansible.builtin.include_tasks: + file: validate-vars.yml + tags: always + +- name: Install and configure Itential Platform + notify: Enable and Start Platform + block: + - name: Configure OS + tags: configure_os + block: + # TODO: Remove once the Itential RPM is creating the directories correctly + - name: Create itential user + ansible.builtin.include_tasks: + file: create-itential-user.yml + + # TODO: Remove once the Itential RPM is creating the directories correctly + - name: Create itential directories + ansible.builtin.file: + name: "{{ item }}" + state: directory + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: "0775" + with_items: + - "{{ platform_server_dir }}" + - "{{ platform_config_dir }}" + - "{{ platform_log_dir }}" + + - name: Ensure secure mode for TemplateBuilder + ansible.builtin.lineinfile: + path: /etc/sudoers + insertafter: EOF + state: present + line: "{{ platform_user }} ALL=(ALL) NOPASSWD: /usr/sbin/chroot, /sbin/chroot" + + - name: Configure firewalld + ansible.builtin.include_tasks: + file: configure-firewalld.yml + + - name: Install Dependencies, Platform, Adapters and App Artifacts + notify: Update Itential release file + block: + - name: Install Dependencies + tags: install_dependencies + block: + - name: Install Platform package dependencies + ansible.builtin.include_tasks: + file: install-platform-dependency-packages.yml + + - name: Install NodeJS + tags: install_nodejs + block: + - name: Install NodeJS + ansible.builtin.include_tasks: + file: install-nodejs.yml + + - name: Install Python + tags: install_python + block: + - name: Install Python + ansible.builtin.include_tasks: + file: install-python.yml + + - name: Install Platform + tags: install_platform + block: + - name: Install Platform + ansible.builtin.include_tasks: + file: install-platform.yml + + - name: Install Adapters + tags: install_adapters + block: + - name: Install Adapters + ansible.builtin.include_tasks: + file: install-adapters.yml + + - name: Install App Artifacts + tags: install_app_artifacts + when: platform_app_artifacts_enabled | bool + block: + - name: Install App Artifacts + ansible.builtin.include_tasks: + file: install-app-artifacts.yml + + - name: Configure SELinux + tags: configure_selinux + block: + - name: Configure SELinux + ansible.builtin.include_tasks: + file: configure-selinux.yml + + - name: Configure Vault + when: platform_configure_vault | bool + tags: configure_vault + block: + - name: Configure Vault + ansible.builtin.include_tasks: + file: configure-vault.yml + + - name: Copy certs + tags: copy_certs + block: + - name: Copy certs + ansible.builtin.include_tasks: + file: copy-certs.yml + + - name: Configure Platform + tags: configure_platform + block: + - name: Configure Platform + ansible.builtin.include_tasks: + file: configure-platform.yml + +- name: Start Itential Platform service + tags: + - always + - start_service + - start_platform_service + block: + - name: Start Itential Platform service + ansible.builtin.include_tasks: + file: start-service.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/preflight.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/preflight.yml new file mode 100644 index 00000000..3c654baf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/preflight.yml @@ -0,0 +1,56 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "{{ iap_release }}-{{ ansible_distribution | lower }}-{{ ansible_distribution_major_version }}.yml" + - "release-undefined.yml" + +- name: Run common checks + ansible.builtin.include_role: + name: preflight + vars: + preflight_url_checks: + - "https://gitlab.com/itentialopensource" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: workingdir + +- name: Set pass to true if all conditions pass + ansible.builtin.set_fact: + results: '{{ results | combine({"pass": true}) }}' + when: + - results.cpuCores >= platform_cpu_cores + - results.get(mountvarname, 0) >= platform_free_disk_space + - results.memory >= platform_ram + - results.url_status.values() | unique | length == 1 and results.url_status.values() | unique | first == 200 + +- name: Create Platform preflight results + ansible.builtin.template: + src: "platform.preflight.j2" + dest: "{{ workingdir.path }}/preflightResults.txt" + mode: '0777' + +- name: Fetch Platform results + ansible.builtin.fetch: + src: "{{ workingdir.path }}/preflightResults.txt" + dest: "{{ preflight_directory }}/platform_{{ inventory_hostname }}_results.txt" + flat: true + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent + +- name: Check if host passed preflight checks. + ansible.builtin.assert: + that: results["pass"] == true + fail_msg: "Platform host did not pass the preflight checks" + success_msg: "Platform host passed the preflight checks" + when: + - preflight_enforce_checks is defined + - preflight_enforce_checks diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/set-file-ownership.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/set-file-ownership.yml new file mode 100644 index 00000000..6ea7ba6c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/set-file-ownership.yml @@ -0,0 +1,18 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +# TODO: Remove this file once the RPM is creating the directories correctly + +# Using chown and chmod is a faster way to enforce the file ownership and +# permissions. The file module in ansible checks each and every file/dir +# in the tree, 'chown -R' does not, it just sets it. +- name: Set appropriate ownership on all itential files + ansible.builtin.command: + cmd: "chown -R {{ platform_user }}:{{ platform_group }} {{ platform_server_dir }}" + changed_when: true + +- name: Set appropriate permissions on all itential files + ansible.builtin.command: + cmd: "chmod -R 775 {{ platform_server_dir }}" + changed_when: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/start-service.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/start-service.yml new file mode 100644 index 00000000..f2674cc9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/start-service.yml @@ -0,0 +1,19 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Ensure Itential Platform is running + when: platform_start_service | bool + block: + - name: Flush all handlers + ansible.builtin.meta: flush_handlers + + - name: Start Itential Platform + ansible.builtin.systemd: + name: itential-platform + state: started + + - name: Assert that Itential Platform is running + ansible.builtin.systemd: + name: itential-platform + register: platform_status + failed_when: platform_status.status.ActiveState != "active" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/update-release-file.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/update-release-file.yml new file mode 100644 index 00000000..1cd90e19 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/update-release-file.yml @@ -0,0 +1,120 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Update release file with Itential Platform version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^PLATFORM=" + line: "PLATFORM={{ platform_release }}" + mode: "0644" + create: true + +- name: Gather the package facts + ansible.builtin.package_facts: + manager: auto + +- name: Capture Platform packages + ansible.builtin.set_fact: + filtered_package_names: "{{ ansible_facts.packages | list + | select('match', '^itential.*') | list }}" + +- name: Update release file with Itential packages + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^PLATFORM_PACKAGES=" + line: "PLATFORM_PACKAGES={{ filtered_package_names }}" + mode: "0644" + create: true + +- name: Capture Python version + ansible.builtin.command: + cmd: "{{ platform_python_executable }} -V" + register: python_installed_version + changed_when: false + +- name: Update release file with Python version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^PYTHON=" + line: "PYTHON={{ python_installed_version.stdout }}" + mode: "0644" + create: true + +- name: Capture Pip version + ansible.builtin.command: + cmd: "{{ platform_pip_executable }} -V" + register: pip_installed_version + changed_when: false + +- name: Update release file with Pip version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^PIP=" + line: "PIP={{ pip_installed_version.stdout }}" + mode: "0644" + create: true + +- name: Capture Jinja2 version + ansible.builtin.shell: + cmd: "set -o pipefail && {{ platform_pip_executable }} list --retries 1 --timeout 1 + | grep -i jinja2 | awk '{print $2}'" + become: true + become_user: "{{ platform_user }}" + register: jinja2_installed_version + changed_when: false + +- name: Update release file with Jinja2 version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^JINJA2=" + line: "JINJA2={{ jinja2_installed_version.stdout }}" + mode: "0644" + create: true + +- name: Capture MarkupSafe version + ansible.builtin.shell: + cmd: "set -o pipefail && {{ platform_pip_executable }} list --retries 1 --timeout 1 + | grep -i markupsafe | awk '{print $2}'" + become: true + become_user: "{{ platform_user }}" + register: markupsafe_installed_version + changed_when: false + +- name: Update release file with MarkupSafe version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^MARKUPSAFE=" + line: "MARKUPSAFE={{ markupsafe_installed_version.stdout }}" + mode: "0644" + create: true + +- name: Capture TextFSM version + ansible.builtin.shell: + cmd: "set -o pipefail && {{ platform_pip_executable }} list --retries 1 --timeout 1 + | grep -i textfsm | awk '{print $2}'" + become: true + become_user: "{{ platform_user }}" + register: textfsm_installed_version + changed_when: false + +- name: Update release file with TextFMS version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^TEXTFSM=" + line: "TEXTFSM={{ textfsm_installed_version.stdout }}" + mode: "0644" + create: true + +- name: Capture NodeJS version + ansible.builtin.command: + cmd: node --version + register: nodejs_installed_version + changed_when: false + +- name: Update release file with NodeJS version + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^NODEJS=" + line: "NODEJS={{ nodejs_installed_version.stdout }}" + mode: "0644" + create: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/upgrade-platform.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/upgrade-platform.yml new file mode 100644 index 00000000..eb18e3b7 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/upgrade-platform.yml @@ -0,0 +1,31 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate vars + ansible.builtin.include_tasks: + file: validate-vars.yml + tags: always + +# Install the new Itential Platform packages and update properties +- name: Upgrade platform and update service and properties + notify: + - Enable and Start Platform + - Update Itential release file + block: + - name: Install Platform packages + ansible.builtin.include_tasks: + file: install-platform.yml + + - name: Configure Platform + ansible.builtin.include_tasks: + file: configure-platform.yml + +- name: Start Itential Platform service + tags: + - always + - start_service + - start_platform_service + block: + - name: Start Itential Platform service + ansible.builtin.include_tasks: + file: start-service.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/upload-platform-archive-from-local.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/upload-platform-archive-from-local.yml new file mode 100644 index 00000000..6494e816 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/upload-platform-archive-from-local.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Upload the Itential Platform artifact file using rsync + ansible.posix.synchronize: + src: "{{ artifact }}" + dest: "{{ platform_package_temp_download_dir.path }}/{{ artifact }}" + rsync_opts: "--copy-links" + when: platform_upload_using_rsync + changed_when: false + +- name: Upload the Itential Platform artifact file using copy + ansible.builtin.copy: + src: "{{ artifact }}" + dest: "{{ platform_package_temp_download_dir.path }}/{{ artifact }}" + owner: "{{ platform_user }}" + group: "{{ platform_group }}" + mode: "0775" + force: false + when: not platform_upload_using_rsync + changed_when: false diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/validate-vars.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/validate-vars.yml new file mode 100644 index 00000000..bd47efa2 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/tasks/validate-vars.yml @@ -0,0 +1,150 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate and set installation variables + tags: always + block: + - name: Validate Itential Platform packages array is populated + ansible.builtin.assert: + that: + - platform_packages is defined + - platform_packages is iterable + - platform_packages | length > 0 + fail_msg: platform_packages must be defined and contain as least one artifact + when: not offline_install_enabled | bool + + - name: Validate Itential Platform packages array contains only RPMs + ansible.builtin.assert: + that: "{{ item.endswith('.rpm') }}" + fail_msg: platform_packages can only contain RPM packages ending in .rpm" + loop: "{{ platform_packages }}" + when: not offline_install_enabled | bool + + - name: Validate download auth method is defined when downloading Itential Platform packages + ansible.builtin.assert: + that: (repository_username is defined and repository_password is defined) or + repository_api_key is defined + fail_msg: >- + repository_api_key or repository_username/repository_password + must be defined when downloading platform_packages + when: + - not offline_install_enabled | bool + - platform_packages is search('http') + + - name: Validate installation variables are defined + ansible.builtin.assert: + that: | + (platform_release is defined) or + (platform_nodejs_package is defined and + platform_python_version is defined and + platform_python_packages is defined and + platform_python_app_dependencies is defined) + fail_msg: >- + platform_release OR + platform_nodejs_package, platform_python_version, platform_python_packages, and + platform_python_app_dependencies must be defined + + - name: Validate installation variables when not using platform_release + ansible.builtin.assert: + that: + - platform_nodejs_package is defined + - platform_python_version is defined + - platform_python_packages is defined + - platform_python_app_dependencies is defined + fail_msg: >- + platform_nodejs_package, platform_python_version, platform_python_packages, and + platform_python_app_dependencies must be defined when platform_release is not defined + when: platform_release is not defined + + - name: Validate that the platform_encryption_key variable exists + ansible.builtin.assert: + that: platform_encryption_key is defined + fail_msg: platform_encryption_key variable must be defined + when: validate_platform_encryption_key | default(true) + + - name: Validate that the platform_encryption_key variable is correctly formatted + ansible.builtin.assert: + that: + - platform_encryption_key is match('^[0-9a-fA-F]+$') + - platform_encryption_key | length == 64 + fail_msg: platform_encryption_key must be a 64 character hexadecimal string + when: validate_platform_encryption_key | default(true) + + - name: Validate Hashicorp Vault variables + when: platform_configure_vault | bool + block: + - name: Validate Hashicorp token is set when using token authentication + ansible.builtin.assert: + that: platform_vault_token is truthy + fail_msg: platform_vault_token must be defined when using token authentication + when: platform_vault_auth_method == 'token' + + - name: Validate Hashicorp approle id and secret id are set when using approle authentication + ansible.builtin.assert: + that: + - platform_vault_role_id is truthy + - platform_vault_secret_id is truthy + fail_msg: platform_vault_role_id and platform_vault_secret_id must be defined when using approle authentication + when: platform_vault_auth_method == 'approle' + + - name: Set installation variables when using Itential Platform release defaults + when: platform_release is defined + block: + - name: Load Itential Platform release default variables + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "platform-release-{{ platform_release }}.yml" + - "platform-release-{{ platform_release | string | split('.') | first }}.yml" + - "platform-release-undefined.yml" + + - name: Check for valid Itential Platform release + ansible.builtin.assert: + that: platform_invalid_release is not defined + fail_msg: >- + Deployer does not support installing Itential Platform release {{ platform_release }}" + + - name: Set platform_nodejs_package to the default value + when not defined in inventory + ansible.builtin.set_fact: + platform_nodejs_package: + "{{ platform_nodejs_package_default[ansible_distribution_major_version] }}" + when: platform_nodejs_package is not defined + + - name: Set platform_python_version to the default value + when not defined in inventory + ansible.builtin.set_fact: + platform_python_version: + "{{ platform_python_version_default[ansible_distribution_major_version] }}" + when: platform_python_version is not defined + + - name: Set platform_python_packages to the default value + when not defined in inventory + ansible.builtin.set_fact: + platform_python_packages: + "{{ platform_python_packages_default[ansible_distribution_major_version] }}" + when: platform_python_packages is not defined + + - name: Set platform_python_app_dependencies to the default value + when not defined in inventory + ansible.builtin.set_fact: + platform_python_app_dependencies: + "{{ platform_python_app_dependencies_default[ansible_distribution_major_version] }}" + when: platform_python_app_dependencies is not defined + + - name: Print Itential Platform installation details + ansible.builtin.debug: + msg: + - "Platform packages: {{ platform_packages }}" + - "Platform dependency packages: {{ platform_package_dependencies }}" + - "NodeJS package: {{ platform_nodejs_package }}" + - "Python version: {{ platform_python_version }}" + - "Python packages: {{ platform_python_packages }}" + - "Python base dependencies: {{ platform_python_base_dependencies }}" + - "Python Platform dependencies: {{ platform_python_app_dependencies }}" + when: not offline_install_enabled | bool + + - name: Print Itential Platform installation details (offline) + ansible.builtin.debug: + msg: "Offline install using packages from {{ platform_offline_control_node_root }}" + when: offline_install_enabled | bool diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/6-properties.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/6-properties.j2 new file mode 100644 index 00000000..6438d49d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/6-properties.j2 @@ -0,0 +1,847 @@ +########## +# SERVER # +########## +# The name of the profile document to load from the MongoDB where legacy configuration +# properties are stored. Not required for installations that are using environment +# variables or a properties file. +{% if platform_profile_id %} +profile_id = {{ platform_profile_id }} +{% else %} +# profile_id = +{% endif %} + +# The file path to the directory containing additional services (applications and adapters). +{% set service_dirs = [] %} +{% if platform_root_dir != platform_root_dir_default %} +{% set service_dirs = service_dirs + [platform_services_dir] %} +{% endif %} +{% if platform_service_directory %} +{% set service_dirs = service_dirs + (platform_service_directory | select() | list) %} +{% endif %} +{% if service_dirs %} +service_directory = {{ service_dirs | unique | join(',') }} +{% else %} +# service_directory = +{% endif %} + +# An identifier for the server instance. This is used to uniquely identify the server in a +# multi-server environment. If not provided, the server will generate one on startup. +{% if platform_server_id %} +server_id = {{ platform_server_id }} +{% else %} +# server_id = +{% endif %} + +# A whitelist of services (applications/adapters) to initialize on startup of the platform. +# If no value is given, all services will be initialized. +{% if platform_services %} +services = {{ platform_services | join(',') }} +{% else %} +# services = +{% endif %} + +# The service type that will be denied CRUD operation access. +{% if platform_service_blacklist %} +service_blacklist = {{ platform_service_blacklist }} +{% else %} +# service_blacklist = +{% endif %} + +# Indicates whether the platform is using encrypted code files. +{% if ( (platform_encrypted is defined) and + (platform_encrypted is boolean) ) %} +platform_encrypted = {{ platform_encrypted | to_nice_json }} +{% else %} +# platform_encrypted = +{% endif %} + +# 64-length hex string describing a 256 bit encryption key. +{% if platform_encryption_key %} +encryption_key = {{ platform_encryption_key }} +{% else %} +# encryption_key = +{% endif %} + +# The amount of time a service should wait before shutting down, in seconds. +{% if platform_shutdown_timeout %} +platform_shutdown_timeout = {{ platform_shutdown_timeout }} +{% else %} +# platform_shutdown_timeout = +{% endif %} + +# The application/adapter launch delay, in seconds. +{% if platform_service_launch_delay %} +service_launch_delay = {{ platform_service_launch_delay }} +{% else %} +# service_launch_delay = +{% endif %} + +# The application/adapter launch timeout, in seconds. +{% if platform_service_launch_timeout %} +service_launch_timeout = {{ platform_service_launch_timeout }} +{% else %} +# service_launch_timeout = +{% endif %} + +# How often to update service health, measured in seconds. +{% if platform_service_health_check_interval %} +service_health_check_interval = {{ platform_service_health_check_interval }} +{% else %} +# service_health_check_interval = +{% endif %} + +# The number of failed health checks in a row before a service is considered to be “unhealthy”. +{% if platform_service_health_check_unhealthy_threshold %} +service_health_check_unhealthy_threshold = {{ platform_service_health_check_unhealthy_threshold }} +{% else %} +# service_health_check_unhealthy_threshold = +{% endif %} + +# If true, the platform will periodically check for dead processes. +{% if ( (platform_dead_process_check_enabled is defined) and + (platform_dead_process_check_enabled is boolean) ) %} +dead_process_check_enabled = {{ platform_dead_process_check_enabled | to_nice_json }} +{% else %} +# dead_process_check_enabled = +{% endif %} + +# How often to check if application/adapter stopped sending healthcheck pings, in seconds. +{% if platform_dead_process_check_interval %} +dead_process_check_interval = {{ platform_dead_process_check_interval }} +{% else %} +# dead_process_check_interval = +{% endif %} + +# Maximum time period for application/adapter without sending healthcheck ping, in seconds. +{% if platform_dead_process_max_period %} +dead_process_max_period = {{ platform_dead_process_max_period }} +{% else %} +# dead_process_max_period = +{% endif %} + +# Specifies the amount of times services will retry on crash before stopping. +{% if platform_service_crash_recovery_max_retries %} +service_crash_recovery_max_retries = {{ platform_service_crash_recovery_max_retries }} +{% else %} +# service_crash_recovery_max_retries = +{% endif %} + +# Specifies the amount of times between each retry before the count will reset in milliseconds. +{% if platform_service_crash_recovery_reset_retries_after_ms %} +service_crash_recovery_reset_retries_after_ms = {{ platform_service_crash_recovery_reset_retries_after_ms }} +{% else %} +# service_crash_recovery_reset_retries_after_ms = +{% endif %} + +# The timeout for external API requests, in seconds. +{% if platform_external_request_timeout %} +external_request_timeout = {{ platform_external_request_timeout }} +{% else %} +# external_request_timeout = +{% endif %} + +# The interval for how often IAP polls for the number of devices, in hours. +{% if platform_device_count_polling_interval %} +device_count_polling_interval = {{ platform_device_count_polling_interval }} +{% else %} +# device_count_polling_interval = +{% endif %} + +# If true, the platform will track detailed audit events. +{% if ( (platform_audit_enabled is defined) and + (platform_audit_enabled is boolean) ) %} +audit_enabled = {{ platform_audit_enabled | to_nice_json }} +{% else %} +# audit_enabled = +{% endif %} + + +############################# +# MONGO DATABASE CONNECTION # +############################# +# Instructs the MongoDB driver to use the configured username/password when connecting to MongoDB. +{% if ( (platform_mongo_auth_enabled is defined) and + (platform_mongo_auth_enabled is boolean) ) %} +mongo_auth_enabled = {{ platform_mongo_auth_enabled | to_nice_json }} +{% else %} +# mongo_auth_enabled = +{% endif %} + +# The username to use when connecting to MongoDB. +{% if platform_mongo_user %} +mongo_user = {{ platform_mongo_user }} +{% else %} +# mongo_user = +{% endif %} + +# The password to use when connecting to MongoDB. +{% if platform_mongo_password_encrypted is defined %} +mongo_password = {{ platform_mongo_password_encrypted }} +{% elif platform_mongo_password_vault and platform_configure_vault | bool %} +mongo_password = {{ platform_mongo_password_vault }} +{% elif platform_mongo_password %} +mongo_password = {{ platform_mongo_password }} +{% else %} +# mongo_password = +{% endif %} + +# The name of the database that the MongoDB user must authenticate against. +{% if platform_mongo_auth_db %} +mongo_auth_db = {{ platform_mongo_auth_db }} +{% else %} +# mongo_auth_db = +{% endif %} + +# If true, the server will not check if it is connecting to a compatible MongoDB version. +{% if ( (platform_mongo_bypass_version_check is defined) and + (platform_mongo_bypass_version_check is boolean) ) %} +mongo_bypass_version_check = {{ platform_mongo_bypass_version_check | to_nice_json }} +{% else %} +# mongo_bypass_version_check = +{% endif %} + +# The name of the MongoDB logical database to connect to. +{% if platform_mongo_db_name %} +mongo_db_name = {{ platform_mongo_db_name }} +{% else %} +# mongo_db_name = +{% endif %} + +# The MongoDB connection string. For a replica set this will include all members of the +# replica set. For Mongo Atlas this will be the SRV connection format. +{% if platform_mongo_url %} +mongo_url = {{ platform_mongo_url }} +{% else %} +# mongo_url = +{% endif %} + +# Instruct the MongoDB driver to use TLS protocols when connecting to the database. +{% if ( (platform_mongo_tls_enabled is defined) and + (platform_mongo_tls_enabled is boolean) ) %} +mongo_tls_enabled = {{ platform_mongo_tls_enabled | to_nice_json }} +{% else %} +# mongo_tls_enabled = +{% endif %} + +# If true, disables the validation checks for TLS certificates on other servers in the cluster +# and allows the use of invalid or self-signed certificates to connect. +{% if ( (platform_mongo_tls_allow_invalid_certificates is defined) and + (platform_mongo_tls_allow_invalid_certificates is boolean) ) %} +mongo_tls_allow_invalid_certificates = {{ platform_mongo_tls_allow_invalid_certificates | to_nice_json }} +{% else %} +# mongo_tls_allow_invalid_certificates = +{% endif %} + +# The .pem file that contains the root certificate chain from the Certificate Authority. +# Specify the file name of the .pem file using absolute paths. +{% if platform_mongo_tls_ca_file %} +mongo_tls_ca_file = {{ platform_mongo_tls_ca_file }} +{% else %} +# mongo_tls_ca_file = +{% endif %} + +# The maximum number of connections in a connection pool. +# Each application/adapter has its own connection pool. +{% if platform_mongo_max_pool_size %} +mongo_max_pool_size = {{ platform_mongo_max_pool_size }} +{% else %} +# mongo_max_pool_size = +{% endif %} + + +#################### +# REDIS CONNECTION # +#################### +# The Redis keyspace (database number) to use for the connection. +{% if platform_redis_db %} +redis_db = {{ platform_redis_db }} +{% else %} +# redis_db = +{% endif %} + +# The username to use when connecting to Redis. +{% if platform_redis_username and platform_redis_auth_enabled | bool %} +redis_username = {{ platform_redis_username }} +{% else %} +# redis_username = +{% endif %} + +# The password to use when connecting to Redis. +{% if platform_redis_password_encrypted is defined and platform_redis_auth_enabled | bool %} +redis_password = {{ platform_redis_password_encrypted }} +{% elif platform_redis_password_vault and platform_configure_vault | bool %} +redis_password = {{ platform_redis_password_vault }} +{% elif platform_redis_password and platform_redis_auth_enabled | bool %} +redis_password = {{ platform_redis_password }} +{% else %} +# redis_password = +{% endif %} + +# The maximum number of times to retry a request to Redis when the connection is lost. +{% if platform_redis_max_retries_per_request %} +redis_max_retries_per_request = {{ platform_redis_max_retries_per_request }} +{% else %} +# redis_max_retries_per_request = +{% endif %} + +# The maximum number of times to retry writing a heartbeat message to Redis from a service. +{% if platform_redis_max_heartbeat_write_retries %} +redis_max_heartbeat_write_retries = {{ platform_redis_max_heartbeat_write_retries }} +{% else %} +# redis_max_heartbeat_write_retries = +{% endif %} + +# The hostname of the Redis server. Not used when connecting to Redis Sentinels. +{% if platform_redis_host and not platform_redis_sentinels %} +redis_host = {{ platform_redis_host }} +{% else %} +# redis_host = +{% endif %} + +# The port to use when connecting to this Redis instance. +{% if platform_redis_port %} +redis_port = {{ platform_redis_port }} +{% else %} +# redis_port = +{% endif %} + +# The username to use when authenticating with a Redis Sentinel cluster +{% if platform_redis_sentinel_username and platform_redis_auth_enabled | bool %} +redis_sentinel_username = {{ platform_redis_sentinel_username }} +{% else %} +# redis_sentinel_username = +{% endif %} + +# The password to use when authenticating with a Redis Sentinel cluster +{% if platform_redis_sentinel_password_encrypted is defined and platform_redis_auth_enabled | bool %} +redis_sentinel_password = {{ platform_redis_sentinel_password_encrypted }} +{% elif platform_redis_sentinel_password and platform_redis_auth_enabled | bool %} +redis_sentinel_password = {{ platform_redis_sentinel_password }} +{% else %} +# redis_sentinel_password = +{% endif %} + +# The list of Redis Sentinel servers (hostnames and ports) to use for high availability. +{% if platform_redis_sentinels %} +redis_sentinels = {{ platform_redis_sentinels | to_json }} +{% else %} +# redis_sentinels = +{% endif %} + +# The Redis primary name. This only has meaning when Redis is running with replication enabled. +# The sentinels will monitor this node and consider it down only when the sentinels agree. +# Note: The primary name should not include special characters other than: .-_ and no whitespaces. +{% if platform_redis_name %} +redis_name = {{ platform_redis_name }} +{% else %} +# redis_name = +{% endif %} + +# Redis TLS configuration options for secure connections. +# Refer to NodeJS TLS library for all supported options. +{% if platform_redis_tls %} +redis_tls = {{ platform_redis_tls }} +{% else %} +# redis_tls = +{% endif %} + + +############################## +# HASHICORP VAULT CONNECTION # +############################## +# The URL to the Hashicorp Vault server. +{% if platform_configure_vault | bool and platform_vault_url %} +vault_url = {{ platform_vault_url }} +{% else %} +# vault_url = +{% endif %} + +# The authorization method to connect to Hashicorp Vault. Either token or approle. +{% if platform_configure_vault | bool and platform_vault_auth_method %} +vault_auth_method = {{ platform_vault_auth_method }} +{% else %} +# vault_auth_method = +{% endif %} + +# Hashicorp Vault Role ID used for AppRole authentication. +{% if platform_configure_vault and platform_vault_role_id_property %} +vault_role_id = {{ platform_vault_role_id_property }} +{% else %} +# vault_role_id = +{% endif %} + +# Hashicorp Vault Secret ID used for AppRole login. +{% if platform_configure_vault and platform_vault_secret_id_property %} +vault_secret_id = {{ platform_vault_secret_id_property }} +{% else %} +# vault_secret_id = +{% endif %} + +# The path where the AppRole was enabled. +{% if platform_configure_vault and platform_vault_approle_path %} +vault_approle_path = {{ platform_vault_approle_path }} +{% else %} +# vault_approle_path = +{% endif %} + +# The file path to a token file. The token is used for authentication to access Vault secrets. +{% if platform_configure_vault and platform_vault_auth_method == "token" and platform_vault_token_file %} +vault_token = {{ platform_vault_token_file }} +{% else %} +# vault_token = +{% endif %} + +# The endpoint for the Secrets Engine that is used. +{% if platform_configure_vault and platform_vault_secrets_endpoint %} +vault_secrets_endpoint = {{ platform_vault_secrets_endpoint }} +{% else %} +# vault_secrets_endpoint = +{% endif %} + +# If true, only reads secrets from Hashicorp Vault. Otherwise, the platform can write secrets +# to Vault for storage. +{% if ( (platform_configure_vault is defined) and + (platform_vault_read_only is boolean) ) %} +vault_read_only = {{ platform_vault_read_only | to_nice_json }} +{% else %} +# vault_read_only = +{% endif %} + + +################### +# WORKFLOW WORKER # +################### +# If true, will start working tasks immediately after the server startup process is complete. +# If false, the task worker must be enabled manually via the UI/API. +{% if ( (platform_task_worker_enabled is defined) and + (platform_task_worker_enabled is boolean) ) %} +task_worker_enabled = {{ platform_task_worker_enabled | to_nice_json }} +{% else %} +# task_worker_enabled = +{% endif %} + +# If true, will allow jobs to be started after the server startup process is complete. +# If false, API calls to start Jobs will return an error until enabled manually via the UI/API. +{% if ( (platform_job_worker_enabled is defined) and + (platform_job_worker_enabled is boolean) ) %} +job_worker_enabled = {{ platform_job_worker_enabled | to_nice_json }} +{% else %} +# job_worker_enabled = +{% endif %} + + +###################### +# INTEGRATION WORKER # +###################### +# The number of threads available for API requests. +{% if platform_integration_thread_count %} +integration_thread_count = {{ platform_integration_thread_count }} +{% else %} +# integration_thread_count = +{% endif %} + +# The number of milliseconds until an integration request times out. +{% if platform_integration_timeout %} +integration_timeout = {{ platform_integration_timeout }} +{% else %} +# integration_timeout = +{% endif %} + + +############### +# PLATFORM UI # +############### +# Path to the layout file extended in pug templates. +{% if platform_ui_layout_file %} +ui_layout_file = {{ platform_ui_layout_file }} +{% else %} +# ui_layout_file = +{% endif %} + +# Path to the HTML file that will be displayed as the home page for the UI. +{% if platform_ui_home_file %} +ui_home_file = {{ platform_ui_home_file }} +{% else %} +# ui_home_file = +{% endif %} + +# Path to the HTML file that will be displayed as the login page for the UI. +{% if platform_ui_login_file %} +ui_login_file = {{ platform_ui_login_file }} +{% else %} +# ui_login_file = +{% endif %} + +# Path to the HTML file that will be displayed as the profile page for the UI. +{% if platform_ui_profile_file %} +ui_profile_file = {{ platform_ui_profile_file }} +{% else %} +# ui_profile_file = +{% endif %} + +# Path to the favicon file that will be displayed in the browser tab. +{% if platform_ui_favicon_file %} +ui_favicon_file = {{ platform_ui_favicon_file }} +{% else %} +# ui_favicon_file = +{% endif %} + +# Path to the apple touch icon file that will be displayed on iOS devices. +{% if platform_ui_apple_touch_icon_file %} +ui_apple_touch_icon_file = {{ platform_ui_apple_touch_icon_file }} +{% else %} +# ui_apple_touch_icon_file = +{% endif %} + + +################## +# AUTHENTICATION # +################## +# If true, logs out existing sessions for a user when they log in with a new session. +{% if ( (platform_auth_unique_sessions_enabled is defined) and + (platform_auth_unique_sessions_enabled is boolean) ) %} +auth_unique_sessions_enabled = {{ platform_auth_unique_sessions_enabled | to_nice_json }} +{% else %} +# auth_unique_sessions_enabled = +{% endif %} + +# Members of these groups will be implicitly assigned with admin permissions. +{% if platform_auth_admin_groups %} +auth_admin_groups = {{ platform_auth_admin_groups | to_json }} +{% else %} +# auth_admin_groups = +{% endif %} + +# Enables a AAA adapter to custom build the principal object for a user with +# a "buildPrincipal" method. +{% if ( (platform_auth_broker_principal_enabled is defined) and + (platform_auth_broker_principal_enabled is boolean) ) %} +auth_broker_principal_enabled = {{ platform_auth_broker_principal_enabled | to_nice_json }} +{% else %} +# auth_broker_principal_enabled = +{% endif %} + +# The name of the cookie used for a user session. +{% if platform_auth_session_cookie_name %} +auth_session_cookie_name = {{ platform_auth_session_cookie_name }} +{% else %} +# auth_session_cookie_name = +{% endif %} + +# The time in minutes before a user session expires. +{% if platform_auth_session_ttl %} +auth_session_ttl = {{ platform_auth_session_ttl }} +{% else %} +# auth_session_ttl = +{% endif %} + +# Enables a default user to be used for login when SSO is not configured and no AAA Adapter exists. +{% if ( (platform_default_user_enabled is defined) and + (platform_default_user_enabled is boolean) ) %} +default_user_enabled = {{ platform_default_user_enabled | to_nice_json }} +{% else %} +# default_user_enabled = +{% endif %} + +# The username of the default user. +{% if platform_default_user_username %} +default_user_username = {{ platform_default_user_username }} +{% else %} +# default_user_username = +{% endif %} + +# The password of the default user. +{% if platform_default_user_password_encrypted is defined %} +default_user_password = {{ platform_default_user_password_encrypted }} +{% elif platform_default_user_password %} +default_user_password = {{ platform_default_user_password }} +{% else %} +# default_user_password = +{% endif %} + + +############# +# WEBSERVER # +############# +# A toggle to instruct the webserver to include HTTP cache control headers on the response. +{% if ( (platform_webserver_cache_control_enabled is defined) and + (platform_webserver_cache_control_enabled is boolean) ) %} +webserver_cache_control_enabled = {{ platform_webserver_cache_control_enabled | to_nice_json }} +{% else %} +# webserver_cache_control_enabled = +{% endif %} + +# Timeout to use for incoming HTTP requests to the platform API, in milliseconds. +{% if platform_webserver_timeout %} +webserver_timeout = {{ platform_webserver_timeout }} +{% else %} +# webserver_timeout = +{% endif %} + +# The value of the HTTP Access-Control-Allow-Origin header returned to clients. +{% if platform_webserver_response_header_access_control_allow_origin %} +webserver_response_header_access_control_allow_origin = {{ platform_webserver_response_header_access_control_allow_origin }} +{% else %} +# webserver_response_header_access_control_allow_origin = +{% endif %} + +# If true, allows the webserver to respond to insecure HTTP requests. +{% if ( (platform_webserver_http_enabled is defined) and + (platform_webserver_http_enabled is boolean) ) %} +webserver_http_enabled = {{ platform_webserver_http_enabled | to_nice_json }} +{% else %} +# webserver_http_enabled = +{% endif %} + +# The port on which the webserver listens for HTTP requests. +{% if platform_webserver_http_port %} +webserver_http_port = {{ platform_webserver_http_port }} +{% else %} +# webserver_http_port = +{% endif %} + +# If true, allows the webserver to respond to secure HTTPS requests. +{% if ( (platform_webserver_https_enabled is defined) and + (platform_webserver_https_enabled is boolean) ) %} +webserver_https_enabled = {{ platform_webserver_https_enabled | to_nice_json }} +{% else %} +# webserver_https_enabled = +{% endif %} + +# The port on which the webserver listens for HTTPS requests. +{% if platform_webserver_https_port %} +webserver_https_port = {{ platform_webserver_https_port }} +{% else %} +# webserver_https_port = +{% endif %} + +# The path to the public key file used for HTTPS connections. +{% if platform_webserver_https_key %} +webserver_https_key = {{ platform_webserver_https_key }} +{% else %} +# webserver_https_key = +{% endif %} + +# The passphrase for the private key used to enable TLS sessions. +{% if platform_webserver_https_passphrase %} +webserver_https_passphrase = {{ platform_webserver_https_passphrase }} +{% else %} +# webserver_https_passphrase = +{% endif %} + +# The path to the certificate file used for HTTPS connections. +{% if platform_webserver_https_cert %} +webserver_https_cert = {{ platform_webserver_https_cert }} +{% else %} +# webserver_https_cert = +{% endif %} + +# The set of allowed SSL/TLS protocol versions. +{% if platform_webserver_https_secure_protocol %} +webserver_https_secure_protocol = {{ platform_webserver_https_secure_protocol }} +{% else %} +# webserver_https_secure_protocol = +{% endif %} + +# The allowed SSL/TLS cipher suite. +{% if platform_webserver_https_ciphers %} +webserver_https_ciphers = {{ platform_webserver_https_ciphers }} +{% else %} +# webserver_https_ciphers = +{% endif %} + +# Specifies the number of renegotiations that are allowed in a single HTTPS connection. +{% if platform_webserver_https_client_reneg_limit %} +webserver_https_client_reneg_limit = {{ platform_webserver_https_client_reneg_limit }} +{% else %} +# webserver_https_client_reneg_limit = +{% endif %} + +# Specifies the time renegotiation window in seconds for a single HTTPS connection. +{% if platform_webserver_https_client_reneg_window %} +webserver_https_client_reneg_window = {{ platform_webserver_https_client_reneg_window }} +{% else %} +# webserver_https_client_reneg_window = +{% endif %} + +# The set of allowed HTTP verbs in addition to those defined in the standard HTTP/1.1 protocol. +{% if platform_webserver_http_allowed_optional_verbs %} +webserver_http_allowed_optional_verbs = {{ platform_webserver_http_allowed_optional_verbs }} +{% else %} +# webserver_http_allowed_optional_verbs = +{% endif %} + + +########### +# LOGGING # +########### +# The maximum number of each log file to keep as rotation occurs. +{% if platform_log_max_files %} +log_max_files = {{ platform_log_max_files }} +{% else %} +# log_max_files = +{% endif %} + +# The maximum file size in bytes of each log file before rotation occurs. +{% if platform_log_max_file_size %} +log_max_file_size = {{ platform_log_max_file_size }} +{% else %} +# log_max_file_size = +{% endif %} + +# The minimum log level to display in the log file. +{% if platform_log_level %} +log_level = {{ platform_log_level }} +{% else %} +# log_level = +{% endif %} + +# The absolute directory path where log files are written. +{% if platform_log_dir %} +log_directory = {{ platform_log_dir }} +{% else %} +# log_directory = +{% endif %} + +# The name of the primary platform log file. +{% if platform_log_filename %} +log_filename = {{ platform_log_filename }} +{% else %} +# log_filename = +{% endif %} + +# The minimum log level to display in the console (stdout). +{% if platform_log_level_console %} +log_level_console = {{ platform_log_level_console }} +{% else %} +# log_level_console = +{% endif %} + +# The absolute directory path where webserver log files are written. +{% if platform_webserver_log_directory %} +webserver_log_directory = {{ platform_webserver_log_directory }} +{% else %} +# webserver_log_directory = +{% endif %} + +# The name of the webserver log file. +{% if platform_webserver_log_filename %} +webserver_log_filename = {{ platform_webserver_log_filename }} +{% else %} +# webserver_log_filename = +{% endif %} + +# The minimum log level to send to the syslog server. +{% if platform_log_level_syslog %} +log_level_syslog = {{ platform_log_level_syslog }} +{% else %} +# log_level_syslog = +{% endif %} + +# The hostname or IP address of the syslog server. +{% if platform_syslog_host %} +syslog_host = {{ platform_syslog_host }} +{% else %} +# syslog_host = +{% endif %} + +# The port number of the syslog server. +{% if platform_syslog_port %} +syslog_port = {{ platform_syslog_port }} +{% else %} +# syslog_port = +{% endif %} + +# The protocol to use when sending logs to the syslog server. +{% if platform_syslog_protocol %} +syslog_protocol = {{ platform_syslog_protocol }} +{% else %} +# syslog_protocol = +{% endif %} + +# The syslog facility to use when sending logs to the syslog server. +{% if platform_syslog_facility %} +syslog_facility = {{ platform_syslog_facility }} +{% else %} +# syslog_facility = +{% endif %} + +# The syslog message format to use when sending logs to the syslog server. +{% if platform_syslog_type %} +syslog_type = {{ platform_syslog_type }} +{% else %} +# syslog_type = +{% endif %} + +# The path to the syslog server file. +{% if platform_syslog_path %} +syslog_path = {{ platform_syslog_path }} +{% else %} +# syslog_path = +{% endif %} + +# The process property to include as the process id in the syslog message. +{% if platform_syslog_pid %} +syslog_pid = {{ platform_syslog_pid }} +{% else %} +# syslog_pid = +{% endif %} + +# The hostname to include in the syslog message. +{% if platform_syslog_localhost %} +syslog_localhost = {{ platform_syslog_localhost }} +{% else %} +# syslog_localhost = +{% endif %} + +# The process property to include as the application name in the syslog message. +{% if platform_syslog_app_name %} +syslog_app_name = {{ platform_syslog_app_name }} +{% else %} +# syslog_app_name = +{% endif %} + +# The end of line character to include in the syslog message. +{% if platform_syslog_eol %} +syslog_eol = {{ platform_syslog_eol }} +{% else %} +# syslog_eol = +{% endif %} + + +########### +# BROKERS # +########### +# A list of adapter types that manages the devices. +{% if platform_device_broker_default_adapter_priority %} +device_broker_default_adapter_priority = {{ platform_device_broker_default_adapter_priority }} +{% else %} +# device_broker_default_adapter_priority = +{% endif %} + +# Runs a command on a device. +{% if platform_device_broker_run_command_adapter_preference %} +device_broker_run_command_adapter_preference = {{ platform_device_broker_run_command_adapter_preference }} +{% else %} +# device_broker_run_command_adapter_preference = +{% endif %} + +# If true, the platform will perform strict JSON Schema validation on messages into the brokers +# and coming back to the broker layer from adapters. +{% if ( (platform_broker_validation_enabled is defined) and + (platform_broker_validation_enabled is boolean) ) %} +broker_validation_enabled = {{ platform_broker_validation_enabled | to_nice_json }} +{% else %} +# broker_validation_enabled = +{% endif %} + + +######## +# SNMP # +######## +# Remote SNMP destination configuration objects. +{% if platform_snmp_alarm_configs %} +snmp_alarm_configs = {{ platform_snmp_alarm_configs | to_json }} +{% else %} +# snmp_alarm_configs = +{% endif %} diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/iag_adapter_service_config.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/iag_adapter_service_config.j2 new file mode 100644 index 00000000..ecae041c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/iag_adapter_service_config.j2 @@ -0,0 +1,133 @@ +{ + "name": "IAG-{{ item }}", + "model": "@itential/adapter-automation_gateway", + "type": "Adapter", + "properties": { + "id": "IAG-{{ item }}", + "type": "AutomationGateway", + "brokers": [ + "device", + "method" + ], + "groups": [], + "properties": { + "host": "{{ item }}", + "port": 8083, + "base_path": "", + "version": "v2.0", + "cache_location": "none", + "stub": false, + "protocol": "http", + "authentication": { + "auth_method": "request_token", + "username": "admin@itential", + "password": "admin", + "token": "token", + "token_user_field": "username", + "token_password_field": "password", + "token_result_field": "token", + "token_URI_path": "/api/v2.0/login", + "invalid_token_error": 401, + "token_timeout": {{ platform_iag_adapter_token_timeout }}, + "token_cache": "local", + "auth_field": "header.headers.Authorization", + "auth_field_format": "{token}" + }, + "healthcheck": { + "type": "intermittent", + "frequency": 300000, + "protocol": "REST", + "URI_Path": "/api/v2.0/poll" + }, + "throttle": { + "throttle_enabled": false, + "number_pronghorns": 1, + "sync_async": "sync", + "max_in_queue": 1000, + "concurrent_max": 1, + "expire_timeout": 0, + "avg_runtime": 200 + }, + "request": { + "number_redirects": 0, + "number_retries": 3, + "limit_retry_error": 0, + "failover_codes": [], + "attempt_timeout": 600000, + "global_request": { + "payload": {}, + "uriOptions": {}, + "addlHeaders": {}, + "authData": {} + }, + "healthcheck_on_timeout": false, + "return_raw": false, + "archiving": false + }, + "proxy": { + "enabled": false, + "host": "", + "port": 8083, + "protocol": "http" + }, + "ssl": { + "ecdhCurve": "", + "enabled": false, + "accept_invalid_cert": false, + "ca_file": "", + "key_file": "", + "cert_file": "", + "secure_protocol": "", + "ciphers": "" + }, + "visibility": { + "grpc": "all", + "module": "all", + "role": "all", + "playbook": "certified", + "script": "all", + "collection_module": "all", + "collection_role": "all", + "nornir": "all", + "netconf": "all", + "netmiko": "all" + }, + "cluster_name": "", + "save_metric": false, + "mongo": { + "host": "", + "port": 443, + "database": "", + "username": "", + "password": "************", + "replSet": "" + }, + "strip_escapes": false + } + }, + "isEncrypted": true, + "loggerProps": { + "console_level": "info", + "description": "Logging", + "log_directory": "{{ platform_log_dir }}", + "log_filename": "IAG-{{ item }}.log", + "log_level": "info", + "log_max_file_size": 10485760, + "log_max_files": 10, + "log_timezone_offset": 0, + "syslog": { + "app_name": "", + "eol": "", + "facility": "local0", + "host": "127.0.0.1", + "level": "warning", + "localhost": "", + "path": "", + "pid": "process.pid", + "port": 514, + "protocol": "udp4", + "type": "BSD" + } + }, + "virtual": false +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/itential-platform.service.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/itential-platform.service.j2 new file mode 100644 index 00000000..bb6d85c3 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/itential-platform.service.j2 @@ -0,0 +1,19 @@ +[Unit] +Description=Itential Platform Service +After=network.target +Requires=network.target + +[Service] +Type=simple +User={{ platform_user }} +WorkingDirectory={{ platform_server_dir }} +{% if platform_configure_vault and platform_vault_auth_method == "approle" %} +EnvironmentFile={{ platform_vault_token_dir }}/vault-role-secrets.env +{% endif %} +ExecStart=/usr/bin/node --max-old-space-size=8192 server.js --config-file {{ platform_config_dir }}/platform.properties +Restart=on-failure +ExecReload=/bin/kill -USR2 $MAINPID +KillMode=mixed + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/platform.preflight.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/platform.preflight.j2 new file mode 100644 index 00000000..ba58491a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/templates/platform.preflight.j2 @@ -0,0 +1,18 @@ +Name: {{results['name']}} +Role: Platform +Pass: {{results['pass']}} + + +SELinux | {{results['SELinux']}} +http_proxy | {{ 'Yes' if results['http_proxy'] else 'None'}} +https_proxy | {{ 'Yes' if results['https_proxy'] else 'None'}} +IPv6 | {{ 'Enabled' if results['ipv6'] else 'Disabled'}} + +CPU | {{ 'Pass' if results['cpuCores'] >= platform_cpu_cores else 'FAIL'}} | Cores: {{results['cpuCores']}} Req: {{platform_cpu_cores}} +HDD | {{ 'Pass' if results['/_sizeAvailable'] >= platform_free_disk_space else 'FAIL'}} | Free: {{results['/_sizeAvailable']}} on {{results['mount']}} Req: {{platform_free_disk_space}} +Memory | {{ 'Pass' if results['memory'] >= platform_ram else 'FAIL'}} | Free: {{results['memory']}} Req: {{platform_ram}} + +URL | Status +{% for key, value in results['url_status'].items() %} +{{key}} | {{value}} +{% endfor %} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/main.yml new file mode 100644 index 00000000..c5b71a6b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/main.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Itential Platform directory defaults +platform_root_dir_default: /opt/itential/platform +platform_server_dir_default: /opt/itential/platform/server +platform_services_dir_default: /opt/itential/platform/services +platform_config_dir_default: /etc/itential +platform_log_dir_default: /var/log/itential +platform_itential_home_dir_default: /home/itential + +# The Platform server and services directories cannot be overridden in the inventory. Only the +# Platform root directory can. +platform_server_dir: "{{ platform_root_dir }}/server" +platform_services_dir: "{{ platform_root_dir }}/services" + +# What to write in application properties file for Role ID (defaults to env var reference) +platform_vault_role_id_property: "${ITENTIAL_VAULT_ROLE_ID}" + +# What to write in application properties file for Secret ID (defaults to env var reference) +platform_vault_secret_id_property: "${ITENTIAL_VAULT_SECRET_ID}" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/platform-release-6.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/platform-release-6.yml new file mode 100644 index 00000000..36a9c8d4 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/platform-release-6.yml @@ -0,0 +1,37 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +platform_nodejs_package_default: + "8": "@nodejs:20/common" + "9": "@nodejs:20" + "2023": "nodejs20" + +platform_python_version_default: + "8": 3.11 + "9": 3.11 + "2023": 3.11 + +platform_python_packages_default: + "8": + - python3.11 + - python3.11-pip + "9": + - python3.11 + - python3.11-pip + "2023": + - python3.11 + - python3.11-pip + +platform_python_app_dependencies_default: + "8": + - jinja2==3.1.2 + - markupsafe==2.1.4 + - textfsm==1.1.3 + "9": + - jinja2==3.1.2 + - markupsafe==2.1.4 + - textfsm==1.1.3 + "2023": + - jinja2==3.1.2 + - markupsafe==2.1.4 + - textfsm==1.1.3 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/platform-release-undefined.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/platform-release-undefined.yml new file mode 100644 index 00000000..0ef7298d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/platform/vars/platform-release-undefined.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +platform_invalid_release: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/tasks/main.yml new file mode 100644 index 00000000..d06379bf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/tasks/main.yml @@ -0,0 +1,114 @@ +# # Copyright (c) 2024, Itential, Inc +# # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include environment specs + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "{{ preflight_env }}.specs.yml" + - "undefined.specs.yml" + +- name: Check for valid environment + ansible.builtin.fail: + msg: "Do defined environment. Please add env: dev, staging, or prod to your host file." + when: invalid_env is defined + +- name: Initialize Results + ansible.builtin.set_fact: + results: '{}' + +- name: Set Results var to JSON + ansible.builtin.set_fact: + results: "{{ results | from_json }}" + +- name: Set Inventory Name + ansible.builtin.set_fact: + results: '{{ results | combine({"name": inventory_hostname}) }}' + +- name: Initialize pass to false + ansible.builtin.set_fact: + results: '{{ results | combine({"pass": false}) }}' + +- name: Set OS + ansible.builtin.set_fact: + results: '{{ results | combine({"os": ansible_facts.os_family}) }}' + +- name: Set OS Version + ansible.builtin.set_fact: + results: '{{ results | combine({"osVersion": ansible_facts.distribution_version}) }}' + +- name: Set Mount + ansible.builtin.set_fact: + results: '{{ results | combine({"mount": preflight_mounts}) }}' + +- name: Set SELinux Variable + ansible.builtin.set_fact: + selinux: "{{ 'enabled' if (ansible_facts.selinux.config_mode == 'enforcing') else 'disabled' }}" + +- name: Set SELinux Variable in results + ansible.builtin.set_fact: + results: '{{ results | combine({"SELinux": selinux}) }}' + +- name: Set IPv6 Variable + ansible.builtin.set_fact: + results: '{{ results | combine({"ipv6": ansible_facts.all_ipv6_addresses | length > 0}) }}' + +- name: Set CPU cores + ansible.builtin.set_fact: + results: '{{ results | combine({"cpuCores": ansible_processor_cores}) }}' + +- name: Set RAM + ansible.builtin.set_fact: + results: '{{ results | combine({"memory": (ansible_memory_mb["real"]["total"] / 1000)}) }}' + +- name: Get mount info + ansible.builtin.set_fact: + mount_info: "{{ ansible_facts.mounts | + selectattr('mount', 'defined') | + selectattr('size_available', 'defined') | + selectattr('mount', '==', preflight_mounts) | list | unique }}" + +- name: Get size_available from mount + ansible.builtin.set_fact: + size_available: "{{ mount_info[0]['size_available'] / 1024 / 1024 / 1024 }}" + +- name: Set Size Available + ansible.builtin.set_fact: + results: '{{ results | combine({preflight_mounts + "_sizeAvailable": size_available | int}) }}' + mountvarname: "{{ preflight_mounts }}_sizeAvailable" + +- name: Set http_proxy + ansible.builtin.set_fact: + results: '{{ results | combine({"http_proxy": ansible_env.http_proxy | default(false)}) }}' + +- name: Set https_proxy + ansible.builtin.set_fact: + results: '{{ results | combine({"https_proxy": ansible_env.http_proxy | default(false)}) }}' + +- name: Initialize url status variable + ansible.builtin.set_fact: + url_status: {} + +- name: Check if urls are available + when: + - preflight_url_checks is defined + - preflight_url_checks is iterable + - preflight_url_checks | length > 0 + block: + - name: Test url availability + ansible.builtin.uri: + url: "{{ item }}" + timeout: 3 + return_content: false + register: url_result + ignore_errors: true + with_items: "{{ preflight_url_checks }}" + + - name: Update URL status + ansible.builtin.set_fact: + url_status: "{{ url_status | combine({item.item: item.status}) }}" + with_items: "{{ url_result.results }}" + +- name: Set url_status + ansible.builtin.set_fact: + results: '{{ results | combine({"url_status": url_status}) }}' diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/dev.specs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/dev.specs.yml new file mode 100644 index 00000000..764e9d19 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/dev.specs.yml @@ -0,0 +1,26 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Platform - Dev +platform_cpu_cores: 8 +platform_os: [8, 9] +platform_ram: 32 +platform_free_disk_space: 250 + +# MongoDB - Dev +mongodb_cpu_cores: 8 +mongodb_os: [8, 9] +mongodb_ram: 64 +mongodb_free_disk_space: 1000 + +# Redis - Dev +redis_cpu_cores: 4 +redis_os: [8, 9] +redis_ram: 16 +redis_free_disk_space: 100 + +# Gateway - Dev +gateway_cpu_cores: 4 +gateway_os: [8, 9] +gateway_ram: 16 +gateway_free_disk_space: 10 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/prod.specs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/prod.specs.yml new file mode 100644 index 00000000..bf994c7e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/prod.specs.yml @@ -0,0 +1,26 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Platform - Prod +platform_cpu_cores: 16 +platform_os: [8, 9] +platform_ram: 64 +platform_free_disk_space: 250 + +# MongoDB - Prod +mongodb_cpu_cores: 16 +mongodb_os: [8, 9] +mongodb_ram: 128 +mongodb_free_disk_space: 1000 + +# Redis - Prod +redis_cpu_cores: 8 +redis_os: [8, 9] +redis_ram: 32 +redis_free_disk_space: 100 + +# Gateway - Prod +gateway_cpu_cores: 16 +gateway_os: [8, 9] +gateway_ram: 32 +gateway_free_disk_space: 50 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/staging.specs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/staging.specs.yml new file mode 100644 index 00000000..d400325a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/staging.specs.yml @@ -0,0 +1,26 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Platform - Staging +platform_cpu_cores: 16 +platform_os: [8, 9] +platform_ram: 64 +platform_free_disk_space: 250 + +# MongoDB - Staging +mongodb_cpu_cores: 16 +mongodb_os: [8, 9] +mongodb_ram: 128 +mongodb_free_disk_space: 1000 + +# Redis - Staging +redis_cpu_cores: 8 +redis_os: [8, 9] +redis_ram: 32 +redis_free_disk_space: 100 + +# Gateway - Staging +gateway_cpu_cores: 4 +gateway_os: [8, 9] +gateway_ram: 16 +gateway_free_disk_space: 10 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/undefined.specs.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/undefined.specs.yml new file mode 100644 index 00000000..2a04726c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/preflight/vars/undefined.specs.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +invalid_env: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/defaults/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/defaults/main.yml new file mode 100644 index 00000000..258f46e9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/defaults/main.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +prometheus_process_exporter_web_listen_port: 9256 +prometheus_node_exporter_web_listen_port: 9100 +prometheus_redis_exporter_web_listen_port: 9121 +prometheus_mongodb_exporter_web_listen_port: 9216 +prometheus_itential_platform_web_listen_port: 3000 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/handlers/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/handlers/main.yml new file mode 100644 index 00000000..16437e76 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/handlers/main.yml @@ -0,0 +1,7 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Restart Prometheus + ansible.builtin.systemd: + name: prometheus + state: restarted diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/tasks/main.yml new file mode 100644 index 00000000..7706f985 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/tasks/main.yml @@ -0,0 +1,36 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Prometheus + ansible.builtin.import_role: + name: prometheus.prometheus.prometheus + +- name: Create Itential scrape config file + notify: Restart Prometheus + tags: itential_scrape_config_install + block: + - name: Create Itential scrape config file + ansible.builtin.template: + src: scrape_configs.j2 + dest: "{{ prometheus_config_dir }}/scrape_configs/itential.yml" + owner: "{{ prometheus_system_user }}" + group: "{{ prometheus_system_group }}" + mode: "0644" + lstrip_blocks: true + +- name: Ensure Prometheus is running + tags: always + block: + - name: Flush all handlers + ansible.builtin.meta: flush_handlers + + - name: Start Prometheus + ansible.builtin.systemd: + name: prometheus + state: started + + - name: Assert that Prometheus is running + ansible.builtin.systemd: + name: prometheus + register: prometheus_status + failed_when: prometheus_status.status.ActiveState != "active" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/templates/scrape_configs.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/templates/scrape_configs.j2 new file mode 100644 index 00000000..e10053d9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/prometheus/templates/scrape_configs.j2 @@ -0,0 +1,136 @@ +{{ ansible_managed | comment }} + +{%- set iap_exporter_targets = [] %} +{%- set process_exporter_targets = [] %} +{%- set node_export_targets = [] %} +{%- set mongodb_exporter_targets = [] %} +{%- set redis_exporter_targets = [] %} + +{%- if 'platform' in groups -%} +{% for host in groups['platform'] %} +{% set iap_exporter_web_listen_address = host + ":" + prometheus_itential_platform_web_listen_port | string %} +{{- iap_exporter_targets.append( iap_exporter_web_listen_address ) -}} +{% if 'process_exporter_web_listen_address' in hostvars[host] %} +{% set process_exporter_web_listen_address = hostvars[host].process_exporter_web_listen_address %} +{% else %} +{% set process_exporter_web_listen_address = host + ":" + prometheus_process_exporter_web_listen_port | string %} +{% endif %} +{{- process_exporter_targets.append( process_exporter_web_listen_address ) -}} +{% if 'node_exporter_web_listen_address' in hostvars[host] %} +{% set node_exporter_web_listen_address = hostvars[host].node_exporter_web_listen_address %} +{% else %} +{% set node_exporter_web_listen_address = host + ":" + prometheus_node_exporter_web_listen_port | string %} +{% endif %} +{{- node_export_targets.append( node_exporter_web_listen_address ) -}} +{% endfor %} +{% endif %} + +{%- if 'gateway' in groups -%} +{% for host in groups['gateway'] %} +{% if 'process_exporter_web_listen_address' in hostvars[host] %} +{% set process_exporter_web_listen_address = hostvars[host].process_exporter_web_listen_address %} +{% else %} +{% set process_exporter_web_listen_address = host + ":" + prometheus_process_exporter_web_listen_port | string %} +{% endif %} +{{- process_exporter_targets.append( process_exporter_web_listen_address ) -}} +{% if 'node_exporter_web_listen_address' in hostvars[host] %} +{% set node_exporter_web_listen_address = hostvars[host].node_exporter_web_listen_address %} +{% else %} +{% set node_exporter_web_listen_address = host + ":" + prometheus_node_exporter_web_listen_port | string %} +{% endif %} +{{- node_export_targets.append( node_exporter_web_listen_address ) -}} +{% endfor %} +{% endif %} + +{%- if 'mongodb' in groups -%} +{% for host in groups['mongodb'] %} +{% if 'mongodb_exporter_web_listen_address' in hostvars[host] %} +{% set mongodb_exporter_web_listen_address = hostvars[host].mongodb_exporter_web_listen_address %} +{% else %} +{% set mongodb_exporter_web_listen_address = host + ":" + prometheus_mongodb_exporter_web_listen_port | string %} +{% endif %} +{{- mongodb_exporter_targets.append( mongodb_exporter_web_listen_address ) -}} +{% if 'node_exporter_web_listen_address' in hostvars[host] %} +{% set node_exporter_web_listen_address = hostvars[host].node_exporter_web_listen_address %} +{% else %} +{% set node_exporter_web_listen_address = host + ":" + prometheus_node_exporter_web_listen_port | string %} +{% endif %} +{{- node_export_targets.append( node_exporter_web_listen_address ) -}} +{% endfor %} +{% endif %} + +{%- if 'redis' in groups -%} +{% for host in groups['redis'] %} +{% if 'redis_exporter_web_listen_address' in hostvars[host] %} +{% set redis_exporter_web_listen_address = hostvars[host].redis_exporter_web_listen_address %} +{% else %} +{% set redis_exporter_web_listen_address = host + ":" + prometheus_redis_exporter_web_listen_port | string %} +{% endif %} +{{- redis_exporter_targets.append( redis_exporter_web_listen_address ) -}} +{% if 'node_exporter_web_listen_address' in hostvars[host] %} +{% set node_exporter_web_listen_address = hostvars[host].node_exporter_web_listen_address %} +{% else %} +{% set node_exporter_web_listen_address = host + ":" + prometheus_node_exporter_web_listen_port | string %} +{% endif %} +{{- node_export_targets.append( node_exporter_web_listen_address ) -}} +{% endfor %} +{% endif %} + +{%- if 'vault' in groups -%} +{% for host in groups['vault'] %} +{% if 'node_exporter_web_listen_address' in hostvars[host] %} +{% set node_exporter_web_listen_address = hostvars[host].node_exporter_web_listen_address %} +{% else %} +{% set node_exporter_web_listen_address = host + ":" + prometheus_node_exporter_web_listen_port | string %} +{% endif %} +{{- node_export_targets.append( node_exporter_web_listen_address ) -}} +{% endfor %} +{% endif %} + +scrape_configs: +{% if node_export_targets | length > 0 %} + - job_name: node_exporter + static_configs: + - targets: +{% for target in node_export_targets %} + - {{ target }} +{% endfor %} + +{% endif %} +{% if process_exporter_targets | length > 0 %} + - job_name: process_exporter + static_configs: + - targets: +{% for target in process_exporter_targets %} + - {{ target }} +{% endfor %} + +{% endif %} +{% if iap_exporter_targets | length > 0 %} + - job_name: iap_exporter + metrics_path: "/prometheus_metrics" + static_configs: + - targets: +{% for target in iap_exporter_targets %} + - {{ target }} +{% endfor %} + +{% endif %} +{% if redis_exporter_targets | length > 0 %} + - job_name: redis_exporter + static_configs: + - targets: +{% for target in redis_exporter_targets %} + - {{ target }} +{% endfor %} + +{% endif %} +{% if mongodb_exporter_targets | length > 0 %} + - job_name: mongo_exporter + static_configs: + - targets: +{% for target in mongodb_exporter_targets %} + - {{ target }} +{% endfor %} + +{% endif %} diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/python/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/python/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/create-symlinks.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/create-symlinks.yml new file mode 100644 index 00000000..9158d30e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/create-symlinks.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate that python_executable and python_pip_executable are set + ansible.builtin.assert: + that: + - python_executable is defined + - python_pip_executable is defined + msg: python_executable and python_pip_executable must be set + +- name: Create python3 symlink to /usr/local/bin/python3 + ansible.builtin.file: + state: link + src: "{{ python_executable }}" + path: /usr/local/bin/python3 + +- name: Create pip3 symlink to /usr/local/bin/pip3 + ansible.builtin.file: + state: link + src: "{{ python_pip_executable }}" + path: /usr/local/bin/pip3 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/install-dependencies.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/install-dependencies.yml new file mode 100644 index 00000000..886ad496 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/install-dependencies.yml @@ -0,0 +1,53 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate python_pip_executable or python_venv is set + ansible.builtin.assert: + that: python_pip_executable is defined or python_venv is defined + msg: "python_pip_executable or python_venv must be set" + +- name: Use Python virtual env + when: python_venv is defined + block: + - name: Install base Python dependencies in virtual env + ansible.builtin.pip: + name: "{{ python_base_dependencies }}" + virtualenv: "{{ python_venv }}" + when: + - python_base_dependencies is defined + - python_base_dependencies is iterable + - python_base_dependencies | length > 0 + + - name: Install application Python dependencies in virtual env + ansible.builtin.pip: + name: "{{ python_app_dependencies }}" + virtualenv: "{{ python_venv }}" + when: + - python_app_dependencies is defined + - python_app_dependencies is iterable + - python_app_dependencies | length > 0 + +- name: Use Python executable + when: + - python_pip_executable is defined + - python_venv is not defined + block: + - name: Install base Python dependencies using pip executable + ansible.builtin.pip: + name: "{{ python_base_dependencies }}" + executable: "{{ python_pip_executable }}" + umask: "0022" + when: + - python_base_dependencies is defined + - python_base_dependencies is iterable + - python_base_dependencies | length > 0 + + - name: Install application Python dependencies using pip executable + ansible.builtin.pip: + name: "{{ python_app_dependencies }}" + executable: "{{ python_pip_executable }}" + umask: "0022" + when: + - python_app_dependencies is defined + - python_app_dependencies is iterable + - python_app_dependencies | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/main.yml new file mode 100644 index 00000000..6025d64f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/python/tasks/main.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +- name: Install Python packages + ansible.builtin.dnf: + name: "{{ item }}" + state: present + with_items: "{{ python_packages }}" + register: python_install_result + when: + - python_packages is defined + - not offline_install_enabled diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/install.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/install.yml new file mode 100644 index 00000000..ac62dd8b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/install.yml @@ -0,0 +1,29 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Packages required to configure SELinux +redis_security_packages: + - policycoreutils-python-utils + +# Redis install from source - boolean +# When set to 'true' Redis will be installed from source. +# Otherwise Redis will be installed from YUM. +redis_install_from_source: true + +# Packages required to build Redis from source +redis_build_packages: + - tar + - unzip + - gcc + - gcc-c++ + - make + - systemd-devel + +# The Remi and EPEL repos are used only when: +# - redis_install_from_source is set to 'false' +# - common_install_yum_repos is set to 'true' +# - redis_packages contains 'remi' +redis_remi_repo_url: "http://rpms.remirepo.net/enterprise/remi-release-\ + {{ ansible_distribution_version }}.rpm" +redis_epel_repo_url: "https://dl.fedoraproject.org/pub/epel/epel-release-latest-\ + {{ ansible_distribution_major_version }}.noarch.rpm" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/offline.yml new file mode 100644 index 00000000..b0232568 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/offline.yml @@ -0,0 +1,15 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Base directories +redis_offline_packages_root: "{{ offline_itential_packages_path }}/{{ platform_release }}/redis" +redis_offline_target_node_root: "{{ offline_target_node_root }}/{{ redis_offline_packages_root }}" +redis_offline_control_node_root: "{{ offline_control_node_root }}/{{ redis_offline_packages_root }}" + +# Target node download directories +redis_offline_target_node_rpms_dir: "{{ redis_offline_target_node_root }}/rpms" +redis_offline_target_node_archives_dir: "{{ redis_offline_target_node_root }}/archives" + +# Control node download directories +redis_offline_control_node_rpms_dir: "{{ redis_offline_control_node_root }}/rpms" +redis_offline_control_node_archives_dir: "{{ redis_offline_control_node_root }}/archives" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/pki.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/pki.yml new file mode 100644 index 00000000..14b00462 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/pki.yml @@ -0,0 +1,122 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Redis PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +redis_pki_base_dir: /etc/pki/redis + +# Subdirectory names - customize the layout +redis_pki_private_subdir: private + +# Derived subdirectory paths - built from base + subdir name +redis_pki_private_dir: "{{ redis_pki_base_dir }}/{{ redis_pki_private_subdir }}" + +# ============================================================================ +# Certificate and Key Filenames - Customize naming +# ============================================================================ + +# Redis server certificate filename +redis_tls_cert_filename: "{{ inventory_hostname }}.crt" + +# Redis server private key filename +redis_tls_key_filename: "{{ inventory_hostname }}.key" + +# Redis CA certificate filename +redis_tls_ca_filename: ca-bundle.crt + +# Redis DH parameters filename +redis_tls_dh_params_filename: dhparams.pem + +# Redis Sentinel certificate filename +redis_sentinel_tls_cert_filename: sentinel.crt + +# Redis Sentinel private key filename +redis_sentinel_tls_key_filename: sentinel.key + +# ============================================================================ +# Redis Server Full Certificate Paths - Built from components +# ============================================================================ + +# Redis server certificate path +redis_tls_cert_file: "{{ redis_pki_base_dir }}/{{ redis_tls_cert_filename }}" + +# Redis server private key path +redis_tls_key_file: "{{ redis_pki_private_dir }}/{{ redis_tls_key_filename }}" + +# Redis CA certificate path +redis_tls_ca_file: "{{ redis_pki_base_dir }}/{{ redis_tls_ca_filename }}" + +# Redis DH parameters path +redis_tls_dh_params_file: "{{ redis_pki_base_dir }}/{{ redis_tls_dh_params_filename }}" + +# ============================================================================ +# Redis Sentinel Full Certificate Paths - Built from components +# ============================================================================ + +# Sentinel certificate path +redis_sentinel_tls_cert_file: "{{ redis_pki_base_dir }}/{{ redis_sentinel_tls_cert_filename }}" + +# Sentinel private key path +redis_sentinel_tls_key_file: "{{ redis_pki_private_dir }}/{{ redis_sentinel_tls_key_filename }}" + +# ============================================================================ +# Source Directory - Define in inventory +# ============================================================================ + +# Source directory for certificate files (on Ansible controller) +redis_pki_src_dir: "" + +# ============================================================================ +# Source File Paths - Built from source directory + filename +# ============================================================================ + +# Redis server source paths - auto-build from source dir + filename +redis_tls_cert_source: "{{ redis_pki_src_dir }}/{{ redis_tls_cert_filename }}" +redis_tls_key_source: "{{ redis_pki_src_dir }}/{{ redis_tls_key_filename }}" +redis_tls_ca_source: "{{ redis_pki_src_dir }}/{{ redis_tls_ca_filename }}" +redis_tls_dh_params_source: "{{ redis_pki_src_dir }}/{{ redis_tls_dh_params_filename }}" + +# Sentinel source paths - auto-build from source dir + filename +redis_sentinel_tls_cert_source: "{{ redis_pki_src_dir }}/{{ redis_sentinel_tls_cert_filename }}" +redis_sentinel_tls_key_source: "{{ redis_pki_src_dir }}/{{ redis_sentinel_tls_key_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI directories and files +redis_pki_owner: redis + +# Group for PKI directories and files +redis_pki_group: redis + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +redis_pki_base_dir_mode: "0750" + +# Private subdirectory permissions +redis_pki_private_dir_mode: "0700" + +# Server certificate permissions +redis_tls_cert_mode: "0644" + +# Server private key permissions +redis_tls_key_mode: "0600" + +# CA certificate permissions +redis_tls_ca_mode: "0644" + +# DH parameters permissions +redis_tls_dh_params_mode: "0644" + +# Sentinel certificate permissions +redis_sentinel_tls_cert_mode: "0644" + +# Sentinel private key permissions +redis_sentinel_tls_key_mode: "0600" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/redis.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/redis.yml new file mode 100644 index 00000000..d34243b0 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/redis.yml @@ -0,0 +1,57 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The location of the Redis binary +# redis_bin_dir: /usr/bin +redis_bin_dir: "{{ redis_install_from_source | bool | ternary('/usr/local/bin', '/usr/bin') }}" + +# The location of the Redis config file +redis_conf_dir: "{{ redis_conf_dir_default }}" +redis_conf_file: "{{ redis_conf_dir }}/redis.conf" + +# The location of the Redis log file +redis_log_dir: "{{ redis_log_dir_default }}" +redis_log: "{{ redis_log_dir }}/redis.log" + +# The name of the Redis data file +redis_db_filename: dump.rdb + +# The location of the Redis data directory +redis_data_dir: "{{ redis_data_dir_default }}" + +# Redis user and group +redis_owner: redis +redis_group: redis + +# Default redis port +redis_port: "{{ redis_port_default }}" + +# Bind to localhost + private network interface +redis_bind: 127.0.0.1 {{ ansible_default_ipv4.address }} + +# Feature flags that can be overridden in the hosts file +# Essentially, a default installation will have auth, but not tls +redis_auth_enabled: true +redis_tls_enabled: false + +# Replication settings +redis_replicaof: "{{ groups['redis_master'][0] }} {{ redis_port }}" + +# Default redis user passwords +# These are meant to be changed by the customer. By default they are meant to +# be predictable and simple. +redis_user_admin_password: admin +redis_user_itential_password: itential +redis_user_repluser_password: repluser +redis_user_sentineladmin_password: admin +redis_user_sentineluser_password: sentineluser +redis_user_prometheus_password: prometheus + +# By default the prometheus user will be enabled. If this is set to false, the prometheus user +# will not be created. +redis_prometheus_user_enabled: true + +# Redis TLS configuration options +redis_tls_port: "{{ redis_tls_port_default }}" +redis_tls_auth_clients: "no" +redis_tls_protocols: "TLSv1.2 TLSv1.3" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/sentinel.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/sentinel.yml new file mode 100644 index 00000000..aaf87a05 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/defaults/main/sentinel.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The location of the Redis Sentinel config file +redis_sentinel_conf_file: "{{ redis_conf_dir }}/sentinel.conf" + +# The location of the Redis Sentinel log file +redis_sentinel_log: "{{ redis_log_dir }}/sentinel.log" + +# The Redis Sentinel master name +redis_sentinel_master_name: itentialmaster + +# The default redis sentinel listen port +redis_sentinel_port: "{{ redis_sentinel_port_default }}" + +# Bind to localhost + private network interface +redis_sentinel_bind: 127.0.0.1 {{ ansible_default_ipv4.address }} + +# Auto-calculate quorum based on sentinel count (recommended) +# Set to explicit number to override (must be <= number of sentinels) +redis_sentinel_quorum: auto diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/files/itential_redis_sentinel.te b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/files/itential_redis_sentinel.te new file mode 100644 index 00000000..95b3268b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/files/itential_redis_sentinel.te @@ -0,0 +1,14 @@ +module itential_redis_sentinel 1.0; + +require { + type init_t; + type redis_exec_t; + type init_exec_t; + type default_t; + class lnk_file read; +} + +#============= init_t ============== +allow init_t default_t:lnk_file read; +allow init_t init_exec_t:lnk_file read; +allow init_t redis_exec_t:lnk_file read; diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/handlers/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/handlers/main.yml new file mode 100644 index 00000000..f9bbfcca --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/handlers/main.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Enable and Start Redis + throttle: 1 + ansible.builtin.systemd: + name: redis + enabled: true + state: restarted + daemon_reload: true + when: redis_is_data_node + +- name: Enable and Start Redis Sentinel + throttle: 1 + ansible.builtin.systemd: + name: redis-sentinel + enabled: true + state: restarted + daemon_reload: true + when: redis_is_sentinel_node + +- name: Update Itential release file + ansible.builtin.include_tasks: + file: update-release-file.yml diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-redis-tls.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-redis-tls.yml new file mode 100644 index 00000000..92e4c8b1 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-redis-tls.yml @@ -0,0 +1,82 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create Redis PKI base directory + ansible.builtin.file: + path: "{{ redis_pki_base_dir }}" + state: directory + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_pki_base_dir_mode }}" + tags: + - redis + - redis_certificates + - certificates + +- name: Create Redis private directory + ansible.builtin.file: + path: "{{ redis_pki_private_dir }}" + state: directory + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_pki_private_dir_mode }}" + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis TLS certificate + ansible.builtin.copy: + src: "{{ redis_tls_cert_source }}" + dest: "{{ redis_tls_cert_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_cert_mode }}" + when: redis_tls_cert_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis TLS private key + ansible.builtin.copy: + src: "{{ redis_tls_key_source }}" + dest: "{{ redis_tls_key_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_key_mode }}" + when: redis_tls_key_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis CA bundle + ansible.builtin.copy: + src: "{{ redis_tls_ca_source }}" + dest: "{{ redis_tls_ca_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_ca_mode }}" + when: redis_tls_ca_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis DH params + ansible.builtin.copy: + src: "{{ redis_tls_dh_params_source }}" + dest: "{{ redis_tls_dh_params_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_dh_params_mode }}" + when: redis_tls_dh_params_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-redis.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-redis.yml new file mode 100644 index 00000000..2175534d --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-redis.yml @@ -0,0 +1,44 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Gather service facts + ansible.builtin.service_facts: + +- name: Open Redis port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ redis_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +- name: Create Redis systemd file + ansible.builtin.template: + src: redis.service.j2 + dest: /usr/lib/systemd/system/redis.service + owner: root + group: root + mode: "0644" + +- name: Use template to generate redis.conf + ansible.builtin.template: + src: redis.conf.j2 + dest: "{{ redis_conf_file }}" + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0640" + setype: redis_conf_t + backup: true + tags: configure_redis + +- name: Deploy logrotate config for Redis + ansible.builtin.template: + src: redis.logrotate.j2 + dest: /etc/logrotate.d/redis + owner: root + group: root + mode: '0644' diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-selinux.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-selinux.yml new file mode 100644 index 00000000..9868d3f2 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-selinux.yml @@ -0,0 +1,90 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Configure SELinux + when: ansible_selinux.status == "enabled" + block: + - name: Install Redis security packages + ansible.builtin.dnf: + name: "{{ redis_security_packages }}" + state: present + update_cache: true + when: + - not offline_install_enabled | bool + - redis_security_packages is defined + - redis_security_packages is iterable + - redis_security_packages | length > 0 + + - name: Install Redis security packages (offline) + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + when: offline_install_enabled | bool + vars: + offline_rpms_path: "{{ redis_offline_control_node_rpms_dir }}/security" + + - name: SELinux - Install custom profiles + ansible.builtin.include_role: + name: selinux + + - name: SELinux - Configure port when using non-standard Redis port + community.general.seport: + ports: "{{ redis_port }}" + proto: tcp + setype: redis_port_t + state: present + when: + - redis_is_data_node + - redis_port != redis_port_default + + - name: SELinux - Configure port when using non-standard Sentinel port + community.general.seport: + ports: "{{ redis_sentinel_port }}" + proto: tcp + setype: redis_port_t + state: present + when: + - redis_is_sentinel_node + - redis_sentinel_port != redis_sentinel_port_default + + - name: SELinux - Configure file context when using non-standard bin directory + ansible.builtin.include_role: + name: selinux + tasks_from: configure-context + vars: + selinux_target: "{{ redis_bin_dir }}/redis-server" + selinux_setype: redis_exec_t + selinux_ftype: f + selinux_path: "{{ redis_bin_dir }}" + when: redis_bin_dir != redis_bin_dir_default_packages or + redis_bin_dir != redis_bin_dir_default_source + + - name: SELinux - Configure file context when using non-standard log directory + ansible.builtin.include_role: + name: selinux + tasks_from: configure-context + vars: + selinux_target: "{{ redis_log_dir }}(/.*)?" + selinux_setype: redis_log_t + selinux_path: "{{ redis_log_dir }}" + when: redis_log_dir != redis_log_dir_default + + - name: SELinux - Configure file context when using non-standard data directory + ansible.builtin.include_role: + name: selinux + tasks_from: configure-context + vars: + selinux_target: "{{ redis_data_dir }}(/.*)?" + selinux_setype: redis_var_lib_t + selinux_path: "{{ redis_data_dir }}" + when: redis_data_dir != redis_data_dir_default + + - name: SELinux - Configure file context when using non-standard configuration directory + ansible.builtin.include_role: + name: selinux + tasks_from: configure-context + vars: + selinux_target: "{{ redis_conf_dir }}(/.*)?" + selinux_setype: redis_conf_t + selinux_path: "{{ redis_conf_dir }}" + when: redis_conf_dir != redis_conf_dir_default diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-sentinel.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-sentinel.yml new file mode 100644 index 00000000..37be5f22 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/configure-sentinel.yml @@ -0,0 +1,96 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Gather service facts + ansible.builtin.service_facts: + +- name: Open Sentinel port on FirewallD Public Zone + ansible.posix.firewalld: + port: "{{ redis_sentinel_port }}/tcp" + permanent: true + state: enabled + zone: public + immediate: true + when: + - ansible_facts.services["firewalld.service"] is defined + - ansible_facts.services["firewalld.service"].state == "running" + - ansible_facts.services["firewalld.service"].status == "enabled" + +- name: Create Redis Sentinel data directory + ansible.builtin.file: + state: directory + path: "{{ redis_data_dir }}/sentinel" + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0755" + seuser: system_u + serole: object_r + setype: redis_var_lib_t + +- name: Create Redis Sentinel systemd file + ansible.builtin.template: + src: redis-sentinel.service.j2 + dest: /usr/lib/systemd/system/redis-sentinel.service + owner: root + group: root + mode: "0644" + +# Sentinel quorum configuration +# - If redis_sentinel_quorum is not 'auto', use the explicit value +# - Otherwise, calculate majority quorum: ceil(sentinel_count / 2) +# This ensures quorum is "more than half" of sentinels +# Examples: 1→1, 2→1, 3→2, 4→2, 5→3, 6→3, 7→4 +# - Defaults to 1 if redis_sentinel group is undefined or empty +- name: Set sentinel quorum + ansible.builtin.set_fact: + redis_sentinel_quorum_final: >- + {{ + redis_sentinel_quorum if redis_sentinel_quorum != 'auto' + else ((groups['redis_sentinel'] | default([]) | length / 2) | round(0, 'ceil') | int) | default(1) + }} + +- name: Validate sentinel quorum + ansible.builtin.assert: + that: + - redis_sentinel_quorum_final | int >= 1 + - redis_sentinel_quorum_final | int <= (groups['redis_sentinel'] | default([]) | length) + - groups['redis_sentinel'] | default([]) | length >= 3 or redis_sentinel_quorum != 'auto' + fail_msg: "Invalid quorum {{ redis_sentinel_quorum_final }} for {{ groups['redis_sentinel'] | default([]) | length }} sentinels (min 3 recommended)" + success_msg: "Sentinel quorum: {{ redis_sentinel_quorum_final }}/{{ groups['redis_sentinel'] | default([]) | length }}" + run_once: true + +- name: Display sentinel quorum configuration + ansible.builtin.debug: + msg: "Using sentinel quorum: {{ redis_sentinel_quorum_final }} out of {{ groups['redis_sentinel'] | default([]) | length }} sentinels" + run_once: true + +- name: Check if sentinel is running + ansible.builtin.systemd: + name: redis-sentinel + register: redis_sentinel_service + failed_when: false + +- name: Stop sentinel for config update + ansible.builtin.systemd: + name: redis-sentinel + state: stopped + when: redis_sentinel_service.status.ActiveState == 'active' + +- name: Deploy sentinel.conf + ansible.builtin.template: + src: sentinel.conf.j2 + dest: "{{ redis_sentinel_conf_file }}" + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0640" + setype: redis_conf_t + backup: true + notify: Enable and Start Redis Sentinel + +- name: Deploy logrotate config for Redis Sentinel + ansible.builtin.template: + src: redis-sentinel.logrotate.j2 + dest: /etc/logrotate.d/redis-sentinel + owner: root + group: root + mode: '0644' diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/download-packages.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/download-packages.yml new file mode 100644 index 00000000..7af518b6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/download-packages.yml @@ -0,0 +1,95 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include tasks to validate variables + ansible.builtin.include_tasks: + file: validate-vars.yml + tags: always + +- name: Include tasks to validate offline variables + ansible.builtin.include_tasks: + file: validate-vars-offline.yml + +- name: Download Redis security RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ redis_security_packages }} " + offline_download_dir: "{{ redis_offline_target_node_rpms_dir }}/security" + +- name: Copy Redis dependency RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ redis_offline_target_node_rpms_dir }}/security" + offline_dest_dir: "{{ redis_offline_control_node_rpms_dir }}/security" + +- name: Download package from Remi repo + when: not redis_install_from_source | bool + block: + - name: Include tasks to install Remi repo + ansible.builtin.include_tasks: + file: install-remi-repo.yml + when: + - redis_packages is defined + - redis_packages is search('remi') + + - name: Download Redis RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ redis_packages }} " + offline_download_dir: "{{ redis_offline_target_node_rpms_dir }}/redis" + + - name: Copy Redis RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ redis_offline_target_node_rpms_dir }}/redis" + offline_dest_dir: "{{ redis_offline_control_node_rpms_dir }}/redis" + +- name: Download source packages + when: redis_install_from_source | bool + block: + - name: Create archives directory + ansible.builtin.file: + path: "{{ redis_offline_target_node_archives_dir }}" + state: directory + mode: '0755' + + - name: Download Redis archive + ansible.builtin.get_url: + url: "{{ redis_source_url }}" + dest: "{{ redis_offline_target_node_archives_dir }}" + mode: "0644" + + - name: Copy Redis archive to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ redis_offline_target_node_archives_dir }}" + offline_dest_dir: "{{ redis_offline_control_node_archives_dir }}" + + - name: Download Redis build RPMs + ansible.builtin.import_role: + name: offline + tasks_from: download-rpms + vars: + offline_download_method: yum_module + offline_download_packages: "{{ redis_build_packages }}" + offline_download_dir: "{{ redis_offline_target_node_rpms_dir }}/build" + + - name: Copy Redis build RPMs to control node + ansible.builtin.import_role: + name: offline + tasks_from: fetch-packages + vars: + offline_src_dir: "{{ redis_offline_target_node_rpms_dir }}/build" + offline_dest_dir: "{{ redis_offline_control_node_rpms_dir }}/build" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-common.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-common.yml new file mode 100644 index 00000000..61ab99d6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-common.yml @@ -0,0 +1,68 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Kernel Adjust +# Memory overcommit must be enabled! Without it, a background save or replication may fail under +# low memory condition. +# Being disabled, it can can also cause failures without low memory condition, +# see https://github.com/jemalloc/jemalloc/issues/1328 +- name: Adjust Memory Overcommit + ansible.posix.sysctl: + name: vm.overcommit_memory + value: 1 + +- name: Create Redis group + ansible.builtin.group: + name: "{{ redis_group }}" + +- name: Create Redis user + ansible.builtin.user: + name: "{{ redis_owner }}" + group: "{{ redis_group }}" + state: present + +- name: Create Redis bin directory + ansible.builtin.file: + state: directory + path: "{{ redis_bin_dir }}" + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0755" + when: (redis_bin_dir != redis_bin_dir_default_packages or + (redis_bin_dir != redis_bin_dir_default_source and redis_install_from_source | bool)) + +- name: Create Redis data directory + ansible.builtin.file: + state: directory + path: "{{ redis_data_dir }}" + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0755" + seuser: system_u + serole: object_r + setype: redis_var_lib_t + when: redis_data_dir != redis_data_dir_default or redis_install_from_source | bool + +- name: Create Redis log directory + ansible.builtin.file: + state: directory + path: "{{ redis_log_dir }}" + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0755" + seuser: system_u + serole: object_r + setype: redis_log_t + when: redis_log_dir != redis_log_dir_default or redis_install_from_source | bool + +- name: Create Redis configuration directory + ansible.builtin.file: + path: "{{ redis_conf_dir }}" + state: directory + owner: "{{ redis_owner }}" + group: "{{ redis_group }}" + mode: "0750" + seuser: system_u + serole: object_r + setype: redis_conf_t + when: redis_conf_dir != redis_conf_dir_default or redis_install_from_source | bool diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-from-repo.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-from-repo.yml new file mode 100644 index 00000000..4d05685b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-from-repo.yml @@ -0,0 +1,27 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Redis from packages + when: not offline_install_enabled | bool + block: + - name: Include tasks to install Remi repo + ansible.builtin.include_tasks: + file: install-remi-repo.yml + when: + - redis_packages is defined + - redis_packages is search('remi') + + - name: Install Redis from packages + ansible.builtin.dnf: + name: '{{ redis_packages }}' + state: present + update_cache: true + enablerepo: "{{ redis_packages is search('remi') | ternary('remi', omit) }}" + +- name: Install Redis from packages (offline) + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + when: offline_install_enabled | bool + vars: + offline_rpms_path: "{{ redis_offline_control_node_rpms_dir }}/redis" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-from-source.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-from-source.yml new file mode 100644 index 00000000..5e0faa0b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-from-source.yml @@ -0,0 +1,127 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Check to see if Redis is already installed + ansible.builtin.stat: + path: "{{ redis_bin_dir }}/redis-server" + register: redis_installed + +- name: Determine if a rebuild is required + when: redis_installed.stat.exists + block: + - name: Determine current Redis version + ansible.builtin.shell: + cmd: 'set -o pipefail && redis-server --version | cut -d" " -f3 | cut -d"=" -f2' + register: current_redis_result + check_mode: false + changed_when: false + failed_when: current_redis_result.rc != 0 + environment: + PATH: "{{ ansible_env.PATH }}:{{ redis_bin_dir }}" + + - name: Set requires build flag if this is a new Redis version + ansible.builtin.set_fact: + requires_rebuild: "{{ current_redis_result.stdout != (redis_source_url + | basename | split('.tar.gz') | first) }}" + +- name: Install Redis + when: (not redis_installed.stat.exists) or (requires_rebuild | default(false)) + block: + - name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: redis_build_temp_dir + + - name: Online install + when: not offline_install_enabled | bool + block: + - name: Install Redis build packages + ansible.builtin.dnf: + name: "{{ item }}" + state: present + register: redis_install_result + with_items: "{{ redis_build_packages }}" + when: + - redis_build_packages is defined + - redis_build_packages is iterable + - redis_build_packages | length > 0 + + - name: Download Redis source archive + ansible.builtin.get_url: + url: "{{ redis_source_url }}" + dest: "{{ redis_build_temp_dir.path }}" + mode: "0644" + register: redis_download + + - name: Unarchive Redis source archive + ansible.builtin.unarchive: + src: "{{ redis_download.dest }}" + dest: "{{ redis_build_temp_dir.path }}" + remote_src: true + register: unarchive_result + + - name: Set the Redis build directory + ansible.builtin.set_fact: + redis_build_dir: "{{ unarchive_result.src.split('.tar.gz')[0] }}" + + - name: Offline install + when: offline_install_enabled | bool + block: + - name: Install Redis build packages (offline) + ansible.builtin.import_role: + name: offline + tasks_from: install-rpms + vars: + offline_rpms_path: "{{ redis_offline_control_node_rpms_dir }}/build" + + - name: Copy Redis archive (offline) + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ redis_build_temp_dir.path }}/{{ item | basename }}" + mode: '0644' + with_fileglob: "{{ redis_offline_control_node_archives_dir }}/redis*.tar.gz" + + - name: Find Redis archive (offline) + ansible.builtin.find: + paths: "{{ redis_build_temp_dir.path }}" + patterns: "redis*.tar.gz" + register: redis_archive + + - name: Unarchive Redis source archive (offline) + ansible.builtin.unarchive: + src: "{{ redis_archive.files[0].path }}" + dest: "{{ redis_build_temp_dir.path }}" + remote_src: true + register: unarchive_result + + - name: Set the Redis build directory (offline) + ansible.builtin.set_fact: + redis_build_dir: "{{ unarchive_result.src.split('.tar.gz')[0] }}" + + - name: Make Redis + community.general.make: + chdir: "{{ redis_build_dir }}" + target: install + params: + USE_SYSTEMD: true + PREFIX: "{{ redis_bin_dir | dirname }}" + tags: make_redis + + - name: Remove temporary working directory + ansible.builtin.file: + path: "{{ redis_build_temp_dir.path }}" + state: absent + + - name: Uninstall Redis build packages (offline) + ansible.builtin.dnf: + name: "{{ item }}" + allowerasing: true + autoremove: true + state: absent + with_items: "{{ redis_install_result.results | selectattr('changed', 'equalto', true) + | map(attribute='item') }}" + when: + - not offline_install_enabled | bool + - redis_install_result.results is defined + - redis_install_result.results is iterable + - redis_install_result.results | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-remi-repo.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-remi-repo.yml new file mode 100644 index 00000000..14bfc4f4 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/install-remi-repo.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Install Remi-related repos + when: + - common_install_yum_repos | bool + - redis_packages is defined + - redis_packages is search('remi') + block: + - name: Install EPEL repo + ansible.builtin.dnf: + name: "{{ redis_epel_repo_url }}" + state: present + update_cache: true + disable_gpg_check: true + retries: 3 + delay: 5 + + - name: Install Remi repo + ansible.builtin.dnf: + name: "{{ redis_remi_repo_url }}" + state: present + update_cache: true + disable_gpg_check: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/main.yml new file mode 100644 index 00000000..ca3a4c59 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/main.yml @@ -0,0 +1,108 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate variables and set node type facts + tags: always + block: + - name: Include tasks to validate variables + ansible.builtin.include_tasks: + file: validate-vars.yml + + - name: Set Redis node type facts + ansible.builtin.set_fact: + redis_is_master_node: "{{ 'redis_master' in group_names }}" + redis_is_replica_node: "{{ 'redis_replica' in group_names }}" + redis_is_sentinel_node: "{{ 'redis_sentinel' in group_names }}" + redis_is_data_node: "{{ 'redis_master' in group_names or 'redis_replica' in group_names }}" + redis_has_replicas: "{{ groups['redis_replica'] is defined and groups['redis_replica'] | length > 0 }}" + redis_has_sentinels: "{{ groups['redis_sentinel'] is defined and groups['redis_sentinel'] | length > 0 }}" + +- name: Install and configure Redis + notify: + - Enable and Start Redis + - Enable and Start Redis Sentinel + block: + - name: Install Redis + tags: install_redis + notify: Update Itential release file + block: + - name: Include common installation tasks + ansible.builtin.include_tasks: + file: install-common.yml + + - name: Include tasks to install Redis from source + ansible.builtin.include_tasks: + file: install-from-source.yml + when: redis_install_from_source | bool + + - name: Include tasks to install Redis using repo + ansible.builtin.include_tasks: + file: install-from-repo.yml + when: not redis_install_from_source | bool + + - name: Configure SELinux + tags: configure_selinux + block: + - name: Include tasks to configure SELinux + ansible.builtin.include_tasks: + file: configure-selinux.yml + when: + - ansible_selinux.status == "enabled" + - redis_install_from_source | bool + + - name: Configure Redis TLS + ansible.builtin.include_tasks: configure-redis-tls.yml + when: redis_tls_enabled | bool + tags: + - redis + - redis_certificates + - certificates + + - name: Configure Redis/Sentinel + tags: configure_redis + block: + - name: Include tasks to configure Redis + ansible.builtin.include_tasks: + file: configure-redis.yml + when: redis_is_data_node + + - name: Include tasks to configure Sentinel + ansible.builtin.include_tasks: + file: configure-sentinel.yml + when: redis_is_sentinel_node + +- name: Ensure Redis is running + tags: always + when: redis_is_data_node + block: + - name: Flush all handlers + ansible.builtin.meta: flush_handlers + + - name: Start Redis + ansible.builtin.systemd: + name: redis + state: started + + - name: Assert that Redis is running + ansible.builtin.systemd: + name: redis + register: redis_status + failed_when: redis_status.status.ActiveState != "active" + +- name: Ensure Redis Sentinel is running + tags: always + when: redis_is_sentinel_node + block: + - name: Flush all handlers + ansible.builtin.meta: flush_handlers + + - name: Start Redis Sentinel + ansible.builtin.systemd: + name: redis-sentinel + state: started + + - name: Assert that Redis Sentinel is running + ansible.builtin.systemd: + name: redis-sentinel + register: redis_sentinel_status + failed_when: redis_sentinel_status.status.ActiveState != "active" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/preflight.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/preflight.yml new file mode 100644 index 00000000..6ebd89c3 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/preflight.yml @@ -0,0 +1,64 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Include release vars + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "release-{{ iap_release }}.yml" + - "release-undefined.yml" + +- name: Check for valid Redis release + ansible.builtin.fail: + msg: "Deployer does not support installing Redis on IAP version {{ iap_release }}" + when: invalid_redis_release is defined + tags: always + +- name: Run common checks + ansible.builtin.include_role: + name: preflight + vars: + preflight_url_checks: "{{ (redis_install_method is defined and + redis_install_method == 'remi_repo') | + ternary([redis_repo_url[ansible_distribution_major_version], redis_epel_repo_url], + [redis_source_url[ansible_distribution_major_version]]) }}" + +- name: Create temporary working directory + ansible.builtin.tempfile: + state: directory + register: workingdir + +- name: Set pass to true if all conditions pass + ansible.builtin.set_fact: + results: '{{ results | combine({"pass": true}) }}' + when: + - results.cpuCores >= redis_cpu_cores + - results.get(mountvarname, 0) >= redis_free_disk_space + - results.memory >= redis_ram + - results.url_status.values() | unique | length == 1 and results.url_status.values() | unique | first == 200 + +- name: Create Redis preflight results + ansible.builtin.template: + src: "redis.preflight.j2" + dest: "{{ workingdir.path }}/redisPreflightResults.txt" + mode: '0777' + +- name: Fetch Redis results + ansible.builtin.fetch: + src: "{{ workingdir.path }}/redisPreflightResults.txt" + dest: "{{ preflight_directory }}/redis_{{ inventory_hostname }}_results.txt" + flat: true + +- name: Remove temporary working directory + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent + +- name: Check if host passed preflight checks. + ansible.builtin.assert: + that: results["pass"] == true + fail_msg: "Redis host did not pass the preflight checks" + success_msg: "Redis host passed the preflight checks" + when: + - preflight_enforce_checks is defined + - preflight_enforce_checks diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/update-release-file.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/update-release-file.yml new file mode 100644 index 00000000..4e526d3c --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/update-release-file.yml @@ -0,0 +1,20 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Determine redis version + ansible.builtin.shell: + cmd: 'set -o pipefail && redis-server --version | cut -d" " -f3 | cut -d"=" -f2' + register: result + check_mode: false + changed_when: false + failed_when: result.rc != 0 + environment: + PATH: "{{ ansible_env.PATH }}:{{ redis_bin_dir }}" + +- name: Write redis release information + ansible.builtin.lineinfile: + path: "{{ common_itential_release_file }}" + regexp: "^REDIS=" + line: "REDIS={{ result.stdout }}" + create: true + mode: "0644" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/validate-vars-offline.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/validate-vars-offline.yml new file mode 100644 index 00000000..e9f9eb72 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/validate-vars-offline.yml @@ -0,0 +1,12 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate distribution major version + ansible.builtin.assert: + that: ansible_distribution_major_version != "7" + msg: Download not supported for EL 7 + +- name: Validate offline_install_enabled variable + ansible.builtin.assert: + that: offline_install_enabled is not defined or not offline_install_enabled | bool + msg: offline_install_enabled must be set to false for download diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/validate-vars.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/validate-vars.yml new file mode 100644 index 00000000..ca38f5bf --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/tasks/validate-vars.yml @@ -0,0 +1,120 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Validate and set installation variables + tags: always + block: + - name: Validate an installation variable is set + ansible.builtin.assert: + that: > + (platform_release is defined) or + (redis_packages is defined) or + (redis_source_url is defined) + fail_msg: "platform_release OR redis_packages OR redis_source_url must be defined" + + - name: Validate redis_source_url and redis_packages exclusivity + ansible.builtin.assert: + that: redis_packages is not defined + fail_msg: "redis_source_url and redis_packages are mutually exclusive" + when: redis_source_url is defined + + - name: Validate redis_source_url or redis_packages is set when not using platform_release + ansible.builtin.assert: + that: redis_source_url is defined or redis_packages is defined + fail_msg: >- + redis_source_url OR redis_packages must be defined + when platform_release is not defined + when: platform_release is not defined + + - name: Validate installation variables when installing from source + when: redis_install_from_source | bool + block: + - name: Validate redis_source_url or platform_release is set when installing from source + ansible.builtin.assert: + that: redis_source_url is defined or platform_release is defined + fail_msg: >- + redis_source_url OR platform_release must be defined + when redis_install_from_source is set to true + + - name: Validate redis_packages is not set when installing from source + ansible.builtin.assert: + that: redis_packages is not defined + fail_msg: >- + redis_packages cannot be defined + when redis_install_from_source is set to true + + - name: Validate installation variables when installing from packages + when: not redis_install_from_source | bool + block: + - name: Validate redis_packages or platform_release is set when installing from packages + ansible.builtin.assert: + that: redis_packages is defined or platform_release is defined + fail_msg: >- + redis_packages OR platform_release must be defined + when redis_install_from_source is set to false + + - name: Validate redis_source_url is not set when installing from packages + ansible.builtin.assert: + that: redis_source_url is not defined + fail_msg: >- + redis_source_url cannot be defined + when redis_install_from_source is set to false + + - name: Validate directories are not overridden when installing from packages + ansible.builtin.assert: + that: + - redis_bin_dir == redis_bin_dir_default_packages + - redis_conf_dir == redis_conf_dir_default + - redis_data_dir == redis_data_dir_default + - redis_log_dir == redis_log_dir_default + fail_msg: default directories cannot be overridden when installing from packages + + - name: Set installation variables when using Itential Platform release defaults + when: platform_release is defined + block: + - name: Load Itential Platform release default variables + ansible.builtin.include_vars: + file: "{{ item }}" + with_first_found: + - "platform-release-{{ platform_release }}.yml" + - "platform-release-{{ platform_release | string | split('.') | first }}.yml" + - "platform-release-undefined.yml" + + - name: Check for valid Redis release + ansible.builtin.assert: + that: redis_invalid_platform_release is not defined + fail_msg: >- + Deployer does not support installing Redis + for Itential Platform release {{ platform_release }} + + - name: Set redis_source_url to the default value when not defined in inventory + ansible.builtin.set_fact: + redis_source_url: "{{ redis_source_url_default[ansible_distribution_major_version] }}" + when: + - redis_source_url is not defined + - redis_install_from_source | bool + + - name: Set redis_packages to the default value when not defined in inventory + ansible.builtin.set_fact: + redis_packages: "{{ redis_packages_default[ansible_distribution_major_version] }}" + when: + - redis_packages is not defined + - not redis_install_from_source | bool + + - name: Print Redis installation details + when: not offline_install_enabled | bool + block: + - name: Print Redis installation details when installing from source + ansible.builtin.debug: + msg: "Redis source URL: {{ redis_source_url }}" + when: redis_install_from_source | bool + + - name: Print Redis installation details when installing from repo + ansible.builtin.debug: + msg: "Redis packages: {{ redis_packages }}" + when: not redis_install_from_source | bool + + - name: Print Redis installation details (offline) + ansible.builtin.debug: + msg: "Redis offline install using files from {{ redis_offline_control_node_root }}" + when: offline_install_enabled | bool diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis-sentinel.logrotate.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis-sentinel.logrotate.j2 new file mode 100644 index 00000000..5ed2446b --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis-sentinel.logrotate.j2 @@ -0,0 +1,35 @@ +# ----------------------------------------------------- +# This file is managed by Ansible. +# Safe to edit, but if you re-run automation, it may be overwritten. +# +# To customize retention, compression, or actions, edit below. + +{{ redis_log_dir }}/sentinel.log { + # How often to rotate (change to weekly/monthly if desired) + daily + + # How many rotations to keep (increase/decrease as needed) + rotate 7 + + # Enable compression for old logs (can comment to disable) + compress + delaycompress + + # Don't complain if log is missing or empty + missingok + notifempty + + # Ensure logrotate runs with the right user/group + su {{ redis_owner }} {{ redis_group }} + + # File permissions & ownership for new logs + create 0640 {{ redis_owner }} {{ redis_group }} + + # Safest for Sentinel: copy+truncate the active file in place + copytruncate + + # Ensures only one rotation at a time if multiple logs exist + sharedscripts + + # NOTE: Sentinel does NOT reopen logs on HUP. Avoid postrotate/HUP. +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis-sentinel.service.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis-sentinel.service.j2 new file mode 100644 index 00000000..28a17604 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis-sentinel.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Redis Sentinel +After=network.target +After=network-online.target +Wants=network-online.target + +[Service] +ExecStart={{ redis_bin_dir }}/redis-sentinel {{ redis_sentinel_conf_file }} --daemonize no --supervised systemd +Type=notify +User={{ redis_owner }} +Group={{ redis_group }} +RuntimeDirectory=redis +RuntimeDirectoryMode=0755 + +[Install] +WantedBy=multi-user.target diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.conf.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.conf.j2 new file mode 100644 index 00000000..fd6163c9 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.conf.j2 @@ -0,0 +1,2090 @@ +# Redis configuration file example. +# +# Note that in order to read the configuration file, Redis must be +# started with the file path as first argument: +# +# ./redis-server /path/to/redis.conf + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +################################## INCLUDES ################################### + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all Redis servers but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +# Note that option "include" won't be rewritten by command "CONFIG REWRITE" +# from admin or Redis Sentinel. Since Redis always uses the last processed +# line as value of a configuration directive, you'd better put includes +# at the beginning of this file to avoid overwriting config change at runtime. +# +# If instead you are interested in using includes to override configuration +# options, it is better to use include as the last line. +# +# include /path/to/local.conf +# include /path/to/other.conf + +################################## MODULES ##################################### + +# Load modules at startup. If the server is not able to load modules +# it will abort. It is possible to use multiple loadmodule directives. +# +# loadmodule /path/to/my_module.so +# loadmodule /path/to/other_module.so + +################################## NETWORK ##################################### + +# By default, if no "bind" configuration directive is specified, Redis listens +# for connections from all available network interfaces on the host machine. +# It is possible to listen to just one or multiple selected interfaces using +# the "bind" configuration directive, followed by one or more IP addresses. +# Each address can be prefixed by "-", which means that redis will not fail to +# start if the address is not available. Being not available only refers to +# addresses that does not correspond to any network interfece. Addresses that +# are already in use will always fail, and unsupported protocols will always BE +# silently skipped. +# +# Examples: +# +# bind 192.168.1.100 10.0.0.1 # listens on two specific IPv4 addresses +# bind 127.0.0.1 ::1 # listens on loopback IPv4 and IPv6 +# bind * -::* # like the default, all available interfaces +# +# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the +# internet, binding to all the interfaces is dangerous and will expose the +# instance to everybody on the internet. So by default we uncomment the +# following bind directive, that will force Redis to listen only on the +# IPv4 and IPv6 (if available) loopback interface addresses (this means Redis +# will only be able to accept client connections from the same host that it is +# running on). +# +# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES +# JUST COMMENT OUT THE FOLLOWING LINE. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bind {{ redis_bind }} + +# Protected mode is a layer of security protection, in order to avoid that +# Redis instances left open on the internet are accessed and exploited. +# +# When protected mode is on and if: +# +# 1) The server is not binding explicitly to a set of addresses using the +# "bind" directive. +# 2) No password is configured. +# +# The server only accepts connections from clients connecting from the +# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain +# sockets. +# +# By default protected mode is enabled. You should disable it only if +# you are sure you want clients from other hosts to connect to Redis +# even if no authentication is configured, nor a specific set of interfaces +# are explicitly listed using the "bind" directive. +# +# Itential recommends binding to specific addresses. Therefore, we recommend +# to disable protected mode +protected-mode no + +# Accept connections on the specified port, default is 6379 (IANA #815344). +# If port 0 is specified Redis will not listen on a TCP socket. +port {{ redis_port }} + +# TCP listen() backlog. +# +# In high requests-per-second environments you need a high backlog in order +# to avoid slow clients connection issues. Note that the Linux kernel +# will silently truncate it to the value of /proc/sys/net/core/somaxconn so +# make sure to raise both the value of somaxconn and tcp_max_syn_backlog +# in order to get the desired effect. +tcp-backlog 511 + +# Unix socket. +# +# Specify the path for the Unix socket that will be used to listen for +# incoming connections. There is no default, so Redis will not listen +# on a unix socket when not specified. +# +# unixsocket /run/redis.sock +# unixsocketperm 700 + +# Close the connection after a client is idle for N seconds (0 to disable) +timeout 0 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Force network equipment in the middle to consider the connection to be +# alive. +# +# On Linux, the specified value (in seconds) is the period used to send ACKs. +# Note that to close the connection the double of the time is needed. +# On other kernels the period depends on the kernel configuration. +# +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 60 + +################################# TLS/SSL ##################################### + +# By default, TLS/SSL is disabled. To enable it, the "tls-port" configuration +# directive can be used to define TLS-listening ports. To enable TLS on the +# default port, use: +# +# port 0 +# tls-port 6379 + +# Configure a X.509 certificate and private key to use for authenticating the +# server to connected clients, masters or cluster peers. These files should be +# PEM formatted. +# +# tls-cert-file redis.crt +# tls-key-file redis.key +# +# If the key file is encrypted using a passphrase, it can be included here +# as well. +# +# tls-key-file-pass secret + +# Normally Redis uses the same certificate for both server functions (accepting +# connections) and client functions (replicating from a master, establishing +# cluster bus connections, etc.). +# +# Sometimes certificates are issued with attributes that designate them as +# client-only or server-only certificates. In that case it may be desired to use +# different certificates for incoming (server) and outgoing (client) +# connections. To do that, use the following directives: +# +# tls-client-cert-file client.crt +# tls-client-key-file client.key +# +# If the key file is encrypted using a passphrase, it can be included here +# as well. +# +# tls-client-key-file-pass secret + +# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange, +# required by older versions of OpenSSL (<3.0). Newer versions do not require +# this configuration and recommend against it. +# +# tls-dh-params-file redis.dh + +# Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL +# clients and peers. Redis requires an explicit configuration of at least one +# of these, and will not implicitly use the system wide configuration. +# +# tls-ca-cert-file ca.crt +# tls-ca-cert-dir /etc/ssl/certs + +# By default, clients (including replica servers) on a TLS port are required +# to authenticate using valid client side certificates. +# +# If "no" is specified, client certificates are not required and not accepted. +# If "optional" is specified, client certificates are accepted and must be +# valid if provided, but are not required. +# +# tls-auth-clients no +# tls-auth-clients optional + +# By default, a Redis replica does not attempt to establish a TLS connection +# with its master. +# +# Use the following directive to enable TLS on replication links. +# +# tls-replication yes + +# By default, the Redis Cluster bus uses a plain TCP connection. To enable +# TLS for the bus protocol, use the following directive: +# +# tls-cluster yes + +# By default, only TLSv1.2 and TLSv1.3 are enabled and it is highly recommended +# that older formally deprecated versions are kept disabled to reduce the attack surface. +# You can explicitly specify TLS versions to support. +# Allowed values are case insensitive and include "TLSv1", "TLSv1.1", "TLSv1.2", +# "TLSv1.3" (OpenSSL >= 1.1.1) or any combination. +# To enable only TLSv1.2 and TLSv1.3, use: +# +# tls-protocols "TLSv1.2 TLSv1.3" + +# Configure allowed ciphers. See the ciphers(1ssl) manpage for more information +# about the syntax of this string. +# +# Note: this configuration applies only to <= TLSv1.2. +# +# tls-ciphers DEFAULT:!MEDIUM + +# Configure allowed TLSv1.3 ciphersuites. See the ciphers(1ssl) manpage for more +# information about the syntax of this string, and specifically for TLSv1.3 +# ciphersuites. +# +# tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256 + +# When choosing a cipher, use the server's preference instead of the client +# preference. By default, the server follows the client's preference. +# +# tls-prefer-server-ciphers yes + +# By default, TLS session caching is enabled to allow faster and less expensive +# reconnections by clients that support it. Use the following directive to disable +# caching. +# +# tls-session-caching no + +# Change the default number of TLS sessions cached. A zero value sets the cache +# to unlimited size. The default size is 20480. +# +# tls-session-cache-size 5000 + +# Change the default timeout of cached TLS sessions. The default timeout is 300 +# seconds. +# +# tls-session-cache-timeout 60 + +################################# GENERAL ##################################### + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +# When Redis is supervised by upstart or systemd, this parameter has no impact. +daemonize no + +# If you run Redis from upstart or systemd, Redis can interact with your +# supervision tree. Options: +# supervised no - no supervision interaction +# supervised upstart - signal upstart by putting Redis into SIGSTOP mode +# requires "expect stop" in your upstart job config +# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# on startup, and updating Redis status on a regular +# basis. +# supervised auto - detect upstart or systemd method based on +# UPSTART_JOB or NOTIFY_SOCKET environment variables +# Note: these supervision methods only signal "process is ready." +# They do not enable continuous pings back to your supervisor. +# +# The default is "no". To run under upstart/systemd, you can simply uncomment +# the line below: +# +# supervised auto + +# If a pid file is specified, Redis writes it where specified at startup +# and removes it at exit. +# +# When the server runs non daemonized, no pid file is created if none is +# specified in the configuration. When the server is daemonized, the pid file +# is used even if not specified, defaulting to "/var/run/redis.pid". +# +# Creating a pid file is best effort: if Redis is not able to create it +# nothing bad happens, the server will start and run normally. +# +# Note that on modern Linux systems "/run/redis.pid" is more conforming +# and should be used instead. +# pidfile /run/redis.pid + +# Specify the server verbosity level. +# This can be one of: +# debug (a lot of information, useful for development/testing) +# verbose (many rarely useful info, but not a mess like the debug level) +# notice (moderately verbose, what you want in production probably) +# warning (only very important / critical messages are logged) +loglevel notice + +# Specify the log file name. Also the empty string can be used to force +# Redis to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile "{{ redis_log }}" + +# To enable logging to the system logger, just set 'syslog-enabled' to yes, +# and optionally update the other syslog parameters to suit your needs. +# syslog-enabled no + +# Specify the syslog identity. +# syslog-ident redis + +# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. +# syslog-facility local0 + +# To disable the built in crash log, which will possibly produce cleaner core +# dumps when they are needed, uncomment the following: +# +# crash-log-enabled no + +# To disable the fast memory check that's run as part of the crash log, which +# will possibly let redis terminate sooner, uncomment the following: +# +# crash-memcheck-enabled no + +# Set the number of databases. The default database is DB 0, you can select +# a different one on a per-connection basis using SELECT where +# dbid is a number between 0 and 'databases'-1 +databases 16 + +# By default Redis shows an ASCII art logo only when started to log to the +# standard output and if the standard output is a TTY and syslog logging is +# disabled. Basically this means that normally a logo is displayed only in +# interactive sessions. +# +# However it is possible to force the pre-4.0 behavior and always show a +# ASCII art logo in startup logs by setting the following option to yes. +always-show-logo no + +# By default, Redis modifies the process title (as seen in 'top' and 'ps') to +# provide some runtime information. It is possible to disable this and leave +# the process name as executed by setting the following to no. +set-proc-title yes + +# When changing the process title, Redis uses the following template to construct +# the modified title. +# +# Template variables are specified in curly brackets. The following variables are +# supported: +# +# {title} Name of process as executed if parent, or type of child process. +# {listen-addr} Bind address or '*' followed by TCP or TLS port listening on, or +# Unix socket if only that's available. +# {server-mode} Special mode, i.e. "[sentinel]" or "[cluster]". +# {port} TCP port listening on, or 0. +# {tls-port} TLS port listening on, or 0. +# {unixsocket} Unix domain socket listening on, or "". +# {config-file} Name of configuration file used. +# +proc-title-template "{title} {listen-addr} {server-mode}" + +################################ SNAPSHOTTING ################################ + +# Save the DB to disk. +# +# save +# +# Redis will save the DB if both the given number of seconds and the given +# number of write operations against the DB occurred. +# +# Snapshotting can be completely disabled with a single empty string argument +# as in following example: +# +# save "" +# +# Unless specified otherwise, by default Redis will save the DB: +# * After 3600 seconds (an hour) if at least 1 key changed +# * After 300 seconds (5 minutes) if at least 100 keys changed +# * After 60 seconds if at least 10000 keys changed +# +# You can set these explicitly by uncommenting the three following lines. +# +# save 3600 1 +# save 300 100 +# save 60 10000 + +# By default Redis will stop accepting writes if RDB snapshots are enabled +# (at least one save point) and the latest background save failed. +# This will make the user aware (in a hard way) that data is not persisting +# on disk properly, otherwise chances are that no one will notice and some +# disaster will happen. +# +# If the background saving process will start working again Redis will +# automatically allow writes again. +# +# However if you have setup your proper monitoring of the Redis server +# and persistence, you may want to disable this feature so that Redis will +# continue to work as usual even if there are problems with disk, +# permissions, and so forth. +stop-writes-on-bgsave-error yes + +# Compress string objects using LZF when dump .rdb databases? +# By default compression is enabled as it's almost always a win. +# If you want to save some CPU in the saving child set it to 'no' but +# the dataset will likely be bigger if you have compressible values or keys. +rdbcompression yes + +# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. +# This makes the format more resistant to corruption but there is a performance +# hit to pay (around 10%) when saving and loading RDB files, so you can disable it +# for maximum performances. +# +# RDB files created with checksum disabled have a checksum of zero that will +# tell the loading code to skip the check. +rdbchecksum yes + +# Enables or disables full sanitation checks for ziplist and listpack etc when +# loading an RDB or RESTORE payload. This reduces the chances of a assertion or +# crash later on while processing commands. +# Options: +# no - Never perform full sanitation +# yes - Always perform full sanitation +# clients - Perform full sanitation only for user connections. +# Excludes: RDB files, RESTORE commands received from the master +# connection, and client connections which have the +# skip-sanitize-payload ACL flag. +# The default should be 'clients' but since it currently affects cluster +# resharding via MIGRATE, it is temporarily set to 'no' by default. +# +# sanitize-dump-payload no + +# The filename where to dump the DB +dbfilename {{ redis_db_filename }} + +# Remove RDB files used by replication in instances without persistence +# enabled. By default this option is disabled, however there are environments +# where for regulations or other security concerns, RDB files persisted on +# disk by masters in order to feed replicas, or stored on disk by replicas +# in order to load them for the initial synchronization, should be deleted +# ASAP. Note that this option ONLY WORKS in instances that have both AOF +# and RDB persistence disabled, otherwise is completely ignored. +# +# An alternative (and sometimes better) way to obtain the same effect is +# to use diskless replication on both master and replicas instances. However +# in the case of replicas, diskless is not always an option. +rdb-del-sync-files no + +# The working directory. +# +# The DB will be written inside this directory, with the filename specified +# above using the 'dbfilename' configuration directive. +# +# The Append Only File will also be created inside this directory. +# +# Note that you must specify a directory here, not a file name. +dir {{ redis_data_dir }} + +################################# REPLICATION ################################# + +# Master-Replica replication. Use replicaof to make a Redis instance a copy of +# another Redis server. A few things to understand ASAP about Redis replication. +# +# +------------------+ +---------------+ +# | Master | ---> | Replica | +# | (receive writes) | | (exact copy) | +# +------------------+ +---------------+ +# +# 1) Redis replication is asynchronous, but you can configure a master to +# stop accepting writes if it appears to be not connected with at least +# a given number of replicas. +# 2) Redis replicas are able to perform a partial resynchronization with the +# master if the replication link is lost for a relatively small amount of +# time. You may want to configure the replication backlog size (see the next +# sections of this file) with a sensible value depending on your needs. +# 3) Replication is automatic and does not need user intervention. After a +# network partition replicas automatically try to reconnect to masters +# and resynchronize with them. +# +# replicaof +{% if redis_is_replica_node %} +replicaof {{ redis_replicaof }} +{% endif %} + +# If the master is password protected (using the "requirepass" configuration +# directive below) it is possible to tell the replica to authenticate before +# starting the replication synchronization process, otherwise the master will +# refuse the replica request. +# +# masterauth +# +# However this is not enough if you are using Redis ACLs (for Redis version +# 6 or greater), and the default user is not capable of running the PSYNC +# command and/or other commands needed for replication. In this case it's +# better to configure a special user to use with replication, and specify the +# masteruser configuration as such: +# +# masteruser +# +# When masteruser is specified, the replica will authenticate against its +# master using the new AUTH form: AUTH . +{% if redis_is_data_node and redis_auth_enabled %} +masterauth {{ redis_user_repluser_password }} +masteruser repluser +{% endif %} + +# When a replica loses its connection with the master, or when the replication +# is still in progress, the replica can act in two different ways: +# +# 1) if replica-serve-stale-data is set to 'yes' (the default) the replica will +# still reply to client requests, possibly with out of date data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) If replica-serve-stale-data is set to 'no' the replica will reply with +# an error "SYNC with master in progress" to all commands except: +# INFO, REPLICAOF, AUTH, PING, SHUTDOWN, REPLCONF, ROLE, CONFIG, SUBSCRIBE, +# UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST, +# HOST and LATENCY. +# +replica-serve-stale-data yes + +# You can configure a replica instance to accept writes or not. Writing against +# a replica instance may be useful to store some ephemeral data (because data +# written on a replica will be easily deleted after resync with the master) but +# may also cause problems if clients are writing to it because of a +# misconfiguration. +# +# Since Redis 2.6 by default replicas are read-only. +# +# Note: read only replicas are not designed to be exposed to untrusted clients +# on the internet. It's just a protection layer against misuse of the instance. +# Still a read only replica exports by default all the administrative commands +# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve +# security of read only replicas using 'rename-command' to shadow all the +# administrative / dangerous commands. +replica-read-only yes + +# Replication SYNC strategy: disk or socket. +# +# New replicas and reconnecting replicas that are not able to continue the +# replication process just receiving differences, need to do what is called a +# "full synchronization". An RDB file is transmitted from the master to the +# replicas. +# +# The transmission can happen in two different ways: +# +# 1) Disk-backed: The Redis master creates a new process that writes the RDB +# file on disk. Later the file is transferred by the parent +# process to the replicas incrementally. +# 2) Diskless: The Redis master creates a new process that directly writes the +# RDB file to replica sockets, without touching the disk at all. +# +# With disk-backed replication, while the RDB file is generated, more replicas +# can be queued and served with the RDB file as soon as the current child +# producing the RDB file finishes its work. With diskless replication instead +# once the transfer starts, new replicas arriving will be queued and a new +# transfer will start when the current one terminates. +# +# When diskless replication is used, the master waits a configurable amount of +# time (in seconds) before starting the transfer in the hope that multiple +# replicas will arrive and the transfer can be parallelized. +# +# With slow disks and fast (large bandwidth) networks, diskless replication +# works better. +repl-diskless-sync no + +# When diskless replication is enabled, it is possible to configure the delay +# the server waits in order to spawn the child that transfers the RDB via socket +# to the replicas. +# +# This is important since once the transfer starts, it is not possible to serve +# new replicas arriving, that will be queued for the next RDB transfer, so the +# server waits a delay in order to let more replicas arrive. +# +# The delay is specified in seconds, and by default is 5 seconds. To disable +# it entirely just set it to 0 seconds and the transfer will start ASAP. +repl-diskless-sync-delay 5 + +# ----------------------------------------------------------------------------- +# WARNING: RDB diskless load is experimental. Since in this setup the replica +# does not immediately store an RDB on disk, it may cause data loss during +# failovers. RDB diskless load + Redis modules not handling I/O reads may also +# cause Redis to abort in case of I/O errors during the initial synchronization +# stage with the master. Use only if you know what you are doing. +# ----------------------------------------------------------------------------- +# +# Replica can load the RDB it reads from the replication link directly from the +# socket, or store the RDB to a file and read that file after it was completely +# received from the master. +# +# In many cases the disk is slower than the network, and storing and loading +# the RDB file may increase replication time (and even increase the master's +# Copy on Write memory and salve buffers). +# However, parsing the RDB file directly from the socket may mean that we have +# to flush the contents of the current database before the full rdb was +# received. For this reason we have the following options: +# +# "disabled" - Don't use diskless load (store the rdb file to the disk first) +# "on-empty-db" - Use diskless load only when it is completely safe. +# "swapdb" - Keep a copy of the current db contents in RAM while parsing +# the data directly from the socket. note that this requires +# sufficient memory, if you don't have it, you risk an OOM kill. +repl-diskless-load disabled + +# Replicas send PINGs to server in a predefined interval. It's possible to +# change this interval with the repl_ping_replica_period option. The default +# value is 10 seconds. +# +# repl-ping-replica-period 10 +repl-ping-replica-period 5 + +# The following option sets the replication timeout for: +# +# 1) Bulk transfer I/O during SYNC, from the point of view of replica. +# 2) Master timeout from the point of view of replicas (data, pings). +# 3) Replica timeout from the point of view of masters (REPLCONF ACK pings). +# +# It is important to make sure that this value is greater than the value +# specified for repl-ping-replica-period otherwise a timeout will be detected +# every time there is low traffic between the master and the replica. The default +# value is 60 seconds. +# +# repl-timeout 60 +repl-timeout 30 + +# Disable TCP_NODELAY on the replica socket after SYNC? +# +# If you select "yes" Redis will use a smaller number of TCP packets and +# less bandwidth to send data to replicas. But this can add a delay for +# the data to appear on the replica side, up to 40 milliseconds with +# Linux kernels using a default configuration. +# +# If you select "no" the delay for data to appear on the replica side will +# be reduced but more bandwidth will be used for replication. +# +# By default we optimize for low latency, but in very high traffic conditions +# or when the master and replicas are many hops away, turning this to "yes" may +# be a good idea. +repl-disable-tcp-nodelay no + +# Set the replication backlog size. The backlog is a buffer that accumulates +# replica data when replicas are disconnected for some time, so that when a +# replica wants to reconnect again, often a full resync is not needed, but a +# partial resync is enough, just passing the portion of data the replica +# missed while disconnected. +# +# The bigger the replication backlog, the longer the replica can endure the +# disconnect and later be able to perform a partial resynchronization. +# +# The backlog is only allocated if there is at least one replica connected. +# +# repl-backlog-size 1mb +repl-backlog-size 536870912 + +# After a master has no connected replicas for some time, the backlog will be +# freed. The following option configures the amount of seconds that need to +# elapse, starting from the time the last replica disconnected, for the backlog +# buffer to be freed. +# +# Note that replicas never free the backlog for timeout, since they may be +# promoted to masters later, and should be able to correctly "partially +# resynchronize" with other replicas: hence they should always accumulate backlog. +# +# A value of 0 means to never release the backlog. +# +# repl-backlog-ttl 3600 + +# The replica priority is an integer number published by Redis in the INFO +# output. It is used by Redis Sentinel in order to select a replica to promote +# into a master if the master is no longer working correctly. +# +# A replica with a low priority number is considered better for promotion, so +# for instance if there are three replicas with priority 10, 100, 25 Sentinel +# will pick the one with priority 10, that is the lowest. +# +# However a special priority of 0 marks the replica as not able to perform the +# role of master, so a replica with priority of 0 will never be selected by +# Redis Sentinel for promotion. +# +# By default the priority is 100. +replica-priority 100 + +# ----------------------------------------------------------------------------- +# By default, Redis Sentinel includes all replicas in its reports. A replica +# can be excluded from Redis Sentinel's announcements. An unannounced replica +# will be ignored by the 'sentinel replicas ' command and won't be +# exposed to Redis Sentinel's clients. +# +# This option does not change the behavior of replica-priority. Even with +# replica-announced set to 'no', the replica can be promoted to master. To +# prevent this behavior, set replica-priority to 0. +# +# replica-announced yes + +# It is possible for a master to stop accepting writes if there are less than +# N replicas connected, having a lag less or equal than M seconds. +# +# The N replicas need to be in "online" state. +# +# The lag in seconds, that must be <= the specified value, is calculated from +# the last ping received from the replica, that is usually sent every second. +# +# This option does not GUARANTEE that N replicas will accept the write, but +# will limit the window of exposure for lost writes in case not enough replicas +# are available, to the specified number of seconds. +# +# For example to require at least 3 replicas with a lag <= 10 seconds use: +# +# min-replicas-to-write 3 +# min-replicas-max-lag 10 +# +# Setting one or the other to 0 disables the feature. +# +# By default min-replicas-to-write is set to 0 (feature disabled) and +# min-replicas-max-lag is set to 10. +{% if redis_is_master_node and redis_has_replicas %} +min-replicas-to-write 1 +min-replicas-max-lag 10 +{% endif %} + +# A Redis master is able to list the address and port of the attached +# replicas in different ways. For example the "INFO replication" section +# offers this information, which is used, among other tools, by +# Redis Sentinel in order to discover replica instances. +# Another place where this info is available is in the output of the +# "ROLE" command of a master. +# +# The listed IP address and port normally reported by a replica is +# obtained in the following way: +# +# IP: The address is auto detected by checking the peer address +# of the socket used by the replica to connect with the master. +# +# Port: The port is communicated by the replica during the replication +# handshake, and is normally the port that the replica is using to +# listen for connections. +# +# However when port forwarding or Network Address Translation (NAT) is +# used, the replica may actually be reachable via different IP and port +# pairs. The following two options can be used by a replica in order to +# report to its master a specific set of IP and port, so that both INFO +# and ROLE will report those values. +# +# There is no need to use both the options if you need to override just +# the port or the IP address. +# +{% if redis_is_data_node %} +replica-announce-ip {{ inventory_hostname }} +replica-announce-port {{ redis_port }} +{% endif %} +# replica-announce-ip 5.5.5.5 +# replica-announce-port 1234 + +############################### KEYS TRACKING ################################# + +# Redis implements server assisted support for client side caching of values. +# This is implemented using an invalidation table that remembers, using +# a radix key indexed by key name, what clients have which keys. In turn +# this is used in order to send invalidation messages to clients. Please +# check this page to understand more about the feature: +# +# https://redis.io/topics/client-side-caching +# +# When tracking is enabled for a client, all the read only queries are assumed +# to be cached: this will force Redis to store information in the invalidation +# table. When keys are modified, such information is flushed away, and +# invalidation messages are sent to the clients. However if the workload is +# heavily dominated by reads, Redis could use more and more memory in order +# to track the keys fetched by many clients. +# +# For this reason it is possible to configure a maximum fill value for the +# invalidation table. By default it is set to 1M of keys, and once this limit +# is reached, Redis will start to evict keys in the invalidation table +# even if they were not modified, just to reclaim memory: this will in turn +# force the clients to invalidate the cached values. Basically the table +# maximum size is a trade off between the memory you want to spend server +# side to track information about who cached what, and the ability of clients +# to retain cached objects in memory. +# +# If you set the value to 0, it means there are no limits, and Redis will +# retain as many keys as needed in the invalidation table. +# In the "stats" INFO section, you can find information about the number of +# keys in the invalidation table at every given moment. +# +# Note: when key tracking is used in broadcasting mode, no memory is used +# in the server side so this setting is useless. +# +# tracking-table-max-keys 1000000 + +################################## SECURITY ################################### + +# Warning: since Redis is pretty fast, an outside user can try up to +# 1 million passwords per second against a modern box. This means that you +# should use very strong passwords, otherwise they will be very easy to break. +# Note that because the password is really a shared secret between the client +# and the server, and should not be memorized by any human, the password +# can be easily a long string from /dev/urandom or whatever, so by using a +# long and unguessable password no brute force attack will be possible. + +# Redis ACL users are defined in the following format: +# +# user ... acl rules ... +# +# For example: +# +# user worker +@list +@connection ~jobs:* on >ffa9203c493aa99 +# +# The special username "default" is used for new connections. If this user +# has the "nopass" rule, then new connections will be immediately authenticated +# as the "default" user without the need of any password provided via the +# AUTH command. Otherwise if the "default" user is not flagged with "nopass" +# the connections will start in not authenticated state, and will require +# AUTH (or the HELLO command AUTH option) in order to be authenticated and +# start to work. +# +# The ACL rules that describe what a user can do are the following: +# +# on Enable the user: it is possible to authenticate as this user. +# off Disable the user: it's no longer possible to authenticate +# with this user, however the already authenticated connections +# will still work. +# skip-sanitize-payload RESTORE dump-payload sanitation is skipped. +# sanitize-payload RESTORE dump-payload is sanitized (default). +# + Allow the execution of that command +# - Disallow the execution of that command +# +@ Allow the execution of all the commands in such category +# with valid categories are like @admin, @set, @sortedset, ... +# and so forth, see the full list in the server.c file where +# the Redis command table is described and defined. +# The special category @all means all the commands, but currently +# present in the server, and that will be loaded in the future +# via modules. +# +|subcommand Allow a specific subcommand of an otherwise +# disabled command. Note that this form is not +# allowed as negative like -DEBUG|SEGFAULT, but +# only additive starting with "+". +# allcommands Alias for +@all. Note that it implies the ability to execute +# all the future commands loaded via the modules system. +# nocommands Alias for -@all. +# ~ Add a pattern of keys that can be mentioned as part of +# commands. For instance ~* allows all the keys. The pattern +# is a glob-style pattern like the one of KEYS. +# It is possible to specify multiple patterns. +# allkeys Alias for ~* +# resetkeys Flush the list of allowed keys patterns. +# & Add a glob-style pattern of Pub/Sub channels that can be +# accessed by the user. It is possible to specify multiple channel +# patterns. +# allchannels Alias for &* +# resetchannels Flush the list of allowed channel patterns. +# > Add this password to the list of valid password for the user. +# For example >mypass will add "mypass" to the list. +# This directive clears the "nopass" flag (see later). +# < Remove this password from the list of valid passwords. +# nopass All the set passwords of the user are removed, and the user +# is flagged as requiring no password: it means that every +# password will work against this user. If this directive is +# used for the default user, every new connection will be +# immediately authenticated with the default user without +# any explicit AUTH command required. Note that the "resetpass" +# directive will clear this condition. +# resetpass Flush the list of allowed passwords. Moreover removes the +# "nopass" status. After "resetpass" the user has no associated +# passwords and there is no way to authenticate without adding +# some password (or setting it as "nopass" later). +# reset Performs the following actions: resetpass, resetkeys, off, +# -@all. The user returns to the same state it has immediately +# after its creation. +# +# ACL rules can be specified in any order: for instance you can start with +# passwords, then flags, or key patterns. However note that the additive +# and subtractive rules will CHANGE MEANING depending on the ordering. +# For instance see the following example: +# +# user alice on +@all -DEBUG ~* >somepassword +# +# This will allow "alice" to use all the commands with the exception of the +# DEBUG command, since +@all added all the commands to the set of the commands +# alice can use, and later DEBUG was removed. However if we invert the order +# of two ACL rules the result will be different: +# +# user alice on -DEBUG +@all ~* >somepassword +# +# Now DEBUG was removed when alice had yet no commands in the set of allowed +# commands, later all the commands are added, so the user will be able to +# execute everything. +# +# Basically ACL rules are processed left-to-right. +# +# For more information about ACL configuration please refer to +# the Redis web site at https://redis.io/topics/acl +{% if redis_auth_enabled %} +user default off +user admin on allkeys allchannels allcommands >{{ redis_user_admin_password }} +user itential on ~* &* -@all +@read +@write +@stream +@transaction +@sortedset +@list +@hash +@string +@fast +@scripting +@connection +@pubsub +script|load +script|exists -script|flush -flushall -flushdb -save -bgsave -bgrewriteaof -replicaof -psync -replconf -shutdown -failover -cluster -asking -sync -readonly -readwrite +info +role >{{ redis_user_itential_password }} +{% if redis_prometheus_user_enabled %} +user prometheus on -@all +@connection +memory -readonly +strlen +config|get +xinfo +pfcount +zcard +type +xlen -readwrite -command +client -wait +scard +llen +hlen +get +eval +slowlog +cluster|info -hello -echo +info +latency +scan -reset -auth -asking >{{ redis_user_prometheus_password }} +{% endif %} +{% if redis_is_data_node %} +{% if redis_has_replicas %} +user repluser on allchannels +psync +replconf +ping >{{ redis_user_repluser_password }} +{% endif %} +{% if redis_has_sentinels %} +user sentineluser on &* -@all +slaveof +ping +info +role +publish +subscribe +psubscribe +punsubscribe +client|setname +client|kill +multi +exec +replicaof +script|kill +config|rewrite >{{ redis_user_sentineluser_password }} +{% endif %} +{% endif %} +{% endif %} + +# ACL LOG +# +# The ACL Log tracks failed commands and authentication events associated +# with ACLs. The ACL Log is useful to troubleshoot failed commands blocked +# by ACLs. The ACL Log is stored in memory. You can reclaim memory with +# ACL LOG RESET. Define the maximum entry length of the ACL Log below. +acllog-max-len 128 + +# Using an external ACL file +# +# Instead of configuring users here in this file, it is possible to use +# a stand-alone file just listing users. The two methods cannot be mixed: +# if you configure users here and at the same time you activate the external +# ACL file, the server will refuse to start. +# +# The format of the external ACL user file is exactly the same as the +# format that is used inside redis.conf to describe users. +# +# aclfile /etc/redis/users.acl + +# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatibility +# layer on top of the new ACL system. The option effect will be just setting +# the password for the default user. Clients will still authenticate using +# AUTH as usually, or more explicitly with AUTH default +# if they follow the new protocol: both will work. +# +# The requirepass is not compatable with aclfile option and the ACL LOAD +# command, these will cause requirepass to be ignored. +# +# requirepass foobared + +# New users are initialized with restrictive permissions by default, via the +# equivalent of this ACL rule 'off resetkeys -@all'. Starting with Redis 6.2, it +# is possible to manage access to Pub/Sub channels with ACL rules as well. The +# default Pub/Sub channels permission if new users is controlled by the +# acl-pubsub-default configuration directive, which accepts one of these values: +# +# allchannels: grants access to all Pub/Sub channels +# resetchannels: revokes access to all Pub/Sub channels +# +# To ensure backward compatibility while upgrading Redis 6.0, acl-pubsub-default +# defaults to the 'allchannels' permission. +# +# Future compatibility note: it is very likely that in a future version of Redis +# the directive's default of 'allchannels' will be changed to 'resetchannels' in +# order to provide better out-of-the-box Pub/Sub security. Therefore, it is +# recommended that you explicitly define Pub/Sub permissions for all users +# rather then rely on implicit default values. Once you've set explicit +# Pub/Sub for all existing users, you should uncomment the following line. +# +# acl-pubsub-default resetchannels + +# Command renaming (DEPRECATED). +# +# ------------------------------------------------------------------------ +# WARNING: avoid using this option if possible. Instead use ACLs to remove +# commands from the default user, and put them only in some admin user you +# create for administrative purposes. +# ------------------------------------------------------------------------ +# +# It is possible to change the name of dangerous commands in a shared +# environment. For instance the CONFIG command may be renamed into something +# hard to guess so that it will still be available for internal-use tools +# but not available for general clients. +# +# Example: +# +# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 +# +# It is also possible to completely kill a command by renaming it into +# an empty string: +# +# rename-command CONFIG "" +# +# Please note that changing the name of commands that are logged into the +# AOF file or transmitted to replicas may cause problems. + +################################### CLIENTS #################################### + +# Set the max number of connected clients at the same time. By default +# this limit is set to 10000 clients, however if the Redis server is not +# able to configure the process file limit to allow for the specified limit +# the max number of allowed clients is set to the current file limit +# minus 32 (as Redis reserves a few file descriptors for internal uses). +# +# Once the limit is reached Redis will close all the new connections sending +# an error 'max number of clients reached'. +# +# IMPORTANT: When Redis Cluster is used, the max number of connections is also +# shared with the cluster bus: every node in the cluster will use two +# connections, one incoming and another outgoing. It is important to size the +# limit accordingly in case of very large clusters. +# +# maxclients 10000 + +############################## MEMORY MANAGEMENT ################################ + +# Set a memory usage limit to the specified amount of bytes. +# When the memory limit is reached Redis will try to remove keys +# according to the eviction policy selected (see maxmemory-policy). +# +# If Redis can't remove keys according to the policy, or if the policy is +# set to 'noeviction', Redis will start to reply with errors to commands +# that would use more memory, like SET, LPUSH, and so on, and will continue +# to reply to read-only commands like GET. +# +# This option is usually useful when using Redis as an LRU or LFU cache, or to +# set a hard memory limit for an instance (using the 'noeviction' policy). +# +# WARNING: If you have replicas attached to an instance with maxmemory on, +# the size of the output buffers needed to feed the replicas are subtracted +# from the used memory count, so that network problems / resyncs will +# not trigger a loop where keys are evicted, and in turn the output +# buffer of replicas is full with DELs of keys evicted triggering the deletion +# of more keys, and so forth until the database is completely emptied. +# +# In short... if you have replicas attached it is suggested that you set a lower +# limit for maxmemory so that there is some free RAM on the system for replica +# output buffers (but this is not needed if the policy is 'noeviction'). +# +# maxmemory + +# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory +# is reached. You can select one from the following behaviors: +# +# volatile-lru -> Evict using approximated LRU, only keys with an expire set. +# allkeys-lru -> Evict any key using approximated LRU. +# volatile-lfu -> Evict using approximated LFU, only keys with an expire set. +# allkeys-lfu -> Evict any key using approximated LFU. +# volatile-random -> Remove a random key having an expire set. +# allkeys-random -> Remove a random key, any key. +# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) +# noeviction -> Don't evict anything, just return an error on write operations. +# +# LRU means Least Recently Used +# LFU means Least Frequently Used +# +# Both LRU, LFU and volatile-ttl are implemented using approximated +# randomized algorithms. +# +# Note: with any of the above policies, when there are no suitable keys for +# eviction, Redis will return an error on write operations that require +# more memory. These are usually commands that create new keys, add data or +# modify existing keys. A few examples are: SET, INCR, HSET, LPUSH, SUNIONSTORE, +# SORT (due to the STORE argument), and EXEC (if the transaction includes any +# command that requires memory). +# +# The default is: +# +maxmemory-policy noeviction + +# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated +# algorithms (in order to save memory), so you can tune it for speed or +# accuracy. By default Redis will check five keys and pick the one that was +# used least recently, you can change the sample size using the following +# configuration directive. +# +# The default of 5 produces good enough results. 10 Approximates very closely +# true LRU but costs more CPU. 3 is faster but not very accurate. +# +# maxmemory-samples 5 + +# Eviction processing is designed to function well with the default setting. +# If there is an unusually large amount of write traffic, this value may need to +# be increased. Decreasing this value may reduce latency at the risk of +# eviction processing effectiveness +# 0 = minimum latency, 10 = default, 100 = process without regard to latency +# +# maxmemory-eviction-tenacity 10 + +# Starting from Redis 5, by default a replica will ignore its maxmemory setting +# (unless it is promoted to master after a failover or manually). It means +# that the eviction of keys will be just handled by the master, sending the +# DEL commands to the replica as keys evict in the master side. +# +# This behavior ensures that masters and replicas stay consistent, and is usually +# what you want, however if your replica is writable, or you want the replica +# to have a different memory setting, and you are sure all the writes performed +# to the replica are idempotent, then you may change this default (but be sure +# to understand what you are doing). +# +# Note that since the replica by default does not evict, it may end using more +# memory than the one set via maxmemory (there are certain buffers that may +# be larger on the replica, or data structures may sometimes take more memory +# and so forth). So make sure you monitor your replicas and make sure they +# have enough memory to never hit a real out-of-memory condition before the +# master hits the configured maxmemory setting. +# +# replica-ignore-maxmemory yes + +# Redis reclaims expired keys in two ways: upon access when those keys are +# found to be expired, and also in background, in what is called the +# "active expire key". The key space is slowly and interactively scanned +# looking for expired keys to reclaim, so that it is possible to free memory +# of keys that are expired and will never be accessed again in a short time. +# +# The default effort of the expire cycle will try to avoid having more than +# ten percent of expired keys still in memory, and will try to avoid consuming +# more than 25% of total memory and to add latency to the system. However +# it is possible to increase the expire "effort" that is normally set to +# "1", to a greater value, up to the value "10". At its maximum value the +# system will use more CPU, longer cycles (and technically may introduce +# more latency), and will tolerate less already expired keys still present +# in the system. It's a tradeoff between memory, CPU and latency. +# +# active-expire-effort 1 + +############################# LAZY FREEING #################################### + +# Redis has two primitives to delete keys. One is called DEL and is a blocking +# deletion of the object. It means that the server stops processing new commands +# in order to reclaim all the memory associated with an object in a synchronous +# way. If the key deleted is associated with a small object, the time needed +# in order to execute the DEL command is very small and comparable to most other +# O(1) or O(log_N) commands in Redis. However if the key is associated with an +# aggregated value containing millions of elements, the server can block for +# a long time (even seconds) in order to complete the operation. +# +# For the above reasons Redis also offers non blocking deletion primitives +# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and +# FLUSHDB commands, in order to reclaim memory in background. Those commands +# are executed in constant time. Another thread will incrementally free the +# object in the background as fast as possible. +# +# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. +# It's up to the design of the application to understand when it is a good +# idea to use one or the other. However the Redis server sometimes has to +# delete keys or flush the whole database as a side effect of other operations. +# Specifically Redis deletes objects independently of a user call in the +# following scenarios: +# +# 1) On eviction, because of the maxmemory and maxmemory policy configurations, +# in order to make room for new data, without going over the specified +# memory limit. +# 2) Because of expire: when a key with an associated time to live (see the +# EXPIRE command) must be deleted from memory. +# 3) Because of a side effect of a command that stores data on a key that may +# already exist. For example the RENAME command may delete the old key +# content when it is replaced with another one. Similarly SUNIONSTORE +# or SORT with STORE option may delete existing keys. The SET command +# itself removes any old content of the specified key in order to replace +# it with the specified string. +# 4) During replication, when a replica performs a full resynchronization with +# its master, the content of the whole database is removed in order to +# load the RDB file just transferred. +# +# In all the above cases the default is to delete objects in a blocking way, +# like if DEL was called. However you can configure each case specifically +# in order to instead release memory in a non-blocking way like if UNLINK +# was called, using the following configuration directives. + +lazyfree-lazy-eviction no +lazyfree-lazy-expire no +lazyfree-lazy-server-del no +replica-lazy-flush no + +# It is also possible, for the case when to replace the user code DEL calls +# with UNLINK calls is not easy, to modify the default behavior of the DEL +# command to act exactly like UNLINK, using the following configuration +# directive: + +lazyfree-lazy-user-del no + +# FLUSHDB, FLUSHALL, and SCRIPT FLUSH support both asynchronous and synchronous +# deletion, which can be controlled by passing the [SYNC|ASYNC] flags into the +# commands. When neither flag is passed, this directive will be used to determine +# if the data should be deleted asynchronously. + +lazyfree-lazy-user-flush no + +################################ THREADED I/O ################################# + +# Redis is mostly single threaded, however there are certain threaded +# operations such as UNLINK, slow I/O accesses and other things that are +# performed on side threads. +# +# Now it is also possible to handle Redis clients socket reads and writes +# in different I/O threads. Since especially writing is so slow, normally +# Redis users use pipelining in order to speed up the Redis performances per +# core, and spawn multiple instances in order to scale more. Using I/O +# threads it is possible to easily speedup two times Redis without resorting +# to pipelining nor sharding of the instance. +# +# By default threading is disabled, we suggest enabling it only in machines +# that have at least 4 or more cores, leaving at least one spare core. +# Using more than 8 threads is unlikely to help much. We also recommend using +# threaded I/O only if you actually have performance problems, with Redis +# instances being able to use a quite big percentage of CPU time, otherwise +# there is no point in using this feature. +# +# So for instance if you have a four cores boxes, try to use 2 or 3 I/O +# threads, if you have a 8 cores, try to use 6 threads. In order to +# enable I/O threads use the following configuration directive: +# +# io-threads 4 +# +# Setting io-threads to 1 will just use the main thread as usual. +# When I/O threads are enabled, we only use threads for writes, that is +# to thread the write(2) syscall and transfer the client buffers to the +# socket. However it is also possible to enable threading of reads and +# protocol parsing using the following configuration directive, by setting +# it to yes: +# +# io-threads-do-reads no +# +# Usually threading reads doesn't help much. +# +# NOTE 1: This configuration directive cannot be changed at runtime via +# CONFIG SET. Aso this feature currently does not work when SSL is +# enabled. +# +# NOTE 2: If you want to test the Redis speedup using redis-benchmark, make +# sure you also run the benchmark itself in threaded mode, using the +# --threads option to match the number of Redis threads, otherwise you'll not +# be able to notice the improvements. + +############################ KERNEL OOM CONTROL ############################## + +# On Linux, it is possible to hint the kernel OOM killer on what processes +# should be killed first when out of memory. +# +# Enabling this feature makes Redis actively control the oom_score_adj value +# for all its processes, depending on their role. The default scores will +# attempt to have background child processes killed before all others, and +# replicas killed before masters. +# +# Redis supports three options: +# +# no: Don't make changes to oom-score-adj (default). +# yes: Alias to "relative" see below. +# absolute: Values in oom-score-adj-values are written as is to the kernel. +# relative: Values are used relative to the initial value of oom_score_adj when +# the server starts and are then clamped to a range of -1000 to 1000. +# Because typically the initial value is 0, they will often match the +# absolute values. +oom-score-adj no + +# When oom-score-adj is used, this directive controls the specific values used +# for master, replica and background child processes. Values range -2000 to +# 2000 (higher means more likely to be killed). +# +# Unprivileged processes (not root, and without CAP_SYS_RESOURCE capabilities) +# can freely increase their value, but not decrease it below its initial +# settings. This means that setting oom-score-adj to "relative" and setting the +# oom-score-adj-values to positive values will always succeed. +oom-score-adj-values 0 200 800 + + +#################### KERNEL transparent hugepage CONTROL ###################### + +# Usually the kernel Transparent Huge Pages control is set to "madvise" or +# or "never" by default (/sys/kernel/mm/transparent_hugepage/enabled), in which +# case this config has no effect. On systems in which it is set to "always", +# redis will attempt to disable it specifically for the redis process in order +# to avoid latency problems specifically with fork(2) and CoW. +# If for some reason you prefer to keep it enabled, you can set this config to +# "no" and the kernel global to "always". + +disable-thp yes + +############################## APPEND ONLY MODE ############################### + +# By default Redis asynchronously dumps the dataset on disk. This mode is +# good enough in many applications, but an issue with the Redis process or +# a power outage may result into a few minutes of writes lost (depending on +# the configured save points). +# +# The Append Only File is an alternative persistence mode that provides +# much better durability. For instance using the default data fsync policy +# (see later in the config file) Redis can lose just one second of writes in a +# dramatic event like a server power outage, or a single write if something +# wrong with the Redis process itself happens, but the operating system is +# still running correctly. +# +# AOF and RDB persistence can be enabled at the same time without problems. +# If the AOF is enabled on startup Redis will load the AOF, that is the file +# with the better durability guarantees. +# +# Please check https://redis.io/topics/persistence for more information. + +appendonly yes + +# The name of the append only file (default: "appendonly.aof") + +appendfilename "appendonly.aof" + +# The fsync() call tells the Operating System to actually write data on disk +# instead of waiting for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log. Slow, Safest. +# everysec: fsync only one time every second. Compromise. +# +# The default is "everysec", as that's usually the right compromise between +# speed and data safety. It's up to you to understand if you can relax this to +# "no" that will let the operating system flush the output buffer when +# it wants, for better performances (but if you can live with the idea of +# some data loss consider the default persistence mode that's snapshotting), +# or on the contrary, use "always" that's very slow but a bit safer than +# everysec. +# +# More details please check the following article: +# http://antirez.com/post/redis-persistence-demystified.html +# +# If unsure, use "everysec". + +# appendfsync always +appendfsync everysec +# appendfsync no + +# When the AOF fsync policy is set to always or everysec, and a background +# saving process (a background save or AOF log background rewriting) is +# performing a lot of I/O against the disk, in some Linux configurations +# Redis may block too long on the fsync() call. Note that there is no fix for +# this currently, as even performing fsync in a different thread will block +# our synchronous write(2) call. +# +# In order to mitigate this problem it's possible to use the following option +# that will prevent fsync() from being called in the main process while a +# BGSAVE or BGREWRITEAOF is in progress. +# +# This means that while another child is saving, the durability of Redis is +# the same as "appendfsync none". In practical terms, this means that it is +# possible to lose up to 30 seconds of log in the worst scenario (with the +# default Linux settings). +# +# If you have latency problems turn this to "yes". Otherwise leave it as +# "no" that is the safest pick from the point of view of durability. + +no-appendfsync-on-rewrite yes + +# Automatic rewrite of the append only file. +# Redis is able to automatically rewrite the log file implicitly calling +# BGREWRITEAOF when the AOF log size grows by the specified percentage. +# +# This is how it works: Redis remembers the size of the AOF file after the +# latest rewrite (if no rewrite has happened since the restart, the size of +# the AOF at startup is used). +# +# This base size is compared to the current size. If the current size is +# bigger than the specified percentage, the rewrite is triggered. Also +# you need to specify a minimal size for the AOF file to be rewritten, this +# is useful to avoid rewriting the AOF file even if the percentage increase +# is reached but it is still pretty small. +# +# Specify a percentage of zero in order to disable the automatic AOF +# rewrite feature. + +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# An AOF file may be found to be truncated at the end during the Redis +# startup process, when the AOF data gets loaded back into memory. +# This may happen when the system where Redis is running +# crashes, especially when an ext4 filesystem is mounted without the +# data=ordered option (however this can't happen when Redis itself +# crashes or aborts but the operating system still works correctly). +# +# Redis can either exit with an error when this happens, or load as much +# data as possible (the default now) and start if the AOF file is found +# to be truncated at the end. The following option controls this behavior. +# +# If aof-load-truncated is set to yes, a truncated AOF file is loaded and +# the Redis server starts emitting a log to inform the user of the event. +# Otherwise if the option is set to no, the server aborts with an error +# and refuses to start. When the option is set to no, the user requires +# to fix the AOF file using the "redis-check-aof" utility before to restart +# the server. +# +# Note that if the AOF file will be found to be corrupted in the middle +# the server will still exit with an error. This option only applies when +# Redis will try to read more data from the AOF file but not enough bytes +# will be found. +aof-load-truncated yes + +# When rewriting the AOF file, Redis is able to use an RDB preamble in the +# AOF file for faster rewrites and recoveries. When this option is turned +# on the rewritten AOF file is composed of two different stanzas: +# +# [RDB file][AOF tail] +# +# When loading, Redis recognizes that the AOF file starts with the "REDIS" +# string and loads the prefixed RDB file, then continues loading the AOF +# tail. +aof-use-rdb-preamble yes + +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# +# If the maximum execution time is reached Redis will log that a script is +# still in execution after the maximum allowed time and will start to +# reply to queries with an error. +# +# When a long running script exceeds the maximum execution time only the +# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be +# used to stop a script that did not yet call any write commands. The second +# is the only way to shut down the server in the case a write command was +# already issued by the script but the user doesn't want to wait for the natural +# termination of the script. +# +# Set it to 0 or a negative value for unlimited execution without warnings. +lua-time-limit 5000 + +################################ REDIS CLUSTER ############################### + +# Normal Redis instances can't be part of a Redis Cluster; only nodes that are +# started as cluster nodes can. In order to start a Redis instance as a +# cluster node enable the cluster support uncommenting the following: +# +# cluster-enabled yes + +# Every cluster node has a cluster configuration file. This file is not +# intended to be edited by hand. It is created and updated by Redis nodes. +# Every Redis Cluster node requires a different cluster configuration file. +# Make sure that instances running in the same system do not have +# overlapping cluster configuration file names. +# +# cluster-config-file nodes-6379.conf + +# Cluster node timeout is the amount of milliseconds a node must be unreachable +# for it to be considered in failure state. +# Most other internal time limits are a multiple of the node timeout. +# +# cluster-node-timeout 15000 + +# A replica of a failing master will avoid to start a failover if its data +# looks too old. +# +# There is no simple way for a replica to actually have an exact measure of +# its "data age", so the following two checks are performed: +# +# 1) If there are multiple replicas able to failover, they exchange messages +# in order to try to give an advantage to the replica with the best +# replication offset (more data from the master processed). +# Replicas will try to get their rank by offset, and apply to the start +# of the failover a delay proportional to their rank. +# +# 2) Every single replica computes the time of the last interaction with +# its master. This can be the last ping or command received (if the master +# is still in the "connected" state), or the time that elapsed since the +# disconnection with the master (if the replication link is currently down). +# If the last interaction is too old, the replica will not try to failover +# at all. +# +# The point "2" can be tuned by user. Specifically a replica will not perform +# the failover if, since the last interaction with the master, the time +# elapsed is greater than: +# +# (node-timeout * cluster-replica-validity-factor) + repl-ping-replica-period +# +# So for example if node-timeout is 30 seconds, and the cluster-replica-validity-factor +# is 10, and assuming a default repl-ping-replica-period of 10 seconds, the +# replica will not try to failover if it was not able to talk with the master +# for longer than 310 seconds. +# +# A large cluster-replica-validity-factor may allow replicas with too old data to failover +# a master, while a too small value may prevent the cluster from being able to +# elect a replica at all. +# +# For maximum availability, it is possible to set the cluster-replica-validity-factor +# to a value of 0, which means, that replicas will always try to failover the +# master regardless of the last time they interacted with the master. +# (However they'll always try to apply a delay proportional to their +# offset rank). +# +# Zero is the only value able to guarantee that when all the partitions heal +# the cluster will always be able to continue. +# +# cluster-replica-validity-factor 10 + +# Cluster replicas are able to migrate to orphaned masters, that are masters +# that are left without working replicas. This improves the cluster ability +# to resist to failures as otherwise an orphaned master can't be failed over +# in case of failure if it has no working replicas. +# +# Replicas migrate to orphaned masters only if there are still at least a +# given number of other working replicas for their old master. This number +# is the "migration barrier". A migration barrier of 1 means that a replica +# will migrate only if there is at least 1 other working replica for its master +# and so forth. It usually reflects the number of replicas you want for every +# master in your cluster. +# +# Default is 1 (replicas migrate only if their masters remain with at least +# one replica). To disable migration just set it to a very large value or +# set cluster-allow-replica-migration to 'no'. +# A value of 0 can be set but is useful only for debugging and dangerous +# in production. +# +# cluster-migration-barrier 1 + +# Turning off this option allows to use less automatic cluster configuration. +# It both disables migration to orphaned masters and migration from masters +# that became empty. +# +# Default is 'yes' (allow automatic migrations). +# +# cluster-allow-replica-migration yes + +# By default Redis Cluster nodes stop accepting queries if they detect there +# is at least a hash slot uncovered (no available node is serving it). +# This way if the cluster is partially down (for example a range of hash slots +# are no longer covered) all the cluster becomes, eventually, unavailable. +# It automatically returns available as soon as all the slots are covered again. +# +# However sometimes you want the subset of the cluster which is working, +# to continue to accept queries for the part of the key space that is still +# covered. In order to do so, just set the cluster-require-full-coverage +# option to no. +# +# cluster-require-full-coverage yes + +# This option, when set to yes, prevents replicas from trying to failover its +# master during master failures. However the replica can still perform a +# manual failover, if forced to do so. +# +# This is useful in different scenarios, especially in the case of multiple +# data center operations, where we want one side to never be promoted if not +# in the case of a total DC failure. +# +# cluster-replica-no-failover no + +# This option, when set to yes, allows nodes to serve read traffic while the +# the cluster is in a down state, as long as it believes it owns the slots. +# +# This is useful for two cases. The first case is for when an application +# doesn't require consistency of data during node failures or network partitions. +# One example of this is a cache, where as long as the node has the data it +# should be able to serve it. +# +# The second use case is for configurations that don't meet the recommended +# three shards but want to enable cluster mode and scale later. A +# master outage in a 1 or 2 shard configuration causes a read/write outage to the +# entire cluster without this option set, with it set there is only a write outage. +# Without a quorum of masters, slot ownership will not change automatically. +# +# cluster-allow-reads-when-down no + +# In order to setup your cluster make sure to read the documentation +# available at https://redis.io web site. + +########################## CLUSTER DOCKER/NAT support ######################## + +# In certain deployments, Redis Cluster nodes address discovery fails, because +# addresses are NAT-ted or because ports are forwarded (the typical case is +# Docker and other containers). +# +# In order to make Redis Cluster working in such environments, a static +# configuration where each node knows its public address is needed. The +# following four options are used for this scope, and are: +# +# * cluster-announce-ip +# * cluster-announce-port +# * cluster-announce-tls-port +# * cluster-announce-bus-port +# +# Each instructs the node about its address, client ports (for connections +# without and with TLS) and cluster message bus port. The information is then +# published in the header of the bus packets so that other nodes will be able to +# correctly map the address of the node publishing the information. +# +# If cluster-tls is set to yes and cluster-announce-tls-port is omitted or set +# to zero, then cluster-announce-port refers to the TLS port. Note also that +# cluster-announce-tls-port has no effect if cluster-tls is set to no. +# +# If the above options are not used, the normal Redis Cluster auto-detection +# will be used instead. +# +# Note that when remapped, the bus port may not be at the fixed offset of +# clients port + 10000, so you can specify any port and bus-port depending +# on how they get remapped. If the bus-port is not set, a fixed offset of +# 10000 will be used as usual. +# +# Example: +# +# cluster-announce-ip 10.1.1.5 +# cluster-announce-tls-port 6379 +# cluster-announce-port 0 +# cluster-announce-bus-port 6380 + +################################## SLOW LOG ################################### + +# The Redis Slow Log is a system to log queries that exceeded a specified +# execution time. The execution time does not include the I/O operations +# like talking with the client, sending the reply and so forth, +# but just the time needed to actually execute the command (this is the only +# stage of command execution where the thread is blocked and can not serve +# other requests in the meantime). +# +# You can configure the slow log with two parameters: one tells Redis +# what is the execution time, in microseconds, to exceed in order for the +# command to get logged, and the other parameter is the length of the +# slow log. When a new command is logged the oldest one is removed from the +# queue of logged commands. + +# The following time is expressed in microseconds, so 1000000 is equivalent +# to one second. Note that a negative number disables the slow log, while +# a value of zero forces the logging of every command. +slowlog-log-slower-than 10000 + +# There is no limit to this length. Just be aware that it will consume memory. +# You can reclaim memory used by the slow log with SLOWLOG RESET. +slowlog-max-len 128 + +################################ LATENCY MONITOR ############################## + +# The Redis latency monitoring subsystem samples different operations +# at runtime in order to collect data related to possible sources of +# latency of a Redis instance. +# +# Via the LATENCY command this information is available to the user that can +# print graphs and obtain reports. +# +# The system only logs operations that were performed in a time equal or +# greater than the amount of milliseconds specified via the +# latency-monitor-threshold configuration directive. When its value is set +# to zero, the latency monitor is turned off. +# +# By default latency monitoring is disabled since it is mostly not needed +# if you don't have latency issues, and collecting data has a performance +# impact, that while very small, can be measured under big load. Latency +# monitoring can easily be enabled at runtime using the command +# "CONFIG SET latency-monitor-threshold " if needed. +latency-monitor-threshold 0 + +############################# EVENT NOTIFICATION ############################## + +# Redis can notify Pub/Sub clients about events happening in the key space. +# This feature is documented at https://redis.io/topics/notifications +# +# For instance if keyspace events notification is enabled, and a client +# performs a DEL operation on key "foo" stored in the Database 0, two +# messages will be published via Pub/Sub: +# +# PUBLISH __keyspace@0__:foo del +# PUBLISH __keyevent@0__:del foo +# +# It is possible to select the events that Redis will notify among a set +# of classes. Every class is identified by a single character: +# +# K Keyspace events, published with __keyspace@__ prefix. +# E Keyevent events, published with __keyevent@__ prefix. +# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... +# $ String commands +# l List commands +# s Set commands +# h Hash commands +# z Sorted set commands +# x Expired events (events generated every time a key expires) +# e Evicted events (events generated when a key is evicted for maxmemory) +# t Stream commands +# d Module key type events +# m Key-miss events (Note: It is not included in the 'A' class) +# A Alias for g$lshzxetd, so that the "AKE" string means all the events +# (Except key-miss events which are excluded from 'A' due to their +# unique nature). +# +# The "notify-keyspace-events" takes as argument a string that is composed +# of zero or multiple characters. The empty string means that notifications +# are disabled. +# +# Example: to enable list and generic events, from the point of view of the +# event name, use: +# +# notify-keyspace-events Elg +# +# Example 2: to get the stream of the expired keys subscribing to channel +# name __keyevent@0__:expired use: +# +# notify-keyspace-events Ex +# +# By default all notifications are disabled because most users don't need +# this feature and the feature has some overhead. Note that if you don't +# specify at least one of K or E, no events will be delivered. +notify-keyspace-events "" + +############################### GOPHER SERVER ################################# + +# Redis contains an implementation of the Gopher protocol, as specified in +# the RFC 1436 (https://www.ietf.org/rfc/rfc1436.txt). +# +# The Gopher protocol was very popular in the late '90s. It is an alternative +# to the web, and the implementation both server and client side is so simple +# that the Redis server has just 100 lines of code in order to implement this +# support. +# +# What do you do with Gopher nowadays? Well Gopher never *really* died, and +# lately there is a movement in order for the Gopher more hierarchical content +# composed of just plain text documents to be resurrected. Some want a simpler +# internet, others believe that the mainstream internet became too much +# controlled, and it's cool to create an alternative space for people that +# want a bit of fresh air. +# +# Anyway for the 10nth birthday of the Redis, we gave it the Gopher protocol +# as a gift. +# +# --- HOW IT WORKS? --- +# +# The Redis Gopher support uses the inline protocol of Redis, and specifically +# two kind of inline requests that were anyway illegal: an empty request +# or any request that starts with "/" (there are no Redis commands starting +# with such a slash). Normal RESP2/RESP3 requests are completely out of the +# path of the Gopher protocol implementation and are served as usual as well. +# +# If you open a connection to Redis when Gopher is enabled and send it +# a string like "/foo", if there is a key named "/foo" it is served via the +# Gopher protocol. +# +# In order to create a real Gopher "hole" (the name of a Gopher site in Gopher +# talking), you likely need a script like the following: +# +# https://github.com/antirez/gopher2redis +# +# --- SECURITY WARNING --- +# +# If you plan to put Redis on the internet in a publicly accessible address +# to server Gopher pages MAKE SURE TO SET A PASSWORD to the instance. +# Once a password is set: +# +# 1. The Gopher server (when enabled, not by default) will still serve +# content via Gopher. +# 2. However other commands cannot be called before the client will +# authenticate. +# +# So use the 'requirepass' option to protect your instance. +# +# Note that Gopher is not currently supported when 'io-threads-do-reads' +# is enabled. +# +# To enable Gopher support, uncomment the following line and set the option +# from no (the default) to yes. +# +# gopher-enabled no + +############################### ADVANCED CONFIG ############################### + +# Hashes are encoded using a memory efficient data structure when they have a +# small number of entries, and the biggest entry does not exceed a given +# threshold. These thresholds can be configured using the following directives. +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 + +# Lists are also encoded in a special way to save a lot of space. +# The number of entries allowed per internal list node can be specified +# as a fixed maximum size or a maximum number of elements. +# For a fixed maximum size, use -5 through -1, meaning: +# -5: max size: 64 Kb <-- not recommended for normal workloads +# -4: max size: 32 Kb <-- not recommended +# -3: max size: 16 Kb <-- probably not recommended +# -2: max size: 8 Kb <-- good +# -1: max size: 4 Kb <-- good +# Positive numbers mean store up to _exactly_ that number of elements +# per list node. +# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), +# but if your use case is unique, adjust the settings as necessary. +list-max-ziplist-size -2 + +# Lists may also be compressed. +# Compress depth is the number of quicklist ziplist nodes from *each* side of +# the list to *exclude* from compression. The head and tail of the list +# are always uncompressed for fast push/pop operations. Settings are: +# 0: disable all list compression +# 1: depth 1 means "don't start compressing until after 1 node into the list, +# going from either the head or tail" +# So: [head]->node->node->...->node->[tail] +# [head], [tail] will always be uncompressed; inner nodes will compress. +# 2: [head]->[next]->node->node->...->node->[prev]->[tail] +# 2 here means: don't compress head or head->next or tail->prev or tail, +# but compress all nodes between them. +# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] +# etc. +list-compress-depth 0 + +# Sets have a special encoding in just one case: when a set is composed +# of just strings that happen to be integers in radix 10 in the range +# of 64 bit signed integers. +# The following configuration setting sets the limit in the size of the +# set in order to use this special memory saving encoding. +set-max-intset-entries 512 + +# Similarly to hashes and lists, sorted sets are also specially encoded in +# order to save a lot of space. This encoding is only used when the length and +# elements of a sorted set are below the following limits: +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 + +# HyperLogLog sparse representation bytes limit. The limit includes the +# 16 bytes header. When an HyperLogLog using the sparse representation crosses +# this limit, it is converted into the dense representation. +# +# A value greater than 16000 is totally useless, since at that point the +# dense representation is more memory efficient. +# +# The suggested value is ~ 3000 in order to have the benefits of +# the space efficient encoding without slowing down too much PFADD, +# which is O(N) with the sparse encoding. The value can be raised to +# ~ 10000 when CPU is not a concern, but space is, and the data set is +# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. +hll-sparse-max-bytes 3000 + +# Streams macro node max size / items. The stream data structure is a radix +# tree of big nodes that encode multiple items inside. Using this configuration +# it is possible to configure how big a single node can be in bytes, and the +# maximum number of items it may contain before switching to a new node when +# appending new stream entries. If any of the following settings are set to +# zero, the limit is ignored, so for instance it is possible to set just a +# max entries limit by setting max-bytes to 0 and max-entries to the desired +# value. +stream-node-max-bytes 4096 +stream-node-max-entries 100 + +# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in +# order to help rehashing the main Redis hash table (the one mapping top-level +# keys to values). The hash table implementation Redis uses (see dict.c) +# performs a lazy rehashing: the more operation you run into a hash table +# that is rehashing, the more rehashing "steps" are performed, so if the +# server is idle the rehashing is never complete and some more memory is used +# by the hash table. +# +# The default is to use this millisecond 10 times every second in order to +# actively rehash the main dictionaries, freeing memory when possible. +# +# If unsure: +# use "activerehashing no" if you have hard latency requirements and it is +# not a good thing in your environment that Redis can reply from time to time +# to queries with 2 milliseconds delay. +# +# use "activerehashing yes" if you don't have such hard requirements but +# want to free memory asap when possible. +activerehashing yes + +# The client output buffer limits can be used to force disconnection of clients +# that are not reading data from the server fast enough for some reason (a +# common reason is that a Pub/Sub client can't consume messages as fast as the +# publisher can produce them). +# +# The limit can be set differently for the three different classes of clients: +# +# normal -> normal clients including MONITOR clients +# replica -> replica clients +# pubsub -> clients subscribed to at least one pubsub channel or pattern +# +# The syntax of every client-output-buffer-limit directive is the following: +# +# client-output-buffer-limit +# +# A client is immediately disconnected once the hard limit is reached, or if +# the soft limit is reached and remains reached for the specified number of +# seconds (continuously). +# So for instance if the hard limit is 32 megabytes and the soft limit is +# 16 megabytes / 10 seconds, the client will get disconnected immediately +# if the size of the output buffers reach 32 megabytes, but will also get +# disconnected if the client reaches 16 megabytes and continuously overcomes +# the limit for 10 seconds. +# +# By default normal clients are not limited because they don't receive data +# without asking (in a push way), but just after a request, so only +# asynchronous clients may create a scenario where data is requested faster +# than it can read. +# +# Instead there is a default limit for pubsub and replica clients, since +# subscribers and replicas receive data in a push fashion. +# +# Both the hard or the soft limit can be disabled by setting them to zero. +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit replica 512mb 128mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 + +# Client query buffers accumulate new commands. They are limited to a fixed +# amount by default in order to avoid that a protocol desynchronization (for +# instance due to a bug in the client) will lead to unbound memory usage in +# the query buffer. However you can configure it here if you have very special +# needs, such us huge multi/exec requests or alike. +# +# client-query-buffer-limit 1gb + +# In the Redis protocol, bulk requests, that are, elements representing single +# strings, are normally limited to 512 mb. However you can change this limit +# here, but must be 1mb or greater +# +# proto-max-bulk-len 512mb + +# Redis calls an internal function to perform many background tasks, like +# closing connections of clients in timeout, purging expired keys that are +# never requested, and so forth. +# +# Not all tasks are performed with the same frequency, but Redis checks for +# tasks to perform according to the specified "hz" value. +# +# By default "hz" is set to 10. Raising the value will use more CPU when +# Redis is idle, but at the same time will make Redis more responsive when +# there are many keys expiring at the same time, and timeouts may be +# handled with more precision. +# +# The range is between 1 and 500, however a value over 100 is usually not +# a good idea. Most users should use the default of 10 and raise this up to +# 100 only in environments where very low latency is required. +hz 10 + +# Normally it is useful to have an HZ value which is proportional to the +# number of clients connected. This is useful in order, for instance, to +# avoid too many clients are processed for each background task invocation +# in order to avoid latency spikes. +# +# Since the default HZ value by default is conservatively set to 10, Redis +# offers, and enables by default, the ability to use an adaptive HZ value +# which will temporarily raise when there are many connected clients. +# +# When dynamic HZ is enabled, the actual configured HZ will be used +# as a baseline, but multiples of the configured HZ value will be actually +# used as needed once more clients are connected. In this way an idle +# instance will use very little CPU time while a busy instance will be +# more responsive. +dynamic-hz yes + +# When a child rewrites the AOF file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +aof-rewrite-incremental-fsync yes + +# When redis saves RDB file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +rdb-save-incremental-fsync yes + +# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good +# idea to start with the default settings and only change them after investigating +# how to improve the performances and how the keys LFU change over time, which +# is possible to inspect via the OBJECT FREQ command. +# +# There are two tunable parameters in the Redis LFU implementation: the +# counter logarithm factor and the counter decay time. It is important to +# understand what the two parameters mean before changing them. +# +# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis +# uses a probabilistic increment with logarithmic behavior. Given the value +# of the old counter, when a key is accessed, the counter is incremented in +# this way: +# +# 1. A random number R between 0 and 1 is extracted. +# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). +# 3. The counter is incremented only if R < P. +# +# The default lfu-log-factor is 10. This is a table of how the frequency +# counter changes with a different number of accesses with different +# logarithmic factors: +# +# +--------+------------+------------+------------+------------+------------+ +# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | +# +--------+------------+------------+------------+------------+------------+ +# | 0 | 104 | 255 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 1 | 18 | 49 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 10 | 10 | 18 | 142 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 100 | 8 | 11 | 49 | 143 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# +# NOTE: The above table was obtained by running the following commands: +# +# redis-benchmark -n 1000000 incr foo +# redis-cli object freq foo +# +# NOTE 2: The counter initial value is 5 in order to give new objects a chance +# to accumulate hits. +# +# The counter decay time is the time, in minutes, that must elapse in order +# for the key counter to be divided by two (or decremented if it has a value +# less <= 10). +# +# The default value for the lfu-decay-time is 1. A special value of 0 means to +# decay the counter every time it happens to be scanned. +# +# lfu-log-factor 10 +# lfu-decay-time 1 + +########################### ACTIVE DEFRAGMENTATION ####################### +# +# What is active defragmentation? +# ------------------------------- +# +# Active (online) defragmentation allows a Redis server to compact the +# spaces left between small allocations and deallocations of data in memory, +# thus allowing to reclaim back memory. +# +# Fragmentation is a natural process that happens with every allocator (but +# less so with Jemalloc, fortunately) and certain workloads. Normally a server +# restart is needed in order to lower the fragmentation, or at least to flush +# away all the data and create it again. However thanks to this feature +# implemented by Oran Agra for Redis 4.0 this process can happen at runtime +# in a "hot" way, while the server is running. +# +# Basically when the fragmentation is over a certain level (see the +# configuration options below) Redis will start to create new copies of the +# values in contiguous memory regions by exploiting certain specific Jemalloc +# features (in order to understand if an allocation is causing fragmentation +# and to allocate it in a better place), and at the same time, will release the +# old copies of the data. This process, repeated incrementally for all the keys +# will cause the fragmentation to drop back to normal values. +# +# Important things to understand: +# +# 1. This feature is disabled by default, and only works if you compiled Redis +# to use the copy of Jemalloc we ship with the source code of Redis. +# This is the default with Linux builds. +# +# 2. You never need to enable this feature if you don't have fragmentation +# issues. +# +# 3. Once you experience fragmentation, you can enable this feature when +# needed with the command "CONFIG SET activedefrag yes". +# +# The configuration parameters are able to fine tune the behavior of the +# defragmentation process. If you are not sure about what they mean it is +# a good idea to leave the defaults untouched. + +# Enabled active defragmentation +# activedefrag no + +# Minimum amount of fragmentation waste to start active defrag +# active-defrag-ignore-bytes 100mb + +# Minimum percentage of fragmentation to start active defrag +# active-defrag-threshold-lower 10 + +# Maximum percentage of fragmentation at which we use maximum effort +# active-defrag-threshold-upper 100 + +# Minimal effort for defrag in CPU percentage, to be used when the lower +# threshold is reached +# active-defrag-cycle-min 1 + +# Maximal effort for defrag in CPU percentage, to be used when the upper +# threshold is reached +# active-defrag-cycle-max 25 + +# Maximum number of set/hash/zset/list fields that will be processed from +# the main dictionary scan +# active-defrag-max-scan-fields 1000 + +# Jemalloc background thread for purging will be enabled by default +jemalloc-bg-thread yes + +# It is possible to pin different threads and processes of Redis to specific +# CPUs in your system, in order to maximize the performances of the server. +# This is useful both in order to pin different Redis threads in different +# CPUs, but also in order to make sure that multiple Redis instances running +# in the same host will be pinned to different CPUs. +# +# Normally you can do this using the "taskset" command, however it is also +# possible to this via Redis configuration directly, both in Linux and FreeBSD. +# +# You can pin the server/IO threads, bio threads, aof rewrite child process, and +# the bgsave child process. The syntax to specify the cpu list is the same as +# the taskset command: +# +# Set redis server/io threads to cpu affinity 0,2,4,6: +# server_cpulist 0-7:2 +# +# Set bio threads to cpu affinity 1,3: +# bio_cpulist 1,3 +# +# Set aof rewrite child process to cpu affinity 8,9,10,11: +# aof_rewrite_cpulist 8-11 +# +# Set bgsave child process to cpu affinity 1,10,11 +# bgsave_cpulist 1,10-11 + +# In some cases redis will emit warnings and even refuse to start if it detects +# that the system is in bad state, it is possible to suppress these warnings +# by setting the following config which takes a space delimited list of warnings +# to suppress +# +# ignore-warnings ARM64-COW-BUG diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.logrotate.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.logrotate.j2 new file mode 100644 index 00000000..e7bb9fb6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.logrotate.j2 @@ -0,0 +1,35 @@ +# ----------------------------------------------------- +# This file is managed by Ansible. +# Safe to edit, but if you re-run automation, it may be overwritten. +# +# To customize retention, compression, or actions, edit below. + +{{ redis_log_dir }}/redis.log { + # How often to rotate (change to weekly/monthly if desired) + daily + + # How many rotations to keep (increase/decrease as needed) + rotate 7 + + # Enable compression for old logs (can comment to disable) + compress + delaycompress + + # Don't complain if log is missing or empty + missingok + notifempty + + # Ensure logrotate runs with the right user/group + su {{ redis_owner }} {{ redis_group }} + + # File permissions & ownership for new logs + create 0640 {{ redis_owner }} {{ redis_group }} + + # Safest for Redis: copy+truncate the active file in place + copytruncate + + # Ensures only one rotation at a time if multiple logs exist + sharedscripts + + # NOTE: Redis does NOT reopen logs on HUP. Avoid postrotate/HUP. +} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.preflight.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.preflight.j2 new file mode 100644 index 00000000..ea154acd --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.preflight.j2 @@ -0,0 +1,18 @@ +Name: {{results['name']}} +Role: Redis +Pass: {{results['pass']}} + + +SELinux | {{results['SELinux']}} +http_proxy | {{ 'Yes' if results['http_proxy'] else 'None'}} +https_proxy | {{ 'Yes' if results['https_proxy'] else 'None'}} +IPv6 | {{ 'Enabled' if results['ipv6'] else 'Disabled'}} + +CPU | {{ 'Pass' if results['cpuCores'] >= redis_cpu_cores else 'FAIL'}} | Cores: {{results['cpuCores']}} Req: {{redis_cpu_cores}} +HDD | {{ 'Pass' if results['/_sizeAvailable'] >= redis_free_disk_space else 'FAIL'}} | Free: {{results['/_sizeAvailable']}} on {{results['mount']}} Req: {{redis_free_disk_space}} +Memory | {{ 'Pass' if results['memory'] >= redis_ram else 'FAIL'}} | Free: {{results['memory']}} Req: {{redis_ram}} + +URL | Status +{% for key, value in results['url_status'].items() %} +{{key}} | {{value}} +{% endfor %} \ No newline at end of file diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.service.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.service.j2 new file mode 100644 index 00000000..7d33767a --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/redis.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Redis persistent key-value database +After=network.target +After=network-online.target +Wants=network-online.target + +[Service] +ExecStart={{redis_bin_dir }}/redis-server {{ redis_conf_file }} --daemonize no --supervised systemd +Type=notify +User={{ redis_owner }} +Group={{ redis_group }} +RuntimeDirectory=redis +RuntimeDirectoryMode=0755 + +[Install] +WantedBy=multi-user.target diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/sentinel.conf.j2 b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/sentinel.conf.j2 new file mode 100644 index 00000000..22d97cb6 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/templates/sentinel.conf.j2 @@ -0,0 +1,355 @@ +# Example sentinel.conf + +# *** IMPORTANT *** +# +# By default Sentinel will not be reachable from interfaces different than +# localhost, either use the 'bind' directive to bind to a list of network +# interfaces, or disable protected mode with "protected-mode no" by +# adding it to this configuration file. +# +# Before doing that MAKE SURE the instance is protected from the outside +# world via firewalling or other means. +# +# For example you may use one of the following: +# +bind {{ redis_sentinel_bind }} +# +# protected-mode no + +# port +# The port that this sentinel instance will run on +port {{ redis_sentinel_port }} + +# By default Redis Sentinel does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis-sentinel.pid when +# daemonized. +daemonize no + +# When running daemonized, Redis Sentinel writes a pid file in +# /var/run/redis-sentinel.pid by default. You can specify a custom pid file +# location here. +# pidfile /var/run/redis-sentinel.pid + +# Specify the log file name. Also the empty string can be used to force +# Sentinel to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile {{ redis_log_dir }}/sentinel.log + +# +# The above two configuration directives are useful in environments where, +# because of NAT, Sentinel is reachable from outside via a non-local address. +# +# When announce-ip is provided, the Sentinel will claim the specified IP address +# in HELLO messages used to gossip its presence, instead of auto-detecting the +# local address as it usually does. +# +# Similarly when announce-port is provided and is valid and non-zero, Sentinel +# will announce the specified TCP port. +# +# The two options don't need to be used together, if only announce-ip is +# provided, the Sentinel will announce the specified IP and the server port +# as specified by the "port" option. If only announce-port is provided, the +# Sentinel will announce the auto-detected local IP and the specified port. +# +# Example: +# +# sentinel announce-ip 1.2.3.4 +sentinel announce-ip {{ inventory_hostname }} +sentinel announce-port {{ redis_sentinel_port }} + +# dir +# Every long running process should have a well-defined working directory. +# For Redis Sentinel to chdir to /tmp at startup is the simplest thing +# for the process to don't interfere with administrative tasks such as +# unmounting filesystems. +dir {{ redis_data_dir }}/sentinel + +# sentinel monitor +# +# Tells Sentinel to monitor this master, and to consider it in O_DOWN +# (Objectively Down) state only if at least sentinels agree. +# +# Note that whatever is the ODOWN quorum, a Sentinel will require to +# be elected by the majority of the known Sentinels in order to +# start a failover, so no failover can be performed in minority. +# +# Replicas are auto-discovered, so you don't need to specify replicas in +# any way. Sentinel itself will rewrite this configuration file adding +# the replicas using additional configuration options. +# Also note that the configuration file is rewritten when a +# replica is promoted to master. +# +# Note: master name should not include special characters or spaces. +# The valid charset is A-z 0-9 and the three characters ".-_". +sentinel monitor {{ redis_sentinel_master_name }} {{ groups['redis_master'][0] }} {{ redis_port }} {{ redis_sentinel_quorum_final }} + +# sentinel auth-pass +# +# Set the password to use to authenticate with the master and replicas. +# Useful if there is a password set in the Redis instances to monitor. +# +# Note that the master password is also used for replicas, so it is not +# possible to set a different password in masters and replicas instances +# if you want to be able to monitor these instances with Sentinel. +# +# However you can have Redis instances without the authentication enabled +# mixed with Redis instances requiring the authentication (as long as the +# password set is the same for all the instances requiring the password) as +# the AUTH command will have no effect in Redis instances with authentication +# switched off. +# +# Example: +# +# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd +{% if redis_auth_enabled %} +sentinel auth-pass {{ redis_sentinel_master_name }} {{ redis_user_sentineluser_password }} +{% endif %} + +# sentinel auth-user +# +# This is useful in order to authenticate to instances having ACL capabilities, +# that is, running Redis 6.0 or greater. When just auth-pass is provided the +# Sentinel instance will authenticate to Redis using the old "AUTH " +# method. When also an username is provided, it will use "AUTH ". +# In the Redis servers side, the ACL to provide just minimal access to +# Sentinel instances, should be configured along the following lines: +# +# user sentinel-user >somepassword +client +subscribe +publish \ +# +ping +info +multi +slaveof +config +client +exec on +{% if redis_auth_enabled %} +sentinel auth-user {{ redis_sentinel_master_name }} sentineluser + +user default off +user admin on >{{ redis_user_sentineladmin_password }} ~* &* +@all +user sentineluser on >{{ redis_user_sentineluser_password }} &* -@all +auth +client|getname +client|id +client|setname +command +hello +ping +role +sentinel|is-master-down-by-addr +sentinel|get-master-addr-by-name +sentinel|master +sentinel|myid +sentinel|replicas +sentinel|sentinels +{% endif %} + +# sentinel down-after-milliseconds +# +# Number of milliseconds the master (or any attached replica or sentinel) should +# be unreachable (as in, not acceptable reply to PING, continuously, for the +# specified period) in order to consider it in S_DOWN state (Subjectively +# Down). +# +# Default is 30 seconds. +sentinel down-after-milliseconds {{ redis_sentinel_master_name }} 5000 + +# IMPORTANT NOTE: starting with Redis 6.2 ACL capability is supported for +# Sentinel mode, please refer to the Redis website https://redis.io/topics/acl +# for more details. + +# Sentinel's ACL users are defined in the following format: +# +# user ... acl rules ... +# +# For example: +# +# user worker +@admin +@connection ~* on >ffa9203c493aa99 +# +# For more information about ACL configuration please refer to the Redis +# website at https://redis.io/topics/acl and redis server configuration +# template redis.conf. + +# ACL LOG +# +# The ACL Log tracks failed commands and authentication events associated +# with ACLs. The ACL Log is useful to troubleshoot failed commands blocked +# by ACLs. The ACL Log is stored in memory. You can reclaim memory with +# ACL LOG RESET. Define the maximum entry length of the ACL Log below. +acllog-max-len 128 + +# Using an external ACL file +# +# Instead of configuring users here in this file, it is possible to use +# a stand-alone file just listing users. The two methods cannot be mixed: +# if you configure users here and at the same time you activate the external +# ACL file, the server will refuse to start. +# +# The format of the external ACL user file is exactly the same as the +# format that is used inside redis.conf to describe users. +# +# aclfile /etc/redis/sentinel-users.acl + +# requirepass +# +# You can configure Sentinel itself to require a password, however when doing +# so Sentinel will try to authenticate with the same password to all the +# other Sentinels. So you need to configure all your Sentinels in a given +# group with the same "requirepass" password. Check the following documentation +# for more info: https://redis.io/topics/sentinel +# +# IMPORTANT NOTE: starting with Redis 6.2 "requirepass" is a compatibility +# layer on top of the ACL system. The option effect will be just setting +# the password for the default user. Clients will still authenticate using +# AUTH as usually, or more explicitly with AUTH default +# if they follow the new protocol: both will work. +# +# New config files are advised to use separate authentication control for +# incoming connections (via ACL), and for outgoing connections (via +# sentinel-user and sentinel-pass) +# +# The requirepass is not compatable with aclfile option and the ACL LOAD +# command, these will cause requirepass to be ignored. +# +# sentinel sentinel-user +# +# You can configure Sentinel to authenticate with other Sentinels with specific +# user name. +{% if redis_auth_enabled %} +sentinel sentinel-user sentineluser +sentinel sentinel-pass {{ redis_user_sentineluser_password }} +{% endif %} + +# sentinel sentinel-pass +# +# The password for Sentinel to authenticate with other Sentinels. If sentinel-user +# is not configured, Sentinel will use 'default' user with sentinel-pass to authenticate. + +# sentinel parallel-syncs +# +# How many replicas we can reconfigure to point to the new replica simultaneously +# during the failover. Use a low number if you use the replicas to serve query +# to avoid that all the replicas will be unreachable at about the same +# time while performing the synchronization with the master. +sentinel parallel-syncs {{ redis_sentinel_master_name }} 1 + +# sentinel failover-timeout +# +# Specifies the failover timeout in milliseconds. It is used in many ways: +# +# - The time needed to re-start a failover after a previous failover was +# already tried against the same master by a given Sentinel, is two +# times the failover timeout. +# +# - The time needed for a replica replicating to a wrong master according +# to a Sentinel current configuration, to be forced to replicate +# with the right master, is exactly the failover timeout (counting since +# the moment a Sentinel detected the misconfiguration). +# +# - The time needed to cancel a failover that is already in progress but +# did not produced any configuration change (SLAVEOF NO ONE yet not +# acknowledged by the promoted replica). +# +# - The maximum time a failover in progress waits for all the replicas to be +# reconfigured as replicas of the new master. However even after this time +# the replicas will be reconfigured by the Sentinels anyway, but not with +# the exact parallel-syncs progression as specified. +# +# Default is 3 minutes. +sentinel failover-timeout {{ redis_sentinel_master_name }} 60000 + +# SCRIPTS EXECUTION +# +# sentinel notification-script and sentinel reconfig-script are used in order +# to configure scripts that are called to notify the system administrator +# or to reconfigure clients after a failover. The scripts are executed +# with the following rules for error handling: +# +# If script exits with "1" the execution is retried later (up to a maximum +# number of times currently set to 10). +# +# If script exits with "2" (or an higher value) the script execution is +# not retried. +# +# If script terminates because it receives a signal the behavior is the same +# as exit code 1. +# +# A script has a maximum running time of 60 seconds. After this limit is +# reached the script is terminated with a SIGKILL and the execution retried. + +# NOTIFICATION SCRIPT +# +# sentinel notification-script +# +# Call the specified notification script for any sentinel event that is +# generated in the WARNING level (for instance -sdown, -odown, and so forth). +# This script should notify the system administrator via email, SMS, or any +# other messaging system, that there is something wrong with the monitored +# Redis systems. +# +# The script is called with just two arguments: the first is the event type +# and the second the event description. +# +# The script must exist and be executable in order for sentinel to start if +# this option is provided. +# +# Example: +# +# sentinel notification-script mymaster /var/redis/notify.sh + +# CLIENTS RECONFIGURATION SCRIPT +# +# sentinel client-reconfig-script +# +# When the master changed because of a failover a script can be called in +# order to perform application-specific tasks to notify the clients that the +# configuration has changed and the master is at a different address. +# +# The following arguments are passed to the script: +# +# +# +# is currently always "failover" +# is either "leader" or "observer" +# +# The arguments from-ip, from-port, to-ip, to-port are used to communicate +# the old address of the master and the new address of the elected replica +# (now a master). +# +# This script should be resistant to multiple invocations. +# +# Example: +# +# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh + +# SECURITY +# +# By default SENTINEL SET will not be able to change the notification-script +# and client-reconfig-script at runtime. This avoids a trivial security issue +# where clients can set the script to anything and trigger a failover in order +# to get the program executed. + +sentinel deny-scripts-reconfig yes + +# REDIS COMMANDS RENAMING +# +# Sometimes the Redis server has certain commands, that are needed for Sentinel +# to work correctly, renamed to unguessable strings. This is often the case +# of CONFIG and SLAVEOF in the context of providers that provide Redis as +# a service, and don't want the customers to reconfigure the instances outside +# of the administration console. +# +# In such case it is possible to tell Sentinel to use different command names +# instead of the normal ones. For example if the master "mymaster", and the +# associated replicas, have "CONFIG" all renamed to "GUESSME", I could use: +# +# SENTINEL rename-command mymaster CONFIG GUESSME +# +# After such configuration is set, every time Sentinel would use CONFIG it will +# use GUESSME instead. Note that there is no actual need to respect the command +# case, so writing "config guessme" is the same in the example above. +# +# SENTINEL SET can also be used in order to perform this configuration at runtime. +# +# In order to set a command back to its original name (undo the renaming), it +# is possible to just rename a command to itself: +# +# SENTINEL rename-command mymaster CONFIG CONFIG + +# HOSTNAMES SUPPORT +# +# Normally Sentinel uses only IP addresses and requires SENTINEL MONITOR +# to specify an IP address. Also, it requires the Redis replica-announce-ip +# keyword to specify only IP addresses. +# +# You may enable hostnames support by enabling resolve-hostnames. Note +# that you must make sure your DNS is configured properly and that DNS +# resolution does not introduce very long delays. +# +SENTINEL resolve-hostnames yes + +# When resolve-hostnames is enabled, Sentinel still uses IP addresses +# when exposing instances to users, configuration files, etc. If you want +# to retain the hostnames when announced, enable announce-hostnames below. +# +SENTINEL announce-hostnames yes diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/main.yml new file mode 100644 index 00000000..4ae3075f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/main.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Default directories +redis_bin_dir_default_packages: /usr/bin +redis_bin_dir_default_source: /usr/local/bin +redis_conf_dir_default: /etc/redis +redis_log_dir_default: /var/log/redis +redis_data_dir_default: /var/lib/redis + +# Default ports +redis_port_default: 6379 +redis_sentinel_port_default: 26379 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/platform-release-6.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/platform-release-6.yml new file mode 100644 index 00000000..ddfbfb0e --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/platform-release-6.yml @@ -0,0 +1,19 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# The keys represent the EL major version (ansible_distribution_major_version) + +# The redis_packages_default is used when the redis_install_from_source is set to 'false' +redis_packages_default: + "8": + - "@redis:remi-7.2" + "9": + - "@redis:remi-7.2" + "2023": + - "@redis:remi-7.2" + +# The redis_source_url_default is used when the redis_install_from_source is set to 'true' +redis_source_url_default: + "8": "https://github.com/redis/redis/archive/7.4.6.tar.gz" + "9": "https://github.com/redis/redis/archive/7.4.6.tar.gz" + "2023": "https://github.com/redis/redis/archive/7.4.6.tar.gz" diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/platform-release-undefined.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/platform-release-undefined.yml new file mode 100644 index 00000000..fd6ca840 --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/redis/vars/platform-release-undefined.yml @@ -0,0 +1,4 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +redis_invalid_platform_release: true diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/README.md b/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/README.md new file mode 100644 index 00000000..e69de29b diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/tasks/configure-context.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/tasks/configure-context.yml new file mode 100644 index 00000000..9c44386f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/tasks/configure-context.yml @@ -0,0 +1,42 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: SELinux - Validate selinux_target, selinux_setype, selinux_path are set + ansible.builtin.assert: + that: + - selinux_target is defined + - selinux_setype is defined + - selinux_path is defined + fail_msg: selinux_target, selinux_setype, selinux_path must be set + +- name: SELinux - Set fcontext on target + community.general.sefcontext: + target: "{{ selinux_target }}" + setype: "{{ selinux_setype }}" + ftype: "{{ selinux_ftype is defined | ternary(selinux_ftype, omit) }}" + +# To ensure idempotency, a restorecon with the passive check option (-n) is run first +- name: SELinux - Check security context on target directory + ansible.builtin.command: + argv: + - restorecon + - -irvFn + - "{{ selinux_path }}" + register: restorecon_check_result + changed_when: false + failed_when: + - restorecon_check_result.rc is defined + - restorecon_check_result.rc > 0 + +- name: SELinux - Apply new file context to target directory + ansible.builtin.command: + argv: + - restorecon + - -irvF + - "{{ selinux_path }}" + register: restorecon_result + changed_when: restorecon_result.rc == 0 + failed_when: + - restorecon_result.rc is defined + - restorecon_result.rc > 0 + when: restorecon_check_result.stdout_lines | length > 0 diff --git a/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/tasks/main.yml b/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/tasks/main.yml new file mode 100644 index 00000000..cbfe6f2f --- /dev/null +++ b/.ansible/collections/ansible_collections/itential/deployer/roles/selinux/tasks/main.yml @@ -0,0 +1,116 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Update SELinux + when: ansible_selinux.status == "enabled" + tags: configure_selinux + block: + - name: SELinux - Find the policy files for role on the control node + ansible.builtin.find: + paths: "{{ ansible_parent_role_paths | first }}/files/" + patterns: "*.te" + recurse: false + file_type: file + register: search_results + delegate_to: localhost + become: false + + - name: SELinux - Create the list of policy files + ansible.builtin.set_fact: + policy_files: "{{ search_results.files | map(attribute='path') }}" + + - name: SELinux - Check to see if the policy has already been installed + ansible.builtin.shell: + cmd: "set -o pipefail && semodule -l | grep {{ item | basename | splitext | first }}" + with_items: "{{ policy_files }}" + register: installed_result + changed_when: false + failed_when: false + + - name: SELinux - Create a list of policies that have already been installed + ansible.builtin.set_fact: + installed_policy_files: "{{ installed_policy_files | default([]) + [item.item] }}" + with_items: "{{ installed_result.results }}" + when: item.rc == 0 + + - name: SELinux - Remove the policies already installed from the policy list + ansible.builtin.set_fact: + policy_files: "{{ policy_files | reject('search', item) }}" + loop: "{{ installed_policy_files }}" + when: + - installed_policy_files is defined + - installed_policy_files is iterable + - installed_policy_files | length > 0 + + - name: SELinux - Install the policy files + when: + - policy_files is defined + - policy_files is iterable + - policy_files | length > 0 + block: + - name: SELinux - Create a temporary working directory + ansible.builtin.tempfile: + state: directory + register: workingdir + + - name: SELinux - Copy the custom policy files from the control node + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ workingdir.path }}/{{ item | basename }}" + mode: "0644" + loop: "{{ policy_files }}" + + - name: SELinux - Find the custom policy files on the target node + ansible.builtin.find: + paths: "{{ workingdir.path }}" + patterns: "*.te" + register: selinux_policies + + - name: SELinux - Compile the modules + ansible.builtin.command: + argv: + - checkmodule + - -M + - -m + - -o + - "{{ workingdir.path }}/{{ item.path | basename | splitext | first }}.mod" + - "{{ item.path }}" + with_items: + - "{{ selinux_policies.files }}" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 + + - name: SELinux - Find the compiled modules on the target node + ansible.builtin.find: + paths: "{{ workingdir.path }}" + patterns: "*.mod" + register: compiled_modules + + - name: SELinux - Package the modules + ansible.builtin.command: + argv: + - semodule_package + - -o + - "{{ workingdir.path }}/{{ item.path | basename | splitext | first }}.pp" + - -m + - "{{ item.path }}" + with_items: + - "{{ compiled_modules.files }}" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 + + - name: SELinux - Install the modules + ansible.builtin.shell: semodule -i *.pp + args: + executable: /bin/bash + chdir: "{{ workingdir.path }}" + register: result + changed_when: result.rc == 0 + failed_when: result.rc > 0 + + - name: SELinux - Remove the temporary working directory + ansible.builtin.file: + path: "{{ workingdir.path }}" + state: absent diff --git a/docs/itential_gateway_guide.md b/docs/itential_gateway_guide.md index 22a587ae..d601d045 100644 --- a/docs/itential_gateway_guide.md +++ b/docs/itential_gateway_guide.md @@ -57,16 +57,36 @@ The following table lists the default variables located in `roles/gateway/defaul | `gateway_https` | Boolean | Flag to enable HTTPS. | `false` | | `gateway_https_port` | Integer | The IAG HTTPS listen port. | `8443` | | `gateway_ssl_copy_certs` | Boolean | Flag to enable copying the IAG SSL certificate. | `true` | -| `gateway_ssl_dir` | String | The IAG SSL directory. | `{{ gateway_install_dir }}/conf/certs` | -| `gateway_ssl_cert_src` | String | The SSL cert file. | `server.crt` | -| `gateway_ssl_cert_dest` | String | The SSL cert destination. | `{{ gateway_ssl_dir }}/{{ gateway_ssl_cert_src }}` | -| `gateway_ssl_key_src` | String | The SSL key file. | `server.key` | -| `gateway_ssl_key_dest` | String | The SSL key file destination. | `{{ gateway_ssl_dir }}/{{ gateway_ssl_key_src }}` | -| `gateway_ssl_rootca_src` | String | The SSL root CA file. | `rootCA.crt` | -| `gateway_ssl_rootca_dest` | String | The SSL root CA destination. | `{{ gateway_ssl_dir }}/{{ gateway_ssl_rootca_src }}` | +| `gateway_pki_base_dir` | String | The base PKI directory for Gateway certificates. | `/etc/pki/automation-gateway` | +| `gateway_https_cert_filename` | String | HTTPS certificate filename. | `{{ inventory_hostname }}.crt` | +| `gateway_https_key_filename` | String | HTTPS private key filename. | `{{ inventory_hostname }}.key` | +| `gateway_https_ca_filename` | String | HTTPS CA bundle filename. | `ca-bundle.crt` | +| `gateway_pki_src_dir` | String | Source directory for Gateway certificates (on Ansible controller). | (set in inventory) | +| `gateway_https_cert_file` | String | Deployed HTTPS certificate path. | `{{ gateway_pki_https_dir }}/{{ gateway_https_cert_filename }}` | +| `gateway_https_key_file` | String | Deployed HTTPS private key path. | `{{ gateway_pki_private_dir }}/{{ gateway_https_key_filename }}` | +| `gateway_https_ca_file` | String | Deployed HTTPS CA bundle path. | `{{ gateway_pki_https_dir }}/{{ gateway_https_ca_filename }}` | | `gateway_tlsv1_2` | Boolean | Flag to enable TLS 1.2. | `false` | | `gateway_http_server_threads` | Integer | The number of http server threads for handling requests. | `{{ ansible_processor_cores * 4 }}` | +## PKI Certificate Configuration + +Gateway requires HTTPS certificates for the API server and optionally MongoDB client certificates. + +### Certificate Requirements + +Each Gateway server requires: +- **HTTPS certificate**: `{{ inventory_hostname }}.crt` +- **HTTPS private key**: `{{ inventory_hostname }}.key` +- **CA bundle**: `ca-bundle.crt` + +### Certificate Organization + +Organize certificates per server on the Ansible controller: +certificates/ +├── gateway +│   ├── ca-bundle.crt +│   ├── ip-10-222-1-183.ec2.internal.crt +│   ├── ip-10-222-1-183.ec2.internal.key ## Configuring HTTPS The Gateway role supports configuring Native HTTPS. The Gateway role does not generate SSL certificates. diff --git a/docs/itential_platform_guide.md b/docs/itential_platform_guide.md index 954547ad..78e1ae0d 100644 --- a/docs/itential_platform_guide.md +++ b/docs/itential_platform_guide.md @@ -219,9 +219,9 @@ located in `roles/platform/defaults/main/webserver.yml`. | platform_webserver_http_port | Integer | The port on which the webserver listens for HTTP requests. | 3000 | | platform_webserver_https_enabled | Boolean | If true, allows the webserver to respond to secure HTTPS requests. | `false` | | platform_webserver_https_port | Integer | The port on which the webserver listens for HTTPS requests. | 3443 | -| platform_webserver_https_key | String | The path to the public key file used for HTTPS connections. | `/opt/itential/platform/keys/key.pem` | +| platform_webserver_https_key | String | The path to the private key file used for HTTPS connections. | `/etc/pki/itential-platform/private/{{ inventory_hostname }}.key` | | platform_webserver_https_passphrase | String | The passphrase for the private key used to enable TLS sessions. | | -| platform_webserver_https_cert | String | The path to the certificate file used for HTTPS connections. | `/opt/itential/platform/keys/cert.pem` | +| platform_webserver_https_cert | String | The path to the certificate file used for HTTPS connections. | `/etc/pki/itential-platform/https/{{ inventory_hostname }}.crt` | | platform_webserver_https_secure_protocol | String | The set of allowed SSL/TLS protocol versions. | `TLS_method` | | platform_webserver_https_ciphers | String | The allowed SSL/TLS cipher suite. | `ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA` | | platform_webserver_https_client_reneg_limit | Integer | Specifies the number of renegotiations that are allowed in a single HTTPS connection. | 3 | @@ -266,9 +266,15 @@ located in `roles/platform/defaults/main/platform.yml`. | :------- | :--- | :---------- | :------------ | | platform_server_dir | String | The Itential Platform installation directory. | `/opt/itential/platform/server` | | platform_config_dir | String | The Itential Platform configuration directory. | `/etc/itential` | -| platform_tls_dir | String | The Itential Platform TLS directory. | `/etc/ssl/itential-platform` | +| platform_pki_base_dir | String | The base PKI directory for Platform certificates. | `/etc/pki/itential-platform` | +| platform_https_cert_filename | String | HTTPS certificate filename. | `{{ inventory_hostname }}.crt` | +| platform_https_key_filename | String | HTTPS private key filename. | `{{ inventory_hostname }}.key` | +| platform_https_ca_filename | String | HTTPS CA bundle filename. | `ca-bundle.crt` | +| platform_mongodb_ca_filename | String | MongoDB client CA bundle filename. | `ca-bundle.crt` | +| platform_https_pki_src_dir | String | Source directory for HTTPS certificates. | (set in inventory) | +| platform_mongodb_pki_src_dir | String | Source directory for MongoDB client certificates. | (set in inventory) | | platform_itential_home_dir | String | The Itential Platform itential user home directory. | `/home/itential` | -| platform_mongodb_root_ca_file_destination | String | Destination as referenced by itential user when connecting from itential host. This is ultimately stored in the mongo database to be read by Itential Platform, therefore this is the location as seen from the Itential Platform host. | `/opt/itential/keys/mongo-rootCA.pem` | +| platform_mongodb_root_ca_file_destination | String | Destination as referenced by itential user when connecting from itential host. This is ultimately stored in the mongo database to be read by Itential Platform, therefore this is the location as seen from the Itential Platform host. | `/etc/pki/itential-platform/mongodb/ca-bundle.crt` | | platform_package_dependencies | List(String) | Required OS packages for install. | `glibc-common, openldap, openldap-clients, openssl, git` | | platform_python_base_dependencies | List(String) | Required python packages for install. | `pip, setuptools, wheel` | | platform_python_executable | String | The python executable locations. These will be symlinks to the appropriate executables in /usr/bin. | `/usr/bin/python{{ platform_python_version }}` | @@ -444,7 +450,7 @@ By default the Platform will install files into the following directories: | /opt/itential/platform/server | platform_server_dir | No | | /opt/itential/platform/services | platform_services_dir | No | | /etc/itential | platform_config_dir | Yes | -| /etc/ssl/itential-platform | platform_tls_dir | Yes | +| /etc/pki/itential-platform | platform_pki_base_dir | Yes | | /var/log/itential | platform_log_dir | Yes | | /home/itential | platform_itential_home_dir | Yes | @@ -463,7 +469,39 @@ Example overrides: ```yaml platform_root_dir: /app/itential/platform platform_config_dir: /app/itential/conf -platform_tls_dir: /app/itential/ssl +platform_pki_base_dir: /app/itential/pki platform_log_dir: /app/itential/log platform_itential_home_dir: /export/home/itential ``` +### PKI Certificate Configuration + +Platform requires HTTPS certificates for the web server and optionally MongoDB client certificates for mutual TLS. + +#### Certificate Requirements + +**HTTPS Certificates** (required): +- Server certificate: `{{ inventory_hostname }}.crt` +- Private key: `{{ inventory_hostname }}.key` +- CA bundle: `ca-bundle.crt` + +**MongoDB Client Certificates** (optional for mutual TLS): +- Client certificate: `client.pem` +- Client private key: `mongodb-client.key` +- CA bundle: `ca-bundle.crt` + +#### Certificate Organization + +Organize certificates per server on the Ansible controller: +certificates/ +├── platform +│   ├── ca-bundle.crt +│   ├── ip-10-222-1-169.ec2.internal.crt +│   ├── ip-10-222-1-64.ec2.internal.crt +│   ├── ip-10-222-1-64.ec2.internal.key + +#### Deployed Locations + +- Base directory: `/etc/pki/itential-platform/` +- HTTPS cert: `/etc/pki/itential-platform/https/{{ inventory_hostname }}.crt` +- HTTPS key: `/etc/pki/itential-platform/private/{{ inventory_hostname }}.key` +- MongoDB CA: `/etc/pki/itential-platform/mongodb/ca-bundle.crt` \ No newline at end of file diff --git a/docs/mongodb_guide.md b/docs/mongodb_guide.md index a6a7d3cf..408de275 100644 --- a/docs/mongodb_guide.md +++ b/docs/mongodb_guide.md @@ -91,8 +91,12 @@ The following table contains the most commonly overridden variables. | `mongodb_itential_db_name` | String | The name of the itential database. | `itential` | | `mongodb_replication_enabled` | Boolean | Flag to enable MongoDB replication | `false` | | `mongodb_replset_name` | String | The MongoDB replica set name. | `rs0` | -| `mongodb_ssl_root_dir` | String | The base directory for SSL certs and key files. | `/etc/ssl/certs` | | `mongodb_tls_enabled` | Boolean | Flag to enable MongoDB TLS. | `false` | +| `mongodb_pki_base_dir` | String | The base directory for PKI certificates and keys. | `/etc/pki/mongodb` | +| `mongodb_tls_server_cert_filename` | String | Server certificate filename (combined cert+key). | `{{ inventory_hostname }}.pem` | +| `mongodb_tls_ca_cert_filename` | String | CA certificate bundle filename. | `ca-bundle.crt` | +| `mongodb_replica_keyfile_filename` | String | Replica set authentication keyfile. | `replica.key` | +| `mongodb_pki_src_dir` | String | Source directory for certificates (on Ansible controller). | (set in inventory) | | `mongodb_user_admin_password` | String | The MongoDB admin user password. | `admin` | | `mongodb_user_itential_password` | String | The MongoDB itential user password. | `itential` | @@ -147,9 +151,33 @@ These variables apply to advanced situations. ## Configuring TLS -The `mongodb` role does not generate SSL certificates. They must be generated by the user and put -in the top level `files` directory on the Ansible control node. These files are uploaded to the -location defined in `mongodb_ssl_root_dir`. +The `mongodb` role does not generate TLS certificates. Certificates must be generated by the user and organized in a per-server directory structure. + +### Certificate Requirements + +Each MongoDB server requires: +- **Server certificate**: `{{ inventory_hostname }}.pem` (combined certificate + private key in PEM format) +- **CA certificate**: `ca-bundle.crt` (Certificate Authority bundle) +- **Replica keyfile**: `replica.key` (for replica set authentication) + +### Certificate Organization + +Certificates should be organized per server on the Ansible controller: +certificates/ +├── mongodb +│   ├── ca-bundle.crt +│   ├── hostname1.pem +│   ├── hostname2.pem +│   ├── hostname3.pem +│   ├── replica.key + +### Deployed Certificate Locations + +Certificates are deployed to: +- **Base directory**: `/etc/pki/mongodb/` +- **Server cert**: `/etc/pki/mongodb/{{ inventory_hostname }}.pem` +- **CA bundle**: `/etc/pki/mongodb/ca-bundle.crt` +- **Replica keyfile**: `/etc/pki/mongodb/private/replica.key` ## SELinux diff --git a/docs/tls_guide.md b/docs/tls_guide.md new file mode 100644 index 00000000..0975fae2 --- /dev/null +++ b/docs/tls_guide.md @@ -0,0 +1,346 @@ +# Certificate Deployment Scenarios - Configuration Guide + +## Overview + +The deployer supports 3 certificate deployment scenarios by configuring filename variables in your inventory. + +| Scenario | Use Case | Certificates Needed | +|----------|----------|---------------------| +| **Scenario 1** | Per-host certificates (most secure) | One unique cert per server | +| **Scenario 2** | Per-role certificates (simplified management) | One cert shared per role | +| **Scenario 3** | Single wildcard certificate (simplest) | One cert for everything | + +--- + +## Scenario 1: Per-Host Certificates (Current - Most Secure) + +**Certificate Structure:** +``` +certificates/ +├── mongodb/ +│ ├── mongo_host1.ec2.internal.pem +│ ├── mongo_host2.ec2.internal.pem +│ ├── mongo_host3.ec2.internal.pem +│ └── ca-bundle.crt +├── platform/ +│ ├── platform_host1.ec2.internal.crt +│ ├── platform_host1.ec2.internal.key +│ ├── platform_host2.ec2.internal.crt +│ ├── platform_host2.ec2.internal.key +│ └── ca-bundle.crt +└── ... +``` + +**Inventory Configuration:** +```yaml +# MongoDB +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates/mongodb" + # Default: mongodb_tls_server_cert_filename: "{{ inventory_hostname }}.pem" + # No override needed - this is the default + +# Platform +platform: + vars: + platform_https_pki_src_dir: "{{ playbook_dir }}/certificates/platform" + # Default: platform_https_cert_filename: "{{ inventory_hostname }}.crt" + # Default: platform_https_key_filename: "{{ inventory_hostname }}.key" + # No override needed + +# Redis +redis: + vars: + redis_pki_src_dir: "{{ playbook_dir }}/certificates/redis" + # Default: redis_tls_cert_filename: "{{ inventory_hostname }}.crt" + # Default: redis_tls_key_filename: "{{ inventory_hostname }}.key" + # No override needed + +# Gateway +gateway: + vars: + gateway_pki_src_dir: "{{ playbook_dir }}/certificates/gateway" + # Default: gateway_https_cert_filename: "{{ inventory_hostname }}.crt" + # Default: gateway_https_key_filename: "{{ inventory_hostname }}.key" + # No override needed +``` + +**Pros:** +- ✅ Most secure (compromise of one server doesn't affect others) +- ✅ Easy to rotate individual server certificates +- ✅ Clear audit trail (which cert on which server) + +**Cons:** +- ❌ More certificates to manage +- ❌ More certificate generation overhead + +--- + +## Scenario 2: Per-Role Certificates (Simplified Management) + +**Certificate Structure:** +``` +certificates/ +├── mongodb/ +│ ├── mongodb.pem ← Shared by all MongoDB servers +│ ├── ca-bundle.crt +│ └── replica.key +├── platform/ +│ ├── platform.crt ← Shared by all Platform servers +│ ├── platform.key +│ ├── client.pem +│ ├── mongodb-client.key +│ └── ca-bundle.crt +├── redis/ +│ ├── redis.crt ← Shared by all Redis servers +│ ├── redis.key +│ └── ca-bundle.crt +└── gateway/ + ├── gateway.crt ← Shared by all Gateway servers + ├── gateway.key + └── ca-bundle.crt +``` + +**Inventory Configuration:** +```yaml +# MongoDB - All servers use mongodb.pem +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates/mongodb" + mongodb_tls_server_cert_filename: "mongodb.pem" + +# Platform - All servers use platform.crt/key +platform: + vars: + platform_https_pki_src_dir: "{{ playbook_dir }}/certificates/platform" + platform_https_cert_filename: "platform.crt" + platform_https_key_filename: "platform.key" + +# Redis - All servers use redis.crt/key +redis: + vars: + redis_pki_src_dir: "{{ playbook_dir }}/certificates/redis" + redis_tls_cert_filename: "redis.crt" + redis_tls_key_filename: "redis.key" + +# Gateway - All servers use gateway.crt/key +gateway: + vars: + gateway_pki_src_dir: "{{ playbook_dir }}/certificates/gateway" + gateway_https_cert_filename: "gateway.crt" + gateway_https_key_filename: "gateway.key" +``` + +**Certificate Requirements:** +- Subject Alternative Names (SANs) must include all server hostnames/IPs for each role +- Example MongoDB cert SANs: `DNS:mongo_host1.ec2.internal, DNS:mongo_host2.ec2.internal, DNS:mongo_host3.ec2.internal` + +**Pros:** +- ✅ Fewer certificates to manage +- ✅ Simpler certificate generation (one per role) +- ✅ Easy to deploy new servers (just copy same cert) + +**Cons:** +- ❌ Certificate compromise affects all servers in that role +- ❌ Certificate rotation requires updating all servers +- ❌ Larger certificate files (many SANs) + +--- + +## Scenario 3: Single Wildcard Certificate (Simplest) + +**Certificate Structure:** +``` +certificates/ +├── wildcard.crt ← One cert for everything +├── wildcard.key +└── ca-bundle.crt +``` + +**Inventory Configuration:** +```yaml +# MongoDB +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates" + mongodb_tls_server_cert_filename: "wildcard.pem" + +# Platform +platform: + vars: + platform_https_pki_src_dir: "{{ playbook_dir }}/certificates" + platform_mongodb_pki_src_dir: "{{ playbook_dir }}/certificates" + platform_https_cert_filename: "wildcard.crt" + platform_https_key_filename: "wildcard.key" + +# Redis +redis: + vars: + redis_pki_src_dir: "{{ playbook_dir }}/certificates" + redis_tls_cert_filename: "wildcard.crt" + redis_tls_key_filename: "wildcard.key" + +# Gateway +gateway: + vars: + gateway_pki_src_dir: "{{ playbook_dir }}/certificates" + gateway_https_cert_filename: "wildcard.crt" + gateway_https_key_filename: "wildcard.key" +``` + +**Certificate Requirements:** +- Wildcard certificate covering all hostnames: `*.ec2.internal` or `*.example.com` +- OR certificate with SANs for ALL servers across ALL roles + +**Note for MongoDB:** +- Need to create `wildcard.pem` (combined cert+key): + ```bash + cat wildcard.crt wildcard.key > wildcard.pem + chmod 600 wildcard.pem + ``` + +**Pros:** +- ✅ Simplest to manage (one certificate) +- ✅ Easy to deploy anywhere +- ✅ Fast certificate rotation (update once, deploy everywhere) + +**Cons:** +- ❌ Least secure (compromise affects everything) +- ❌ Single point of failure +- ❌ Wildcard certificates may not be allowed by security policy +- ❌ Very large SAN list if not using wildcard + +--- + +## Comparison Matrix + +| Feature | Scenario 1
(Per-Host) | Scenario 2
(Per-Role) | Scenario 3
(Wildcard) | +|---------|--------------------------|--------------------------|--------------------------| +| **Certificates to manage** | High | Medium | Low (1) | +| **Security level** | Highest | Medium | Lowest | +| **Certificate generation** | Complex | Moderate | Simple | +| **Rotation complexity** | Low (per server) | Medium (per role) | High (everything at once) | +| **New server deployment** | Need new cert | Copy role cert | Copy same cert | +| **SAN requirements** | Single hostname | Multiple hostnames | All hostnames or wildcard | +| **Blast radius if compromised** | One server | One role | Everything | + +--- + +## Migration Between Scenarios + +### From Scenario 1 → Scenario 2 + +**Step 1:** Generate role-level certificates with SANs +```bash +# Example: MongoDB cert with all MongoDB server SANs +openssl req -new -x509 -days 365 -key mongodb.key -out mongodb.crt \ + -subj "/CN=mongodb" \ + -addext "subjectAltName=DNS:mongo_host1.ec2.internal,DNS:mongo_host2.ec2.internal,DNS:mongo_host3.ec2.internal" +``` + +**Step 2:** Update inventory to use role filenames +```yaml +mongodb: + vars: + mongodb_tls_server_cert_filename: "mongodb.pem" # Changed +``` + +**Step 3:** Update certificates directory structure +```bash +# Old structure: certificates/mongodb/mongo_host1.ec2.internal.pem +# New structure: certificates/mongodb/mongodb.pem +``` + +### From Scenario 2 → Scenario 3 + +**Step 1:** Generate wildcard or multi-SAN certificate covering all servers + +**Step 2:** Update inventory to use wildcard filenames +```yaml +mongodb: + vars: + mongodb_pki_src_dir: "{{ playbook_dir }}/certificates" # Single directory + mongodb_tls_server_cert_filename: "wildcard.pem" +``` + +--- + +## Recommendations by Environment + +### Development/Testing +- **Use:** Scenario 3 (Wildcard) +- **Why:** Simplest, fastest to set up, easy to regenerate + +### Staging +- **Use:** Scenario 2 (Per-Role) +- **Why:** Balance of simplicity and security, mirrors production patterns + +### Production +- **Use:** Scenario 1 (Per-Host) +- **Why:** Best security, compliance requirements, limited blast radius + +--- + +## Quick Reference - Variable Override Locations + +All filename variables can be overridden in your inventory: + +**MongoDB:** +- `mongodb_tls_server_cert_filename` +- `mongodb_tls_ca_cert_filename` +- `mongodb_replica_keyfile_filename` + +**Platform:** +- `platform_https_cert_filename` +- `platform_https_key_filename` +- `platform_https_ca_filename` +- `platform_mongodb_ca_filename` +- `platform_mongodb_client_cert_filename` +- `platform_mongodb_client_key_filename` + +**Redis:** +- `redis_tls_cert_filename` +- `redis_tls_key_filename` +- `redis_tls_ca_cert_filename` + +**Gateway:** +- `gateway_https_cert_filename` +- `gateway_https_key_filename` +- `gateway_https_ca_filename` + +--- + +## Example: Mixed Scenario (Advanced) + +You can even mix scenarios per role: + +```yaml +# MongoDB: Per-host (most critical) +mongodb: + vars: + mongodb_tls_server_cert_filename: "{{ inventory_hostname }}.pem" + +# Platform: Per-host (user-facing) +platform: + vars: + platform_https_cert_filename: "{{ inventory_hostname }}.crt" + platform_https_key_filename: "{{ inventory_hostname }}.key" + +# Redis: Per-role (internal, less critical) +redis: + vars: + redis_tls_cert_filename: "redis.crt" + redis_tls_key_filename: "redis.key" + +# Gateway: Per-role (behind load balancer) +gateway: + vars: + gateway_https_cert_filename: "gateway.crt" + gateway_https_key_filename: "gateway.key" +``` + +--- + +## Key Takeaway + +**The deployer is flexible!** You don't need code changes - just configure the filename variables in your inventory to match your certificate structure. The `{{ inventory_hostname }}` default supports Scenario 1, but you can override it for Scenarios 2 and 3. \ No newline at end of file diff --git a/roles/gateway/defaults/main/gateway.yml b/roles/gateway/defaults/main/gateway.yml index 4ec39c37..72c83e24 100644 --- a/roles/gateway/defaults/main/gateway.yml +++ b/roles/gateway/defaults/main/gateway.yml @@ -38,16 +38,12 @@ gateway_user_home_dir: "/home/{{ gateway_user }}" gateway_user_shell_rc_file: "{{ gateway_user_home_dir }}/.bashrc" # Default HTTPS/SSL settings -gateway_https: false +gateway_https: true gateway_https_port: 8443 + +# Flag to enable copying the Gateway SSL certificates gateway_ssl_copy_certs: true -gateway_ssl_dir: "{{ gateway_install_dir }}/conf/certs" -gateway_ssl_cert_src: server.crt -gateway_ssl_cert_dest: "{{ gateway_ssl_dir }}/{{ gateway_ssl_cert_src }}" -gateway_ssl_key_src: server.key -gateway_ssl_key_dest: "{{ gateway_ssl_dir }}/{{ gateway_ssl_key_src }}" -gateway_ssl_rootca_src: rootCA.crt -gateway_ssl_rootca_dest: "{{ gateway_ssl_dir }}/{{ gateway_ssl_rootca_src }}" + gateway_tlsv1_2: false # The number of http server threads for handling requests diff --git a/roles/gateway/defaults/main/pki.yml b/roles/gateway/defaults/main/pki.yml new file mode 100644 index 00000000..32dfdb6c --- /dev/null +++ b/roles/gateway/defaults/main/pki.yml @@ -0,0 +1,101 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Gateway PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +gateway_pki_base_dir: /etc/pki/automation-gateway + +# Subdirectory names - customize the layout +gateway_pki_private_subdir: private +gateway_pki_https_subdir: https + +# Derived subdirectory paths - built from base + subdir name +gateway_pki_private_dir: "{{ gateway_pki_base_dir }}/{{ gateway_pki_private_subdir }}" +gateway_pki_https_dir: "{{ gateway_pki_base_dir }}/{{ gateway_pki_https_subdir }}" + +# ============================================================================ +# Certificate and Key Filenames - Customize naming +# ============================================================================ + +# HTTPS server certificate filename +gateway_https_cert_filename: "{{ inventory_hostname }}.crt" + +# HTTPS server private key filename +gateway_https_key_filename: "{{ inventory_hostname }}.key" + +# HTTPS CA bundle filename +gateway_https_ca_filename: ca-bundle.crt + +# ============================================================================ +# Full Certificate Paths - Built from components +# ============================================================================ + +# HTTPS server certificate path +gateway_https_cert_file: "{{ gateway_pki_https_dir }}/{{ gateway_https_cert_filename }}" + +# HTTPS server private key path +gateway_https_key_file: "{{ gateway_pki_private_dir }}/{{ gateway_https_key_filename }}" + +# HTTPS CA bundle path +gateway_https_ca_file: "{{ gateway_pki_https_dir }}/{{ gateway_https_ca_filename }}" + +# ============================================================================ +# Source Directory - Define in inventory +# ============================================================================ + +# Source directory for certificate files (on Ansible controller) +gateway_pki_src_dir: "" + +# ============================================================================ +# Source File Paths - Built from source directory + filename +# ============================================================================ + +# HTTPS source paths - auto-build from source dir + filename +gateway_https_cert_source: "{{ gateway_pki_src_dir }}/{{ gateway_https_cert_filename }}" +gateway_https_key_source: "{{ gateway_pki_src_dir }}/{{ gateway_https_key_filename }}" +gateway_https_ca_source: "{{ gateway_pki_src_dir }}/{{ gateway_https_ca_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI directories and files +gateway_pki_owner: "{{ gateway_user }}" + +# Group for PKI directories and files +gateway_pki_group: "{{ gateway_group }}" + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +gateway_pki_base_dir_mode: "0750" + +# Subdirectory permissions +gateway_pki_subdir_mode: "0750" + +# Private directory permissions +gateway_pki_private_dir_mode: "0700" + +# HTTPS certificate permissions +gateway_https_cert_mode: "0644" + +# HTTPS private key permissions +gateway_https_key_mode: "0600" + +# HTTPS CA bundle permissions +gateway_https_ca_mode: "0644" + +# ============================================================================ +# Backward Compatibility - Legacy Variable Names +# These maintain compatibility with existing templates +# ============================================================================ + +# Legacy variables for templates (point to new paths) +gateway_ssl_cert_dest: "{{ gateway_https_cert_file }}" +gateway_ssl_key_dest: "{{ gateway_https_key_file }}" +gateway_ssl_rootca_dest: "{{ gateway_https_ca_file }}" diff --git a/roles/gateway/handlers/main.yml b/roles/gateway/handlers/main.yml new file mode 100644 index 00000000..c9a31cf6 --- /dev/null +++ b/roles/gateway/handlers/main.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Restart automation-gateway + ansible.builtin.service: + name: automation-gateway + state: restarted + listen: restart automation-gateway diff --git a/roles/gateway/tasks/configure-gateway-https.yml b/roles/gateway/tasks/configure-gateway-https.yml new file mode 100644 index 00000000..c2294db0 --- /dev/null +++ b/roles/gateway/tasks/configure-gateway-https.yml @@ -0,0 +1,88 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create Gateway PKI base directory + ansible.builtin.file: + path: "{{ gateway_pki_base_dir }}" + state: directory + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_pki_base_dir_mode }}" + tags: + - gateway + - gateway_certificates + - certificates + +- name: Create Gateway PKI subdirectories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_pki_subdir_mode }}" + loop: + - "{{ gateway_pki_https_dir }}" + tags: + - gateway + - gateway_certificates + - certificates + +- name: Create Gateway private directory + ansible.builtin.file: + path: "{{ gateway_pki_private_dir }}" + state: directory + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_pki_private_dir_mode }}" + tags: + - gateway + - gateway_certificates + - certificates + +- name: Copy Gateway HTTPS certificate + ansible.builtin.copy: + src: "{{ gateway_https_cert_source }}" + dest: "{{ gateway_https_cert_file }}" + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_https_cert_mode }}" + when: + - gateway_ssl_copy_certs | bool + - gateway_https_cert_source | length > 0 + notify: restart automation-gateway + tags: + - gateway + - gateway_certificates + - certificates + +- name: Copy Gateway HTTPS private key + ansible.builtin.copy: + src: "{{ gateway_https_key_source }}" + dest: "{{ gateway_https_key_file }}" + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_https_key_mode }}" + when: + - gateway_ssl_copy_certs | bool + - gateway_https_key_source | length > 0 + notify: restart automation-gateway + tags: + - gateway + - gateway_certificates + - certificates + +- name: Copy Gateway CA bundle + ansible.builtin.copy: + src: "{{ gateway_https_ca_source }}" + dest: "{{ gateway_https_ca_file }}" + owner: "{{ gateway_pki_owner }}" + group: "{{ gateway_pki_group }}" + mode: "{{ gateway_https_ca_mode }}" + when: + - gateway_ssl_copy_certs | bool + - gateway_https_ca_source | length > 0 + notify: restart automation-gateway + tags: + - gateway + - gateway_certificates + - certificates diff --git a/roles/gateway/tasks/main.yml b/roles/gateway/tasks/main.yml index a415449d..c1b4b8aa 100644 --- a/roles/gateway/tasks/main.yml +++ b/roles/gateway/tasks/main.yml @@ -97,10 +97,13 @@ state: directory when: gateway_enable_python_venv | bool - - name: Copy certs - ansible.builtin.include_tasks: - file: copy-certs.yml - when: gateway_https and gateway_ssl_copy_certs + - name: Configure Gateway HTTPS + ansible.builtin.include_tasks: configure-gateway-https.yml + when: gateway_https | bool + tags: + - gateway + - gateway_certificates + - certificates - name: Install Python tags: install_python diff --git a/roles/mongodb/defaults/main/mongodb.yml b/roles/mongodb/defaults/main/mongodb.yml index 44785c8c..4d6bf787 100644 --- a/roles/mongodb/defaults/main/mongodb.yml +++ b/roles/mongodb/defaults/main/mongodb.yml @@ -13,19 +13,6 @@ mongodb_log_dir: /var/log/mongodb # Directory that stores the mongodb pid file mongodb_pid_dir: /var/run/mongodb -# The base directory for SSL certs and key files -mongodb_ssl_root_dir: /etc/ssl/certs - -# Key file destination location -# The key file is used to authenticate members of a replica set -mongodb_auth_keyfile_destination: "{{ mongodb_ssl_root_dir }}/mongodb/mongo-replicaset-key.pem" - -# Destination location of the certificate key file used for TLS connections -mongodb_cert_keyfile_destination: "{{ mongodb_ssl_root_dir }}/mongodb/mongo-certificate.pem" - -# Destination location of the CA root file used for TLS connections -mongodb_root_ca_file_destination: "{{ mongodb_ssl_root_dir }}/mongodb/mongo-rootCA.pem" - # The Mongo user and group mongodb_owner: mongod mongodb_group: mongod @@ -57,7 +44,7 @@ mongodb_itential_db_name: itential # or TLS settings applied. mongodb_replication_enabled: false mongodb_auth_enabled: true -mongodb_tls_enabled: false +mongodb_tls_enabled: true # Default mongo user names mongodb_user_admin: admin diff --git a/roles/mongodb/defaults/main/pki.yml b/roles/mongodb/defaults/main/pki.yml new file mode 100644 index 00000000..13fba653 --- /dev/null +++ b/roles/mongodb/defaults/main/pki.yml @@ -0,0 +1,85 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# MongoDB PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +mongodb_pki_base_dir: /etc/pki/mongodb + +# Subdirectory names - customize the layout +mongodb_pki_private_subdir: private + +# Derived subdirectory paths - built from base + subdir name +mongodb_pki_private_dir: "{{ mongodb_pki_base_dir }}/{{ mongodb_pki_private_subdir }}" + +# ============================================================================ +# Certificate and Key Filenames - Customize naming +# ============================================================================ + +# TLS server certificate filename (combined cert + key PEM) +mongodb_tls_server_cert_filename: "{{ inventory_hostname }}.pem" + +# CA certificate filename +mongodb_tls_ca_cert_filename: ca-bundle.crt + +# Replica set authentication keyfile filename +mongodb_replica_keyfile_filename: replica.key + +# ============================================================================ +# Full Certificate Paths - Built from components, but can be overridden +# ============================================================================ + +# TLS server certificate path (used by mongod for TLS connections) +mongodb_cert_keyfile_destination: "{{ mongodb_pki_base_dir }}/{{ mongodb_tls_server_cert_filename }}" + +# CA certificate path (used to validate client certificates) +mongodb_root_ca_file_destination: "{{ mongodb_pki_base_dir }}/{{ mongodb_tls_ca_cert_filename }}" + +# Replica set keyfile path (used for internal authentication) +mongodb_auth_keyfile_destination: "{{ mongodb_pki_private_dir }}/{{ mongodb_replica_keyfile_filename }}" + +# ============================================================================ +# Source Directory and File Paths - Define source directory in inventory +# ============================================================================ + +# Source directory for certificate files (on Ansible controller) +# Set this in your inventory to point to your certificate directory +mongodb_pki_src_dir: "" + +mongodb_ssl_root_dir: "{{ mongodb_pki_base_dir }}" +# Source paths - built from source directory + filename +# These auto-build from mongodb_pki_src_dir, but can be overridden individually +mongodb_cert_keyfile_source: "{{ mongodb_pki_src_dir }}/{{ mongodb_tls_server_cert_filename }}" +mongodb_root_ca_file_source: "{{ mongodb_pki_src_dir }}/{{ mongodb_tls_ca_cert_filename }}" +mongodb_auth_keyfile_source: "{{ mongodb_pki_src_dir }}/{{ mongodb_replica_keyfile_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI directories and files +mongodb_pki_owner: "{{ mongodb_owner }}" + +# Group for PKI directories and files +mongodb_pki_group: "{{ mongodb_group }}" + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +mongodb_pki_base_dir_mode: "0750" + +# Private subdirectory permissions +mongodb_pki_private_dir_mode: "0700" + +# TLS server certificate permissions +mongodb_tls_server_cert_mode: "0640" + +# CA certificate permissions +mongodb_tls_ca_cert_mode: "0644" + +# Replica keyfile permissions +mongodb_replica_keyfile_mode: "0400" diff --git a/roles/mongodb/tasks/configure-mongodb-auth.yml b/roles/mongodb/tasks/configure-mongodb-auth.yml index aa0c8fd4..0cf0e97b 100644 --- a/roles/mongodb/tasks/configure-mongodb-auth.yml +++ b/roles/mongodb/tasks/configure-mongodb-auth.yml @@ -10,13 +10,21 @@ when: mongodb_replication_enabled | bool block: - - name: Ensure that the directory exists for the certificates and key files + - name: Ensure PKI base directory exists ansible.builtin.file: state: directory - path: "{{ mongodb_ssl_root_dir }}/mongodb" - owner: root - group: root - mode: "0775" + path: "{{ mongodb_pki_base_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_base_dir_mode }}" + + - name: Ensure PKI private directory exists for keyfile + ansible.builtin.file: + state: directory + path: "{{ mongodb_pki_private_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_private_dir_mode }}" - name: Check if replica set key exists on the primary node ansible.builtin.stat: @@ -48,17 +56,17 @@ ansible.builtin.copy: dest: "{{ mongodb_auth_keyfile_destination }}" content: "{{ keyfile.content | b64decode }}" - owner: "{{ mongodb_owner }}" - group: "{{ mongodb_group }}" - mode: "0400" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_replica_keyfile_mode }}" when: inventory_hostname != groups['mongodb'][0] - name: Set the key file ownership and permissions ansible.builtin.file: path: "{{ mongodb_auth_keyfile_destination }}" - owner: "{{ mongodb_owner }}" - group: "{{ mongodb_group }}" - mode: '0400' + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_replica_keyfile_mode }}" # Execute the template to apply changes to the mongo.conf for auth - name: Create MongoDB config file (auth) diff --git a/roles/mongodb/tasks/configure-mongodb-tls.yml b/roles/mongodb/tasks/configure-mongodb-tls.yml index c8529149..adb4f0b0 100644 --- a/roles/mongodb/tasks/configure-mongodb-tls.yml +++ b/roles/mongodb/tasks/configure-mongodb-tls.yml @@ -1,35 +1,56 @@ # Copyright (c) 2024, Itential, Inc # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) --- -# Ensure that the directory exists for the certificates and key files -- name: Ensure that the directory exists for the certificates and key files +- name: Create MongoDB PKI base directory ansible.builtin.file: state: directory - path: "{{ mongodb_ssl_root_dir }}/mongodb" - owner: root - group: root - mode: "0775" + path: "{{ mongodb_pki_base_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_base_dir_mode }}" + tags: + - mongodb + - mongodb_certificates + - certificates + +- name: Create MongoDB private directory + ansible.builtin.file: + state: directory + path: "{{ mongodb_pki_private_dir }}" + owner: "{{ mongodb_pki_owner }}" + group: "{{ mongodb_pki_group }}" + mode: "{{ mongodb_pki_private_dir_mode }}" + tags: + - mongodb + - mongodb_certificates + - certificates -# Copy the predefined certificate file to the mongodb host. This certificate is -# the .pem file that contains both the TLS certificate and key. - name: Copy certificate to MongoDB host if TLS enabled ansible.builtin.copy: src: "{{ mongodb_cert_keyfile_source }}" dest: "{{ mongodb_cert_keyfile_destination }}" - mode: "0400" - group: "{{ mongodb_group }}" - owner: "{{ mongodb_owner }}" + mode: "{{ mongodb_tls_server_cert_mode }}" + group: "{{ mongodb_pki_group }}" + owner: "{{ mongodb_pki_owner }}" + notify: restart mongod + tags: + - mongodb + - mongodb_certificates + - certificates -# # Copy the predefined root CA certificate file to the mongodb host. - name: Copy CA certificate to MongoDB host if TLS enabled ansible.builtin.copy: src: "{{ mongodb_root_ca_file_source }}" dest: "{{ mongodb_root_ca_file_destination }}" - mode: "0400" - group: "{{ mongodb_group }}" - owner: "{{ mongodb_owner }}" + mode: "{{ mongodb_tls_ca_cert_mode }}" + group: "{{ mongodb_pki_group }}" + owner: "{{ mongodb_pki_owner }}" + notify: restart mongod + tags: + - mongodb + - mongodb_certificates + - certificates -# Execute the template to apply changes to the mongo.conf for TLS support - name: Create MongoDB config file (TLS) ansible.builtin.template: src: mongod.conf.j2 @@ -39,13 +60,14 @@ mode: "0644" vars: stage: "tls" + notify: restart mongod + tags: + - mongodb + - mongodb_config -- name: Start mongo (TLS) - ansible.builtin.service: - name: mongod - state: restarted - enabled: true - register: mongod_service_result - until: mongod_service_result.status.ActiveState == "active" - retries: "{{ mongodb_mongod_service_retries }}" - delay: "{{ mongodb_mongod_service_delay }}" +- name: Flush handlers to restart mongod with TLS config + ansible.builtin.meta: flush_handlers + tags: + - mongodb + - mongodb_certificates + - certificates diff --git a/roles/platform/defaults/main/mongodb.yml b/roles/platform/defaults/main/mongodb.yml index c1ddcf43..029789c4 100644 --- a/roles/platform/defaults/main/mongodb.yml +++ b/roles/platform/defaults/main/mongodb.yml @@ -24,16 +24,12 @@ platform_mongo_db_name: itential platform_mongo_url: mongodb://localhost:27017 # Instruct the MongoDB driver to use TLS protocols when connecting to the database. -platform_mongo_tls_enabled: false +platform_mongo_tls_enabled: true # If true, disables the validation checks for TLS certificates on other servers in the cluster # and allows the use of invalid or self-signed certificates to connect. platform_mongo_tls_allow_invalid_certificates: false -# The .pem file that contains the root certificate chain from the Certificate Authority. -# Specify the file name of the .pem file using absolute paths. -platform_mongo_tls_ca_file: - # The maximum number of connections in a connection pool. # Each application/adapter has its own connection pool. platform_mongo_max_pool_size: diff --git a/roles/platform/defaults/main/pki.yml b/roles/platform/defaults/main/pki.yml new file mode 100644 index 00000000..53ab5a06 --- /dev/null +++ b/roles/platform/defaults/main/pki.yml @@ -0,0 +1,143 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Platform PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +platform_pki_base_dir: /etc/pki/itential-platform + +# Subdirectory names - customize the layout +platform_pki_private_subdir: private +platform_pki_https_subdir: https +platform_pki_mongodb_subdir: mongodb + +# Derived subdirectory paths - built from base + subdir name +platform_pki_private_dir: "{{ platform_pki_base_dir }}/{{ platform_pki_private_subdir }}" +platform_pki_https_dir: "{{ platform_pki_base_dir }}/{{ platform_pki_https_subdir }}" +platform_pki_mongodb_dir: "{{ platform_pki_base_dir }}/{{ platform_pki_mongodb_subdir }}" + +# ============================================================================ +# HTTPS Certificate Filenames - Customize naming +# ============================================================================ + +# HTTPS server certificate filename +platform_https_cert_filename: "{{ inventory_hostname }}.crt" + +# HTTPS private key filename +platform_https_key_filename: "{{ inventory_hostname }}.key" + +# HTTPS CA bundle filename +platform_https_ca_filename: ca-bundle.crt + +# ============================================================================ +# HTTPS Full Certificate Paths - Built from components +# ============================================================================ + +# HTTPS server certificate path +platform_webserver_https_cert: "{{ platform_pki_https_dir }}/{{ platform_https_cert_filename }}" + +# HTTPS private key path +platform_webserver_https_key: "{{ platform_pki_private_dir }}/{{ platform_https_key_filename }}" + +# HTTPS CA bundle path +platform_webserver_https_ca: "{{ platform_pki_https_dir }}/{{ platform_https_ca_filename }}" + +# ============================================================================ +# MongoDB Client Certificate Filenames - Customize naming +# ============================================================================ + +# MongoDB CA certificate filename +platform_mongodb_ca_filename: ca-bundle.crt + +# ============================================================================ +# MongoDB Client Full Certificate Paths - Built from components +# ============================================================================ + +# MongoDB CA certificate path (used to validate MongoDB server) +platform_mongodb_root_ca_file_destination: "{{ platform_pki_mongodb_dir }}/{{ platform_mongodb_ca_filename }}" + +# ============================================================================ +# Application Configuration Mappings +# These map to the paths expected by Platform's properties.json +# ============================================================================ + +# MongoDB CA file for application properties.json +# This variable is used in templates and needs to point to the destination path +platform_mongo_tls_ca_file: "{{ platform_mongodb_root_ca_file_destination }}" + +# ============================================================================ +# Source Directories - Define in inventory +# ============================================================================ + +# Source directory for HTTPS certificates (on Ansible controller) +platform_https_pki_src_dir: "/Users/ananth.munagala/deployer_checkins/PE-1386/certificates/platform" + +# Source directory for MongoDB certificates (on Ansible controller) +platform_mongodb_pki_src_dir: "/Users/ananth.munagala/deployer_checkins/PE-1386/certificates/platform" + +# ============================================================================ +# Source File Paths - Built from source directory + filename +# ============================================================================ + +# HTTPS source paths - auto-build from source dir + filename +platform_certfile_source: "{{ platform_https_pki_src_dir }}/{{ platform_https_cert_filename }}" +platform_keyfile_source: "{{ platform_https_pki_src_dir }}/{{ platform_https_key_filename }}" +platform_https_ca_source: "{{ platform_https_pki_src_dir }}/{{ platform_https_ca_filename }}" + +# MongoDB client source paths - auto-build from source dir + filename +platform_mongodb_root_ca_file_source: "{{ platform_mongodb_pki_src_dir }}/{{ platform_mongodb_ca_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI base directory +platform_pki_base_owner: root + +# Group for PKI base directory +platform_pki_base_group: itential + +# Owner for private key files +platform_pki_private_owner: root + +# Group for private key files +platform_pki_private_group: itential + +# Owner for certificate files +platform_pki_cert_owner: "{{ platform_user }}" + +# Group for certificate files +platform_pki_cert_group: "{{ platform_group }}" + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +platform_pki_base_dir_mode: "0750" + +# Subdirectory permissions +platform_pki_subdir_mode: "0750" + +# Private directory permissions +platform_pki_private_dir_mode: "0750" + +# HTTPS certificate permissions +platform_https_cert_mode: "0644" + +# HTTPS private key permissions +platform_https_key_mode: "0640" + +# HTTPS CA bundle permissions +platform_https_ca_mode: "0644" + +# MongoDB CA certificate permissions +platform_mongodb_ca_mode: "0644" + +# MongoDB client certificate permissions +platform_mongodb_client_cert_mode: "0640" + +# MongoDB client private key permissions +platform_mongodb_client_key_mode: "0600" diff --git a/roles/platform/defaults/main/platform.yml b/roles/platform/defaults/main/platform.yml index 4ad71e11..b12066dc 100644 --- a/roles/platform/defaults/main/platform.yml +++ b/roles/platform/defaults/main/platform.yml @@ -4,13 +4,12 @@ # Itential Platform directories platform_root_dir: "{{ platform_root_dir_default }}" platform_config_dir: "{{ platform_config_dir_default }}" -platform_tls_dir: "{{ platform_tls_dir_default }}" +# platform_tls_dir: "{{ platform_tls_dir_default }}" platform_itential_home_dir: "{{ platform_itential_home_dir_default }}" # Destination as referenced by itential user when connecting from itential host. # This is ultimately stored in the mongo database to be read by Itential Platform, therefore # this is the location as seen from the Itential Platform host. -platform_mongodb_root_ca_file_destination: /opt/itential/keys/mongo-rootCA.pem platform_package_dependencies: - glibc-common diff --git a/roles/platform/defaults/main/webserver.yml b/roles/platform/defaults/main/webserver.yml index 9144e037..13ace775 100644 --- a/roles/platform/defaults/main/webserver.yml +++ b/roles/platform/defaults/main/webserver.yml @@ -17,20 +17,14 @@ platform_webserver_http_enabled: true platform_webserver_http_port: 3000 # If true, allows the webserver to respond to secure HTTPS requests. -platform_webserver_https_enabled: false +platform_webserver_https_enabled: true # The port on which the webserver listens for HTTPS requests. platform_webserver_https_port: 3443 -# The path to the public key file used for HTTPS connections. -platform_webserver_https_key: "{{ platform_tls_dir }}/private/server.key" - # The passphrase for the private key used to enable TLS sessions. platform_webserver_https_passphrase: -# The path to the certificate file used for HTTPS connections. -platform_webserver_https_cert: "{{ platform_tls_dir }}/certs/server.crt" - # The set of allowed SSL/TLS protocol versions. platform_webserver_https_secure_protocol: TLS_method diff --git a/roles/platform/handlers/main.yml b/roles/platform/handlers/main.yml index e18b9e96..15291cbf 100644 --- a/roles/platform/handlers/main.yml +++ b/roles/platform/handlers/main.yml @@ -8,6 +8,7 @@ state: restarted daemon_reload: true when: platform_start_service | bool + listen: restart itential-platform - name: Update Itential release file ansible.builtin.include_tasks: diff --git a/roles/platform/tasks/copy-certs.yml b/roles/platform/tasks/copy-certs.yml index c328f44b..fda641b2 100644 --- a/roles/platform/tasks/copy-certs.yml +++ b/roles/platform/tasks/copy-certs.yml @@ -1,48 +1,112 @@ # Copyright (c) 2024, Itential, Inc # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) --- +# ============================================================================ +# Create Platform PKI Directory Structure +# ============================================================================ + +- name: Create Platform PKI base directory + ansible.builtin.file: + path: "{{ platform_pki_base_dir }}" + state: directory + owner: "{{ platform_pki_base_owner }}" + group: "{{ platform_pki_base_group }}" + mode: "{{ platform_pki_base_dir_mode }}" + tags: + - platform + - platform_certificates + - certificates + +- name: Create Platform PKI subdirectories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ platform_pki_base_owner }}" + group: "{{ platform_pki_base_group }}" + mode: "{{ platform_pki_subdir_mode }}" + loop: + - "{{ platform_pki_https_dir }}" + - "{{ platform_pki_mongodb_dir }}" + tags: + - platform + - platform_certificates + - certificates + +- name: Create Platform private key directory + ansible.builtin.file: + path: "{{ platform_pki_private_dir }}" + state: directory + owner: "{{ platform_pki_private_owner }}" + group: "{{ platform_pki_private_group }}" + mode: "{{ platform_pki_private_dir_mode }}" + tags: + - platform + - platform_certificates + - certificates + +# ============================================================================ +# HTTPS Certificates +# ============================================================================ + - name: Copy HTTPS key and cert files when: platform_webserver_https_enabled | bool + tags: + - platform + - platform_certificates + - platform_https + - certificates block: - - name: Ensure the private directory exists + - name: Ensure the HTTPS private key directory exists ansible.builtin.file: path: "{{ platform_webserver_https_key | dirname }}" state: directory - owner: root - group: itential - mode: '0750' + owner: "{{ platform_pki_private_owner }}" + group: "{{ platform_pki_private_group }}" + mode: "{{ platform_pki_private_dir_mode }}" - - name: Ensure the certs directory exists + - name: Ensure the HTTPS cert directory exists ansible.builtin.file: path: "{{ platform_webserver_https_cert | dirname }}" state: directory - owner: root - group: root - mode: '0755' + owner: "{{ platform_pki_base_owner }}" + group: "{{ platform_pki_base_group }}" + mode: "{{ platform_pki_subdir_mode }}" - name: Put the HTTPS key file in the correct location ansible.builtin.copy: src: "{{ platform_keyfile_source }}" dest: "{{ platform_webserver_https_key }}" - mode: "0640" - owner: root - group: itential + mode: "{{ platform_https_key_mode }}" + owner: "{{ platform_pki_private_owner }}" + group: "{{ platform_pki_private_group }}" + notify: restart itential-platform - name: Put the HTTPS cert file in the correct location ansible.builtin.copy: src: "{{ platform_certfile_source }}" dest: "{{ platform_webserver_https_cert }}" - mode: "0644" - owner: root - group: root + mode: "{{ platform_https_cert_mode }}" + owner: "{{ platform_pki_cert_owner }}" + group: "{{ platform_pki_cert_group }}" + notify: restart itential-platform + +# ============================================================================ +# MongoDB Client Certificates +# ============================================================================ - name: Copy MongoDB root CA file to the appropriate location ansible.builtin.copy: src: "{{ platform_mongodb_root_ca_file_source }}" dest: "{{ platform_mongodb_root_ca_file_destination }}" - mode: "0400" - owner: "{{ platform_user }}" - group: "{{ platform_group }}" + mode: "{{ platform_mongodb_ca_mode }}" + owner: "{{ platform_pki_cert_owner }}" + group: "{{ platform_pki_cert_group }}" when: - platform_mongo_tls_enabled | bool - platform_mongodb_root_ca_file_source is defined + notify: restart itential-platform + tags: + - platform + - platform_certificates + - platform_mongodb + - certificates \ No newline at end of file diff --git a/roles/platform/vars/main.yml b/roles/platform/vars/main.yml index b314ae7f..c5b71a6b 100644 --- a/roles/platform/vars/main.yml +++ b/roles/platform/vars/main.yml @@ -6,7 +6,6 @@ platform_root_dir_default: /opt/itential/platform platform_server_dir_default: /opt/itential/platform/server platform_services_dir_default: /opt/itential/platform/services platform_config_dir_default: /etc/itential -platform_tls_dir_default: /etc/ssl/itential-platform platform_log_dir_default: /var/log/itential platform_itential_home_dir_default: /home/itential diff --git a/roles/redis/defaults/main/pki.yml b/roles/redis/defaults/main/pki.yml new file mode 100644 index 00000000..14b00462 --- /dev/null +++ b/roles/redis/defaults/main/pki.yml @@ -0,0 +1,122 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# ============================================================================ +# Redis PKI Configuration - All components customizable +# ============================================================================ + +# Base PKI directory - override to use different root location +redis_pki_base_dir: /etc/pki/redis + +# Subdirectory names - customize the layout +redis_pki_private_subdir: private + +# Derived subdirectory paths - built from base + subdir name +redis_pki_private_dir: "{{ redis_pki_base_dir }}/{{ redis_pki_private_subdir }}" + +# ============================================================================ +# Certificate and Key Filenames - Customize naming +# ============================================================================ + +# Redis server certificate filename +redis_tls_cert_filename: "{{ inventory_hostname }}.crt" + +# Redis server private key filename +redis_tls_key_filename: "{{ inventory_hostname }}.key" + +# Redis CA certificate filename +redis_tls_ca_filename: ca-bundle.crt + +# Redis DH parameters filename +redis_tls_dh_params_filename: dhparams.pem + +# Redis Sentinel certificate filename +redis_sentinel_tls_cert_filename: sentinel.crt + +# Redis Sentinel private key filename +redis_sentinel_tls_key_filename: sentinel.key + +# ============================================================================ +# Redis Server Full Certificate Paths - Built from components +# ============================================================================ + +# Redis server certificate path +redis_tls_cert_file: "{{ redis_pki_base_dir }}/{{ redis_tls_cert_filename }}" + +# Redis server private key path +redis_tls_key_file: "{{ redis_pki_private_dir }}/{{ redis_tls_key_filename }}" + +# Redis CA certificate path +redis_tls_ca_file: "{{ redis_pki_base_dir }}/{{ redis_tls_ca_filename }}" + +# Redis DH parameters path +redis_tls_dh_params_file: "{{ redis_pki_base_dir }}/{{ redis_tls_dh_params_filename }}" + +# ============================================================================ +# Redis Sentinel Full Certificate Paths - Built from components +# ============================================================================ + +# Sentinel certificate path +redis_sentinel_tls_cert_file: "{{ redis_pki_base_dir }}/{{ redis_sentinel_tls_cert_filename }}" + +# Sentinel private key path +redis_sentinel_tls_key_file: "{{ redis_pki_private_dir }}/{{ redis_sentinel_tls_key_filename }}" + +# ============================================================================ +# Source Directory - Define in inventory +# ============================================================================ + +# Source directory for certificate files (on Ansible controller) +redis_pki_src_dir: "" + +# ============================================================================ +# Source File Paths - Built from source directory + filename +# ============================================================================ + +# Redis server source paths - auto-build from source dir + filename +redis_tls_cert_source: "{{ redis_pki_src_dir }}/{{ redis_tls_cert_filename }}" +redis_tls_key_source: "{{ redis_pki_src_dir }}/{{ redis_tls_key_filename }}" +redis_tls_ca_source: "{{ redis_pki_src_dir }}/{{ redis_tls_ca_filename }}" +redis_tls_dh_params_source: "{{ redis_pki_src_dir }}/{{ redis_tls_dh_params_filename }}" + +# Sentinel source paths - auto-build from source dir + filename +redis_sentinel_tls_cert_source: "{{ redis_pki_src_dir }}/{{ redis_sentinel_tls_cert_filename }}" +redis_sentinel_tls_key_source: "{{ redis_pki_src_dir }}/{{ redis_sentinel_tls_key_filename }}" + +# ============================================================================ +# File Ownership - Customize per environment +# ============================================================================ + +# Owner for PKI directories and files +redis_pki_owner: redis + +# Group for PKI directories and files +redis_pki_group: redis + +# ============================================================================ +# File Permissions - Customize per security requirements +# ============================================================================ + +# Base PKI directory permissions +redis_pki_base_dir_mode: "0750" + +# Private subdirectory permissions +redis_pki_private_dir_mode: "0700" + +# Server certificate permissions +redis_tls_cert_mode: "0644" + +# Server private key permissions +redis_tls_key_mode: "0600" + +# CA certificate permissions +redis_tls_ca_mode: "0644" + +# DH parameters permissions +redis_tls_dh_params_mode: "0644" + +# Sentinel certificate permissions +redis_sentinel_tls_cert_mode: "0644" + +# Sentinel private key permissions +redis_sentinel_tls_key_mode: "0600" diff --git a/roles/redis/defaults/main/redis.yml b/roles/redis/defaults/main/redis.yml index 6248d4cd..d34243b0 100644 --- a/roles/redis/defaults/main/redis.yml +++ b/roles/redis/defaults/main/redis.yml @@ -50,3 +50,8 @@ redis_user_prometheus_password: prometheus # By default the prometheus user will be enabled. If this is set to false, the prometheus user # will not be created. redis_prometheus_user_enabled: true + +# Redis TLS configuration options +redis_tls_port: "{{ redis_tls_port_default }}" +redis_tls_auth_clients: "no" +redis_tls_protocols: "TLSv1.2 TLSv1.3" diff --git a/roles/redis/tasks/configure-redis-tls.yml b/roles/redis/tasks/configure-redis-tls.yml new file mode 100644 index 00000000..92e4c8b1 --- /dev/null +++ b/roles/redis/tasks/configure-redis-tls.yml @@ -0,0 +1,82 @@ +# Copyright (c) 2024, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create Redis PKI base directory + ansible.builtin.file: + path: "{{ redis_pki_base_dir }}" + state: directory + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_pki_base_dir_mode }}" + tags: + - redis + - redis_certificates + - certificates + +- name: Create Redis private directory + ansible.builtin.file: + path: "{{ redis_pki_private_dir }}" + state: directory + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_pki_private_dir_mode }}" + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis TLS certificate + ansible.builtin.copy: + src: "{{ redis_tls_cert_source }}" + dest: "{{ redis_tls_cert_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_cert_mode }}" + when: redis_tls_cert_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis TLS private key + ansible.builtin.copy: + src: "{{ redis_tls_key_source }}" + dest: "{{ redis_tls_key_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_key_mode }}" + when: redis_tls_key_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis CA bundle + ansible.builtin.copy: + src: "{{ redis_tls_ca_source }}" + dest: "{{ redis_tls_ca_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_ca_mode }}" + when: redis_tls_ca_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates + +- name: Copy Redis DH params + ansible.builtin.copy: + src: "{{ redis_tls_dh_params_source }}" + dest: "{{ redis_tls_dh_params_file }}" + owner: "{{ redis_pki_owner }}" + group: "{{ redis_pki_group }}" + mode: "{{ redis_tls_dh_params_mode }}" + when: redis_tls_dh_params_source | length > 0 + notify: restart redis + tags: + - redis + - redis_certificates + - certificates diff --git a/roles/redis/tasks/main.yml b/roles/redis/tasks/main.yml index 83c1b5d5..ca3a4c59 100644 --- a/roles/redis/tasks/main.yml +++ b/roles/redis/tasks/main.yml @@ -50,6 +50,14 @@ - ansible_selinux.status == "enabled" - redis_install_from_source | bool + - name: Configure Redis TLS + ansible.builtin.include_tasks: configure-redis-tls.yml + when: redis_tls_enabled | bool + tags: + - redis + - redis_certificates + - certificates + - name: Configure Redis/Sentinel tags: configure_redis block: