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
80 changes: 80 additions & 0 deletions .copilot/skills/aap-openshift-2-6/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
name: aap-openshift-2-6
description: >-
Summarizes Red Hat Ansible Automation Platform 2.6 operator deployment on OpenShift (AnsibleAutomationPlatform CR, platform gateway, external PostgreSQL for gateway/controller/hub/EDA, channels, CSRF, idle_aap). Use when installing or configuring AAP on OpenShift, AAP operator custom resources, external Postgres, Event-Driven Ansible, or automation hub with the 2.6 operator.
---

# Ansible Automation Platform 2.6 on OpenShift (operator)

Authoritative source: [Installing on OpenShift Container Platform — Red Hat Ansible Automation Platform 2.6](https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/2.6/html-single/installing_on_openshift_container_platform/index). Prefer that guide over this skill for procedure text, screenshots, and version-specific errata.

## Scope

- Ground answers in **AAP 2.6** operator on **OpenShift** unless the user specifies another version or target (KVM, VMware, etc.).
- In **2.6**, the **platform gateway** is the unified UI; components are managed through a parent **`AnsibleAutomationPlatform`** custom resource (CR).

## Planning checklist

1. **Parent CR required**: After installing the operator, create an **`AnsibleAutomationPlatform`** CR—even if `AutomationController`, `AutomationHub`, or EDA objects already exist. Existing components must be registered via matching **`spec.controller.name`**, **`spec.hub.name`**, **`spec.eda.name`** in the **same namespace** as those CRs.
2. **Namespace**: Do not deploy AAP in **`default`**. Docs recommend **`ansible-automation-platform`** or **`aap`**; use a namespace that runs **only** AAP workloads.
3. **Operator channel** (Subscription):
- **`stable-2.6`**: namespace-scoped operator (typical).
- **`stable-2.6-cluster-scoped`**: manages AAP CRs across namespaces; needs broader permissions.
- **Do not** switch between normal and cluster-scoped channels on the same install.
4. **OpenShift**: AAP 2.6 operator is documented for **OpenShift 4.12 through 4.17** and later—confirm current matrix in the same guide if the cluster version is edge.
5. **Storage**: Automation Hub needs **ReadWriteMany** file storage (or S3/Azure per docs), independent of Postgres placement.

## External PostgreSQL (single server, multiple databases)

One external PostgreSQL **instance** may back gateway, controller, hub, and EDA **if each component uses a different database name** on that instance.

| Component | Where to reference the secret on `AnsibleAutomationPlatform` |
|-----------|----------------------------------------------------------------|
| Platform gateway (shared platform DB) | `spec.database.database_secret` |
| Automation controller | `spec.controller.postgres_configuration_secret` |
| Automation hub | `spec.hub.postgres_configuration_secret` |
| Event-Driven Ansible | `spec.eda.database.database_secret` |

**PostgreSQL versions**: Managed DB shipped with the operator uses **PostgreSQL 15**. **External** databases support **15, 16, and 17**; for 16/17 you rely on **external** backup/restore processes (not the operator-managed Postgres backup story).

**Secret (`type: unmanaged`)**: Use **`stringData`** with at least **`host`**, **`port`**, **`database`**, **`username`**, **`password`**, **`type: "unmanaged"`**. For controller/hub, **`sslmode`** is valid for external DBs (`prefer`, `disable`, `allow`, `require`, `verify-ca`, `verify-full`). **Password must not** contain single quote, double quote, or backslash (docs warn this breaks deploy/backup/restore).

**Automation Hub on external Postgres**: Enable the **`hstore`** extension on the Hub database **before** install (migrations assume it; managed Postgres does this automatically).

**Optional_TLS**: If automation controller must trust a private CA, use **`bundle_cacert_secret`** on the `AnsibleAutomationPlatform` CR (secret containing **`bundle-ca.crt`**).

For copy-paste YAML skeletons, see [reference.md](reference.md).

## Configuration discovery

- Parent CR: `oc explain ansibleautomationplatform.spec`
- Nested examples: `oc explain ansibleautomationplatform.spec.controller.postgres_configuration_secret`
- Full tree: `oc explain ansibleautomationplatform.spec.controller --recursive` (repeat for `hub`, `eda`)

Prefer editing the **AnsibleAutomationPlatform** CR so the operator propagates settings. When **removing** parameters, clear them from **both** the parent CR and any nested component CR if the operator created overrides.

## Platform gateway / CSRF / ingress

- Operator creates **Routes** and CSRF defaults for OpenShift Routes.
- **External ingress** (non-Route): configure **`CSRF_TRUSTED_ORIGINS`** (and related gateway settings) per **Configuring your CSRF settings for your platform gateway operator ingress** in the same guide.
- **Controller UI "CSRF" settings** in 2.6 **do not** drive platform gateway CSRF behavior (gateway is separate).

