|
| 1 | +--- |
| 2 | + date: 2025-08-29 |
| 3 | + title: From slim common to no common |
| 4 | + summary: We're replacing the redundant common git subtree in our repositories with a single, centralized Makefile-common. |
| 5 | + author: Drew Minnear |
| 6 | + blog_tags: |
| 7 | + - patterns |
| 8 | + - announce |
| 9 | +--- |
| 10 | +:toc: |
| 11 | +:imagesdir: /images |
| 12 | + |
| 13 | +== Retiring the `common` Directory with a Smarter Makefile |
| 14 | + |
| 15 | +We're simplifying our Validated Patterns workflow in a big way: the `common` directory is going away. |
| 16 | + |
| 17 | +Why does this matter? Fewer moving parts, leaner repositories, and updates that flow automatically to every pattern. Instead of juggling wrapper scripts and redundant logic across repos, everything now runs through a *centralized, smarter Makefile*. |
| 18 | + |
| 19 | +This post explains why we made the change, how it benefits you, and what you need to do to start using this streamlined approach. |
| 20 | + |
| 21 | +=== The Old Way: A `common` Directory in Every Pattern |
| 22 | + |
| 23 | +Originally, every pattern repository included a `common` directory. As the name suggests, it housed shared resources that didn't vary between patterns, primarily *Helm charts* and *Ansible playbooks*. While this worked, it meant that any update to a common script or chart had to be manually propagated across every single pattern repository. |
| 24 | + |
| 25 | +=== The Evolution: Creating Central Hubs of Logic |
| 26 | + |
| 27 | +To improve this, we began breaking the `common` directory apart in a few key stages: |
| 28 | + |
| 29 | +. *Centralizing Helm charts:* We leveraged Argo CD's link:https://argo-cd.readthedocs.io/en/stable/user-guide/multiple_sources/[multi-source config] feature to publish and consume our Helm charts from a central repository, now available at link:https://charts.validatedpatterns.io/[]. |
| 30 | +. *Creating an Ansible Collection:* We moved the common Ansible playbooks into their own dedicated Git repository and published them as a collection: link:https://github.com/validatedpatterns/rhvp.cluster_utils[`rhvp.cluster_utils`]. |
| 31 | +. *Introducing the `utility-container`:* We created the link:https://quay.io/repository/validatedpatterns/utility-container[`utility-container`]. This container image bundles all our essential tools—the `rhvp.cluster_utils` Ansible collection, other collections like `kubernetes.core`, and common binaries (`oc`, `helm`, etc.). |
| 32 | + |
| 33 | +This evolution gave us the ubiquitous `pattern.sh` script. By running `./pattern.sh make install`, you use the `utility-container` to deploy a pattern to an OpenShift cluster. This powerful script ensures you have the correct versions of all tools without needing to install them on your local machine. |
| 34 | + |
| 35 | +At this point, the `common` directory was much slimmer, containing only the Makefile and some shell scripts that were mostly just thin wrappers for Ansible playbook calls. |
| 36 | + |
| 37 | +=== Today's Change: Removing the `common` Directory Entirely |
| 38 | + |
| 39 | +After slimming things down, we realized we could take one final step. We moved the logic from the few remaining wrapper scripts directly into our Ansible playbooks. This made the `common/scripts` directory redundant, and at that point, there was no reason to have the `common` directory at all. |
| 40 | + |
| 41 | +Now, instead of a git subtree, patterns can use a single, powerful Makefile. |
| 42 | + |
| 43 | +This new approach has several key advantages: |
| 44 | + |
| 45 | +* *Lighter Repos:* Pattern repositories no longer need the `common` directory, making them much smaller. |
| 46 | +* *Centralized Updates:* When we fix a bug or add a feature to the common logic, we update it in one place. The changes are automatically available to all patterns using the new Makefile—no more updating dozens of repos! |
| 47 | +* *Simpler Makefiles:* Most patterns now only need a single line in their Makefile: `include Makefile-common`. |
| 48 | + |
| 49 | +TIP: You can always set the environment variable `PATTERN_UTILITY_CONTAINER` inside or outside of pattern.sh to a specific semver tag to manually control the updates. (For example, you can set it to `quay.io/validatedpatterns/utility-container:v1.0.0`.) |
| 50 | + |
| 51 | +=== The Adjustment: Discoverability |
| 52 | + |
| 53 | +One change to be aware of is *discoverability*. Without a local `common` directory full of scripts, it may not be immediately obvious which `make` targets exist or which environment variables you can tweak. |
| 54 | + |
| 55 | +We've solved this in two ways: |
| 56 | + |
| 57 | +. *Built-in docs:* Every `Makefile-common` includes a link back to this post, so the reference is always at your fingertips. |
| 58 | +. *`make help` target:* Run `./pattern.sh make help` to see the list of available targets directly in your terminal. |
| 59 | + |
| 60 | +== Getting Started with the New Structure |
| 61 | + |
| 62 | +Adopting the new approach is straightforward whether you're bootstrapping a brand-new pattern repository or upgrading an existing one. |
| 63 | + |
| 64 | +=== New repositories |
| 65 | + |
| 66 | +. From the root of your repo, run: |
| 67 | ++ |
| 68 | +[source,bash] |
| 69 | +---- |
| 70 | +podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer init |
| 71 | +---- |
| 72 | ++ |
| 73 | +Add secrets scaffolding at any time with: |
| 74 | ++ |
| 75 | +[source,bash] |
| 76 | +---- |
| 77 | +podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer init --with-secrets |
| 78 | +---- |
| 79 | +. Review the changes (`values-*.yaml`, `pattern.sh`, `Makefile`, `Makefile-common`), then commit. |
| 80 | +. Try it out: |
| 81 | ++ |
| 82 | +[source,bash] |
| 83 | +---- |
| 84 | +./pattern.sh make show |
| 85 | +---- |
| 86 | ++ |
| 87 | +[source,bash] |
| 88 | +---- |
| 89 | +./pattern.sh make install |
| 90 | +---- |
| 91 | + |
| 92 | +=== Existing repositories |
| 93 | + |
| 94 | +Move from the legacy `common` structure to the new Makefile-driven setup with a single command: |
| 95 | + |
| 96 | +[source,bash] |
| 97 | +---- |
| 98 | +podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer upgrade |
| 99 | +---- |
| 100 | + |
| 101 | +What this does: |
| 102 | +* Removes `common` (if present) |
| 103 | +* Removes `./pattern.sh` (symlink or file), then copies the latest script |
| 104 | +* Copies `Makefile-common` to the repo root |
| 105 | +* Updates your `Makefile`: |
| 106 | +** If it already contains `include Makefile-common`, it is left unchanged |
| 107 | +** If it exists but lacks the include, the include is prepended to the first line |
| 108 | +** If it doesn't exist, a default `Makefile` is created |
| 109 | + |
| 110 | +If you prefer to fully replace your `Makefile` with the default version, run: |
| 111 | + |
| 112 | +[source,bash] |
| 113 | +---- |
| 114 | +podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer upgrade --replace-makefile |
| 115 | +---- |
| 116 | + |
| 117 | +After upgrading, commit the changes and use the targets described below (for example, `./pattern.sh make show` or `./pattern.sh make install`). |
| 118 | + |
| 119 | +== Using `Makefile-common` |
| 120 | + |
| 121 | +Patterns shipped without the `common` dir now have a `Makefile-common` that provides consistent developer and user targets. |
| 122 | + |
| 123 | +=== How commands are executed |
| 124 | + |
| 125 | +All targets are thin wrappers around ansible playbooks defined in link:https://github.com/validatedpatterns/rhvp.cluster_utils[rhvp.cluster_utils]. By default, `ANSIBLE_STDOUT_CALLBACK` is set to `null` which means all of the noise from ansible is suppressed. If you need it, set that variable in your environment `export ANSIBLE_STDOUT_CALLBACK=default` or just directly use it as part of calling the make targets (`ANSIBLE_STDOUT_CALLBACK=default ./pattern.sh make <target>`). |
| 126 | + |
| 127 | +When you are getting started with secrets it can be difficult to debug what may be wrong in your secret values files. To aid debugging, you could try running: |
| 128 | + |
| 129 | +[source,bash] |
| 130 | +---- |
| 131 | +ANSIBLE_STDOUT_CALLBACK=default EXTRA_PLAYBOOK_OPTS='-e hide_sensitive_output="false" -vvv' ./pattern.sh make load-secrets |
| 132 | +---- |
| 133 | + |
| 134 | +IMPORTANT: *DO NOT* do this in CI environments as it will expose your secrets...Also, for auto-generated secrets they will be different each time you run that command. |
| 135 | + |
| 136 | +=== Overriding variables |
| 137 | + |
| 138 | +All pattern settings can be overridden in *two ways*: |
| 139 | + |
| 140 | +. *Ansible variable* |
| 141 | ++ |
| 142 | +Via the env var `EXTRA_PLAYBOOK_OPTS`, e.g.: |
| 143 | ++ |
| 144 | +[source,bash] |
| 145 | +---- |
| 146 | +EXTRA_PLAYBOOK_OPTS="-e target_branch=myfeature -e target_origin=upstream" ./pattern.sh make show |
| 147 | +---- |
| 148 | +. *Environment variable* |
| 149 | ++ |
| 150 | +[source,bash] |
| 151 | +---- |
| 152 | +TARGET_BRANCH=myfeature TARGET_ORIGIN=upstream ./pattern.sh make show |
| 153 | +---- |
| 154 | + |
| 155 | +*Precedence:* |
| 156 | +`-e var=value` (CLI/inventory) → environment variables → defaults. |
| 157 | + |
| 158 | +== Targets |
| 159 | + |
| 160 | +[[make-show]] |
| 161 | +=== `make show` |
| 162 | + |
| 163 | +Renders the Helm template of the link:https://github.com/validatedpatterns/pattern-install-chart[pattern-install chart] to show the manifests that would be applied by <<make-install,`make install`>>. |
| 164 | + |
| 165 | +WARNING: It does *not* render the namespaces, subscriptions, and projects managed by the Patterns Operator via the clustergroup-chart. It only shows: |
| 166 | + |
| 167 | +* the Patterns Operator subscription and associated configmap |
| 168 | +* the `Pattern` CR which enables installation of the pattern |
| 169 | + |
| 170 | +==== Overrides |
| 171 | + |
| 172 | +[cols="2,2,4,2"] |
| 173 | +|=== |
| 174 | +| Ansible var | Environment var | Purpose | Default |
| 175 | + |
| 176 | +| `pattern_dir` |
| 177 | +| `PATTERN_DIR` |
| 178 | +| Directory containing the pattern repo to be shown/installed |
| 179 | +| current working directory |
| 180 | + |
| 181 | +| `pattern_name` |
| 182 | +| `PATTERN_NAME` |
| 183 | +| Name for the Helm release / Pattern CR |
| 184 | +| basename of `pattern_dir` |
| 185 | + |
| 186 | +| `pattern_install_chart` |
| 187 | +| `PATTERN_INSTALL_CHART` |
| 188 | +| OCI URL for the install chart |
| 189 | +| `oci://quay.io/validatedpatterns/pattern-install` |
| 190 | + |
| 191 | +| `target_branch` |
| 192 | +| `TARGET_BRANCH` |
| 193 | +| Git branch used for the repo |
| 194 | +| `git rev-parse --abbrev-ref HEAD` |
| 195 | + |
| 196 | +| `target_origin` |
| 197 | +| `TARGET_ORIGIN` |
| 198 | +| Git remote for the branch |
| 199 | +| `git config branch.<branch>.remote` |
| 200 | + |
| 201 | +| `target_clustergroup` |
| 202 | +| `TARGET_CLUSTERGROUP` |
| 203 | +| Which clustergroup to install (if different from `main.clusterGroupName` in values-global.yaml) |
| 204 | +| value of `main.clusterGroupName` in values-global.yaml |
| 205 | + |
| 206 | +| `token_secret` |
| 207 | +| `TOKEN_SECRET` |
| 208 | +| Secret name for private repos (link:https://validatedpatterns.io/blog/2023-12-20-private-repos/[docs]) |
| 209 | +| empty |
| 210 | + |
| 211 | +| `token_namespace` |
| 212 | +| `TOKEN_NAMESPACE` |
| 213 | +| Namespace of the secret |
| 214 | +| empty |
| 215 | + |
| 216 | +| `extra_helm_opts` |
| 217 | +| `EXTRA_HELM_OPTS` |
| 218 | +| Extra args to pass to `helm template` |
| 219 | +| empty |
| 220 | + |
| 221 | +| `uuid_file` |
| 222 | +| `UUID_FILE` |
| 223 | +| Path to a file containing a UUID used for analytics. Ensures team-internal deploys can be filtered from external ones. Users generally do not need to override this. |
| 224 | +| `~/.config/validated-patterns/pattern-uuid` if exists, otherwise unset |
| 225 | +|=== |
| 226 | + |
| 227 | +[[make-operator-deploy]] |
| 228 | +=== `make operator-deploy` |
| 229 | + |
| 230 | +Performs validations and applies the manifests rendered by <<make-show,`make show`>> to your cluster. |
| 231 | + |
| 232 | +The <<make-install,`make install`>> target is usually preferred for new installs, since it also handles secret loading. |
| 233 | +The primary use case for `operator-deploy` is updating an existing pattern to point to a different git repo, revision, or origin—without refreshing secrets. |
| 234 | + |
| 235 | +==== Overrides |
| 236 | + |
| 237 | +Same as <<make-show,`make show`>> plus: |
| 238 | + |
| 239 | +[cols="2,2,4,1"] |
| 240 | +|=== |
| 241 | +| Ansible var | Environment var | Purpose | Default |
| 242 | + |
| 243 | +| `disable_validate_origin` |
| 244 | +| `DISABLE_VALIDATE_ORIGIN` |
| 245 | +| Whether git origin reachability should be validated |
| 246 | +| false |
| 247 | +|=== |
| 248 | + |
| 249 | +[[make-install]] |
| 250 | +=== `make install` |
| 251 | + |
| 252 | +Identical to <<make-operator-deploy,`make operator-deploy`>> up through applying the pattern manifests. |
| 253 | +Afterward, if `global.secretLoader.disabled` is *not set* or is `false` in `values-global.yaml`, this target also runs <<make-load-secrets,`make load-secrets`>>. |
| 254 | + |
| 255 | +* If your pattern doesn't use secrets, this is functionally identical to `operator-deploy`. |
| 256 | +* If your pattern does use secrets, `install` ensures they are loaded into Vault in the cluster. |
| 257 | + |
| 258 | +==== Overrides |
| 259 | + |
| 260 | +Same as <<make-operator-deploy,`make operator-deploy`>>. |
| 261 | + |
| 262 | +=== `make validate-prereq` |
| 263 | + |
| 264 | +Validates prerequisites needed for installation: |
| 265 | + |
| 266 | +* Confirms the `pattern_name` matches the value in `values-global.yaml` |
| 267 | +* On host: checks for `python-kubernetes` and the `kubernetes.core` Ansible collection |
| 268 | +* In container: ensures `.main.multiSourceConfig.enabled` is set to `true` in `values-global.yaml` |
| 269 | + |
| 270 | +Typically run as part of `make install`/`make operator-deploy` but can be invoked manually. |
| 271 | + |
| 272 | +=== `make validate-origin` |
| 273 | + |
| 274 | +Ensures the pattern's git origin and branch are reachable. |
| 275 | +Invoked automatically during install unless explicitly disabled, but can also be run standalone. |
| 276 | + |
| 277 | +=== `make validate-cluster` |
| 278 | + |
| 279 | +Ensures you are logged into an OpenShift cluster and that a storage class is available. |
| 280 | +This prevents failed installs due to missing cluster prerequisites. |
| 281 | +Invoked automatically during install but may be run manually for a quick sanity check. |
| 282 | + |
| 283 | +[[make-load-secrets]] |
| 284 | +=== `make load-secrets` |
| 285 | + |
| 286 | +Loads secrets into Vault in the cluster if `global.secretLoader.disabled` is not set or is `false`. |
| 287 | +Run automatically as part of <<make-install,`make install`>>, but can also be run independently if you need to reload secrets. |
| 288 | + |
| 289 | +== Wrapping Up |
| 290 | + |
| 291 | +By retiring the `common` directory, we've eliminated duplication and made every pattern repo smaller, simpler, and easier to maintain. |
| 292 | + |
| 293 | +With a single, centralized Makefile: |
| 294 | +* Updates flow automatically across all patterns |
| 295 | +* Repositories stay lean and uncluttered |
| 296 | +* Developers get a consistent, predictable experience |
| 297 | + |
| 298 | +Ready to try it? Run: |
| 299 | + |
| 300 | +[source,bash] |
| 301 | +---- |
| 302 | +podman run -v "$PWD:/repo:z" quay.io/validatedpatterns/patternizer upgrade |
| 303 | +---- |
| 304 | + |
| 305 | +and commit the changes. Your repo will instantly be on the new path. |
0 commit comments