Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,23 @@ The main purpose of this collections are to:
loading local secrets files into VP secrets stores.

2. Help manage imperative and other utility functions of the cluster

## Clustergroup discovery

The **`clustergroup_discovery`** role lists **main and managed clustergroup value stems** for a Validated Patterns checkout (from **`values-global.yaml`** and **`clusterGroup.managedClusterGroups`** in the main **`values-<main>.yaml|yml`**), and which local **`values-<stem>.yaml|yml`** files exist.

- **`playbooks/list_clustergroups.yml`** — prints discovery facts (stems, load order, file paths).
- **`playbooks/parse_clustergroup_values.yml`** — same, plus optional YAML parse into **`clustergroup_documents`**.

See **`roles/clustergroup_discovery/README.md`** for variables and behavior.

## Pattern repository directory (`pattern_dir`)

Playbooks need the path to your pattern Git checkout (where **`values-global.yaml`**
and related files live). Resolution order: extra var **`pattern_dir`**, environment
variable **`PATTERN_DIR`**, then **`PWD`** and **`pwd`**.

When running from the imperative container or another fixed working directory,
pass the repository root explicitly, for example **`-e pattern_dir=/git/repo`** (or add
equivalent extra vars via **`clusterGroup.imperative.extraPlaybookArgs`** in the
clustergroup chart).
21 changes: 21 additions & 0 deletions playbooks/list_clustergroups.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
# Discover values-<clustergroup>.yaml|yml under pattern_dir.
# Resolves pattern_dir like pattern_settings (extra var pattern_dir, env PATTERN_DIR, cwd).
- name: List pattern clustergroup value stems
hosts: localhost
connection: local
gather_facts: false
become: false
roles:
- pattern_settings
- role: clustergroup_discovery
tasks:
- name: Report clustergroup discovery
ansible.builtin.debug:
msg:
pattern_dir: "{{ pattern_dir }}"
main_clustergroup: "{{ main_clustergroup }}"
managed_clustergroup_names: "{{ managed_clustergroup_names }}"
clustergroup_names: "{{ clustergroup_names }}"
clustergroup_load_order: "{{ clustergroup_load_order }}"
clustergroup_file_entries: "{{ clustergroup_file_entries }}"
22 changes: 22 additions & 0 deletions playbooks/parse_clustergroup_values.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
# Parse every top-level values-<clustergroup>.yaml|yml into clustergroup_documents (stem -> root).
# Use for migration tooling or inspection; other roles can include the same discovery logic.
- name: Parse pattern clustergroup values files
hosts: localhost
connection: local
gather_facts: false
become: false
roles:
- pattern_settings
- role: clustergroup_discovery
vars:
clustergroup_discovery_parse_documents: true
tasks:
- name: Summarize parsed clustergroup documents
ansible.builtin.debug:
msg:
pattern_dir: "{{ pattern_dir }}"
main_clustergroup: "{{ main_clustergroup }}"
managed_clustergroup_names: "{{ managed_clustergroup_names }}"
stems_parsed: "{{ clustergroup_documents | default({}) | dict2items | map(attribute='key') | sort | list }}"
document_count: "{{ clustergroup_documents | default({}) | length }}"
27 changes: 27 additions & 0 deletions roles/clustergroup_discovery/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# clustergroup_discovery

Ansible role that lists **which clustergroup value stems are in use** for a Validated Patterns checkout, without scanning every `values-*.yaml` on disk.

## Behavior

1. Resolve **`pattern_dir`** the same way as `pattern_settings` (extra var, `PATTERN_DIR`, then `PWD` / `pwd`).
2. Read **`main.clusterGroupName`** from `values-global.yaml` under `pattern_dir` (or use `main_clustergroup` / `main_clustergroupname` if the play already set them).
3. Load **`values-<main>.yaml`** or **`values-<main>.yml`** and read **`clusterGroup.managedClusterGroups`**. For each entry, the managed name is **`value.name`** if set, otherwise the **YAML key** (same convention as the clustergroup chart for managed cluster groups).
4. Expose facts:
- **`managed_clustergroup_names`** — sorted unique managed names
- **`clustergroup_load_order`** — `[main, …managed]` (main first; used when merging so later stems override duplicate `applications` keys)
- **`clustergroup_names`** — sorted list of all stems (main + managed)
- **`clustergroup_file_entries`** — `{name, path}` only for stems where a local `values-<stem>.yaml|yml` exists

Optional: set **`clustergroup_discovery_parse_documents: true`** to fill **`clustergroup_documents`** (`<stem>` → parsed YAML root) for each file in `clustergroup_file_entries`.