## Scaling and DR-friendly idle

- To scale **down** controller, hub, gateway, EDA workloads together: set **`idle_aap: true`** under **`spec`** on the **`AnsibleAutomationPlatform`** CR; set **`false`** to bring services back.
- For upgrades/migrations, follow the guide's backup CRs (**AutomationControllerBackup**, **AutomationHubBackup**, **EDABackup**) and release notes.

## Common pitfalls (from product docs)

- **DateStyle / timestamptz**: External DBs with non-ISO `DateStyle` (e.g. Redwood) can break parsing; docs describe setting `datestyle = 'iso, mdy'` and reloading Postgres.
- **PVCs**: Deleting an `AutomationController` or `AutomationHub` CR **does not** delete PVCs—clean up stale claims before redeploying the same instance name.
- **Existing 2.4 external DB on upgrade**: May only need **`spec.database.database_secret`** while other components keep prior DBs until migrated—see **aap-configuring-existing-external-db-all-default-components** in the guide appendix.

## When unsure

1. Cite or follow the linked **Installing on OpenShift Container Platform 2.6** chapter that matches the task (external DB, Hub storage, EDA, Lightspeed, MCP, upgrade).
2. Use **`oc explain`** on the live cluster for field names—CRDs can add fields in newer z-streams.

## Further detail

- [reference.md](reference.md) — Minimal `AnsibleAutomationPlatform` external-DB layout and secret keys.
71 changes: 71 additions & 0 deletions .copilot/skills/aap-openshift-2-6/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# AAP 2.6 on OpenShift — reference snippets

Source: [Installing on OpenShift Container Platform — AAP 2.6](https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/2.6/html-single/installing_on_openshift_container_platform/index) (Appendix: custom resources, Chapter 5 external database sections).

These are structural examples only—adjust names, namespaces, and storage classes to the environment.

## External Postgres secrets (four logical databases, one server)

Use **different** `database:` values in each secret when sharing one PostgreSQL instance.

**Gateway (platform) secret** — referenced by `spec.database.database_secret`:

- Keys follow the gateway external-DB procedure in the guide (same unmanaged connection pattern).

**Controller / Hub secrets** — `postgres_configuration_secret`; include `sslmode` when using TLS.

**EDA secret** — nested as `spec.eda.database.database_secret` in the full-platform example below.

## AnsibleAutomationPlatform: all default components on external Postgres

Matches appendix pattern **`aap-configuring-external-db-all-default-components.yml`** (names are illustrative):

```yaml
apiVersion: aap.ansible.com/v1alpha1
kind: AnsibleAutomationPlatform
metadata:
name: myaap
namespace: ansible-automation-platform
spec:
database:
database_secret: external-postgres-configuration-gateway
controller:
postgres_configuration_secret: external-postgres-configuration-controller
hub:
postgres_configuration_secret: external-postgres-configuration-hub
storage_type: file
file_storage_storage_class: <read-write-many-storage-class>
file_storage_size: 10Gi
eda:
database:
database_secret: external-postgres-configuration-eda
```

Hub still requires **content** storage (RWX file, S3, or Azure) even when Postgres is external.

## Controller external Postgres secret (minimal shape)

```yaml
apiVersion: v1
kind: Secret
metadata:
name: external-postgres-configuration-controller
namespace: ansible-automation-platform
type: Opaque
stringData:
host: "<dns-or-ip-reachable-from-cluster>"
port: "5432"
database: "<controller-db-name>"
username: "<user>"
password: "<password-without-quotes-or-backslashes>"
sslmode: "prefer"
type: "unmanaged"
```

## Lightspeed with external DB (optional)

If **Ansible Lightspeed** is enabled and uses an external DB, the guide shows an additional `lightspeed.database.database_secret` alongside auth/model secrets. See **`aap-configuring-external-db-with-lightspeed-enabled.yml`** in the appendix and the Lightspeed chapters.

## Subscription channel example (CLI)

The guide uses **`channel: 'stable-2.6'`** with `name: ansible-automation-platform-operator` and `source: redhat-operators` / `openshift-marketplace`. Verify the exact channel string in OperatorHub for your cluster date.
124 changes: 124 additions & 0 deletions .copilot/skills/ansible-redhat-cop-practices/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
name: ansible-redhat-cop-practices
description: Applies Red Hat Community of Practice (redhat-cop) Ansible good practices when writing or reviewing roles, playbooks, collections, inventories, and plugins in this project. Use when working with Ansible in EDB_Testing, Trusted Postgres Architect (TPA), redhat-cop, GPA, or Ansible best practices.
---

