Without this patch the `holos show buildplans` BuildPlan output has
incorrect yaml with the v3 encoder. For example apiversion: v1alpha5
instead of apiVersion.
Show subcommand:
This is large change that accomplishes a number of goals. First, there
was no convenient way to show a build plan without using the debug logs
to indentify the tags to inject, then calling the cue command with the
right incantation to inspect the BuildPlan.
This patch addresses the problem by adding a `holos show buildplans`
command. The command loads the Platform spec from the platform
directory, then iterates over all Components to produce the BuildPlan.
This patch adds labels and annotations to the platform Components
collection in order to select and filter the output.
Result:
```
❯ holos show components --selector app.holos.run/cluster=local --format=yaml | head
kind: BuildPlan
apiversion: v1alpha5
metadata:
name: podinfo
spec:
artifacts:
- artifact: clusters/local/components/podinfo/podinfo.gen.yaml
generators:
- kind: Helm
output: helm.gen.yaml
```
---
Interface refactor:
This refactors the interface between the `holos` Go CLI layer and the
various core schema data structures. We now use a proper Go interface.
Concurrent execution over platform components has been improved to
accept a closure function so we can use the same interface method to
process the components. We use this to show each component and render
each component from different subcommands using the same interface
embedded in the builder.Platform struct.
The embedded interface allows us to easily swap in different versions,
e.g. v1beta1 and eventually v1. The number of interface methods are
quite small. 14 methods across 4 interfaces in holos/interface.go.
---
Remove old versions:
This patch removes support for versions prior to v1alpha5 in an effort
to clean up cruft.
Previously the Helm generator had no support for the --kube-version
flag. This is a problem for helm charts that conditionally render
resources based on this capability.
This patch plumbs support through the author and core schemas with a new
field similar to how the enable hooks field is handled.
Previously the Helm generator had no support for the --api-versions
flag. This is a problem for helm charts that conditionally render
resources based on this capability.
This patch plumbs support through the author and core schemas with a new
field similar to how the enable hooks field is handled.
This patch strips down the v1alpha4 core and author schemas to only with
is absolutely necessary for all holos users. Aspects of platform
configuration applicable to some, even most, but not all users will be
moved into documentation topics organized as a recipe book.
The functionality removed from the v1alpha4 author schemas in v1alpha5
will move into self contained examples documented as topics on the docs
site.
The overall purpose is to have a focused, composeable, maintainable
author schema to help people get started and ideally we can support for
years with making breaking changes.
With this patch the v1alpha5 helm guide test passes. We're not going to
have this guide anymore but it demonstrates we're back to where we were
with v1alpha4.
Without this patch each version of the core and author schemas are
duplicated into each docs version. This is unnecessary and difficult to
maintain now that we have docusaurus versioned docs enabled.
This patch updates the schema generation script to check if the docs
version has been released, and if so write into a markdown file in the
versioned docs folder. If not, the version is written into the next
version folder.
This patch also updates some, but not all, document links to the md or
mdx relative file paths. This is necessary to generate the correct
versioned links.
A nice outcome of this change is that technical docs no longer need to
link to version specific pages. For example, `[Core Schema]:
./api/core.md` will always refer to the correct auto generated docs
associated with the docs version.
The api references are in reverse order and don't have good descriptions
in the index listings. This patch adds front matter to each generated
document to order them correctly and add a nice description.
Cue uses --inject, -t as the flags to set variables for fields tagged
using @tag(var,type=string).
We used --tag, which is different and requires a mental mapping. Let's
use the same flag and also pass it multiple times like they require so
we can copy and paste the command line output from the debug logs into a
cue export command to see what's going on.
This patch deprecates the --cluster-name flag, use --inject
holos_cluster=mycluster instead.
This patch also removes the environment field from the Component core
API, leaving this to the user namespace to define via tags. We don't
want to be too opinionated on how users manage their platform, baking
environment into the schema is a slippery slope toward those kinds of
opinions.
Closes: #276
Now that we have CommonLabels as part of the ComponentConfig for all
components, it makes sense to also mix in CommonLabels for a Project.
Common labes are key aspect of the Technical Overview document.
For the Author API, it would be nice to define a schema for the fields
common to all component kinds. Users could then configure all kinds by
unifying the schema into their own platform tree.
This makes a clear use case to extract the common fields back into an
embedded struct like we did in v1alpha3. I removed the embedded struct
in v1alpha4 because it wasn't clear why it should be separate, but now
the use case is clear, to configure all component kinds.
The Kustomize build plan kind needs to support both copying files from
the component directory and pulling resources from https URL's. Without
this patch this support is missing from the Author API
With this patch the Kustomize build plan kind has a KustomizeConfig
field with two structs, Files and Resources. The kustomization
resources list is built up from both of these.
Two transformers are used so we don't affect the GitOps transfomer which
really only needs CommonLabels.
I decided to keep this field exclusive to the Kustomize kind, but it
could replace the Kustomization field of the other kinds as well.
Without this patch the user facing API doesn't have a way to kustomize
the output of all the build plan kinds. This patch ensures the
Kustomization field is present on all of Helm, Kustomize, and
Kubernetes.
This field is inteded for patches and transforms. The second
kustomization in the transformer sequence is intended for common labels
and annotations, managed by a corresponding field instead of a full on
Kustomization resource.
Previously the #Helm and #Kustomize build plan helpers were not defined
in the v1alpha4 Author API. We need this definition to update the
Quickstart guide for v1alpha4 from v1alpha3.
This patch defines the #Helm and #Kustomize helpers in the Author API
similar to how #Kubernetes is defined.
Previously #Kubernetes was defined in the platform code. This is a
problem because every platform engineer would need to copy and paste
this code.
This patch moves the #Kubernetes helper into the cue.mod directory so it
can be imported and used ergonomically.
This patch gets the Author API rendering the namespaces component in the
Bank of Holos guide. It's not the final form of the API yet, we still
need to decide how best to expose the Kubernetes, Helm, and Kustomize
definitions.
I'm thinking we abstract away the transformers and generators within the
Author API Kubernetes definition.
Without this patch the --write-to flag can't be controlled from the
PlatformSpec in the CoreAPI. We need to surface this for the ArgoConfig
struct in the AuthorAPI.
That is to say, in v1alpha3 the --write-to flag was previously assumed
to be deploy/ in ArgoConfig using the DeployFiles functionality. We no
longer have DeployFiles in Core API v1alpha4, all artifacts are instead
written relative to the --write-to flag. Still, we need to expose this
flag in the PlatformSpec so users can use something other than the
deploy directory.
Previously helm charts were cached only by name, which is a problem
because the wrong version would be used when previously cached.
This patch caches charts by name and version to ensure changes in the
version results in pulling the new cached version. It is the user's
responsibility to remove old versions.
This patch also ensures only a single go routine can run cacheChart() at
a time across processes. This is necessary when rendering a platform
because multiple processes will run the Helm generator concurrently, for
example when the same chart is used for multiple environments or
customers.
The mkdir system call serves as the locking mechanism, which is robust
and atomic on all commonly used file systems.
Previously the helm generator was not implemented and returned an error.
This patch is a first pass copying the helm method from
internal/render/helm.go
Basic testing performed with a podinfo chart. It works as the previous
versions in v1alpha3 and before works. This patch does not address the
cached version issue in #273
Previously the Artifact collection was processed sequentially. This
patch provides a modest performance improvement, about 16% faster for
our simple 2 artifact use case, by processing each artifact
concurrently.
Platform rendering provides poor user feedback:
```
❯ holos render platform ./platforms/minimal
rendered namespaces for cluster local in 143.068583ms
rendered namespaces for cluster local in 143.861834ms
rendered namespaces for cluster local in 144.072666ms
rendered namespaces for cluster local in 144.219417ms
rendered platform in 144.326625ms
```
We want to see the metadata.name field of each BuildPlan. This patch
injects the build plan name from the platform spec to make the name
available through the end to end platform rendering process.
Result:
```
❯ holos render platform ./platforms/minimal
rendered stage-namespaces for cluster local in 146.078375ms
rendered prod-namespaces for cluster local in 146.544583ms
rendered test-namespaces for cluster local in 147.0535ms
rendered dev-namespaces for cluster local in 147.499166ms
rendered platform in 147.553875ms
```
The manifest field isn't clear.
Much more clear to have generators produce one Output. Transformers
take multiple Inputs and produce one Output.
The final Transformer, or a single Generator, must produce the final
Artifact.
The Inputs and Output naming to produce an Artifact makes clear the
rendering pipeline we're implementing.
This also makes clear that multiple generators must have at least one
transformer to produce the final output artifact. We model a simple
Join transformer for this case, which is what `holos` was implicitly
doing previously.
Component makes much more sense, that's the domain terminology we use.
BuildContext was meant to be re-used elsewhere, but we never did so the
name serves no purpose.
The repeated enabled booleans and file fields are awkward. It's clear
it's three separate things smashed into one.
kustomize isn't really a generator. It's useless because there is no
way to reference a plain file in a component directory.
This patch replaces the kustomize generator with a file generator which
simply reads one single file. Multiple of these generators may be used
to read one or more files.
Then, kustomize may transform these generated files, which are generated
by simply reading from the filesystem.
This API is much improved over the previous.
```
kind: BuildPlan
apiVersion: v1alpha4
metadata:
name: prod-namespaces
spec:
component: projects/platform/components/namespaces
steps:
- artifact: clusters/no-cluster/components/prod-namespaces/prod-namespaces.gen.yaml
generators:
- kind: Resources
manifest: resources.gen.yaml
resources:
Namespace:
prod-jeff:
metadata:
name: prod-jeff
labels:
kubernetes.io/metadata.name: prod-jeff
kind: Namespace
apiVersion: v1
prod-gary:
metadata:
name: prod-gary
labels:
kubernetes.io/metadata.name: prod-gary
kind: Namespace
apiVersion: v1
prod-nate:
metadata:
name: prod-nate
labels:
kubernetes.io/metadata.name: prod-nate
kind: Namespace
apiVersion: v1
transformers:
- kind: Kustomize
kustomize:
kustomization:
commonLabels:
holos.run/component.name: prod-namespaces
resources:
- resources.gen.yaml
- application.gen.yaml
- artifact: clusters/no-cluster/gitops/prod-namespaces.gen.yaml
generators:
- kind: Resources
manifest: application.gen.yaml
resources:
Application:
argocd:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prod-namespaces
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
path: examples/v1alpha4/deploy/clusters/no-cluster/components/prod-namespaces
repoURL: https://github.com/holos-run/bank-of-holos
targetRevision: main
transformers:
- kind: Kustomize
kustomize:
kustomization:
commonLabels:
holos.run/component.name: prod-namespaces
resources:
- resources.gen.yaml
- application.gen.yaml
```
A build step either produces kubernetes objects or a gitops manifest.
Both are effectively the same, they're just kubernetes resources.
For the use case of applying common labels to both, we'll have the
Author API pass the same Kustomization to two separate build steps. One
step to produce the resources, a second to produce the argocd
application or flux kustomization.
Each step produces a manifest and a gitops file, so we need a unique
name for each step. The most common case will be a single build step
matching the name of the build plan itself.
The kustomize transformer needs a filename to store the output from
generators so it has an input for the transformer. This patch adds
fields for each kind of generator so the kustomize.#Kustomization can be
configured with the files `holos` will write generated output to.
This patch implements the v1alpha4 component rendering builder for a
component BuildPlan. We don't yet have the CUE definitions, so this
hasn't been end to end tested yet, the next step is defining the
generators and transforms in the core API BuildPlan.
The holos cli does not use an interface to handle different Platform api
versions. This makes it difficult to evolve the API in a backwards
compatible way.
This patch adds a top level switch statement to the `holos render
platform` command. The switch discriminates on the Platform API
version. v1alpha3 and earlier are classified as legacy versions and
will use the existing strict types. v1alpha4 and later versions will
use an interface to render the platform, allowing for multiple types to
implement the platform rendering interface.
Previously all generated ArgoCD Application resources go into the
default project following the Quickstart guide. The configuration code
is being organized into the concept of projects in the filesystem, so we
want to the GitOps configuration to also reflect this concept of
projects.
This patch extends the ArgoConfig user facing schema to accept a project
string. The app-projects component automatically manages AppProject
resources in the argocd namespace for each of the defined projects.
This allows CUE configuration in the a project directory to specify the
project name so that all Applications are automatically assigned to the
correct project.
Previously, the #Resources struct listing valid resources to use with
APIObjects in each of the components types was closed. This made it
very difficult for users to mix in new resources and use the Kubernetes
component kind.
This patch moves the definition of the valid resources to package holos
from the schema API. The schema still enforces some light constraints,
but doesn't keep the struct closed.
A new convention is introduced in the form of configuring all components
using _ComponentConfig defined at the root, then unifying this struct
with all of the component kinds. See schema.gen.cue for how this works.
This approach enables mixing in ArgoCD applications to all component
kinds, not just Helm as was done previously. Similarly, the
user-constrained #Resources definition unifies with all component kinds.
It's OK to leave the yaml.Marshall in the schema API. The user
shouldn't ever have to deal with #APIObjects, instead they should pass
Resources through the schema API which will use APIObjects to create
apiObjectMap for each component type and the BuildPlan.
This is still more awkward than I want, but it's a good step in the
right direction.
This patch adds the httpbin routes component. It's missing the
Certificate component, the next step is to wire up automatic certificate
management in the gateway configuration, which is a prime use case for
holos. Similar to how we register components and namespaces, we'll
register certificates.
This patch also adds the #Platform.Domain field to the user facing
schema API. We previously stored the domain in the Model but it makes
sense to lift it up to the Platform and have a sensible default value
for it.
Another example of #237 needing to be addressed soon.