## Playbooks

- `playbooks/list_clustergroups.yml` — runs `pattern_settings` + this role and prints the facts above.
- `playbooks/parse_clustergroup_values.yml` — same with parsing enabled.

Requires `ANSIBLE_ROLES_PATH` (or collection layout) so `pattern_settings` and this role resolve.

## Using this role from other Ansible

Include **`clustergroup_discovery`** (after **`pattern_settings`** or an equivalent that sets **`pattern_dir`** / **`main_clustergroup`**) whenever you need **`clustergroup_load_order`**, **`clustergroup_file_entries`**, or parsed **`clustergroup_documents`** before loading clusterGroup values per stem.
3 changes: 3 additions & 0 deletions roles/clustergroup_discovery/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
# When true, slurp and parse each resolved clustergroup file into clustergroup_documents (stem -> root mapping)
clustergroup_discovery_parse_documents: false
12 changes: 12 additions & 0 deletions roles/clustergroup_discovery/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
galaxy_info:
author: rhvp
description: >-
Resolve main clustergroup from values-global, read managedClusterGroups from the main
values file, then optionally parse existing values-<stem> files for those stems.
license: Apache-2.0
min_ansible_version: "2.14"
galaxy_tags:
- openshift
- gitops
dependencies: []
118 changes: 118 additions & 0 deletions roles/clustergroup_discovery/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
# Discover clustergroups in use: main from values-global, managed from main file's clusterGroup.managedClusterGroups.
# Sets: clustergroup_names (sorted stems), managed_clustergroup_names (sorted, excludes main),
# clustergroup_load_order (main first, then managed sorted — later stems override duplicate keys when merging),
# clustergroup_file_entries ({name, path} only when values-<stem>.yaml|yml exists),
# clustergroup_documents (optional, stem -> parsed YAML root).

- name: Resolve pattern_dir for clustergroup discovery
ansible.builtin.include_tasks: ../pattern_settings/tasks/resolve_overrides.yml
when: (pattern_dir | default('', true) | string | trim | length) == 0

- name: Fail when pattern_dir is empty after resolve
ansible.builtin.fail:
msg: >-
pattern_dir is required (extra var pattern_dir, env PATTERN_DIR, or cwd with values-global.yaml).
when: (pattern_dir | default('', true) | string | trim | length) == 0

- name: Resolve main clustergroup stem from facts or values-global.yaml
ansible.builtin.set_fact:
_clustergroup_discovery_main_stem: >-
{{
(
(main_clustergroupname | default(main_clustergroup | default('', true), true) | string | trim | length) > 0
)
| ternary(
main_clustergroupname | default(main_clustergroup, true) | string | trim,
(
lookup('file', (pattern_dir | string | trim) ~ '/values-global.yaml')
| from_yaml
).main.clusterGroupName | string | trim
)
}}

- name: Fail when main clusterGroupName cannot be resolved
ansible.builtin.fail:
msg: >-
Could not resolve main clustergroup (values-global.yaml missing .main.clusterGroupName or empty).
when: (_clustergroup_discovery_main_stem | string | trim | length) == 0

- name: Stat main clustergroup values file (yaml)
ansible.builtin.stat:
path: "{{ pattern_dir | string | trim }}/values-{{ _clustergroup_discovery_main_stem }}.yaml"
register: _clustergroup_discovery_main_stat_yaml

- name: Stat main clustergroup values file (yml)
ansible.builtin.stat:
path: "{{ pattern_dir | string | trim }}/values-{{ _clustergroup_discovery_main_stem }}.yml"
register: _clustergroup_discovery_main_stat_yml
when: not (_clustergroup_discovery_main_stat_yaml.stat.exists | default(false))

- name: Set path to main clustergroup values file when present
ansible.builtin.set_fact:
_clustergroup_main_values_path: "{{ pattern_dir | string | trim }}/values-{{ _clustergroup_discovery_main_stem }}.yaml"
when: _clustergroup_discovery_main_stat_yaml.stat.exists | default(false)

- name: Set path to main clustergroup values file when only yml exists
ansible.builtin.set_fact:
_clustergroup_main_values_path: "{{ pattern_dir | string | trim }}/values-{{ _clustergroup_discovery_main_stem }}.yml"
when:
- _clustergroup_main_values_path is not defined
- _clustergroup_discovery_main_stat_yml is defined
- _clustergroup_discovery_main_stat_yml.stat.exists | default(false)

- name: Load parsed root from main clustergroup values file
ansible.builtin.set_fact:
_clustergroup_main_root: "{{ lookup('file', _clustergroup_main_values_path) | from_yaml }}"
when: _clustergroup_main_values_path is defined

