Skip to content

Commit 97dbf59

Browse files
authored
Merge pull request #617 from validatedpatterns/automated/patternizer-update
chore: automated patternizer update
2 parents 81f1e2f + bb3ba67 commit 97dbf59

5 files changed

Lines changed: 2389 additions & 0 deletions

File tree

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
---
2+
name: pattern-author
3+
description: >
4+
Author and modify Validated Patterns — GitOps-based deployment configurations
5+
for OpenShift. Use when creating new Patterns, adding applications/subscriptions/namespaces
6+
to existing Patterns, configuring secrets, setting up hub/spoke clusters, or working with
7+
clustergroup values files.
8+
when_to_use: >
9+
When the user asks to create a new Validated Pattern, add a helm chart or application to a
10+
Pattern, configure secrets or vault, set up spoke clusters, modify clustergroup values,
11+
or work with values-global.yaml, values-*.yaml, or values-secret.yaml.template files.
12+
Also when the user mentions "Validated Patterns", "clustergroup", "pattern init", or
13+
"patternizer".
14+
allowed-tools: Read Bash(pattern *) Bash(helm *) Bash(find *) Bash(ls *)
15+
---
16+
17+
# Validated Patterns Author
18+
19+
You are helping author Validated Patterns — GitOps-based deployment configurations for OpenShift built on the [clustergroup helm chart](https://github.com/validatedpatterns/clustergroup-chart/). A Pattern is a Git repository containing values files that define what namespaces, operators, and applications to deploy on one or more OpenShift clusters via ArgoCD.
20+
21+
For complete framework documentation, read [reference.md](reference.md) in this skill directory. Read it before your first Pattern authoring task in a session, or when you need details on a specific framework feature.
22+
23+
## Authoring Workflow
24+
25+
When creating a new Pattern:
26+
27+
1. **Initialize** — Determine the Pattern name and whether secrets are needed. Run `pattern init` or `pattern init --with-secrets` in the Pattern directory.
28+
2. **Identify requirements** — What operators, applications, and custom helm charts does this Pattern need?
29+
3. **Define namespaces** — Add all required namespaces to the clustergroup values file (`values-<clusterGroupName>.yaml`). Include OperatorGroup configuration for operator namespaces.
30+
4. **Define subscriptions** — Add operator subscriptions with at minimum the operator `name`. Set `namespace`, `channel`, and `source` as needed.
31+
5. **Define applications** — Wire in helm charts as applications:
32+
- Local charts: set `path` to the chart location in the repository
33+
- VP-published charts: set `chart` and `chartVersion`
34+
- External Git charts: set `repoURL`, `path`, and `chartVersion` (Git ref)
35+
6. **Configure secrets** (if applicable) — Define secrets in `values-secret.yaml.template` and create corresponding ExternalSecret CRDs in chart templates.
36+
7. **Set up hub/spoke** (if multi-cluster) — Add ACM subscription and `managedClusterGroups` to the hub. Create spoke values files.
37+
8. **Add imperative jobs** (if needed) — Configure Ansible playbooks in the imperative framework for tasks that don't fit the declarative model.
38+
39+
When modifying an existing Pattern, read the current `values-global.yaml` and clustergroup values files first to understand the existing structure before making changes.
40+
41+
## Rules
42+
43+
These rules must always be followed:
44+
45+
- **Map form for namespaces** — Always define namespaces as a map, never a list. Maps merge across values files; lists override entirely.
46+
- **No secrets in Git** — Never put real secrets or credentials in the Pattern repository. Secrets belong in `~/values-secret-<pattern-name>.yaml` on the user's machine.
47+
- **`singleArgoCD: true`** — Always set this for new Patterns.
48+
- **`multiSourceConfig.enabled: true`** — Always set this for new Patterns.
49+
- **Vault only on hub** — The Vault application and namespace belong only on the hub/main cluster. Spoke clusters need ESO only (no Vault). The VP `openshift-external-secrets` chart auto-configures spokes to use the hub's Vault.
50+
- **Chart values stubs** — A chart's `values.yaml` must include default stubs for any `.Values.global.*` or `.Values.clusterGroup.*` values referenced in its templates, so `helm template` works standalone during development.
51+
- **ESO backtick escaping** — In ExternalSecret templates, escape ESO template expressions with backticks to prevent Helm from interpreting them:
52+
53+
```text
54+
"{{ `{{ .field_name }}` }}"
55+
```
56+
57+
- **Idempotent imperative jobs** — All imperative jobs run on a schedule (every 10 minutes by default) and must be idempotent.
58+
- **Re-run `pattern init`** — After adding new local helm charts, re-run `pattern init` to wire them into the clustergroup values file. It is idempotent.
59+
60+
## Common Tasks
61+
62+
### Adding an Operator
63+
64+
Add three things to the clustergroup values file: a namespace, a subscription, and (if the operator needs its own chart for configuration) an application.
65+
66+
```yaml
67+
clusterGroup:
68+
namespaces:
69+
my-operator:
70+
operatorGroup: true
71+
targetNamespaces: []
72+
73+
subscriptions:
74+
my-operator:
75+
name: my-operator
76+
namespace: my-operator
77+
channel: stable
78+
79+
applications:
80+
my-operator-config:
81+
name: my-operator-config
82+
namespace: my-operator
83+
path: charts/my-operator-config
84+
```
85+
86+
Not every operator needs a local chart. If the operator requires no additional configuration beyond installation, the namespace and subscription are sufficient.
87+
88+
### Adding a Local Helm Chart
89+
90+
Place the chart anywhere in the repository (convention: `charts/`). Run `pattern init` to auto-discover it, or manually add it to the clustergroup values:
91+
92+
```yaml
93+
clusterGroup:
94+
namespaces:
95+
my-app:
96+
97+
applications:
98+
my-app:
99+
name: my-app
100+
namespace: my-app
101+
path: charts/my-app
102+
```
103+
104+
### Adding a VP-Published Chart
105+
106+
```yaml
107+
clusterGroup:
108+
applications:
109+
vault:
110+
name: vault
111+
namespace: vault
112+
chart: hashicorp-vault
113+
chartVersion: 0.1.*
114+
```
115+
116+
### Adding a Chart from an External Git Repository
117+
118+
```yaml
119+
clusterGroup:
120+
applications:
121+
external-app:
122+
name: external-app
123+
namespace: external-app
124+
repoURL: https://github.com/org/repo.git
125+
chartVersion: main
126+
path: charts/the-chart
127+
```
128+
129+
### Adding a Secret
130+
131+
1. Define the secret in `values-secret.yaml.template`:
132+
133+
```yaml
134+
version: "2.0"
135+
136+
secrets:
137+
- name: my-secret
138+
vaultPrefixes:
139+
- global
140+
fields:
141+
- name: api-key
142+
onMissingValue: prompt
143+
- name: password
144+
onMissingValue: generate
145+
vaultPolicy: validatedPatternDefaultPolicy
146+
```
147+
148+
2. Add `secretStore` defaults to the chart's `values.yaml`:
149+
150+
```yaml
151+
secretStore:
152+
name: vault-backend
153+
kind: ClusterSecretStore
154+
155+
mysecret:
156+
key: secret/data/global/my-secret
157+
refreshInterval: 2m0s
158+
```
159+
160+
3. Create an ExternalSecret template in the chart:
161+
162+
```yaml
163+
apiVersion: external-secrets.io/v1
164+
kind: ExternalSecret
165+
metadata:
166+
name: my-secret
167+
spec:
168+
refreshInterval: {{ .Values.mysecret.refreshInterval }}
169+
secretStoreRef:
170+
name: {{ .Values.secretStore.name }}
171+
kind: {{ .Values.secretStore.kind }}
172+
target:
173+
name: my-secret
174+
template:
175+
type: Opaque
176+
data:
177+
api-key: "{{ `{{ .api_key }}` }}"
178+
password: "{{ `{{ .password }}` }}"
179+
data:
180+
- secretKey: api_key
181+
remoteRef:
182+
key: {{ .Values.mysecret.key }}
183+
property: api-key
184+
- secretKey: password
185+
remoteRef:
186+
key: {{ .Values.mysecret.key }}
187+
property: password
188+
```
189+
190+
The Vault path is `secret/data/<vaultPrefix>/<secret-name>`. The `secretKey` values become the template variables in `target.template.data`.
191+
192+
### Adding a Spoke Cluster
193+
194+
1. Add ACM and `managedClusterGroups` to the hub clustergroup values:
195+
196+
```yaml
197+
clusterGroup:
198+
name: hub
199+
200+
namespaces:
201+
open-cluster-management:
202+
203+
subscriptions:
204+
acm:
205+
name: advanced-cluster-management
206+
namespace: open-cluster-management
207+
channel: release-2.16
208+
209+
applications:
210+
acm:
211+
name: acm
212+
namespace: open-cluster-management
213+
chart: acm
214+
chartVersion: 0.2.*
215+
216+
managedClusterGroups:
217+
region-one:
218+
name: group-one
219+
acmlabels:
220+
- name: clusterGroup
221+
value: group-one
222+
```
223+
224+
2. Create `values-group-one.yaml` with the spoke's namespaces, subscriptions, and applications.
225+
226+
3. If using secrets on the spoke, include ESO components (without Vault) in the spoke values.
227+
228+
### Adding Conditional Overrides
229+
230+
Define a custom global variable and use `sharedValueFiles`:
231+
232+
```yaml
233+
# values-global.yaml
234+
global:
235+
device: gpu
236+
237+
# values-<clustergroup>.yaml
238+
clusterGroup:
239+
sharedValueFiles:
240+
- /overrides/values-{{ $.Values.global.device }}.yaml
241+
```
242+
243+
Create the override file (e.g., `/overrides/values-gpu.yaml`) with the conditional namespaces, subscriptions, and applications.

0 commit comments

Comments
 (0)