# Red Hat COP Ansible Good Practices

Follow the [Good Practices for Ansible (GPA)](https://redhat-cop.github.io/automation-good-practices/) from the Red Hat Community of Practice. Source: [github.com/redhat-cop/automation-good-practices](https://github.com/redhat-cop/automation-good-practices).

## Guiding principles (Zen of Ansible)

- Clear is better than cluttered. Concise is better than verbose. Simple is better than complex. Readability counts.
- Playbooks are not for programming; put logic in roles or custom modules.
- Declarative is better than imperative (most of the time). Convention over configuration.
- Helping users get things done matters most. User experience beats ideological purity.
- Every task should be idempotent; support check mode where possible.

## Structures

- **Landscape** → deploy at once (workflow or "playbook of playbooks").
- **Type** → one per host; one playbook fully deploys that type.
- **Function** → implemented as a **role**; reusability.
- **Component** → task files inside a role (or separate component-roles if large); maintainability.

Use roles for actual logic; keep playbooks as a list of roles. Avoid mixing `roles` and `tasks` (with include_role/import_role) in the same play—pick one style.

## Roles

### Design and naming

- Design roles by **functionality**, not software implementation (e.g. "NTP configuration" role, not "chrony role").
- **Variable naming**: prefix all defaults and role arguments with the role name (e.g. `foo_packages`, not `packages`). Internal (non-user) variables: prefix with two underscores, e.g. `__foo_variable`.
- **Tags**: prefix with role name or a unique descriptive prefix.
- **Role names**: no dashes (causes issues with collections); use underscores if needed.
- **Modules in roles**: prefix with role name, e.g. `foo_module`.
- Do not rely on host group names in roles; use a (list) variable or make the group name a role parameter. Set that variable at group level in inventory if needed.

### Vars vs defaults

- **defaults/main.yml**: every argument from outside the role gets a default here; document in README. Use for optional keys; no meaningful default → leave commented and let the role fail if undefined.
- **vars/main.yml**: static/magic values and large lists; do not use for user-overridable defaults (high precedence).
- Required packages → `vars/main.yml` as `foo_packages`; extra packages → `foo_extra_packages` in defaults (default `[]`).

### Platform and provider

- Avoid distribution/version checks in tasks. Use **vars per platform**: e.g. `vars/RedHat_8.yml`, `vars/Fedora.yml`, loaded via `include_vars` with `role_path` and a loop from least to most specific (`os_family`, `distribution`, `distribution_major_version`, `distribution_version`). Use `ansible_facts['distribution']` (bracket notation), not `ansible_distribution`.
- Multiple implementations (providers): input variable `$ROLENAME_provider`; if unset, detect current provider or choose by OS. Set `$ROLENAME_provider_os_default` for the default per OS.
- Platform-specific **tasks**: use `lookup('first_found')` with files from most to least specific, with a `default.yml` (or `skip: true`). Use `role_path` for paths.

### Idempotency and check mode

- Roles must be idempotent and report changes correctly (no fake changes on second run). For `command:` (or similar), set `changed_when:` explicitly.
- Support check mode when possible; document and justify if not. Use idempotent modules or `check_mode:`/`changed_when:`; avoid relying on registered vars from skipped non-idempotent tasks.

### Files and templates

- Use `{{ role_path }}/vars/...` and `{{ role_path }}/tasks/...` for includes with variable filenames so files are resolved within the role only.
- Templates: add `{{ ansible_managed | comment }}` at top; no "Last modified" dates (breaks idempotent change reporting). Prefer `backup: true` unless users need it configurable.
- Document clearly which config files the role **replaces** vs modifies.

### Other role rules

- Use Galaxy-compatible skeleton; semantic versioning for tags (0.y.z until stable). Use FQCN in examples (e.g. `kubernetes.core.k8s`, `ansible.posix.synchronize`).
- README: purpose, required/optional arguments, idempotent (Y/N), capabilities, example playbooks, rollback if applicable.
- Sub-task files: prefix task names with a short hint, e.g. `sub | Some task description`.
- From Ansible 2.11+: use `meta/argument_specs.yml` for role argument validation.

## Coding style

- **Naming**: `snake_case`; valid Python identifiers (no special chars in variables). Mnemonic names; avoid abbreviations or capitalize them. Name all tasks, plays, and blocks; task names in **imperative** ("Ensure service is running"). No numbering in role/playbook names.
- **YAML**: indent 2 spaces; indent list contents beyond the list marker. Use `.yml` extension. Use `true`/`false` for booleans (not `yes`/`no` or `True`/`False`). Spell out task arguments in YAML form (no `key=value`). Double quotes for YAML strings; single quotes for Jinja2 strings. No quotes for short keywords like `present`, `absent`.
- **Jinja2**: one space inside `{{ }}`, e.g. `{{ myvar }}`. Use bracket notation for keys: `item['key']`, not `item.key`. Use `| bool` for bare variables in `when:`. Long lines: use YAML folding `>-`; break long `when:` (and conditions) into a list. Prefer filter plugins over complex Jinja for data transformation.
- **Tasks**: prefer dedicated modules over `command`/`shell`; if using them, add a comment and ensure idempotency/check mode. Do not use `meta: end_play` (use `meta: end_host` if needed). Dynamic task names: put Jinja at the **end** of the name string (e.g. "Manage device {{ device }}"). Avoid variables in play names and in default loop variable in task names.
- **Debug**: set `verbosity:` on debug tasks so production logs stay clean.

## Playbooks

- Keep playbooks **simple**: ideally a list of roles (or a list of import_role/include_role tasks). Put logic in roles.
- Use either **roles** or **tasks** (with import_role/include_role), not both in the same play.
- **Tags**: use only (1) role-named tags to enable/disable roles, or (2) purpose-level tags that are safe to run alone. One tag should be enough for a meaningful outcome. Document tags. Never use tags that are unsafe or meaningless when used alone.

## Collections

- Structure at type or landscape level. Package roles in a collection for distribution and execution environments.
- Collection-wide variables: document them; reference in role defaults, e.g. `alpha_controller_username: "{{ mycollection_controller_username }}"`. Keep role variable naming (e.g. `alpha_*`) so roles stay reusable outside the collection.
- Include root README (purpose, license link, supported ansible-core versions, dependencies) and LICENSE or COPYING.

## Inventories

- **Single source of truth (SSOT)**: identify SSOTs (cloud/CMDB/inventory) and combine via dynamic inventory; keep only what is not provided elsewhere in static inventory.
- **As-Is vs To-Be**: keep discovered state (facts) separate from desired state (variables). Do not mix them.
- **Structure**: use an **inventory directory** with `group_vars/`, `host_vars/` (directories per group/host with one or more YAML files), and host/group lists. Avoid a single monolithic file when combining multiple sources.
- **Loop over hosts**: run plays against inventory groups and use host/group variables; do not maintain a separate list of hosts and loop over it. Use `--limit` and Ansible's parallelism instead of hand-written loops over host lists.

## Inventories and variables (precedence)

- Prefer **inventory variables** for desired state; avoid play/playbook variables and `include_vars` for that. Use extra vars for debugging/temporary overrides, not for defining desired state.
- Restrict variable types: prefer inventory vars and role defaults; use scoped (block/task) vars only when needed (e.g. loops, temporary values).

## Plugins

- Document all plugins (parameters, return values, examples). Use reST/Sphinx docstrings and Python type hints. Prefer **pytest** for unit tests. Keep plugin entry files small; move reusable logic to module_utils/ or plugin_utils/. Use ansible.plugin_builder for new plugins. Use clear, specific error messages and appropriate verbosity for info.

## Quick checklist when writing or reviewing

- [ ] Role vars/defaults prefixed with role name; internals with `__`.
- [ ] No hardcoded group names; use variables or parameters.
- [ ] Platform-specific data in vars files; paths use `role_path`.
- [ ] Idempotent tasks; `changed_when:` for command/shell where needed.
- [ ] Playbook is simple (roles or import_role list); not mixing roles + tasks section.
- [ ] Tags are role-level or purpose-level and safe alone.
- [ ] Bracket notation for facts/vars; imperative task names; `.yml`; 2-space indent.
- [ ] Inventory as directory with group_vars/host_vars; desired state in inventory, not extra vars.

## Project context (EDB_Testing)

- **Postgres automation:** Prefer **[TPA](https://github.com/EnterpriseDB/tpa)** for host-based clusters ([docs/install-tpa.md](../../../docs/install-tpa.md)). **OpenShift:** operator + manual/GitOps ([docs/install-kubernetes-manual.md](../../../docs/install-kubernetes-manual.md)); custom Ansible playbooks live in your own project or AAP SCM, not a vendored collection here.
- When authoring roles or playbooks for this repo's **docs/scripts** only, follow the variable-prefix and structure rules in this skill.

## Additional resources

- Full guidelines and rationale: [reference.md](reference.md) (if present)
- Official GPA site: https://redhat-cop.github.io/automation-good-practices/
- Red Hat COP repo: https://github.com/redhat-cop/automation-good-practices
Loading