- name: Default empty main clustergroup root when file is absent
ansible.builtin.set_fact:
_clustergroup_main_root: {}
when: _clustergroup_main_values_path is not defined

- name: Collect managed clustergroup names from main file managedClusterGroups
ansible.builtin.set_fact:
managed_clustergroup_names: "{{ managed_clustergroup_names | default([]) + [_cgd_mcg_name] }}"
vars:
_cgd_mcg_name: "{{ (item.value.name | default(item.key, true)) | string | trim }}"
loop: "{{ (_clustergroup_main_root.clusterGroup | default({})).managedClusterGroups | default({}) | dict2items }}"
loop_control:
label: "{{ _cgd_mcg_name }}"
when:
- _clustergroup_main_root is mapping
- (_clustergroup_main_root.clusterGroup | default({})).managedClusterGroups is defined
- ((_clustergroup_main_root.clusterGroup | default({})).managedClusterGroups | default({})) is mapping

- name: Finalize managed clustergroup names list
ansible.builtin.set_fact:
managed_clustergroup_names: "{{ managed_clustergroup_names | default([]) | unique | sort }}"

- name: Set clustergroup load order (main first so managed values files override on duplicate keys)
ansible.builtin.set_fact:
clustergroup_load_order: >-
{{
(
[_clustergroup_discovery_main_stem]
+ (managed_clustergroup_names | reject('equalto', _clustergroup_discovery_main_stem) | list)
) | unique | list
}}

- name: Set sorted clustergroup names (all stems in use)
ansible.builtin.set_fact:
clustergroup_names: "{{ clustergroup_load_order | sort }}"

- name: Build clustergroup_file_entries for stems that have a local values file
ansible.builtin.include_tasks: resolve_clustergroup_file_path.yml
loop: "{{ clustergroup_load_order }}"
loop_control:
loop_var: clustergroup_discovery_stem

- name: Default empty clustergroup file entries
ansible.builtin.set_fact:
clustergroup_file_entries: []
when: clustergroup_file_entries is not defined

- name: Parse each resolved clustergroup values file when requested
ansible.builtin.include_tasks: parse_documents.yml
when: clustergroup_discovery_parse_documents | default(false) | bool
7 changes: 7 additions & 0 deletions roles/clustergroup_discovery/tasks/parse_documents.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
- name: Parse clustergroup values YAML into clustergroup_documents
ansible.builtin.set_fact:
clustergroup_documents: "{{ clustergroup_documents | default({}) | combine({item.name: (lookup('file', item.path) | from_yaml)}) }}"
loop: "{{ clustergroup_file_entries }}"
loop_control:
label: "{{ item.name }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
# loop_var: clustergroup_discovery_stem — append {name, path} to clustergroup_file_entries when file exists.

- name: Stat values file for stem {{ clustergroup_discovery_stem }} (yaml)
ansible.builtin.stat:
path: "{{ pattern_dir | string | trim }}/values-{{ clustergroup_discovery_stem | string | trim }}.yaml"
register: _clustergroup_discovery_stem_stat_yaml

- name: Stat values file for stem {{ clustergroup_discovery_stem }} (yml)
ansible.builtin.stat:
path: "{{ pattern_dir | string | trim }}/values-{{ clustergroup_discovery_stem | string | trim }}.yml"
register: _clustergroup_discovery_stem_stat_yml

- name: Record clustergroup file entry for {{ clustergroup_discovery_stem }} (prefer yaml)
ansible.builtin.set_fact:
clustergroup_file_entries: "{{ clustergroup_file_entries | default([]) + [_entry] }}"
vars:
_entry:
name: "{{ clustergroup_discovery_stem | string | trim }}"
path: "{{ pattern_dir | string | trim }}/values-{{ clustergroup_discovery_stem | string | trim }}.yaml"
when: _clustergroup_discovery_stem_stat_yaml.stat.exists | default(false)

- name: Record clustergroup file entry for {{ clustergroup_discovery_stem }} (yml fallback)
ansible.builtin.set_fact:
clustergroup_file_entries: "{{ clustergroup_file_entries | default([]) + [_entry] }}"
vars:
_entry:
name: "{{ clustergroup_discovery_stem | string | trim }}"
path: "{{ pattern_dir | string | trim }}/values-{{ clustergroup_discovery_stem | string | trim }}.yml"
when:
- not (_clustergroup_discovery_stem_stat_yaml.stat.exists | default(false))
- _clustergroup_discovery_stem_stat_yml.stat.exists | default(false)