diff --git a/.gitignore b/.gitignore index a34c8e8e..0131655a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ cspell.json .ansible/* +.claude/* .vscode/* .DS_Store **.DS_Store diff --git a/CLAUDE.md b/CLAUDE.md index cc948fdc..83e1b835 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -45,10 +45,11 @@ Also requires the `jmespath` Python module on the control node. | `certify_redis.yml` | `itential.deployer.certify_redis` | Generate Redis/Sentinel installation certification reports | | `certify_mongodb.yml` | `itential.deployer.certify_mongodb` | Generate MongoDB installation certification reports | | `certify_platform.yml` | `itential.deployer.certify_platform` | Generate Platform installation certification reports | -| `verify.yml` | `itential.deployer.verify` | Pre-install environment verification (OS, HW specs, proxy) for all components | +| `verify.yml` | `itential.deployer.verify` | Pre-install environment verification (OS, HW specs, proxy, required repository connectivity) for all components | | `verify_redis.yml` | `itential.deployer.verify_redis` | Pre-install verification for Redis hosts | | `verify_mongodb.yml` | `itential.deployer.verify_mongodb` | Pre-install verification for MongoDB hosts | | `verify_platform.yml` | `itential.deployer.verify_platform` | Pre-install verification for Platform hosts | +| `verify_gateway.yml` | `itential.deployer.verify_gateway` | Pre-install verification for Gateway hosts | | `download_packages_site.yml` | `itential.deployer.download_packages_site` | Download all packages for offline install (Platform stack + Gateway) | | `download_packages_platform_site.yml` | `itential.deployer.download_packages_platform_site` | Download all packages for Platform stack offline install | | `download_packages_platform.yml` | `itential.deployer.download_packages_platform` | Download Platform packages for offline install | diff --git a/README.md b/README.md index c3ace9d8..15392b35 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,6 @@ the Deployer will either install the required repository or download the package | 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. @@ -248,6 +247,17 @@ If internal YUM repositories are used, refer to the > proxy or other such method to restrict access, this list may not represent the final URLs that are > required. +To verify connectivity to these repositories from the target hosts (excluding the Ansible +Control Node rows, which are the control node's own responsibility), run the `verify` playbook: + +```bash +ansible-playbook itential.deployer.verify -i +``` + +This checks each component's target hosts (`gateway`, `platform*`, `mongodb*`, `redis_master`/ +`redis_replica`) against the rows in the table above. See +[Confirm Requirements](#confirm-requirements) for details. + ### Ports and Networking In a clustered environment where components are installed on more than one host, the following @@ -390,7 +400,7 @@ applicable, IAG). For more information, refer to the [Itential Dependencies] pag nodes. - **SSH Access**: The control node must have SSH connectivity to all managed nodes. -The deployer includes a playbook that can be used to confirm the environment is suitable and ready for installation. +The deployer includes a playbook that can be used to confirm the environment is suitable and ready for installation. This includes checking outbound connectivity from each component's target hosts to the URLs listed in the [Required Public Repositories](#required-public-repositories) table above. ```bash # Verify everything @@ -404,6 +414,9 @@ ansible-playbook -i itential.deployer.verify_mongodb # Verify Platform ansible-playbook -i itential.deployer.verify_platform + +# Verify Gateway +ansible-playbook -i itential.deployer.verify_gateway ``` **ⓘ Note:** diff --git a/playbooks/verify.yml b/playbooks/verify.yml index ab15cb1f..f22d5f8f 100644 --- a/playbooks/verify.yml +++ b/playbooks/verify.yml @@ -10,3 +10,26 @@ - name: Verify Platform Installation import_playbook: itential.deployer.verify_platform + +- name: Verify Gateway Installation + import_playbook: itential.deployer.verify_gateway + +# Each component's own final assert is non-fatal (ignore_errors) so that a failure in one +# component (e.g. verify_redis) doesn't abort the ansible-playbook run before the remaining +# import_playbooks above get a chance to execute -- Ansible stops the whole run, not just the +# current play, when a play ends with 100% of its hosts failed. This final play is the one +# place that actually fails the run, and since nothing runs after it, that's safe to do. +- name: Report Overall Verification Result + hosts: all + gather_facts: false + tasks: + - name: Display per-component verification failures for this host + ansible.builtin.debug: + var: component_validation_errors + when: component_validation_errors is defined and component_validation_errors | length > 0 + + - name: Fail if any verification check failed for this host + ansible.builtin.assert: + that: verification_passed | default(true) + fail_msg: "One or more Itential Deployer verification checks failed for this host. See output above for details." + success_msg: "All Itential Deployer verification checks passed for this host." diff --git a/playbooks/verify_gateway.yml b/playbooks/verify_gateway.yml new file mode 100644 index 00000000..66ffc4fe --- /dev/null +++ b/playbooks/verify_gateway.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2026, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- + +- name: Run Gateway Verification Tasks + hosts: gateway + gather_facts: true + become: true + tasks: + - name: Verify Gateway Installation # noqa run-once + ansible.builtin.import_role: + name: itential.deployer.gateway + tasks_from: verify-gateway diff --git a/roles/common/CLAUDE.md b/roles/common/CLAUDE.md index 524d3479..7c900a78 100644 --- a/roles/common/CLAUDE.md +++ b/roles/common/CLAUDE.md @@ -2,13 +2,17 @@ ## Purpose -Provides shared default variables consumed by all other roles. Has no `main.yml` task entry point — it is imported by playbooks solely to inject its defaults into the variable scope. Also contains the shared `verify-host.yml` task file used by the `verify_*` playbooks. +Provides shared default variables consumed by all other roles. Has no `main.yml` task entry point — it is imported by playbooks solely to inject its defaults into the variable scope. Also contains the shared `verify-host.yml`, `verify-connectivity.yml`, and `verify-results.yml` task files used by the `verify_*` playbooks. Has no `vars/main.yml` — each component role owns its own variables (e.g. required-repository lists live in `roles//vars/main.yml`, not here); `common` only ships `defaults/`. ## Entry Point Tasks -There is no `tasks/main.yml`. The only task file is: +There is no `tasks/main.yml`. The task files are: -- `tasks/verify-host.yml` — imported by `verify_redis`, `verify_mongodb`, and `verify_platform` task files via `tasks_from:`. It is not called by any role's `main.yml`. +- `tasks/verify-host.yml` — imported by `verify-mongodb`, `verify-redis`, `verify-platform`, and `verify-gateway` task files via `tasks_from:`. Checks OS/arch/HW specs/proxy and initializes `validation_errors`. +- `tasks/verify-connectivity.yml` — imported by `verify-mongodb`, `verify-redis`, `verify-platform`, and `verify-gateway` (all four components) via `tasks_from:`. Checks outbound connectivity to the URLs in the caller's own `_required_repositories` list, passed in as `required_repositories`. See "verify-connectivity.yml Logic" below. +- `tasks/verify-results.yml` — imported by `verify-mongodb`, `verify-redis`, `verify-sentinel`, `verify-platform`, and `verify-gateway` (all five verify task files) to print `validation_errors` and assert `cpu_validation`/`memory_validation`/`disk_validation`/`os_validation`/`arch_validation`/`proxy_validation`/`connectivity_validation` all passed. Each lookup is wrapped in `| default({'failed': false})` before the `is failed`/`is not failed` test, since not every caller registers every one of these (e.g. `verify-sentinel.yml` never calls `verify-connectivity.yml`, so `connectivity_validation` is undefined there). The final assert itself uses `ignore_errors: true` and sets a per-host `verification_passed` fact — see "Non-Fatal Verify Design" below. It also expects a `component_name` var from the caller (e.g. `"Redis"`, `"Redis Sentinel"`, `"MongoDB"`, `"Platform"`, `"Gateway"`) and merges this component's `validation_errors` into a per-host `component_validation_errors` dict keyed by that name, so `playbooks/verify.yml`'s final report can show which component failed which check, not just an overall pass/fail. + +None of these task files are called by any role's `main.yml`. ## verify-host.yml Logic @@ -20,15 +24,34 @@ Expects two variables from the caller: | `hw_specs_var_name` | `"redis_hw_specs"` | Name of the hardware specs dict variable to validate against | Execution order: -1. Assert `platform_release` and `env` are defined, `env` in `['dev','test','prod']` +1. Assert `platform_release` and `env` are defined, `env` in `['dev','test','prod']` — these two are the only remaining hard (non-`ignore_errors`) asserts in the file, since they represent inventory misconfiguration rather than a per-host result. See "Non-Fatal Verify Design" below for why that distinction matters. 2. Call `itential.deployer.gather_host_information` module to collect OS/arch/hardware facts -3. Validate OS: RedHat/Rocky/OracleLinux 8 or 9, or Amazon Linux 2023 -4. Validate architecture: `x86_64` or `aarch64` +3. Validate OS: RedHat/Rocky/OracleLinux 8 or 9, or Amazon Linux 2023 (`ignore_errors: true`, registers `os_validation`, collects failures into `validation_errors`) +4. Validate architecture: `x86_64` or `aarch64` (`ignore_errors: true`, registers `arch_validation`, collects failures into `validation_errors`) 5. Validate CPU, RAM, and disk against the `hw_specs_var_name[env]` dict (uses `ignore_errors: true` and collects failures into `validation_errors`) 6. Check for proxy settings in env vars, `/etc/environment`, `/etc/profile.d/` -7. Assert all validations passed +7. Assert all validations passed (this is `verify-results.yml`'s final assert, not part of this file) + +The hardware specs dicts (e.g., `redis_hw_specs`, `platform_hw_specs`, `mongodb_hw_specs`) are defined in `roles//vars/platform-release-.yml` and keyed by `env` value. `gateway_hw_specs` is the exception — it's defined in `roles/gateway/vars/main.yml` instead, since Gateway's hardware requirements are not release-specific. + +`verify-gateway.yml` now calls `common:verify-host` too (all four components — Redis, MongoDB, Platform, Gateway — follow the identical `verify-host` → `verify-connectivity` → `verify-results` sequence). + +## verify-connectivity.yml Logic + +Expects one variable from the caller: + +| Variable | Example | Purpose | +|----------|---------|---------| +| `required_repositories` | `"{{ redis_required_repositories }}"` | The list of repository dicts to check — owned by the calling component's role, not by `common` | + +Each component role defines its own `_required_repositories` list in `roles//vars/main.yml` (`redis_required_repositories`, `mongodb_required_repositories`, `platform_required_repositories`, `gateway_required_repositories`), auto-loaded whenever that role runs. Together they mirror the "Required Public Repositories" table in `README.md`, excluding the Ansible Control Node rows. Each entry has a `url`, `type` (`bare` or `path`), optional `check_target`, and `notes`. Redis Sentinel-only hosts reuse `redis_required_repositories` (`verify-sentinel.yml`) since Sentinel is installed from the same Redis source/package. + +Execution order: +1. Check baseline reachability of every entry's bare `url` via `ansible.builtin.uri` — any real HTTP status (100-599) counts as reachable; only a connection-level failure (DNS/TCP/TLS/timeout, which `fetch_url` reports as `status: -1`) counts as unreachable. Append failures to `validation_errors`. +2. For entries with `type: path` that passed step 1, request the specific `check_target` resource and expect an actual `[200, 301, 302]` response. Append failures to `validation_errors`. +3. Assert both checks passed (`ignore_errors: true`, registers `connectivity_validation`), following the same pattern as `cpu_validation`/`memory_validation`/etc. in `verify-host.yml`. -The hardware specs dicts (e.g., `redis_hw_specs`, `platform_hw_specs`, `mongodb_hw_specs`) are defined in `roles//vars/platform-release-.yml` and keyed by `env` value. +Called from `verify-mongodb.yml`, `verify-redis.yml`, `verify-sentinel.yml`, `verify-platform.yml`, and `verify-gateway.yml`. ## Key Variables @@ -41,6 +64,12 @@ The hardware specs dicts (e.g., `redis_hw_specs`, `platform_hw_specs`, `mongodb_ | `offline_control_node_root` | `{{ playbook_dir }}/files` | `defaults/main/offline.yml` | Root on control node where offline packages are staged. | | `offline_itential_packages_path` | `itential_packages/{{ ansible_distribution \| lower }}_{{ ansible_distribution_major_version }}` | `defaults/main/offline.yml` | OS-specific subdirectory under the offline roots. | +## Non-Fatal Verify Design + +`playbooks/verify.yml` chains `verify_redis`/`verify_mongodb`/`verify_platform`/`verify_gateway` together via `import_playbook`. Ansible aborts the *entire* `ansible-playbook` run (not just the current play) the moment a play ends with 100% of its hosts failed — this happens even for later plays targeting completely unrelated hosts. So every task in the verify chain that can fail on a genuine per-host/per-component result (OS/arch checks, the final combined assert in `verify-results.yml`, Gateway's own final assert) uses `ignore_errors: true` + `register:` instead of failing hard, and the final assert in each also sets a per-host `verification_passed` fact and merges `validation_errors` into a per-host `component_validation_errors` dict (keyed by `component_name`, via `combine()` so a later-running component can't erase an earlier one's failures on the same host). `playbooks/verify.yml` ends with one extra `hosts: all` play ("Report Overall Verification Result") that prints `component_validation_errors` (when non-empty) and then asserts `verification_passed | default(true)` for real (no `ignore_errors`) — since nothing runs after it, failing there is safe and is what actually gives the overall run a non-zero exit code, while still letting every component's checks run against every host regardless of earlier failures. + +The two asserts in `verify-host.yml` that check `platform_release`/`env` are deliberately left hard-failing — they indicate the inventory itself is misconfigured (not a specific host failing a real check), typically affects every host identically, and there's little value in continuing past it. + ## Dependencies / Assumptions - The `common` role has no task dependencies. @@ -52,3 +81,6 @@ The hardware specs dicts (e.g., `redis_hw_specs`, `platform_hw_specs`, `mongodb_ - `offline_install_enabled` defaults to `false` here but the `download_packages_*` playbooks override it to `false` explicitly at the play level — the download playbooks always run online even when deploying to offline targets. - The `common_itential_release_file` check in the `os` role skips OS package installation if the file already exists, making the `os` role effectively idempotent for re-runs. - `verify-host.yml` uses `ignore_errors: true` on individual assertions and collects them, then does a final combined assert. This means a failing host will show all failures rather than stopping at the first. +- `verify-connectivity.yml`'s baseline check deliberately does NOT use `ansible.builtin.uri`'s `status_code: -1` — that is not a wildcard; `status_code` is a literal list of acceptable HTTP codes (default `[200]`). Instead it passes `status_code: "{{ range(100, 600) | list }}"` so any real HTTP response passes, and relies on `fetch_url` setting `status: -1` (which is never in that range) to detect genuine connection failures. +- `verify-connectivity.yml` deliberately avoids requiring the `git` binary (e.g. via `git ls-remote`) for the `gitlab.com`/`github.com` rows, since verification runs pre-install and `git` may not be installed on the target yet. It uses plain HTTPS `check_target` requests instead (a real gitlab.com group page, and a `codeload.github.com` tarball URL that also exercises the `github.com` → `codeload.github.com` redirect). +- `verify-results.yml` previously asserted on `platform_validation is not failed`, but nothing ever registered a variable by that name (Platform's own TLS checks register `platform_tls_dir_validation`/`platform_tls_contents_validation` instead) — this made `verify_redis`/`verify_mongodb`/`verify_platform` fail with "the 'failed' test expects a dictionary" on an undefined variable. It was replaced with `connectivity_validation is not failed`. diff --git a/roles/common/tasks/verify-connectivity.yml b/roles/common/tasks/verify-connectivity.yml new file mode 100644 index 00000000..6257b5ae --- /dev/null +++ b/roles/common/tasks/verify-connectivity.yml @@ -0,0 +1,78 @@ +# Copyright (c) 2026, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +# Verifies outbound connectivity to the public repositories a component needs, as listed in +# the "Required Public Repositories" table in README.md (excluding the Ansible Control Node +# rows, which are the control node's responsibility, not a target host's). +# +# Expects one variable from the caller: +# - required_repositories: list of repository dicts -- each component owns its own list in +# roles//vars/main.yml (e.g. redis_required_repositories), with url, type +# (bare|path), optional check_target, and notes. +# +# Appends a message to validation_errors for every failure, then sets connectivity_validation +# via an ignore_errors assert, following the same pattern as verify-host.yml. + +- name: Check baseline reachability of required repositories + ansible.builtin.uri: + url: "{{ item.url }}" + method: GET + # Accept any real HTTP status code (100-599) as "reachable" -- fetch_url only returns + # status -1 when the request never got a response at all (DNS/TCP/TLS/timeout failure). + status_code: "{{ range(100, 600) | list }}" + validate_certs: true + timeout: 10 + register: repository_reachability + loop: "{{ required_repositories }}" + loop_control: + label: "{{ item.url }}" + ignore_errors: true + +- name: Add unreachable repository errors to list + ansible.builtin.set_fact: + validation_errors: "{{ validation_errors + ['Connectivity: ' ~ item.item.url ~ ' (' ~ + item.item.notes ~ ') is unreachable: ' ~ (item.msg | default('unknown error'))] }}" + loop: "{{ repository_reachability.results }}" + loop_control: + label: "{{ item.item.url }}" + when: item is failed + +- name: Identify repositories needing a resource-specific check + ansible.builtin.set_fact: + repositories_needing_path_check: "{{ repository_reachability.results + | rejectattr('failed') + | map(attribute='item') + | selectattr('type', 'equalto', 'path') + | list }}" + +- name: Check resource-specific access for path-type repositories + ansible.builtin.uri: + url: "{{ item.check_target }}" + method: GET + status_code: [200, 301, 302] + validate_certs: true + timeout: 10 + register: repository_path_check + loop: "{{ repositories_needing_path_check }}" + loop_control: + label: "{{ item.check_target }}" + ignore_errors: true + +- name: Add resource-specific check failures to list + ansible.builtin.set_fact: + validation_errors: "{{ validation_errors + ['Connectivity: ' ~ item.item.check_target ~ ' (' ~ + item.item.notes ~ ') did not return a successful response'] }}" + loop: "{{ repository_path_check.results | default([]) }}" + loop_control: + label: "{{ item.item.check_target }}" + when: item is failed + +- name: Verify that repository connectivity checks passed + ansible.builtin.assert: + that: + - repository_reachability.results | selectattr('failed') | list | length == 0 + - repository_path_check.results | default([]) | selectattr('failed') | list | length == 0 + fail_msg: "One or more required repository connectivity checks failed! See above." + quiet: true + ignore_errors: true + register: connectivity_validation diff --git a/roles/common/tasks/verify-host.yml b/roles/common/tasks/verify-host.yml index 1dfce956..a5fddba2 100644 --- a/roles/common/tasks/verify-host.yml +++ b/roles/common/tasks/verify-host.yml @@ -30,6 +30,10 @@ ansible.builtin.set_fact: os: "{{ host_info.os }}" +- name: Initialize validation errors list + ansible.builtin.set_fact: + validation_errors: [] + # OS and Architecture validation - name: Check OS compatibility ansible.builtin.set_fact: @@ -47,6 +51,13 @@ fail_msg: "{{ os.distribution }} {{ os.distribution_version }} is not a supported OS!" success_msg: "OS validation passed!" quiet: true + ignore_errors: true + register: os_validation + +- name: Add OS error to list + ansible.builtin.set_fact: + validation_errors: "{{ validation_errors + ['OS: ' ~ os.distribution ~ ' ' ~ os.distribution_version ~ ' is not a supported OS'] }}" + when: os_validation is failed - name: Check architecture compatibility ansible.builtin.set_fact: @@ -58,10 +69,13 @@ fail_msg: "{{ os.architecture }} is not a supported architecture!" success_msg: "Architecture validation passed!" quiet: true + ignore_errors: true + register: arch_validation -- name: Initialize validation errors list +- name: Add Architecture error to list ansible.builtin.set_fact: - validation_errors: [] + validation_errors: "{{ validation_errors + ['Architecture: ' ~ os.architecture ~ ' is not a supported architecture'] }}" + when: arch_validation is failed - name: Get root partition size ansible.builtin.set_fact: diff --git a/roles/common/tasks/verify-results.yml b/roles/common/tasks/verify-results.yml index 4f5d25ee..203c0c35 100644 --- a/roles/common/tasks/verify-results.yml +++ b/roles/common/tasks/verify-results.yml @@ -2,20 +2,55 @@ # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) --- +# Expects one variable from the caller: +# - component_name: label used to group this component's errors in component_validation_errors +# for playbooks/verify.yml's final report, e.g. "Redis", "Redis Sentinel", "MongoDB", "Platform" +# +# Not every caller registers every one of these (e.g. verify-sentinel.yml skips +# verify-connectivity.yml entirely), so each lookup is defaulted to a non-failed result +# before the "failed" test runs -- that test raises an error on a plain undefined value. # Display results - name: Display failed validation results ansible.builtin.debug: msg: "{{ validation_errors }}" - when: cpu_validation is failed or memory_validation is failed or disk_validation is failed or platform_validation is failed + when: >- + (cpu_validation | default({'failed': false})) is failed or + (memory_validation | default({'failed': false})) is failed or + (disk_validation | default({'failed': false})) is failed or + (os_validation | default({'failed': false})) is failed or + (arch_validation | default({'failed': false})) is failed or + (connectivity_validation | default({'failed': false})) is failed # Assert that none of the tests failed - name: Verify that all tests passed ansible.builtin.assert: that: - - "cpu_validation is not failed" - - "memory_validation is not failed" - - "disk_validation is not failed" - - "proxy_validation is not failed" - - "platform_validation is not failed" + - "(cpu_validation | default({'failed': false})) is not failed" + - "(memory_validation | default({'failed': false})) is not failed" + - "(disk_validation | default({'failed': false})) is not failed" + - "(os_validation | default({'failed': false})) is not failed" + - "(arch_validation | default({'failed': false})) is not failed" + - "(proxy_validation | default({'failed': false})) is not failed" + - "(connectivity_validation | default({'failed': false})) is not failed" fail_msg: "See above, assertions not passed! ✗" success_msg: "All assertions passed! ✓" + ignore_errors: true + register: component_verification + +# Recorded per-host so playbooks/verify.yml can do one final, non-fatal-until-the-end +# assert after every component has been checked, instead of aborting the whole +# ansible-playbook run the moment one component's checks fail on a host. ANDed with any +# prior value (default true) rather than overwritten -- a host can belong to more than one +# component group (e.g. an all-in-one host), and a later component passing must not erase +# an earlier component's failure on the same host. +- name: Record overall verification result for this host + ansible.builtin.set_fact: + verification_passed: "{{ (verification_passed | default(true)) and (component_verification is not failed) }}" + +# Keyed by component_name and merged via combine() rather than overwritten, since a host can +# be checked by more than one component (e.g. an all-in-one host) -- lets playbooks/verify.yml's +# final report show exactly which checks failed for which component, not just a pass/fail flag. +- name: Record this component's validation errors for the final report + ansible.builtin.set_fact: + component_validation_errors: "{{ (component_validation_errors | default({})) | combine({component_name: validation_errors}) }}" + when: validation_errors | length > 0 diff --git a/roles/gateway/CLAUDE.md b/roles/gateway/CLAUDE.md index 4205eafa..8a0da52a 100644 --- a/roles/gateway/CLAUDE.md +++ b/roles/gateway/CLAUDE.md @@ -33,6 +33,10 @@ Installs and configures Itential Automation Gateway (IAG). Handles Python virtua 25. Remove temp working directory 26. `always` block: remove build packages that were installed; assert service is active +## Other Entry Points + +- `tasks/verify-gateway.yml` (invoked by `playbooks/verify_gateway.yml`, tags_from `verify-gateway`) — now follows the same three-step pattern as `verify-redis.yml`/`verify-mongodb.yml`/`verify-platform.yml`: `common:verify-host` (OS/arch/CPU/RAM/disk/proxy, against `gateway_hw_specs`), `common:verify-connectivity` (`gateway_required_repositories`, passed as `required_repositories`), then `common:verify-results` (combined assert + reporting). Passes `component_name: "Gateway"` to each. `verify-results.yml`'s final assert uses `ignore_errors: true` and sets a per-host `verification_passed` fact and merges this component's errors into `component_validation_errors`, for the same reason described in `roles/common/CLAUDE.md`'s "Non-Fatal Verify Design" section — so that a Gateway failure doesn't abort `playbooks/verify.yml` before the other imported verify playbooks run. + ## Key Variables ### gateway.yml defaults @@ -94,6 +98,17 @@ Installs and configures Itential Automation Gateway (IAG). Handles Python virtua | `gateway_offline_control_node_wheels_dir` | `{{ gateway_control_node_root }}/wheels` | Wheels source dir (control) | | `gateway_offline_control_node_collections_dir` | `{{ gateway_control_node_root }}/collections` | Collections source dir (control) | +### vars/main.yml + +| Variable | Purpose | +|----------|---------| +| `gateway_required_repositories` | List of repository dicts (`url`, `type`, optional `check_target`, `notes`) checked by `verify-gateway.yml` via `common:verify-connectivity`. Mirrors the Gateway rows of the README "Required Public Repositories" table. Previously this list lived in `roles/common/vars/main.yml`; `common` no longer has a `vars/` directory. | +| `gateway_hw_specs` | CPU/RAM/disk requirements per `env` (`dev`/`test`/`prod`), checked by `verify-gateway.yml` via `common:verify-host`. Unlike `redis_hw_specs`/`mongodb_hw_specs`/`platform_hw_specs`, this is defined in `vars/main.yml` rather than a `vars/platform-release-.yml` file, since Gateway's hardware requirements are not release-specific. | + +Hardware specs for `verify` playbook (`gateway_hw_specs`): +- dev: 4 CPU, 16 GB RAM, 10 GB disk +- test/prod: 16 CPU, 32 GB RAM, 50 GB disk + ## TLS Configuration HTTPS is **enabled by default** (`gateway_https_enabled: true`, `gateway_pki_copy_certs: true`). diff --git a/roles/gateway/tasks/update-release-file.yml b/roles/gateway/tasks/update-release-file.yml index c387bb6b..26ae1907 100644 --- a/roles/gateway/tasks/update-release-file.yml +++ b/roles/gateway/tasks/update-release-file.yml @@ -4,6 +4,7 @@ - name: Update release file with IAG version ansible.builtin.lineinfile: path: "{{ common_itential_release_file }}" + regexp: "^GATEWAY=" line: "GATEWAY={{ gateway_release }}" mode: "0666" create: true @@ -18,6 +19,7 @@ - name: Update release file with Python version ansible.builtin.lineinfile: path: "{{ common_itential_release_file }}" + regexp: "^PYTHON=" line: "PYTHON={{ python_installed_version.stdout }}" mode: "0666" create: true @@ -32,6 +34,7 @@ - name: Update release file with Pip version ansible.builtin.lineinfile: path: "{{ common_itential_release_file }}" + regexp: "^PIP=" line: "PIP={{ pip_installed_version.stdout }}" mode: "0666" create: true @@ -53,6 +56,7 @@ - name: Update release file with Ansible version ansible.builtin.lineinfile: path: "{{ common_itential_release_file }}" + regexp: "^ANSIBLE=" line: "ANSIBLE={{ gateway_ansible_version }}" mode: "0666" create: true @@ -61,6 +65,7 @@ - name: Update release file with Nornir version ansible.builtin.lineinfile: path: "{{ common_itential_release_file }}" + regexp: "^NORNIR=" line: "NORNIR=true" mode: "0666" create: true diff --git a/roles/gateway/tasks/verify-gateway.yml b/roles/gateway/tasks/verify-gateway.yml new file mode 100644 index 00000000..d55f28e8 --- /dev/null +++ b/roles/gateway/tasks/verify-gateway.yml @@ -0,0 +1,24 @@ +# Copyright (c) 2026, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Verify Gateway host requirements + ansible.builtin.include_role: + name: common + tasks_from: verify-host + vars: + component_name: "Gateway" + hw_specs_var_name: "gateway_hw_specs" + +- name: Verify connectivity to required public repositories + ansible.builtin.include_role: + name: common + tasks_from: verify-connectivity + vars: + required_repositories: "{{ gateway_required_repositories }}" + +- name: Report Gateway results + ansible.builtin.include_role: + name: common + tasks_from: verify-results + vars: + component_name: "Gateway" diff --git a/roles/gateway/vars/main.yml b/roles/gateway/vars/main.yml new file mode 100644 index 00000000..9b514e22 --- /dev/null +++ b/roles/gateway/vars/main.yml @@ -0,0 +1,29 @@ +# Copyright (c) 2026, Itential, Inc +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +gateway_hw_specs: + "dev": + "cpu_count": 4 + "ram_size": 16 + "disk_size": 10 + "test": + "cpu_count": 16 + "ram_size": 32 + "disk_size": 50 + "prod": + "cpu_count": 16 + "ram_size": 32 + "disk_size": 50 + +# Public repositories required for installing Itential Gateway, checked by the verify_gateway +# playbook. Mirrors the Gateway rows of the "Required Public Repositories" table in README.md. +gateway_required_repositories: + - url: "https://registry.aws.itential.com" + type: bare + notes: "Itential packages" + - url: "https://galaxy.ansible.com" + type: bare + notes: "Community Ansible collections" + - url: "https://pypi.org" + type: bare + notes: "Python modules" diff --git a/roles/mongodb/CLAUDE.md b/roles/mongodb/CLAUDE.md index cddbad92..9832131a 100644 --- a/roles/mongodb/CLAUDE.md +++ b/roles/mongodb/CLAUDE.md @@ -104,6 +104,12 @@ Conditionally includes (in order): | `mongodb_tls_cert_src` | `{{ mongodb_pki_src_dir }}/{{ mongodb_tls_server_cert_file }}` | Cert source | | `mongodb_tls_ca_src` | `{{ mongodb_pki_src_dir }}/{{ mongodb_tls_ca_file }}` | CA source | +### vars/main.yml + +| Variable | Purpose | +|----------|---------| +| `mongodb_required_repositories` | List of repository dicts (`url`, `type`, optional `check_target`, `notes`) checked by `verify-mongodb.yml` via `common:verify-connectivity`. Mirrors the MongoDB rows of the README "Required Public Repositories" table. | + ## TLS Configuration TLS is **enabled by default** (`mongodb_tls_enabled: true`, `mongodb_tls_copy_certs: true`). diff --git a/roles/mongodb/tasks/verify-mongodb.yml b/roles/mongodb/tasks/verify-mongodb.yml index aebf00a5..ba7a2ed5 100644 --- a/roles/mongodb/tasks/verify-mongodb.yml +++ b/roles/mongodb/tasks/verify-mongodb.yml @@ -20,7 +20,16 @@ # mongodb specific verification tasks go here... -- name: Verify Platform host requirements +- name: Verify connectivity to required public repositories + ansible.builtin.include_role: + name: common + tasks_from: verify-connectivity + vars: + required_repositories: "{{ mongodb_required_repositories }}" + +- name: Report MongoDB results ansible.builtin.include_role: name: common tasks_from: verify-results + vars: + component_name: "MongoDB" diff --git a/roles/mongodb/vars/main.yml b/roles/mongodb/vars/main.yml index 3aa723a3..99ecf144 100644 --- a/roles/mongodb/vars/main.yml +++ b/roles/mongodb/vars/main.yml @@ -6,3 +6,23 @@ mongodb_port_default: 27017 # The name of the mongo replica set mongodb_replset_name_default: rs0 + +# Public repositories required for installing MongoDB, checked by the verify_mongodb playbook. +# Mirrors the MongoDB rows of the "Required Public Repositories" table in README.md. +mongodb_required_repositories: + - url: "https://repo.mongodb.org" + type: path + check_target: "https://repo.mongodb.org/yum/redhat/" + notes: "MongoDB YUM RPMs" + - url: "https://www.mongodb.org" + type: bare + notes: "MongoDB YUM RPMs" + - url: "https://pgp.mongodb.org" + type: bare + notes: "MongoDB YUM repository GPG Key" + - url: "https://pgp.mongodb.com" + type: bare + notes: "MongoDB YUM repository GPG Key" + - url: "https://pypi.org" + type: bare + notes: "Python modules" diff --git a/roles/platform/CLAUDE.md b/roles/platform/CLAUDE.md index c64d199f..efd4d43e 100644 --- a/roles/platform/CLAUDE.md +++ b/roles/platform/CLAUDE.md @@ -168,6 +168,12 @@ Installs and configures Itential Platform (IAP). Handles OS user/directory setup | `platform_log_max_file_size` | `1048576` | Max log file size (bytes; ~1 MB) | | `platform_log_filename` | `platform.log` | Primary log filename | +### vars/main.yml + +| Variable | Purpose | +|----------|---------| +| `platform_required_repositories` | List of repository dicts (`url`, `type`, optional `check_target`, `notes`) checked by `verify-platform.yml` via `common:verify-connectivity`. Mirrors the Platform rows of the README "Required Public Repositories" table. | + ## TLS Configuration HTTPS and MongoDB client TLS are both **enabled by default** (copy-certs flags default to `true`). diff --git a/roles/platform/tasks/verify-platform.yml b/roles/platform/tasks/verify-platform.yml index e4204aaa..cbf238d7 100644 --- a/roles/platform/tasks/verify-platform.yml +++ b/roles/platform/tasks/verify-platform.yml @@ -19,6 +19,13 @@ hw_specs_var_name: "platform_hw_specs" # platform specific verification tasks go here... +- name: Verify connectivity to required public repositories + ansible.builtin.include_role: + name: common + tasks_from: verify-connectivity + vars: + required_repositories: "{{ platform_required_repositories }}" + - name: Verify TLS certs for platform webserver are defined ansible.builtin.assert: that: platform_https_pki_src_dir is defined and platform_https_pki_src_dir | length > 0 @@ -62,7 +69,9 @@ - platform_webserver_https_enabled | bool - platform_tls_dir_validation is failed or platform_tls_contents_validation is failed -- name: Verify Platform host requirements +- name: Report Platform results ansible.builtin.include_role: name: common tasks_from: verify-results + vars: + component_name: "Platform" diff --git a/roles/platform/vars/main.yml b/roles/platform/vars/main.yml index 66ccb020..65175e13 100644 --- a/roles/platform/vars/main.yml +++ b/roles/platform/vars/main.yml @@ -19,3 +19,20 @@ 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}" + +# Public repositories required for installing Itential Platform, checked by the verify_platform +# playbook. Mirrors the Platform rows of the "Required Public Repositories" table in README.md. +platform_required_repositories: + - url: "https://registry.aws.itential.com" + type: bare + notes: "Itential packages" + - url: "https://registry.npmjs.org" + type: bare + notes: "Core NPM packages" + - url: "https://pypi.org" + type: bare + notes: "Python modules" + - url: "https://gitlab.com" + type: path + check_target: "https://gitlab.com/itentialopensource/adapters" + notes: "Platform Opensource Adapters NodeJS source repository" diff --git a/roles/redis/CLAUDE.md b/roles/redis/CLAUDE.md index 1152ed38..594ae156 100644 --- a/roles/redis/CLAUDE.md +++ b/roles/redis/CLAUDE.md @@ -102,6 +102,12 @@ Installs and configures Redis and Redis Sentinel for use with Itential Platform. | All `_dest` vars | Built from base dir + filename | Destination paths on target | | All `_src` vars | Built from `redis_pki_src_dir` + filename | Source paths on control node | +### vars/main.yml + +| Variable | Purpose | +|----------|---------| +| `redis_required_repositories` | List of repository dicts (`url`, `type`, optional `check_target`, `notes`) checked by `verify-redis.yml` and `verify-sentinel.yml` via `common:verify-connectivity`. Mirrors the Redis rows of the README "Required Public Repositories" table. | + ## TLS Configuration TLS is **disabled by default** (`redis_tls_enabled: false`). diff --git a/roles/redis/tasks/verify-redis.yml b/roles/redis/tasks/verify-redis.yml index 09391d2e..92c8e7b2 100644 --- a/roles/redis/tasks/verify-redis.yml +++ b/roles/redis/tasks/verify-redis.yml @@ -20,7 +20,16 @@ # redis specific verification tasks go here... -- name: Verify Platform host requirements +- name: Verify connectivity to required public repositories + ansible.builtin.include_role: + name: common + tasks_from: verify-connectivity + vars: + required_repositories: "{{ redis_required_repositories }}" + +- name: Report Redis results ansible.builtin.include_role: name: common tasks_from: verify-results + vars: + component_name: "Redis" diff --git a/roles/redis/tasks/verify-sentinel.yml b/roles/redis/tasks/verify-sentinel.yml index 0baf93c3..008d2b09 100644 --- a/roles/redis/tasks/verify-sentinel.yml +++ b/roles/redis/tasks/verify-sentinel.yml @@ -20,7 +20,16 @@ # redis sentinel specific verification tasks go here... -- name: Verify Platform host requirements +- name: Verify connectivity to required public repositories + ansible.builtin.include_role: + name: common + tasks_from: verify-connectivity + vars: + required_repositories: "{{ redis_required_repositories }}" + +- name: Report Redis Sentinel results ansible.builtin.include_role: name: common tasks_from: verify-results + vars: + component_name: "Redis Sentinel" diff --git a/roles/redis/vars/main.yml b/roles/redis/vars/main.yml index 4ae3075f..76c408aa 100644 --- a/roles/redis/vars/main.yml +++ b/roles/redis/vars/main.yml @@ -11,3 +11,23 @@ redis_data_dir_default: /var/lib/redis # Default ports redis_port_default: 6379 redis_sentinel_port_default: 26379 + +# Public repositories required for installing Redis (and Redis Sentinel, which is installed +# from the same source/package), checked by the verify_redis playbook. Mirrors the Redis rows +# of the "Required Public Repositories" table in README.md. +redis_required_repositories: + - url: "http://rpms.remirepo.net" + type: path + check_target: "http://rpms.remirepo.net/enterprise/" + notes: "Redis YUM RPMs" + - url: "https://dl.fedoraproject.org" + type: path + check_target: "https://dl.fedoraproject.org/pub/epel/" + notes: "EPEL YUM RPMs" + - url: "https://github.com" + type: path + check_target: "https://codeload.github.com/redis/redis/tar.gz/refs/heads/unstable" + notes: "Redis source packages" + - url: "https://codeload.github.com" + type: bare + notes: "Redis source packages"