Compare commits

..

31 Commits

Author SHA1 Message Date
Jeff McCune
4127804092 quickstart: v0.93.2 with schema.#Platform
Make sure go install works from the quickstart documentation by doing a
release.  Otherwise, v0.93.1 is installed which doesn't include the
platform schema.
2024-09-09 17:04:32 -07:00
Jeff McCune
8f424cfabe quickstart: sync docs to this commit
Sync the documentation to the current output of the code at this commit.
2024-09-09 17:02:53 -07:00
Jeff McCune
699148abdd quickstart: define a convenince schema for the Platform
Previously, the quickstart step of generating the pod info component and
generating the platform as a whole left the task of integrating the
Component into the Platform as an exercise for the reader.  This is a
problem because it creates unnecessary friction.

This patch addresses the problem by lifting up the Platform concept
into the user-facing Schema API.  The generated platform includes a top
level #Platform definition which exposes the core Platform specification
on the Output field.

The Platform CUE instance then reduces to a simple `#Platform.Output`
which provides the Platform spec to holos for rendering each component
for each cluster.

The CUE code for the schema.#Platform iterates over each
Component to derive the list of components to manage for the Platform.

The CUE code for the generated quickstart platform links the definition
of StandardFleets, which is a Workload fleet and a Management cluster
fleet to the Platform conveninece wrapper.

Finally, the generated podinfo component drops a CUE file at the
repository root to automatically add the component to every workload
cluster.

The result is the only task left for the end user is to define at least
one workload cluster.  Once defined, the component is automatically
managed because it is managed on all workload clusters.

This approach futher opens the door to allow generated components to
define their namespaces and generated secrets on the management cluster
separate from their workloads on the workload clusters.

This patch includes a behavior change, from now on all generated
components should assume they are writing to the root of the user's Git
repository so that they can generate files through the whole tree.

In the future, we should template output paths for generated components.
A simple approach might be to embed a file with a .target suffix, with
the contents being a simple Go template of the file path to write to.
The holos generate subcommand can then check if any given embedded file
foo has a foo.target companion, then write the target to the rendered
template value.
2024-09-09 16:05:00 -07:00
Jeff McCune
73f777759e quickstart: mix-in argocd application resource
Users need to customize the default behavior of the core components,
like the Helm schema wrapper to mix-in an ArgoCD Application resource to
each component.  This patch wires up #Helm in the holos package to
schema.#Helm from the v1alpha3 api.

The result is illustrated in the Quickstart documentation, it is now
simple for users to modify the definition of a Helm component such that
Application resources are mixed in to every component in the platform.
2024-09-09 14:09:24 -07:00
Jeff McCune
8b9070f185 api: add schema to platform cue.mod for consistency
Previosly the end user needed to write, or at least copy and paste, a
large amount of boiler plate code to achieve the goal of declaring a
helm chart component.  There is a gap between the cue code:

    (#Helm & Chart).Output

And the full BuildPlan produced for the Holos cli to execute the
rendering process.  The boiler plate code in schema.cue at the root of
the platform infrastructure repository was largely responsible for
defining how a BuildPlan with one HelmChart component is derived from
this #Helm definition.

This patch moves the definitions into a new, documented API named
`schema`.  End users are expected to define their own #Helm definition
using the schema.#Helm, like so in the root level schema.cue:

    #Helm: schema.#Helm
2024-09-09 11:22:36 -07:00
Jeff McCune
1e8861c8b7 builder: relax api version requirement to fix deploy-dev
Without this patch deployments to the dev environment are failing with
the following error when commits are pushed to the main branch.

    GIT_DETAIL=v0.93.0-3-g4db3fb4 GIT_SUFFIX= bash ./hack/deploy-dev
    Cloning into 'holos-infra'...
    could not validate
    could not run: could not validate invalid BuildPlan: apiVersion invalid: want: v1alpha3 have: v1alpha2 at internal/builder/builder.go:308
    could not run: could not render component: exit status 1 at internal/render/platform.go:48
    make: *** [Makefile:147: dev-deploy] Error 1

This patch removes the api version check in the build plan validation
function.  In the future, we should pass an interface internally in the
holos executable.

The result is holos render platform ./platform succeeds with this patch
applied.
2024-09-06 20:58:56 -07:00
Jeff McCune
bdc182f4eb quickstart: generate podinfo helm chart 2024-09-06 20:57:35 -07:00
Jeff McCune
4db3fb4ead api: optional platform.spec.model
Previously the CUE code needed to specify the Platform.spec.model field,
which created friction.  This patch adds a cue struct tag to unify the
field with an open struct.

    ❯ holos render platform ./platform --log-level=debug
    could not run: could not marshal cue instance platform: cue: marshal error: spec.model: cannot convert incomplete value "_" to JSON at internal/builder/platform.go:45
    spec.model: cannot convert incomplete value "_" to JSON

The render command completes successfully with this patch without the
user having to provide a value for the spec.model field.
2024-09-06 13:38:48 -07:00
Jeff McCune
1911c7fe01 generate: add bare bones quickstart platform
This patch adds the minimal amount of CUE code necessary to successfully
run the following two commands from the quickstart.

    holos generate platform quickstart
    holos render platform ./platform

The result is no componets are rendered, so nothing is done, but it does
succeeed.

This patch surfaces some friction and inconsistency with how the Model
is passed in and the initial structure of the _PlatformConfig.  The tags
are required otherwise holos errors out.
2024-09-06 12:16:59 -07:00
Jeff McCune
5e582ec5c6 generate: do not require registration when generating a platform
Without this patch the `holos generate platform` command automatically
makes an rpc call to holos server.  This creates friction for the
quickstart guide because we don't need to require users to register and
have an organization and platform already created in the server just to
generate a simple platform to exercise a simple helm chart component.

A future patch should implement the behavior of linking a server side
platform to a local git repository by making the API call to get the
platform ID then updating the platform.metadata.json file.
2024-09-06 11:27:05 -07:00
Jeff McCune
e3c3ab6799 api: establish core v1alpha3 for quickstart
Switch holos to use v1alpha3 so we can establish more of the CUE
structures in the documented API using Go structs.
2024-09-06 10:59:45 -07:00
Jeff McCune
f3a1aeaf3f website: tweak landing page features
Still not 100% satisfied with these.  We may want to focus on the high
level core values of Safe, Easy, and Consistent instead.
2024-09-06 08:36:46 -07:00
Jeff McCune
1be7d5597b website: fix sidebars to focus on the tooling 2024-09-05 15:43:20 -07:00
Jeff McCune
2dc492dba8 website: add component to the concepts page 2024-09-05 15:07:16 -07:00
Jeff McCune
1364467853 ci: fix linter 2024-09-04 14:35:56 -07:00
Jeff McCune
7f37ac6721 website: focus landing page on package management
Previously the landing page focused on Holos as a reference platform.
We're refocusing the release on the holos package management tool.  This
patch updates the landing page and adds placeholders for a new quick
start guide which will focus on wrapping a helm chart and a concepts
page which will provide a high level overview of how holos is unique
from other tools.
2024-09-04 13:35:18 -07:00
Jeff McCune
3f3a3e5bb0 website: upgrade docusaurus to 3.5.2
npm i @docusaurus/core@latest @docusaurus/plugin-client-redirects@latest \
    @docusaurus/preset-classic@latest @docusaurus/theme-mermaid@latest \
    @docusaurus/module-type-aliases@latest @docusaurus/tsconfig@latest \
    @docusaurus/types@latest
2024-09-04 09:19:48 -07:00
Jeff McCune
4dc923f540 workflow: fix make lint 2024-08-28 12:42:26 -07:00
Jeff McCune
963ca0e6a7 workflows: move to ubuntu-latest
The gha-rs private runner scale set is no longer necessary now that the
repository is public.
2024-08-28 09:33:15 -07:00
Jeff McCune
ce875e6c18 Revert "docs: KubeStart readme"
This reverts commit ef016948b7.
2024-08-28 09:14:53 -07:00
Jeff McCune
ef016948b7 docs: KubeStart readme 2024-08-26 15:09:21 -07:00
Jeff McCune
df65f103e6 try-holos: embed helm charts
In an effort to increase reliability when trying holos locally.  The
idea being generate to render platform should ideally work without a
network connection provided the executable has already been downloaded.

For example, to give a quick demo without a network connection.
2024-08-23 08:09:37 -07:00
Jeff McCune
98d9831167 try-holos: embed argocd install
Without this patch the argo install manifest may fail because the
resources are fetched from github.

This patch embeds the same resources to increase speed and reliability.
2024-08-23 08:04:33 -07:00
Jeff McCune
fcb0f7d27a try-holos: embed argocd crds
Without this patch the argo crds component takes a few seconds to render
and may fail because the resources are fetched from github.

This patch embeds the same resources to increase speed and reliability.
2024-08-23 07:59:13 -07:00
Jeff McCune
5f3c6a1cc4 try-holos: embed gateway api resources
Without this patch the gateway api component takes a few seconds to
render and may fail because the resources are fetched from github.

This patch embeds the same resources to increase speed and reliability.

Result:

    rendered components/gateway-api for cluster workload in 257.206208ms
2024-08-23 07:55:45 -07:00
Jeff McCune
3ab6ccd864 try-holos: clarify local-ca must be run every time
Building the cluster today I got hung up on a `ERR_CONNECTION_CLOSED`
error from Chrome when trying to access httpbin.

The problem was I forgot to run the local-ca script, thinking I already
had a local ca.  The problem is the script also copies the private key
to the cluster, so it must be run every time the cluster is created.

This patch clarifies the sequence.  When resetting, everything following
the Create the Cluster step needs to be executed.
2024-08-19 16:00:29 -07:00
Jeff McCune
fe168a1a3f try-holos: clarify authentication must come before userinfo
This tripped me up.
2024-08-08 08:51:55 -07:00
Nate McCurdy
4c0d0dd18b readme: Fix typos and md formatting 2024-07-31 14:48:50 -07:00
Jeff McCune
9d0a0b1ed5 workflows: deploy dev-holos-app after image publish (#228)
Previously the image is build on merge to main, but not deployed
anywhere.  This patch adds steps to the publish workflow to deploy the
image that was published using gitops and argocd.
2024-07-30 12:12:32 -07:00
Jeff McCune
b6c6e9bc2f readme: restore from holos generate platform k3d mistake 2024-07-30 10:03:25 -07:00
Jeff McCune
44b560194a publish: add gha workflow to publish images with ko (#225)
Closes: #225
2024-07-29 17:17:32 -07:00
425 changed files with 143801 additions and 693 deletions

View File

@@ -13,10 +13,13 @@
"authroutes",
"buildplan",
"cainjector",
"clsx",
"clusterissuer",
"cookiesecret",
"coredns",
"CRD's",
"crds",
"creds",
"crossplane",
"cuecontext",
"cuelang",
@@ -27,7 +30,12 @@
"errgroup",
"fieldmaskpb",
"flushcache",
"gendoc",
"ghaction",
"gitops",
"godoc",
"golangci",
"goreleaser",
"grpcreflect",
"grpcurl",
"holos",
@@ -37,16 +45,20 @@
"isatty",
"istiod",
"jetstack",
"Jsonnet",
"killall",
"kubeadm",
"kubeconfig",
"kubelogin",
"Kustomization",
"Kustomizations",
"kustomize",
"ldflags",
"libnss",
"loadbalancer",
"mattn",
"mktemp",
"Multicluster",
"mxcl",
"myhostname",
"nameserver",
@@ -57,12 +69,17 @@
"pflag",
"PKCE",
"platformconnect",
"podinfo",
"promhttp",
"protobuf",
"protojson",
"Pulumi",
"putenv",
"quickstart",
"retryable",
"ropc",
"SECRETKEY",
"secretstores",
"spanid",
"spiffe",
"startupapicheck",
@@ -71,12 +88,14 @@
"tablewriter",
"Tiltfile",
"timestamppb",
"Timoni",
"tlsclientconfig",
"tokencache",
"Tokener",
"Traceid",
"traefik",
"uibutton",
"untar",
"Upsert",
"urandom",
"usecases",

57
.github/workflows/dev-deploy.yaml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Dev Deploy
on:
push:
branches: ['main', 'dev-deploy']
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
## Not needed on ubuntu-latest
# - name: Provide GPG and Git
# run: sudo apt update && sudo apt -qq -y install gnupg git curl zip unzip tar bzip2 make jq
## Not needed on ubuntu-latest
# - name: Provide Holos Dependencies
# run: |
# sudo mkdir -p -m 755 /etc/apt/keyrings
# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list
# sudo apt update
# sudo apt install -qq -y kubectl
# curl -fsSL -o- https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Must come after git executable is provided
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: '1.22.x'
- uses: ko-build/setup-ko@v0.7
env:
KO_DOCKER_REPO: quay.io/holos-run/holos
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: make dev-deploy
env:
auth_user: holos-run+pusher
auth_token: ${{ secrets.QUAY_TOKEN }}
run: |
echo "${auth_token}" | ko login quay.io --username "${auth_user}" --password-stdin
make dev-deploy

30
.github/workflows/golangci-lint.yaml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: golangci-lint
on:
push:
branches:
- main
- test
pull_request:
types: [opened, synchronize]
permissions:
# Required: allow read access to the content for analysis.
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read
# Optional: allow write access to checks to allow the action to annotate code in the PR.
checks: write
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.60

View File

@@ -13,9 +13,9 @@ permissions:
contents: read
jobs:
golangci:
lint:
name: lint
runs-on: gha-rs
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -30,16 +30,13 @@ jobs:
with:
go-version: stable
- name: Install Packages
run: sudo apt update && sudo apt -qq -y install git curl zip unzip tar bzip2 make
## Not needed on ubuntu-latest
# - name: Install Packages
# run: sudo apt update && sudo apt -qq -y install git curl zip unzip tar bzip2 make
- name: Install Tools
run: |
set -x
make tools
run: make tools
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
with:
version: latest
skip-pkg-cache: true
- name: Lint
# golangci-lint runs in a separate workflow.
run: make lint -o golangci-lint

View File

@@ -1,36 +0,0 @@
name: Publish
on:
push:
branches: ['main', 'publish']
jobs:
publish:
name: Publish
runs-on: gha-rs
steps:
- name: Provide GPG and Git
run: sudo apt update && sudo apt -qq -y install gnupg git curl zip unzip tar bzip2 make
# Must come after git executable is provided
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: '1.22.x'
- uses: ko-build/setup-ko@v0.7
env:
KO_DOCKER_REPO: quay.io/holos-run/holos
- name: Publish
env:
KO_DOCKER_REPO: quay.io/holos-run/holos
auth_token: ${{ secrets.QUAY_TOKEN }}
auth_user: ${{ secrets.QUAY_USER }}
run: |
echo "${auth_token}" | ko login "https://${KO_DOCKER_REPO}" --username "${auth_user}" --password-stdin
ko build

View File

@@ -12,11 +12,12 @@ permissions:
jobs:
goreleaser:
runs-on: gha-rs
runs-on: ubuntu-latest
steps:
## Not needed on ubuntu-latest
# Must come before Checkout, otherwise goreleaser fails
- name: Provide GPG and Git
run: sudo apt update && sudo apt -qq -y install gnupg git curl zip unzip tar bzip2 make
# - name: Provide GPG and Git
# run: sudo apt update && sudo apt -qq -y install gnupg git curl zip unzip tar bzip2 make
# Must come after git executable is provided
- name: Checkout

1
.gitignore vendored
View File

@@ -1,5 +1,4 @@
/bin/
vendor/
.idea/
coverage.out
/dist/

View File

@@ -58,7 +58,6 @@ tidy: ## Tidy go module.
.PHONY: fmt
fmt: ## Format code.
cd docs/examples && cue fmt ./...
cd internal/generate/platforms && cue fmt ./...
go fmt ./...
@@ -93,11 +92,14 @@ clean: ## Clean executables.
test: ## Run tests.
scripts/test
.PHONY: golangci-lint
golangci-lint:
golangci-lint run
.PHONY: lint
lint: ## Run linters.
lint: golangci-lint ## Run linters.
buf lint
cd internal/frontend/holos && ng lint
golangci-lint run
./hack/cspell
.PHONY: coverage
@@ -133,13 +135,17 @@ website-deps: ## Install Docusaurus deps for go generate
cd doc/website && npm install
.PHONY: image # refer to .ko.yaml as well
image: ## Container image build
KO_DOCKER_REPO=$(DOCKER_REPO) GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) ko build --platform=all --bare ./cmd/holos --tags $(GIT_DETAIL)$(GIT_SUFFIX)
image: ## Container image build for workflows/publish.yaml
KO_DOCKER_REPO=$(DOCKER_REPO) GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) ko build --platform=all --bare ./cmd/holos --tags $(GIT_DETAIL)$(GIT_SUFFIX) --tags latest
.PHONY: deploy
deploy: image ## DEPLOY TO PROD
.PHONY: prod-deploy
prod-deploy: install image ## deploy to PROD
GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) bash ./hack/deploy
.PHONY: dev-deploy
dev-deploy: install image ## deploy to dev
GIT_DETAIL=$(GIT_DETAIL) GIT_SUFFIX=$(GIT_SUFFIX) bash ./hack/deploy-dev
.PHONY: website
website: ## Build website
./hack/build-website

View File

@@ -1,3 +1,35 @@
# k3d Platform
## Holos - A Holistic Development Platform
Refer to https://holos.run/docs/tutorial/local/k3d
<img width="50%"
align="right"
style="display: block; margin: 40px auto;"
src="https://openinfrastructure.co/blog/2016/02/27/logo/logorectangle.png">
Building and maintaining a software development platform is a complex and time
consuming endeavour. Organizations often dedicate a team of 3-4 who need 6-12
months to build the platform.
Holos is a tool and a reference platform to reduce the complexity and speed up
the process of building a modern, cloud native software development platform.
- **Accelerate new projects** - Reduce time to market and operational complexity by starting your new project on top of the Holos reference platform.
- **Modernize existing projects** - Incrementally incorporate your existing platform services into Holos for simpler integration.
- **Unified configuration model** - Increase safety and reduce the risk of config changes with CUE.
- **First class Helm and Kustomize support** - Leverage and reuse your existing investment in existing configuration tools such as Helm and Kustomize.
- **Modern Authentication and Authorization** - Holos seamlessly integrates platform identity and access management with zero-trust beyond corp style authorization policy.
## Quick Installation
```console
go install github.com/holos-run/holos/cmd/holos@latest
```
## Docs and Support
The documentation for developing and using Holos is available at: https://holos.run
For discussion and support, [open a discussion](https://github.com/orgs/holos-run/discussions/new/choose).
## License
Holos is licensed under Apache 2.0 as found in the [LICENSE file](LICENSE).

View File

@@ -0,0 +1,47 @@
package v1alpha3
import "google.golang.org/protobuf/types/known/structpb"
// InternalLabel is an arbitrary unique identifier internal to holos itself.
// The holos cli is expected to never write a InternalLabel value to rendered
// output files, therefore use a [InternalLabel] when the identifier must be
// unique and internal. Defined as a type for clarity and type checking.
//
// A InternalLabel is useful to convert a CUE struct to a list, for example
// producing a list of [APIObject] resources from an [APIObjectMap]. A CUE
// struct using InternalLabel keys is guaranteed to not lose data when rendering
// output because a InternalLabel is expected to never be written to the final
// output.
type InternalLabel string
// Kind is a kubernetes api object kind. Defined as a type for clarity and type
// checking.
type Kind string
// APIObject represents the most basic generic form of a single kubernetes api
// object. Represented as a JSON object internally for compatibility between
// tools, for example loading from CUE.
type APIObject structpb.Struct
// APIObjectMap represents the marshalled yaml representation of kubernetes api
// objects. Do not produce an APIObjectMap directly, instead use [APIObjects]
// to produce the marshalled yaml representation from CUE data, then provide the
// result to [Component].
type APIObjectMap map[Kind]map[InternalLabel]string
// APIObjects represents Kubernetes API objects defined directly from CUE code.
// Useful to mix in resources to any kind of [Component], for example
// adding an ExternalSecret resource to a [HelmChart].
//
// [Kind] must be the resource kind, e.g. Deployment or Service.
//
// [InternalLabel] is an arbitrary internal identifier to uniquely identify the resource
// within the context of a `holos` command. Holos will never write the
// intermediate label to rendered output.
//
// Refer to [Component] which accepts an [APIObjectMap] field provided by
// [APIObjects].
type APIObjects struct {
APIObjects map[Kind]map[InternalLabel]APIObject `json:"apiObjects"`
APIObjectMap APIObjectMap `json:"apiObjectMap"`
}

View File

@@ -0,0 +1,52 @@
package v1alpha3
// FilePath represents a file path.
type FilePath string
// FileContent represents file contents.
type FileContent string
// FileContentMap represents a mapping of file paths to file contents.
type FileContentMap map[FilePath]FileContent
// BuildPlan represents a build plan for the holos cli to execute. The purpose
// of a BuildPlan is to define one or more [Component] kinds. For example a
// [HelmChart], [KustomizeBuild], or [KubernetesObjects].
//
// A BuildPlan usually has an additional empty [KubernetesObjects] for the
// purpose of using the [Component] DeployFiles field to deploy an ArgoCD
// or Flux gitops resource for the holos component.
type BuildPlan struct {
Kind string `json:"kind" cue:"\"BuildPlan\""`
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha3\""`
Spec BuildPlanSpec `json:"spec"`
}
// BuildPlanSpec represents the specification of the build plan.
type BuildPlanSpec struct {
// Disabled causes the holos cli to take no action over the [BuildPlan].
Disabled bool `json:"disabled,omitempty"`
// Components represents multiple [HolosComponent] kinds to manage.
Components BuildPlanComponents `json:"components,omitempty"`
}
type BuildPlanComponents struct {
Resources map[InternalLabel]KubernetesObjects `json:"resources,omitempty"`
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty"`
HelmChartList []HelmChart `json:"helmChartList,omitempty"`
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty"`
}
// Kustomize represents resources necessary to execute a kustomize build.
// Intended for at least two use cases:
//
// 1. Process a [KustomizeBuild] [Component] which represents raw yaml
// file resources in a holos component directory.
// 2. Post process a [HelmChart] [Component] to inject istio, patch jobs,
// add custom labels, etc...
type Kustomize struct {
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty"`
// ResourcesFile is the file name used for api objects in kustomization.yaml
ResourcesFile string `json:"resourcesFile,omitempty"`
}

View File

@@ -0,0 +1,43 @@
package v1alpha3
// Component defines the fields common to all holos component kinds. Every
// holos component kind should embed Component.
type Component struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind"`
// APIVersion represents the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" cue:"\"v1alpha3\""`
// Metadata represents data about the holos component such as the Name.
Metadata Metadata `json:"metadata"`
// APIObjectMap holds the marshalled representation of api objects. Useful to
// mix in resources to each Component type, for example adding an
// ExternalSecret to a [HelmChart] Component. Refer to [APIObjects].
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty"`
// DeployFiles represents file paths relative to the cluster deploy directory
// with the value representing the file content. Intended for defining the
// ArgoCD Application resource or Flux Kustomization resource from within CUE,
// but may be used to render any file related to the build plan from CUE.
DeployFiles FileContentMap `json:"deployFiles,omitempty"`
// Kustomize represents a kubectl kustomize build post-processing step.
Kustomize `json:"kustomize,omitempty"`
// Skip causes holos to take no action regarding this component.
Skip bool `json:"skip" cue:"bool | *false"`
}
// Metadata represents data about the object such as the Name.
type Metadata struct {
// Name represents the name of the holos component.
Name string `json:"name"`
// Namespace is the primary namespace of the holos component. A holos
// component may manage resources in multiple namespaces, in this case
// consider setting the component namespace to default.
//
// This field is optional because not all resources require a namespace,
// particularly CRDs and DeployFiles functionality.
// +optional
Namespace string `json:"namespace,omitempty"`
}

View File

@@ -0,0 +1,11 @@
package v1alpha3
const (
APIVersion = "v1alpha3"
BuildPlanKind = "BuildPlan"
HelmChartKind = "HelmChart"
// ChartDir is the directory name created in the holos component directory to cache a chart.
ChartDir = "vendor"
// ResourcesFile is the file name used to store component output when post-processing with kustomize.
ResourcesFile = "resources.yaml"
)

26
api/core/v1alpha3/doc.go Normal file
View File

@@ -0,0 +1,26 @@
// Package v1alpha3 contains the core API contract between the holos cli and CUE
// configuration code. Platform designers, operators, and software developers
// use this API to write configuration in CUE which `holos` loads. The overall
// shape of the API defines imperative actions `holos` should carry out to
// render the complete yaml that represents a Platform.
//
// [Platform] defines the complete configuration of a platform. With the holos
// reference platform this takes the shape of one management cluster and at
// least two workload cluster. Each cluster has multiple [Component]
// resources applied to it.
//
// Each holos component path, e.g. `components/namespaces` produces exactly one
// [BuildPlan] which in turn contains a set of [Component] kinds.
//
// The primary kinds of [Component] are:
//
// 1. [HelmChart] to render config from a helm chart.
// 2. [KustomizeBuild] to render config from [Kustomize]
// 3. [KubernetesObjects] to render [APIObjects] defined directly in CUE
// configuration.
//
// Note that Holos operates as a data pipeline, so the output of a [HelmChart]
// may be provided to [Kustomize] for post-processing.
package v1alpha3
//go:generate ../../../hack/gendoc

38
api/core/v1alpha3/helm.go Normal file
View File

@@ -0,0 +1,38 @@
package v1alpha3
// HelmChart represents a holos component which wraps around an upstream helm
// chart. Holos orchestrates helm by providing values obtained from CUE,
// renders the output using `helm template`, then post-processes the helm output
// yaml using the general functionality provided by [Component], for
// example [Kustomize] post-rendering and mixing in additional kubernetes api
// objects.
type HelmChart struct {
Component `json:",inline"`
Kind string `json:"kind" cue:"\"HelmChart\""`
// Chart represents a helm chart to manage.
Chart Chart `json:"chart"`
// ValuesContent represents the values.yaml file holos passes to the `helm
// template` command.
ValuesContent string `json:"valuesContent"`
// EnableHooks enables helm hooks when executing the `helm template` command.
EnableHooks bool `json:"enableHooks" cue:"bool | *false"`
}
// Chart represents a helm chart.
type Chart struct {
// Name represents the chart name.
Name string `json:"name"`
// Version represents the chart version.
Version string `json:"version"`
// Release represents the chart release when executing helm template.
Release string `json:"release"`
// Repository represents the repository to fetch the chart from.
Repository Repository `json:"repository,omitempty"`
}
// Repository represents a helm chart repository.
type Repository struct {
Name string `json:"name"`
URL string `json:"url"`
}

View File

@@ -0,0 +1,10 @@
package v1alpha3
const KubernetesObjectsKind = "KubernetesObjects"
// KubernetesObjects represents a [Component] composed of Kubernetes API
// objects provided directly from CUE using [APIObjects].
type KubernetesObjects struct {
Component `json:",inline"`
Kind string `json:"kind" cue:"\"KubernetesObjects\""`
}

View File

@@ -0,0 +1,8 @@
package v1alpha3
// KustomizeBuild represents a [Component] that renders plain yaml files in
// the holos component directory using `kubectl kustomize build`.
type KustomizeBuild struct {
Component `json:",inline"`
Kind string `json:"kind" cue:"\"KustomizeBuild\""`
}

View File

@@ -0,0 +1,44 @@
package v1alpha3
import "google.golang.org/protobuf/types/known/structpb"
// Platform represents a platform to manage. A Platform resource informs holos
// which components to build. The platform resource also acts as a container
// for the platform model form values provided by the PlatformService. The
// primary use case is to collect the cluster names, cluster types, platform
// model, and holos components to build into one resource.
type Platform struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind" cue:"\"Platform\""`
// APIVersion represents the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha3\""`
// Metadata represents data about the object such as the Name.
Metadata PlatformMetadata `json:"metadata"`
// Spec represents the specification.
Spec PlatformSpec `json:"spec"`
}
type PlatformMetadata struct {
// Name represents the Platform name.
Name string `json:"name"`
}
// PlatformSpec represents the specification of a Platform. Think of a platform
// specification as a list of platform components to apply to a list of
// kubernetes clusters combined with the user-specified Platform Model.
type PlatformSpec struct {
// Model represents the platform model holos gets from from the
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
Model structpb.Struct `json:"model" cue:"{...}"`
// Components represents a list of holos components to manage.
Components []PlatformSpecComponent `json:"components"`
}
// PlatformSpecComponent represents a holos component to build or render.
type PlatformSpecComponent struct {
// Path is the path of the component relative to the platform root.
Path string `json:"path"`
// Cluster is the cluster name to provide when rendering the component.
Cluster string `json:"cluster"`
}

View File

@@ -0,0 +1,150 @@
// Package v1alpha3 contains CUE definitions intended as convenience wrappers
// around the core data types defined in package core. The purpose of these
// wrappers is to make life easier for platform engineers by reducing boiler
// plate code and generating component build plans in a consistent manner.
package v1alpha3
import (
core "github.com/holos-run/holos/api/core/v1alpha3"
"google.golang.org/protobuf/types/known/structpb"
)
//go:generate ../../../hack/gendoc
// Helm provides a BuildPlan via the Output field which contains one HelmChart
// from package core. Useful as a convenience wrapper to render a HelmChart
// with optional mix-in resources and Kustomization post-processing.
type Helm struct {
// Name represents the chart name.
Name string
// Version represents the chart version.
Version string
// Namespace represents the helm namespace option when rendering the chart.
Namespace string
// Resources are kubernetes api objects to mix into the output.
Resources map[string]any `cue:"{...}"`
// Repo represents the chart repository
Repo struct {
Name string `json:"name"`
URL string `json:"url"`
}
// Values represents data to marshal into a values.yaml for helm.
Values interface{} `cue:"{...}"`
// Chart represents the derived HelmChart for inclusion in the BuildPlan
// Output field value. The default HelmChart field values are derived from
// other Helm field values and should be sufficient for most use cases.
Chart core.HelmChart
// EnableKustomizePostProcessor processes helm output with kustomize if true.
EnableKustomizePostProcessor bool `cue:"true | *false"`
// KustomizeFiles represents additional files to include in a Kustomization
// resources list. Useful to patch helm output. The implementation is a
// struct with filename keys and structs as values. Holos encodes the struct
// value to yaml then writes the result to the filename key. Component
// authors may then reference the filename in the kustomization.yaml resources
// or patches lists.
// Requires EnableKustomizePostProcessor: true.
KustomizeFiles map[string]any `cue:"{[string]: {...}}"`
// KustomizePatches represents patches to apply to the helm output. Requires
// EnableKustomizePostProcessor: true.
KustomizePatches map[core.InternalLabel]any `cue:"{[string]: {...}}"`
// KustomizeResources represents additional resources files to include in the
// kustomize resources list.
KustomizeResources map[string]any `cue:"{[string]: {...}}"`
// ArgoConfig represents the ArgoCD GitOps configuration for this Component.
ArgoConfig ArgoConfig
// Output represents the derived BuildPlan for the Holos cli to render.
Output core.BuildPlan
}
// Resources represents the default schema for a Kubernetes API object resource.
// For example, a Service, Namespace or Deployment. The top level key is the
// kind of resource so default behavior and strict schema enforcement may be
// enforced for the kind. The second level keys are an arbitrary internal
// label, which serves as the default value for the resource metadata name
// field, but may differ for situations where the same resource kind and name
// are managed in different namespaces.
//
// Refer to [definitions.cue] for the CUE schema definition as an example to
// build on when defining your own Components.
//
// [definitions.cue]: https://github.com/holos-run/holos/blob/main/internal/generate/platforms/cue.mod/pkg/github.com/holos-run/holos/api/schema/v1alpha3/definitions.cue#L9
// type Resources map[string]map[string]any
// ArgoConfig represents the ArgoCD GitOps configuration for a Component.
// Useful to define once at the root of the Platform configuration and reuse
// across all Components.
type ArgoConfig struct {
// Enabled causes holos to render an ArgoCD Application resource for GitOps if true.
Enabled bool `cue:"true | *false"`
// ClusterName represents the cluster within the platform the Application
// resource is intended for.
ClusterName string
// DeployRoot represents the path from the git repository root to the `deploy`
// rendering output directory. Used as a prefix for the
// Application.spec.source.path field.
DeployRoot string `cue:"string | *\".\""`
// RepoURL represents the value passed to the Application.spec.source.repoURL
// field.
RepoURL string
// TargetRevision represents the value passed to the
// Application.spec.source.targetRevision field. Defaults to the branch named
// main.
TargetRevision string `cue:"string | *\"main\""`
}
// Cluster represents a cluster managed by the Platform.
type Cluster struct {
// Name represents the cluster name, for example "east1", "west1", or
// "management".
Name string `json:"name"`
// Primary represents if the cluster is marked as the primary among a set of
// candidate clusters. Useful for promotion of database leaders.
Primary bool `json:"primary" cue:"true | *false"`
}
// Fleet represents a named collection of similarly configured Clusters. Useful
// to segregate workload clusters from their management cluster.
type Fleet struct {
Name string `json:"name"`
// Clusters represents a mapping of Clusters by their name.
Clusters map[string]Cluster `json:"clusters" cue:"{[Name=_]: name: Name}"`
}
// StandardFleets represents the standard set of Clusters in a Platform
// segmented into Fleets by their purpose. The management Fleet contains a
// single Cluster, for example a GKE autopilot cluster with no workloads
// deployed for reliability and cost efficiency. The workload Fleet contains
// all other Clusters which contain workloads and sync Secrets from the
// management cluster.
type StandardFleets struct {
// Workload represents a Fleet of zero or more workload Clusters.
Workload Fleet `json:"workload" cue:"{name: \"workload\"}"`
// Management represents a Fleet with one Cluster named management.
Management Fleet `json:"management" cue:"{name: \"management\", clusters: management: _}"`
}
// Platform is a convenience structure to produce a core Platform specification
// value in the Output field. Useful to collect components at the root of the
// Platform configuration tree as a struct, which are automatically converted
// into a list for the core Platform spec output.
type Platform struct {
// Name represents the Platform name.
Name string `cue:"string | *\"holos\""`
// Components is a structured map of components to manage by their name.
Components map[string]core.PlatformSpecComponent
// Model represents the Platform model holos gets from from the
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
Model structpb.Struct `cue:"{...}"`
// Output represents the core Platform spec for the holos cli to iterate over
// and render each listed Component, injecting the Model.
Output core.Platform
}

View File

@@ -1,6 +1,7 @@
package v1alpha1
import (
"errors"
"fmt"
"strings"
)
@@ -38,7 +39,7 @@ func (bp *BuildPlan) Validate() error {
errs = append(errs, fmt.Sprintf("apiVersion invalid: want: %s have: %s", APIVersion, bp.APIVersion))
}
if len(errs) > 0 {
return fmt.Errorf("invalid BuildPlan: " + strings.Join(errs, ", "))
return errors.New("invalid BuildPlan: " + strings.Join(errs, ", "))
}
return nil
}

3
doc/md/api/core/index.md Normal file
View File

@@ -0,0 +1,3 @@
# Core API
- [v1alpha2](v1alpha2)

403
doc/md/api/core/v1alpha3.md Normal file
View File

@@ -0,0 +1,403 @@
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# v1alpha3
```go
import "github.com/holos-run/holos/api/core/v1alpha3"
```
Package v1alpha3 contains the core API contract between the holos cli and CUE configuration code. Platform designers, operators, and software developers use this API to write configuration in CUE which \`holos\` loads. The overall shape of the API defines imperative actions \`holos\` should carry out to render the complete yaml that represents a Platform.
[Platform](<#Platform>) defines the complete configuration of a platform. With the holos reference platform this takes the shape of one management cluster and at least two workload cluster. Each cluster has multiple [Component](<#Component>) resources applied to it.
Each holos component path, e.g. \`components/namespaces\` produces exactly one [BuildPlan](<#BuildPlan>) which in turn contains a set of [Component](<#Component>) kinds.
The primary kinds of [Component](<#Component>) are:
1. [HelmChart](<#HelmChart>) to render config from a helm chart.
2. [KustomizeBuild](<#KustomizeBuild>) to render config from [Kustomize](<#Kustomize>)
3. [KubernetesObjects](<#KubernetesObjects>) to render [APIObjects](<#APIObjects>) defined directly in CUE configuration.
Note that Holos operates as a data pipeline, so the output of a [HelmChart](<#HelmChart>) may be provided to [Kustomize](<#Kustomize>) for post\-processing.
## Index
- [Constants](<#constants>)
- [type APIObject](<#APIObject>)
- [type APIObjectMap](<#APIObjectMap>)
- [type APIObjects](<#APIObjects>)
- [type BuildPlan](<#BuildPlan>)
- [type BuildPlanComponents](<#BuildPlanComponents>)
- [type BuildPlanSpec](<#BuildPlanSpec>)
- [type Chart](<#Chart>)
- [type Component](<#Component>)
- [type FileContent](<#FileContent>)
- [type FileContentMap](<#FileContentMap>)
- [type FilePath](<#FilePath>)
- [type HelmChart](<#HelmChart>)
- [type InternalLabel](<#InternalLabel>)
- [type Kind](<#Kind>)
- [type KubernetesObjects](<#KubernetesObjects>)
- [type Kustomize](<#Kustomize>)
- [type KustomizeBuild](<#KustomizeBuild>)
- [type Metadata](<#Metadata>)
- [type Platform](<#Platform>)
- [type PlatformMetadata](<#PlatformMetadata>)
- [type PlatformSpec](<#PlatformSpec>)
- [type PlatformSpecComponent](<#PlatformSpecComponent>)
- [type Repository](<#Repository>)
## Constants
<a name="APIVersion"></a>
```go
const (
APIVersion = "v1alpha3"
BuildPlanKind = "BuildPlan"
HelmChartKind = "HelmChart"
// ChartDir is the directory name created in the holos component directory to cache a chart.
ChartDir = "vendor"
// ResourcesFile is the file name used to store component output when post-processing with kustomize.
ResourcesFile = "resources.yaml"
)
```
<a name="KubernetesObjectsKind"></a>
```go
const KubernetesObjectsKind = "KubernetesObjects"
```
<a name="APIObject"></a>
## type APIObject {#APIObject}
APIObject represents the most basic generic form of a single kubernetes api object. Represented as a JSON object internally for compatibility between tools, for example loading from CUE.
```go
type APIObject structpb.Struct
```
<a name="APIObjectMap"></a>
## type APIObjectMap {#APIObjectMap}
APIObjectMap represents the marshalled yaml representation of kubernetes api objects. Do not produce an APIObjectMap directly, instead use [APIObjects](<#APIObjects>) to produce the marshalled yaml representation from CUE data, then provide the result to [Component](<#Component>).
```go
type APIObjectMap map[Kind]map[InternalLabel]string
```
<a name="APIObjects"></a>
## type APIObjects {#APIObjects}
APIObjects represents Kubernetes API objects defined directly from CUE code. Useful to mix in resources to any kind of [Component](<#Component>), for example adding an ExternalSecret resource to a [HelmChart](<#HelmChart>).
[Kind](<#Kind>) must be the resource kind, e.g. Deployment or Service.
[InternalLabel](<#InternalLabel>) is an arbitrary internal identifier to uniquely identify the resource within the context of a \`holos\` command. Holos will never write the intermediate label to rendered output.
Refer to [Component](<#Component>) which accepts an [APIObjectMap](<#APIObjectMap>) field provided by [APIObjects](<#APIObjects>).
```go
type APIObjects struct {
APIObjects map[Kind]map[InternalLabel]APIObject `json:"apiObjects"`
APIObjectMap APIObjectMap `json:"apiObjectMap"`
}
```
<a name="BuildPlan"></a>
## type BuildPlan {#BuildPlan}
BuildPlan represents a build plan for the holos cli to execute. The purpose of a BuildPlan is to define one or more [Component](<#Component>) kinds. For example a [HelmChart](<#HelmChart>), [KustomizeBuild](<#KustomizeBuild>), or [KubernetesObjects](<#KubernetesObjects>).
A BuildPlan usually has an additional empty [KubernetesObjects](<#KubernetesObjects>) for the purpose of using the [Component](<#Component>) DeployFiles field to deploy an ArgoCD or Flux gitops resource for the holos component.
```go
type BuildPlan struct {
Kind string `json:"kind" cue:"\"BuildPlan\""`
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha3\""`
Spec BuildPlanSpec `json:"spec"`
}
```
<a name="BuildPlanComponents"></a>
## type BuildPlanComponents {#BuildPlanComponents}
```go
type BuildPlanComponents struct {
Resources map[InternalLabel]KubernetesObjects `json:"resources,omitempty"`
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty"`
HelmChartList []HelmChart `json:"helmChartList,omitempty"`
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty"`
}
```
<a name="BuildPlanSpec"></a>
## type BuildPlanSpec {#BuildPlanSpec}
BuildPlanSpec represents the specification of the build plan.
```go
type BuildPlanSpec struct {
// Disabled causes the holos cli to take no action over the [BuildPlan].
Disabled bool `json:"disabled,omitempty"`
// Components represents multiple [HolosComponent] kinds to manage.
Components BuildPlanComponents `json:"components,omitempty"`
}
```
<a name="Chart"></a>
## type Chart {#Chart}
Chart represents a helm chart.
```go
type Chart struct {
// Name represents the chart name.
Name string `json:"name"`
// Version represents the chart version.
Version string `json:"version"`
// Release represents the chart release when executing helm template.
Release string `json:"release"`
// Repository represents the repository to fetch the chart from.
Repository Repository `json:"repository,omitempty"`
}
```
<a name="Component"></a>
## type Component {#Component}
Component defines the fields common to all holos component kinds. Every holos component kind should embed Component.
```go
type Component struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind"`
// APIVersion represents the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" cue:"\"v1alpha3\""`
// Metadata represents data about the holos component such as the Name.
Metadata Metadata `json:"metadata"`
// APIObjectMap holds the marshalled representation of api objects. Useful to
// mix in resources to each Component type, for example adding an
// ExternalSecret to a [HelmChart] Component. Refer to [APIObjects].
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty"`
// DeployFiles represents file paths relative to the cluster deploy directory
// with the value representing the file content. Intended for defining the
// ArgoCD Application resource or Flux Kustomization resource from within CUE,
// but may be used to render any file related to the build plan from CUE.
DeployFiles FileContentMap `json:"deployFiles,omitempty"`
// Kustomize represents a kubectl kustomize build post-processing step.
Kustomize `json:"kustomize,omitempty"`
// Skip causes holos to take no action regarding this component.
Skip bool `json:"skip" cue:"bool | *false"`
}
```
<a name="FileContent"></a>
## type FileContent {#FileContent}
FileContent represents file contents.
```go
type FileContent string
```
<a name="FileContentMap"></a>
## type FileContentMap {#FileContentMap}
FileContentMap represents a mapping of file paths to file contents.
```go
type FileContentMap map[FilePath]FileContent
```
<a name="FilePath"></a>
## type FilePath {#FilePath}
FilePath represents a file path.
```go
type FilePath string
```
<a name="HelmChart"></a>
## type HelmChart {#HelmChart}
HelmChart represents a holos component which wraps around an upstream helm chart. Holos orchestrates helm by providing values obtained from CUE, renders the output using \`helm template\`, then post\-processes the helm output yaml using the general functionality provided by [Component](<#Component>), for example [Kustomize](<#Kustomize>) post\-rendering and mixing in additional kubernetes api objects.
```go
type HelmChart struct {
Component `json:",inline"`
Kind string `json:"kind" cue:"\"HelmChart\""`
// Chart represents a helm chart to manage.
Chart Chart `json:"chart"`
// ValuesContent represents the values.yaml file holos passes to the `helm
// template` command.
ValuesContent string `json:"valuesContent"`
// EnableHooks enables helm hooks when executing the `helm template` command.
EnableHooks bool `json:"enableHooks" cue:"bool | *false"`
}
```
<a name="InternalLabel"></a>
## type InternalLabel {#InternalLabel}
InternalLabel is an arbitrary unique identifier internal to holos itself. The holos cli is expected to never write a InternalLabel value to rendered output files, therefore use a [InternalLabel](<#InternalLabel>) when the identifier must be unique and internal. Defined as a type for clarity and type checking.
A InternalLabel is useful to convert a CUE struct to a list, for example producing a list of [APIObject](<#APIObject>) resources from an [APIObjectMap](<#APIObjectMap>). A CUE struct using InternalLabel keys is guaranteed to not lose data when rendering output because a InternalLabel is expected to never be written to the final output.
```go
type InternalLabel string
```
<a name="Kind"></a>
## type Kind {#Kind}
Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
```go
type Kind string
```
<a name="KubernetesObjects"></a>
## type KubernetesObjects {#KubernetesObjects}
KubernetesObjects represents a [Component](<#Component>) composed of Kubernetes API objects provided directly from CUE using [APIObjects](<#APIObjects>).
```go
type KubernetesObjects struct {
Component `json:",inline"`
Kind string `json:"kind" cue:"\"KubernetesObjects\""`
}
```
<a name="Kustomize"></a>
## type Kustomize {#Kustomize}
Kustomize represents resources necessary to execute a kustomize build. Intended for at least two use cases:
1. Process a [KustomizeBuild](<#KustomizeBuild>) [Component](<#Component>) which represents raw yaml file resources in a holos component directory.
2. Post process a [HelmChart](<#HelmChart>) [Component](<#Component>) to inject istio, patch jobs, add custom labels, etc...
```go
type Kustomize struct {
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty"`
// ResourcesFile is the file name used for api objects in kustomization.yaml
ResourcesFile string `json:"resourcesFile,omitempty"`
}
```
<a name="KustomizeBuild"></a>
## type KustomizeBuild {#KustomizeBuild}
KustomizeBuild represents a [Component](<#Component>) that renders plain yaml files in the holos component directory using \`kubectl kustomize build\`.
```go
type KustomizeBuild struct {
Component `json:",inline"`
Kind string `json:"kind" cue:"\"KustomizeBuild\""`
}
```
<a name="Metadata"></a>
## type Metadata {#Metadata}
Metadata represents data about the object such as the Name.
```go
type Metadata struct {
// Name represents the name of the holos component.
Name string `json:"name"`
// Namespace is the primary namespace of the holos component. A holos
// component may manage resources in multiple namespaces, in this case
// consider setting the component namespace to default.
//
// This field is optional because not all resources require a namespace,
// particularly CRDs and DeployFiles functionality.
// +optional
Namespace string `json:"namespace,omitempty"`
}
```
<a name="Platform"></a>
## type Platform {#Platform}
Platform represents a platform to manage. A Platform resource informs holos which components to build. The platform resource also acts as a container for the platform model form values provided by the PlatformService. The primary use case is to collect the cluster names, cluster types, platform model, and holos components to build into one resource.
```go
type Platform struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind" cue:"\"Platform\""`
// APIVersion represents the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha3\""`
// Metadata represents data about the object such as the Name.
Metadata PlatformMetadata `json:"metadata"`
// Spec represents the specification.
Spec PlatformSpec `json:"spec"`
}
```
<a name="PlatformMetadata"></a>
## type PlatformMetadata {#PlatformMetadata}
```go
type PlatformMetadata struct {
// Name represents the Platform name.
Name string `json:"name"`
}
```
<a name="PlatformSpec"></a>
## type PlatformSpec {#PlatformSpec}
PlatformSpec represents the specification of a Platform. Think of a platform specification as a list of platform components to apply to a list of kubernetes clusters combined with the user\-specified Platform Model.
```go
type PlatformSpec struct {
// Model represents the platform model holos gets from from the
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
Model structpb.Struct `json:"model" cue:"{...}"`
// Components represents a list of holos components to manage.
Components []PlatformSpecComponent `json:"components"`
}
```
<a name="PlatformSpecComponent"></a>
## type PlatformSpecComponent {#PlatformSpecComponent}
PlatformSpecComponent represents a holos component to build or render.
```go
type PlatformSpecComponent struct {
// Path is the path of the component relative to the platform root.
Path string `json:"path"`
// Cluster is the cluster name to provide when rendering the component.
Cluster string `json:"cluster"`
}
```
<a name="Repository"></a>
## type Repository {#Repository}
Repository represents a helm chart repository.
```go
type Repository struct {
Name string `json:"name"`
URL string `json:"url"`
}
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)

View File

@@ -0,0 +1,168 @@
<!-- Code generated by gomarkdoc. DO NOT EDIT -->
# v1alpha3
```go
import "github.com/holos-run/holos/api/schema/v1alpha3"
```
Package v1alpha3 contains CUE definitions intended as convenience wrappers around the core data types defined in package core. The purpose of these wrappers is to make life easier for platform engineers by reducing boiler plate code and generating component build plans in a consistent manner.
## Index
- [type ArgoConfig](<#ArgoConfig>)
- [type Cluster](<#Cluster>)
- [type Fleet](<#Fleet>)
- [type Helm](<#Helm>)
- [type Platform](<#Platform>)
- [type StandardFleets](<#StandardFleets>)
<a name="ArgoConfig"></a>
## type ArgoConfig {#ArgoConfig}
ArgoConfig represents the ArgoCD GitOps configuration for a Component. Useful to define once at the root of the Platform configuration and reuse across all Components.
```go
type ArgoConfig struct {
// Enabled causes holos to render an ArgoCD Application resource for GitOps if true.
Enabled bool `cue:"true | *false"`
// ClusterName represents the cluster within the platform the Application
// resource is intended for.
ClusterName string
// DeployRoot represents the path from the git repository root to the `deploy`
// rendering output directory. Used as a prefix for the
// Application.spec.source.path field.
DeployRoot string `cue:"string | *\".\""`
// RepoURL represents the value passed to the Application.spec.source.repoURL
// field.
RepoURL string
// TargetRevision represents the value passed to the
// Application.spec.source.targetRevision field. Defaults to the branch named
// main.
TargetRevision string `cue:"string | *\"main\""`
}
```
<a name="Cluster"></a>
## type Cluster {#Cluster}
Cluster represents a cluster managed by the Platform.
```go
type Cluster struct {
// Name represents the cluster name, for example "east1", "west1", or
// "management".
Name string `json:"name"`
// Primary represents if the cluster is marked as the primary among a set of
// candidate clusters. Useful for promotion of database leaders.
Primary bool `json:"primary" cue:"true | *false"`
}
```
<a name="Fleet"></a>
## type Fleet {#Fleet}
Fleet represents a named collection of similarly configured Clusters. Useful to segregate workload clusters from their management cluster.
```go
type Fleet struct {
Name string `json:"name"`
// Clusters represents a mapping of Clusters by their name.
Clusters map[string]Cluster `json:"clusters" cue:"{[Name=_]: name: Name}"`
}
```
<a name="Helm"></a>
## type Helm {#Helm}
Helm provides a BuildPlan via the Output field which contains one HelmChart from package core. Useful as a convenience wrapper to render a HelmChart with optional mix\-in resources and Kustomization post\-processing.
```go
type Helm struct {
// Name represents the chart name.
Name string
// Version represents the chart version.
Version string
// Namespace represents the helm namespace option when rendering the chart.
Namespace string
// Resources are kubernetes api objects to mix into the output.
Resources map[string]any `cue:"{...}"`
// Repo represents the chart repository
Repo struct {
Name string `json:"name"`
URL string `json:"url"`
}
// Values represents data to marshal into a values.yaml for helm.
Values interface{} `cue:"{...}"`
// Chart represents the derived HelmChart for inclusion in the BuildPlan
// Output field value. The default HelmChart field values are derived from
// other Helm field values and should be sufficient for most use cases.
Chart core.HelmChart
// EnableKustomizePostProcessor processes helm output with kustomize if true.
EnableKustomizePostProcessor bool `cue:"true | *false"`
// KustomizeFiles represents additional files to include in a Kustomization
// resources list. Useful to patch helm output. The implementation is a
// struct with filename keys and structs as values. Holos encodes the struct
// value to yaml then writes the result to the filename key. Component
// authors may then reference the filename in the kustomization.yaml resources
// or patches lists.
// Requires EnableKustomizePostProcessor: true.
KustomizeFiles map[string]any `cue:"{[string]: {...}}"`
// KustomizePatches represents patches to apply to the helm output. Requires
// EnableKustomizePostProcessor: true.
KustomizePatches map[core.InternalLabel]any `cue:"{[string]: {...}}"`
// KustomizeResources represents additional resources files to include in the
// kustomize resources list.
KustomizeResources map[string]any `cue:"{[string]: {...}}"`
// ArgoConfig represents the ArgoCD GitOps configuration for this Component.
ArgoConfig ArgoConfig
// Output represents the derived BuildPlan for the Holos cli to render.
Output core.BuildPlan
}
```
<a name="Platform"></a>
## type Platform {#Platform}
Platform is a convenience structure to produce a core Platform specification value in the Output field. Useful to collect components at the root of the Platform configuration tree as a struct, which are automatically converted into a list for the core Platform spec output.
```go
type Platform struct {
// Name represents the Platform name.
Name string `cue:"string | *\"holos\""`
// Components is a structured map of components to manage by their name.
Components map[string]core.PlatformSpecComponent
// Model represents the Platform model holos gets from from the
// PlatformService.GetPlatform rpc method and provides to CUE using a tag.
Model structpb.Struct `cue:"{...}"`
// Output represents the core Platform spec for the holos cli to iterate over
// and render each listed Component, injecting the Model.
Output core.Platform
}
```
<a name="StandardFleets"></a>
## type StandardFleets {#StandardFleets}
StandardFleets represents the standard set of Clusters in a Platform segmented into Fleets by their purpose. The management Fleet contains a single Cluster, for example a GKE autopilot cluster with no workloads deployed for reliability and cost efficiency. The workload Fleet contains all other Clusters which contain workloads and sync Secrets from the management cluster.
```go
type StandardFleets struct {
// Workload represents a Fleet of zero or more workload Clusters.
Workload Fleet `json:"workload" cue:"{name: \"workload\"}"`
// Management represents a Fleet with one Cluster named management.
Management Fleet `json:"management" cue:"{name: \"management\", clusters: management: _}"`
}
```
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)

3
doc/md/backstory.md Normal file
View File

@@ -0,0 +1,3 @@
# Backstory
Holos is a tool intended to lighten the burden of managing Kubernetes resources. In 2020 we set out to develop a holistic platform composed from open source cloud native components. We quickly became frustrated with how each of the major components packaged and distributed their software in a different way. Many projects choose to distribute their software with Helm charts, while others provide plain yaml files and Kustomize bases. The popular Kube Prometheus Stack project provides Jsonnet to render and update Kubernetes yaml manifests.

65
doc/md/comparison.md Normal file
View File

@@ -0,0 +1,65 @@
# Comparison with other tools
:::tip
Holos is designed to complement and improve, not replace, existing tools in the cloud native ecosystem.
:::
## Helm
### Chart Users
Describe how things are different when using an upstream helm chart.
### Chart Authors
Describe how things are different when writing a new helm chart.
## Kustomize
TODO
## ArgoCD
TODO
## Flux
TODO
## Timoni
| Aspect | Timoni | Holos | Comment |
| -- | -- | -- | -- |
| Language | CUE | CUE | Like Holos, Timoni is also built on CUE. |
| Artifact | OCI Image | Plain YAML Files | The Holos Authors find plain files easier to work with and reason about than OCI images. |
| Outputs to | OCI Image Repository | Local Git repository | Holos is designed for use with existing GitOps tools. |
| Concept | Module | Component | A Timoni Module is analogous to a Holos Component. |
| Concept | Bundle | Platform | A Timoni Bundle is somewhat similar, but smaller in scope to a Holos Platform. |
:::important
The Holos Authors are deeply grateful to Stefan and Timoni for the capability of
importing Kubernetes custom resource definitions into CUE. Without this
functionality, much of the Kubernetes ecosystem would be more difficult to
manage in CUE and therefore in Holos.
:::
## KubeVela
1. Also built on CUE.
2. Intended to create an Application abstraction.
3. Holos prioritizes composition over abstraction.
4. An abstraction of an Application acts as a filter that removes all but the lowest common denominator functionality. The Holos Authors have found this filtering effect to create excessive friction for software developers.
5. Holos focuses instead on composition to empower developers and platform engineers to leverage the unique features and functionality of their software and platform.
## Pulumi
TODO
## Jsonnet
TODO

341
doc/md/concepts.md Normal file
View File

@@ -0,0 +1,341 @@
# Concepts
## Introduction
This page is intended as a high level conceptual overview of the key concepts in
Holos. Refer to the [Core API](/docs/api/core/) for low level reference
documentation.
Holos is a tool built for platform engineers. The Holos authors share three
core values which guide our design decisions for the tool.
1. Safety
2. Ease of use
3. Consistency
Each of the following concepts are intended to support and strengthen one or
more of these core values. In this way we hope to lighten the burden carried by
platform engineers.
## Concepts
- [Component](<#component>) - The primary building block in Holos, wraps a Helm chart, Kustomize base, or plain resources defined in CUE.
- [Platform](<#platform>) - A collection of Components integrated into a software development platform.
- [Model](<#model>) - Structured data included in the Platform specification, available to all Components. For example, your organization's domain name.
- [Rendering](<#rendering>) - Holos is a tool that makes the process of rendering Kubernetes manifests safer, easier, and consistent.
```mermaid
graph BT
Platform[<a href="#platform">Platform</a>]
Component[<a href="#component">Components</a>]
Helm[<a href="#component">Helm</a>]
Kustomize[<a href="#component">Kustomize</a>]
CUE[<a href="#component">CUE</a>]
Component --> Platform
Helm --> Component
Kustomize --> Component
CUE --> Component
```
<!--
```mermaid
---
title: Figure 1 - Holos Concepts
---
mindmap
root((Holos))
Platform
Components
HelmChart
KustomizeBuild
KubernetesObjects
Model
name: Example Org
domain: example.com
Renders
YAML Files
Kubernetes Manifests
ArgoCD Application
FluxCD Kustomization
```
-->
## Component
A Component is the primary building block when managing software with Holos. A
software project you wish to integrate into your platform, for example ArgoCD,
is managed using one or more components.
The primary Component kinds are:
1. **HelmChart** to render config provided by Helm.
2. **KustomizeBuild** to render config provided by Kustomize.
3. **KubernetesObjects** to render config provided by CUE.
Components are intended to integrate unmodified upstream software releases into
your Platform. In this way, the focus of a Component is more about the unique
differentiating aspects of your platform than the upstream software contained in
the Component.
#### Example HelmChart Component
The ArgoCD Component is a good example of a HelmChart component because it takes
advantage of most of the key features that empower you to focus on the key
differentiators of your unique platform.
Take note of the following key points in this example ArgoCD Component:
1. The Component wraps the ArgoCD Helm Chart in a way that's easy to upgrade and maintain over time.
2. Newer Gateway API resources are mixed-in replacing the older Ingress resource included in the chart.
3. Helm output is passed through Kustomize to configure secure mutual TLS encryption.
4. Helm values are easier and safer to manipulate with CUE instead of text markup.
5. Kustomize is easier and safer to manipulate with CUE instead of text markup.
6. Platform data Model values are easily accessible, for example the OIDC issuer and the organizations's domain name.
The Component wraps around the unmodified upstream ArgoCD helm chart
providing easier upgrades as new versions are released.
Note how the Component facilitates composition by allowing us to mix-in new
functionality from the ecosystem without modifying the upstream chart. The
Platform this Component integrates with uses the new Gateway API, but the
upstream helm chart does not yet support Gateway API. See how the Resources
field is used to mix-in a ReferenceGrant from the Gateway API without modifying
the upstream helm chart.
The Platform uses Istio to implement service to service encryption with mutual
TLS. The Component passes the Helm output to Kustomize to integrate with Istio.
Kustomize is used to patch the argocd-server Deployment resource to inject the
Istio sidecar for mutual TLS.
Helm values are safer and easier to work with in CUE. Note how you can modify
helm values using well defined data instead of manipulating text yaml files.
Similarly, the yaml files used for Kustomize are produced by CUE, which is again
safer and easier because the Kustomize spec has been imported into CUE and is
validated.
Finally, the domain name used by this Platform is easily accessible from the
PlatformSpec which is defined at the root level and made available to all
components integrated into the platform. Similarly, data values shared by all
of the Components that make up ArgoCD is defined in a structure accessible by
each of these components.
```cue
package holos
import (
"encoding/yaml"
"strings"
)
// Produce a helm chart build plan.
(#Helm & Chart).Output
let Chart = {
Name: "argo-cd"
Namespace: "argocd"
Version: "7.1.1"
Chart: chart: release: "argocd"
// The upstream chart uses a Job to create the argocd-redis Secret. Enable
// hooks to enable the Job.
Chart: enableHooks: true
Repo: name: "argocd"
Repo: url: "https://argoproj.github.io/argo-helm"
// Ensure all of our mix-in resources go into the same namespace as the Chart.
Resources: [_]: [_]: metadata: namespace: Namespace
// Grant the Gateway namespace the ability to refer to the backend service
// from HTTPRoute resources.
Resources: ReferenceGrant: (#IstioGatewaysNamespace): #ReferenceGrant
// Pass the helm output through kustomize.
EnableKustomizePostProcessor: true
// Force all resources into the component namespace, some resources in the
// helm chart do not specify the namespace so they will get mis-applied
// when the kubectl (client-go) context is another namespace.
KustomizeFiles: "kustomization.yaml": namespace: Namespace
// Patch the backend with the service mesh sidecar.
KustomizePatches: {
mesh: {
target: {
group: "apps"
version: "v1"
kind: "Deployment"
name: "argocd-server"
}
patch: yaml.Marshal(IstioInject)
}
}
Values: #Values & {
kubeVersionOverride: "1.29.0"
// handled in the argo-crds component
crds: install: false
global: domain: "argocd.\(_Platform.Model.org.domain)"
dex: enabled: false
// the service mesh handles secure mTLS
configs: params: "server.insecure": true
configs: cm: {
"admin.enabled": false
"oidc.config": yaml.Marshal(OIDCConfig)
"users.anonymous.enabled": "false"
}
// Refer to https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/
let Policy = [
"g, argocd-view, role:readonly",
"g, prod-cluster-view, role:readonly",
"g, prod-cluster-edit, role:readonly",
"g, prod-cluster-admin, role:admin",
]
configs: rbac: "policy.csv": strings.Join(Policy, "\n")
}
}
let IstioInject = [{
op: "add",
path: "/spec/template/metadata/labels/sidecar.istio.io~1inject",
value: "true",
}]
let OIDCConfig = {
name: "Holos Platform"
issuer: _ArgoCD.issuerURL
clientID: _ArgoCD.clientID
requestedScopes: _ArgoCD.scopesList
// Set redirect uri to https://argocd.example.com/pkce/verify
enablePKCEAuthentication: true
// groups is essential for rbac
requestedIDTokenClaims: groups: essential: true
}
```
## Platform
A Platform refers to all of the software and services integrated together to
provide your organization's software development platform. Holos is designed to
manage all of the resources that compose your Platform using the [Kubernetes
Resource Model][krm] (KRM). Nearly all platforms are larger than Kubernetes
itself. For example, your developers likely need a GCS or S3 bucket to store
data. Holos takes advantage of Crossplane to manage resources in a consistent
way.
Holos defines a [Platform][Platform] object which collects multiple Components
together along with organizational data defined by your Model. Consider the
following example, which is a Platform that manages a single Component which
manages namespaces for each cluster in the Platform.
```cue
package holos
import v1 "github.com/holos-run/holos/api/v1alpha2"
v1.#Platform & {
metadata: name: "example"
spec: components: [{
path: "components/namespaces"
cluster: "cluster1"
}]
}
```
This platform is rendered by the command:
```bash
holos render platform ./platform
```
When Holos renders the platform, it iterates over each component, generates and
executes a [BuildPlan][BuildPlan], then writes the fully rendered output of the
component to the filesystem. In this simple example, two files are produced:
1. `deploy/clusters/cluster1/components/namespaces/namespaces.gen.yaml`
2. `deploy/clusters/cluster1/gitops/namespaces.application.gen.yaml`
The first file is a plain kubernetes manifest containing Namespace resources.
The second file is an ArgoCD Application resource to deploy and manage the
resources defined in the first file.
## Model
The Platform Model is where you store top-level data values used throughout
multiple components in your Platform. Your organization's domain name is a
prime example of the kind of data stored in the Model. Many components derive
host names from your organization's domain name. CUE makes this process safe,
easy, and consistent. For example:
```cue
hostname: "argocd.\(_Platform.Model.org.domain)"
```
When Holos renders a Platform, the model is loaded from a JSON file in the local
filesystem. The platform model file is intended to be committed to version
control along with the rest of the Holos Platform and Component code.
Holos additionally provides a web ui and form to make it easy to enter and
validate top level configuration data. You have complete control over the web
form, it's rendered from JSON data defined by CUE. Customizing the web form is
an advanced topic, the key concept to take away is the Model is for top level,
platform-wide data. You control the shape and structure of the Model, and you
have the ability to collect Model values using a simple web form.
## Rendering
Holos uses the Kubernetes resource model to manage configuration. The Holos
command line interface is the primary method you'll use to manage your platform.
Holos uses CUE to provide a unified configuration model of the platform. This
unified configuration is built up from components packaged with Helm, Kustomize,
CUE, or any other tool that can produce Kubernetes resource manifests as output.
This process can be thought of as a data **rendering pipeline**. The key
concept is that Holos will always produce fully rendered output, but delegates
the _application_ of the configuration to other tools like kubectl apply,
ArgoCD, or Flux.
```mermaid
---
title: Figure 2 - Render Pipeline
---
graph LR
PS[<a href="/docs/api/core/v1alpha2#PlatformSpec">PlatformSpec</a>]
BP[<a href="/docs/api/core/v1alpha2#BuildPlan">BuildPlan</a>]
HC[<a href="/docs/api/core/v1alpha2#HolosComponent">Components</a>]
H[<a href="/docs/api/core/v1alpha2#HelmChart">HelmChart</a>]
K[<a href="/docs/api/core/v1alpha2#KustomizeBuild">KustomizeBuild</a>]
O[<a href="/docs/api/core/v1alpha2#KubernetesObjects">KubernetesObjects</a>]
P[<a href="/docs/api/core/v1alpha2#Kustomize">Kustomize</a>]
Y[Kubernetes <br/>Resources]
G[GitOps <br/>Resource]
FS[Local Files]
C[Kube API Server]
PS --> BP --> HC
HC --> H --> P
HC --> K --> P
HC --> O --> P
P --> Y --> FS
P --> G --> FS
FS --> ArgoCD --> C
FS --> Flux --> C
FS --> kubectl --> C
```
[krm]: https://docs.google.com/document/d/1RmHXdLhNbyOWPW_AtnnowaRfGejw-qlKQIuLKQWlwzs/view#heading=h.sa6p0aye4ide
[Platform]: /docs/api/core/v1alpha2/#Platform
[BuildPlan]: /docs/api/core/v1alpha2/#BuildPlan

View File

@@ -1,5 +1,6 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
# Try Holos Locally
@@ -29,7 +30,7 @@ definitions described in the [Glossary](/docs/glossary).
You'll need the following tools installed to complete this guide.
1. [holos](/docs/guides/install) - to build the platform.
1. [holos](/docs/install) - to build the platform.
2. [helm](https://helm.sh/docs/intro/install/) - to render Holos components that wrap upstream Helm charts.
3. [k3d](https://k3d.io/#installation) - to provide a k8s api server.
4. [OrbStack](https://docs.orbstack.dev/install) or [Docker](https://docs.docker.com/get-docker/) - to use k3d.
@@ -255,10 +256,9 @@ git add deploy
git commit -m "holos render platform ./platform"
```
:::important
:::info[Don't blink, this is where Holos builds the platform]
⚡ Don't blink, this is where Holos actually builds the platform. It usually
takes no more than a few seconds.
It usually takes no more than a few seconds.
Rendering the holos reference platform currently results in about 500K lines of
yaml. In contrast, roughly 80K lines are produced by this slimmed down k3d
@@ -271,6 +271,50 @@ all configuration into one single model.
:::
## Configure DNS {#DNS}
Configure your machine to resolve `*.holos.localhost` to your loopback
interface. This is necessary for requests to reach the workload cluster.
<Tabs>
<TabItem value="macos" label="macOS" default>
Cache sudo credentials.
Admin access is necessary to setup a local dnsmasq instance and configure
macOS's DNS resolver.
```bash
sudo -v
```
Resolve *.holos.localhost DNS queries to 127.0.0.1.
```bash
bash ./scripts/local-dns
```
</TabItem>
<TabItem value="linux" label="Linux">
[NSS-myhostname](http://man7.org/linux/man-pages/man8/nss-myhostname.8.html)
ships with many Linux distributions and should resolve *.localhost
automatically to 127.0.0.1.
Otherwise it is installable with:
```bash
sudo apt install libnss-myhostname
```
</TabItem>
<TabItem value="windows" label="Windows">
Ensure the loopback interface has at least the following names in `C:\windows\system32\drivers\etc\hosts`
```
127.0.0.1 httpbin.holos.localhost app.holos.localhost
```
</TabItem>
</Tabs>
## Create the Cluster {#Create-Cluster}
The Workload Cluster is where your applications and services will be deployed.
@@ -313,72 +357,39 @@ on GKE, EKS, Talos, k3s, and Kubeadm clusters.
Traefik is disabled because Istio provides the same functionality.
### Local CA {#Local-CA}
Holos platforms use cert manager to issue tls certificates. The browser and
tools we're using need to trust these certificates to work together. In this
section we'll create a local trusted certificate authority.
Admin access is necessary for `mkcert` to install the certificate into your
trust stores.
```bash
sudo -v
```
```bash
bash ./scripts/local-ca
```
### DNS Setup {#DNS}
Configure your machine to resolve `*.holos.localhost` to your loopback
interface. This is necessary for requests to reach the workload cluster.
<Tabs>
<TabItem value="macos" label="macOS" default>
Cache sudo credentials.
Admin access is necessary to setup a local dnsmasq instance and configure
macOS's DNS resolver.
```bash
sudo -v
```
Resolve *.holos.localhost DNS queries to 127.0.0.1.
```bash
bash ./scripts/local-dns
```
</TabItem>
<TabItem value="linux" label="Linux">
[NSS-myhostname](http://man7.org/linux/man-pages/man8/nss-myhostname.8.html)
ships with many Linux distributions and should resolve *.localhost
automatically to 127.0.0.1.
Otherwise it is installable with:
```bash
sudo apt install libnss-myhostname
```
</TabItem>
<TabItem value="windows" label="Windows">
Ensure the loopback interface has at least the following names in `C:\windows\system32\drivers\etc\hosts`
```
127.0.0.1 httpbin.holos.localhost app.holos.localhost
```
</TabItem>
</Tabs>
## Apply the Platform Components {#Apply-Platform-Components}
Use `kubectl` to apply each platform component. In production, it's common to
fully automate this process with ArgoCD, but we use `kubectl` to the same
effect.
### Local CA {#Local-CA}
Holos platforms use cert manager to issue tls certificates. The browser and
tools we're using need to trust these certificates to work together.
Admin access is necessary for `mkcert` to manage the certificate into your trust
stores.
```bash
sudo -v
```
Manage the local CA and copy the CA key to the workload cluster so that cert
manager can manage trusted certificates.
```bash
bash ./scripts/local-ca
```
:::warning
Take care to run the local-ca script each time you create the workload cluster
so that Certificates are issued correctly.
:::
### Service Mesh
The platform service mesh provides an ingress gateway and connectivity useful
@@ -415,8 +426,16 @@ certificate authority.
kubectl -n cert-manager wait pod -l app.kubernetes.io/component=webhook --for=condition=Ready
kubectl apply --server-side=true -f deploy/clusters/workload/components/local-ca
kubectl apply --server-side=true -f deploy/clusters/workload/components/certificates
kubectl -n istio-gateways wait certificate httpbin.holos.localhost --for=condition=Ready
```
:::warning
The certificate will time out before becoming ready if the [local-ca](#Local-CA)
script was not run after the cluster was created.
:::
#### Istio {#Istio}
Istio implements the Service Mesh.
@@ -443,7 +462,7 @@ kubectl apply --server-side=true -f deploy/clusters/workload/components/httpbin-
kubectl -n holos-system wait pod -l app.kubernetes.io/instance=httpbin --for=condition=Ready
```
:::important
:::info
Browse to [https://httpbin.holos.localhost/](https://httpbin.holos.localhost/)
to verify end to end connectivity. You should see the httpbin index page.
@@ -482,9 +501,17 @@ kubectl apply --server-side=true -f deploy/clusters/workload/components/authrout
<Tabs groupId="registration">
<TabItem value="registered" label="Signed In">
Verify authentication is working by visiting
<Admonition type="info">
Verify authentication is working by browsing to
[https://httpbin.holos.localhost/holos/authproxy](https://httpbin.holos.localhost/holos/authproxy).
The auth proxy should respond with a simple `Authenticated` response.
We want a simple `Authenticated` response.
<Admonition type="tip">
You may need to refresh the page a few times while the platform configures
itself.
</Admonition>
</Admonition>
Istio will respond with `no healthy upstream` until the pod becomes ready.
Wait for the pod to become ready with:
@@ -495,7 +522,12 @@ kubectl apply --server-side=true -f deploy/clusters/workload/components/authrout
Once authenticated, visit
[https://httpbin.holos.localhost/holos/authproxy/userinfo](https://httpbin.holos.localhost/holos/authproxy/userinfo)
which returns a subset of claims from your id token:
which returns a subset of claims from your id token.
<Admonition type="warning">
If you get `Unauthorized` instead of a json response body, make sure you
[authenticated](https://httpbin.holos.localhost/holos/authproxy) first.
</Admonition>
```json
{
@@ -504,7 +536,6 @@ kubectl apply --server-side=true -f deploy/clusters/workload/components/authrout
"preferredUsername": "demo"
}
```
</TabItem>
<TabItem value="unregistered" label="Signed Out">
The auth proxy will always try to sign you in when you are signed out, so

View File

@@ -1,4 +1,4 @@
# Install Holos
# Installation
Holos is distributed as a single file executable.
@@ -18,4 +18,3 @@ go install github.com/holos-run/holos/cmd/holos@latest
- [helm](https://github.com/helm/helm/releases) to fetch and render Helm chart components.
- [kubectl](https://kubernetes.io/docs/tasks/tools/) to [kustomize](https://kustomize.io/) components.

393
doc/md/quickstart/index.mdx Normal file
View File

@@ -0,0 +1,393 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Admonition from '@theme/Admonition';
# Quickstart Guide
This guide shows you the basics of how Holos. You'll deploy a Helm chart to
Kubernetes using a Component to see how Holos makes the process safer, easier,
and more consistent.
## What you'll need {#Requirements}
You'll need the following tools installed to complete this guide.
1. [holos](/docs/install) - to build the platform.
2. [helm](https://helm.sh/docs/intro/install/) - to render Holos components that
wrap upstream Helm charts.
Optionally, if you'd like to apply the rendered manifests to a real cluster
you'll need:
1. [k3d](https://k3d.io/#installation) - to provide a Kubernetes API server.
2. [OrbStack](https://docs.orbstack.dev/install) or
[Docker](https://docs.docker.com/get-docker/) - to use k3d.
3. [kubectl](https://kubernetes.io/docs/tasks/tools/) - to interact with
kubernetes.
## Install Holos
Install Holos with the following command or other methods listed on the
[Installation](/docs/install/) page.
```bash
go install github.com/holos-run/holos/cmd/holos@latest
```
## Git repository
Start by initializing an empty Git repository. Holos is designed to operate
against local files in a Git repository.
<Tabs groupId="init">
<TabItem value="command" label="Command">
```bash
mkdir holos-quickstart
cd holos-quickstart
git init
```
</TabItem>
<TabItem value="output" label="Output">
```txt
Initialized empty Git repository in /holos-quickstart/.git/
```
</TabItem>
</Tabs>
This guide assumes commands are run from the root directory of this Git
repository unless otherwise stated.
## Generate the Platform {#Generate-Platform}
Generate the Platform code in the repository root. A Platform refers to all of
the software holistically integrated to provide a software development platform
for your organization. In this guide the platform will contain a single
Component to demonstrate how the concepts fit together.
```bash
holos generate platform quickstart
```
Commit the generated platform config to the repository.
<Tabs groupId="commit-platform">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos generate platform quickstart - $(holos --version)"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main (root-commit) 0b17b7f] holos generate platform quickstart
213 files changed, 72349 insertions(+)
...
```
</TabItem>
</Tabs>
## Generate a Component {#generate-component}
The platform you generated is empty. Generate the CUE code definition for a
Component that wraps the podinfo Helm chart.
<Tabs groupId="gen-podinfo">
<TabItem value="command" label="Command">
```bash
holos generate component helm podinfo
```
</TabItem>
<TabItem value="output" label="Output">
```txt
generated component
```
</TabItem>
</Tabs>
This command produces two files. A leaf `components/podinfo/podinfo.gen.cue`
file, and a root `podinfo.gen.cue` file. Holos takes advantage of the fact that
[order is irrelevant](https://cuelang.org/docs/tour/basics/order-irrelevance/)
in CUE to register the component with the Platform specification by adding a
file to the root of the Git repository in addition to defining the component
itself in the leaf component directory.
The Helm chart Component is defined in the `components/podinfo/podinfo.cue`
file, for example:
<Tabs groupId="podinfo-files">
<TabItem value="components/podinfo/podinfo.gen.cue" label="Leaf">
`components/podinfo/podinfo.gen.cue`
```cue
package holos
// Produce a helm chart build plan.
(#Helm & Chart).Output
let Chart = {
Name: "podinfo"
Version: "6.6.2"
Namespace: "default"
Repo: name: "podinfo"
Repo: url: "https://stefanprodan.github.io/podinfo"
Values: {}
}
```
</TabItem>
<TabItem value="podinfo.gen.cue" label="Root">
`podinfo.gen.cue`
```cue
package holos
// Manage podinfo on workload clusters only
for Cluster in #Fleets.workload.clusters {
#Platform: Components: "\(Cluster.name)/podinfo": {
path: "components/podinfo"
cluster: Cluster.name
}
}
```
</TabItem>
</Tabs>
In this example we're providing the minimal information about the Helm chart we
want to manage. The name, version, Kubernetes namespace to deploy into, and the
chart repository location.
This chart deploys cleanly with no values provided, but we include an empty
Values struct to illustrate how Holos improves the consistency and safety of
Helm by taking advantage the strong type checking in CUE. Shared values,
such as the organization domain name, can safely be passed to all Components
across all clusters in the Platform by defining them at the root of the
configuration.
Commit the generated component config to the repository.
<Tabs groupId="commit-component">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos generate component helm podinfo - $(holos --version)"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main cc0e90c] holos generate component helm podinfo
2 files changed, 24 insertions(+)
create mode 100644 components/podinfo/podinfo.gen.cue
create mode 100644 podinfo.gen.cue
```
</TabItem>
</Tabs>
## Render the Component
Individual components can be rendered without needing to be included in a
Platform spec, useful when developing a new component.
<Tabs groupId="render-podinfo">
<TabItem value="command" label="Command">
```bash
holos render component ./components/podinfo --cluster-name=default
```
</TabItem>
<TabItem value="output" label="Output">
```txt
cached
rendered podinfo
```
</TabItem>
</Tabs>
First, the command caches the helm chart locally to speed up subsequent
renderings. Then the command executes helm to produce the output which is
written into the deploy directory.
<Tabs groupId="tree-podinfo">
<TabItem value="command" label="Command">
```bash
tree deploy
```
</TabItem>
<TabItem value="output" label="Output">
```txt
deploy
└── clusters
└── default
└── components
└── podinfo
└── podinfo.gen.yaml
5 directories, 1 file
```
</TabItem>
</Tabs>
The component is deployed to one cluster named default. The same component is
often deployed to multiple clusters, for example east and west for reliability.
:::tip
This example is equivalent to executing `helm template` on the chart and saving
the output to a file. Holos simplifies this task by making it safer and more
consistent across multiple charts.
:::
## Mix in an ArgoCD Application
So far we've seen how Holos is a convenient wrapper around Helm, but we haven't
yet seen how it makes it easier to consistently and safely manage all of the
software that goes into a platform. We'll mix in an ArgoCD
[Application][application] resource to manage the podinfo Component with GitOps.
We'll define this configuration in a way that is automatically and consistently
re-used across all Components added to the Platform in the future, including
Components which are not Helm charts.
Create a new file named `argocd.cue` in the root of your git repository with the
following contents:
<Tabs groupId="argocd-config">
<TabItem value="command" label="File: argocd.cue">
```cue
package holos
#ArgoConfig: {
Enabled: true
RepoURL: "https://example.com/holos-quickstart.git"
}
```
</TabItem>
<TabItem value="note" label="Note">
If you plan to apply the rendered output to a real cluster, change the RepoURL
to the url of the git repository you created in this guide. It is sufficient to
keep the example URL if you're getting a feel for Holos and inspecting the
rendered output without applying it to a live cluster.
</TabItem>
</Tabs>
With this file in place, render the component again.
<Tabs groupId="render-podinfo-argocd">
<TabItem value="command" label="Command">
```bash
holos render component ./components/podinfo --cluster-name=default
```
</TabItem>
<TabItem value="output" label="Output">
```txt
wrote deploy file
rendered gitops/podinfo
rendered podinfo
```
</TabItem>
</Tabs>
Holos uses the locally cached copy of the chart to render the output to improve
performance and reliability. Then, the Helm template output is rendered along
with an additional ArgoCD Application resource for GitOps in the
`podinfo.application.gen.yaml` file.
:::tip
By defining the ArgoCD configuration at the root, we again take advantage of the
fact that [order is
irrelevant](https://cuelang.org/docs/tour/basics/order-irrelevance/) in CUE.
:::
Defining the configuration at the root causes all of the leaf Components to take
on the ArgoCD configuration and render an Application resource for the
Component.
<Tabs groupId="tree-podinfo-argocd">
<TabItem value="command" label="Command">
```bash
tree deploy
```
</TabItem>
<TabItem value="output" label="Output">
```txt
deploy
└── clusters
└── default
├── components
│   └── podinfo
│   └── podinfo.gen.yaml
└── gitops
└── podinfo.application.gen.yaml
6 directories, 2 files
```
</TabItem>
</Tabs>
Note the new `podinfo.application.gen.yaml` created by enabling the ArgoCD in
the Helm component. The Application resource in the file looks like the
following.
<Tabs groupId="podinfo-application">
<TabItem value="file" label="podinfo.application.gen.yaml">
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: podinfo
namespace: argocd
spec:
destination:
server: https://kubernetes.default.svc
project: default
source:
path: ./deploy/clusters/default/components/podinfo
repoURL: https://example.com/holos-quickstart.git
targetRevision: main
```
</TabItem>
</Tabs>
:::tip
Holos will generate a similar Application resource for all additional Components
added to your Platform.
:::
Finally, add and commit the results to your platform Git repository.
<Tabs groupId="commit-argo">
<TabItem value="command" label="Command">
```bash
git add .
git commit -m "holos render component ./components/podinfo --cluster-name=default"
```
</TabItem>
<TabItem value="output" label="Output">
```txt
[main f95cef1] holos render component ./components/podinfo --cluster-name=default
3 files changed, 134 insertions(+)
create mode 100644 argocd.cue
create mode 100644 deploy/clusters/default/components/podinfo/podinfo.gen.yaml
create mode 100644 deploy/clusters/default/gitops/podinfo.application.gen.yaml
```
</TabItem>
</Tabs>
In this section we learned how Holos provides a simple way to add an ArgoCD
Application resource for the podinfo Component which wraps a Helm chart. Holos
provides consistency by managing an Application resource for every Component
added to the platform, all by defining the configuration of ArgoCD in the
`argocd.cue` file in the root of the Git repository.
## Quickstart Recap {#quickstart-recap}
In this guide we learned how to:
1. Install Holos.
2. Generate a Git repository for the Platform config.
3. Create a Component that wraps the upstream podinfo Helm Chart without modifications.
4. Render individual components.
5. Mix in an ArgoCD Application resource to every Component in the Platform.
[application]: https://argo-cd.readthedocs.io/en/stable/user-guide/application-specification/

31
doc/md/runbooks/deploy.md Normal file
View File

@@ -0,0 +1,31 @@
# Deployment
This document describes how deployment from `main` is configured.
1. Refer to the publish workflow.
2. Uses a SSH deploy key to:
3. Clone the holos-infra repo.
4. Write the image tag to saas/userdata/components/dev-holos-app/images.json
5. Run holos render platform ./platform
6. Commit and push the results.
7. ArgoCD takes over the rollout.
## Credentials
TODO: Lock this down more, the deploy key has too much access to the infra
repository.
```bash
mkdir -p tmp
cd tmp
ssh-keygen -t ed25519 -f holos-infra.key -m pem -C holos-run/holos -N ''
gh secret set DEPLOY_SSH_PRIVATE_KEY < holos-infra.key
gh api --method POST \
-H "Accept: application/vnd.github+json" \
/repos/holos-run/holos-infra/keys \
-f title='holos-run/holos deploy key' \
-f key="$(cat holos-infra.key.pub)" \
-F read_only=false
cd ..
rm -rf tmp
```

View File

@@ -4,7 +4,7 @@ import type * as Preset from '@docusaurus/preset-classic';
const config: Config = {
title: 'Holos',
tagline: 'The Platform Operating System',
tagline: 'The Holistic Package Manager for Cloud Native Applications',
favicon: 'img/favicon.ico',
// Set the production url of your site here
@@ -35,15 +35,17 @@ const config: Config = {
mermaid: true
},
// TODO: These redirects don't seem to be working, at least with the `npm run
// start` dev server.
plugins: [
[
'@docusaurus/plugin-client-redirects',
{
redirects: [
{
from: "/docs/tutorial/local/k3d/",
to: "/docs/guides/try-holos/",
from: "/docs/tutorial/local/k3d/"
}
},
],
},
],
@@ -96,13 +98,13 @@ const config: Config = {
items: [
{
type: 'doc',
docId: 'guides/try-holos/index',
docId: 'quickstart/index',
position: 'left',
label: 'Try Holos',
},
{
type: 'doc',
docId: 'intro',
docId: 'concepts',
position: 'left',
label: 'Docs',
},
@@ -133,8 +135,12 @@ const config: Config = {
title: 'Docs',
items: [
{
label: 'Try Holos Locally',
to: '/docs/guides/try-holos',
label: 'Get Started',
to: '/docs/quickstart',
},
{
label: 'Concepts',
to: '/docs/concepts',
},
{
label: 'Documentation',
@@ -151,7 +157,7 @@ const config: Config = {
items: [
{
label: 'Discuss',
href: 'https://github.com/orgs/holos-run/discussions',
href: 'https://github.com/holos-run/holos/discussions',
},
],
},

File diff suppressed because it is too large Load Diff

View File

@@ -15,10 +15,10 @@
"typecheck": "tsc"
},
"dependencies": {
"@docusaurus/core": "3.4.0",
"@docusaurus/plugin-client-redirects": "^3.4.0",
"@docusaurus/preset-classic": "3.4.0",
"@docusaurus/theme-mermaid": "^3.4.0",
"@docusaurus/core": "^3.5.2",
"@docusaurus/plugin-client-redirects": "^3.5.2",
"@docusaurus/preset-classic": "^3.5.2",
"@docusaurus/theme-mermaid": "^3.5.2",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
@@ -26,9 +26,9 @@
"react-dom": "^18.0.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.4.0",
"@docusaurus/tsconfig": "^3.4.0",
"@docusaurus/types": "^3.4.0",
"@docusaurus/module-type-aliases": "^3.5.2",
"@docusaurus/tsconfig": "^3.5.2",
"@docusaurus/types": "^3.5.2",
"@wcj/html-to-markdown-cli": "^2.1.1",
"cspell": "^8.10.4",
"html-to-markdown": "^1.0.0",

View File

@@ -12,40 +12,29 @@ import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';
*/
const sidebars: SidebarsConfig = {
doc: [
'intro',
{
type: 'category',
label: 'Guides',
collapsed: false,
items: [
'guides/install',
'guides/try-holos/index',
'guides/try-holos/platform-manifests',
'guides/argocd/index',
'guides/backstage/index',
'guides/observability/index',
],
},
{
type: 'category',
label: 'Design',
collapsed: false,
items: [
'design/rendering',
],
},
{
type: 'category',
label: 'Reference Platform',
collapsed: false,
items: [
'reference-platform/architecture',
],
},
'glossary',
'quickstart/index',
'concepts',
'install',
'comparison',
],
api: [
'api/core/v1alpha2',
{
label: 'Schema',
type: 'category',
collapsed: false,
items: [
'api/schema/v1alpha3',
],
},
{
label: 'Core API',
type: 'category',
collapsed: true,
items: [
'api/core/v1alpha3',
'api/core/v1alpha2',
],
},
'cli',
],
};

View File

@@ -8,36 +8,50 @@ type FeatureItem = {
description: JSX.Element;
};
// TODO: Consider focusing on the three pillars of Safe, Easy, Consistent.
const FeatureList: FeatureItem[] = [
{
title: 'Zero Trust Security',
Svg: require('@site/static/img/base00/undraw_security_on_re_e491.svg').default,
title: 'Kustomize Helm',
Svg: require('@site/static/img/base00/undraw_together_re_a8x4.svg').default,
description: (
<>
Spend more time on your business features and less time rebuilding
authentication and authorization. Holos provides zero trust security
with no code needed to protect your services.
Super charge your existing Helm charts by providing well defined,
validated input values, post-processing the output with Kustomize,
and mixing in your own custom resources. All without modifying upstream
charts to alleviate the pain of upgrades.
</>
),
},
{
title: 'Multi-Cloud',
Svg: require('@site/static/img/base00/undraw_cloud_hosting_7xb1.svg').default,
title: 'Unified Data Model',
Svg: require('@site/static/img/base00/undraw_fitting_pieces_re_nss7.svg').default,
description: (
<>
Avoid vendor lock in, downtime, and price hikes. Holos is designed to
easily deploy workloads into multiple clouds and multiple regions.
Unify all of your platform components into one well-defined, strongly
typed data model with CUE. Holos makes it easier and safer to integrate
seamlessly with software distributed with current and future tools that
produce Kubernetes resource manifests.
</>
),
},
{
title: 'Developer Portal',
Svg: require('@site/static/img/base00/undraw_data_trends_re_2cdy.svg').default,
title: 'Deep Insights',
Svg: require('@site/static/img/base00/undraw_code_review_re_woeb.svg').default,
description: (
<>
Ship high quality code quickly, provide a great developer experience,
and maintain control over your infrastructure with the integrated
Backstage developer portal.
Reduce risk and increase confidence in your configuration changes.
Holos offers clear visibility into complete resource configuration
<i>before</i> being applied.
</>
),
},
{
title: 'Interoperable',
Svg: require('@site/static/img/base00/undraw_version_control_re_mg66.svg').default,
description: (
<>
Holos is designed for compatibility with your preferred tools and
processes, for example git diff and code reviews.
</>
),
},

View File

@@ -21,3 +21,7 @@
align-items: center;
justify-content: center;
}
.divider {
margin: 0 5px;
}

View File

@@ -17,19 +17,26 @@ function HomepageHeader() {
</Heading>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<p className="projectDesc">
Holos is a holistic software development platform built from the most
popular open source projects.<br /> Build your developer platform in
no time.
Holos adds CUE's type safety, unified structure, and strong validation
features to your current software packages, including Helm and
Kustomize. These features make the experience of integrating software
packages into a holistic platform a pleasant journey.
</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/docs/intro">
to="docs/quickstart">
Get Started
</Link>
<span className={styles.divider}></span>
<Link
className="button button--primary button--lg"
to="docs/concepts">
Learn More
</Link>
</div>
</div>
</header>
</header >
);
}
@@ -37,8 +44,8 @@ export default function Home(): JSX.Element {
const { siteConfig } = useDocusaurusContext();
return (
<Layout
title={`Hello from ${siteConfig.title}`}
description="Holos provides a software development platform that holistically integrates the most popular cloud native projects.">
title={`${siteConfig.title} Package Manager`}
description="Holos adds CUE's type safety, unified structure, and strong validation features to your current software packages, including Helm and Kustomize.">
<HomepageHeader />
<main>
<HomepageFeatures />

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 28 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="581.17725" height="668" viewBox="0 0 581.17725 668" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M248.22582,95.78906h89.68896v73.14404h-89.68896V95.78906Zm87.68896,2h-85.68896v69.14404h85.68896V97.78906Z" fill="#3f3d56"/><rect x="286.81782" y="130.98987" width="70.42636" height="1.99974" transform="translate(181.51001 450.39061) rotate(-88.47361)" fill="#3f3d56"/><rect x="260.34565" y="130.98987" width="70.42636" height="1.99974" transform="translate(155.74299 423.92783) rotate(-88.47361)" fill="#3f3d56"/><rect x="233.87348" y="130.98987" width="70.42636" height="1.99974" transform="translate(129.97597 397.46506) rotate(-88.47361)" fill="#3f3d56"/><path d="M348.72143,167.19043h2v-25.20508l-.72803-.20605c-.60986-.17334-61.65332-17.0542-116.78076,.00732l-.70459,.21777v22.75928h2v-21.28271c51.125-15.53857,107.2041-1.80664,114.21338,.02783v23.68164Z" fill="#3f3d56"/><path d="M233.76635,153.69775c64.82178-17.31445,115.12402-.19727,115.625-.02246l.66016-1.8877c-.50586-.17676-51.35449-17.50244-116.80127-.02246l.51611,1.93262Z" fill="#3f3d56"/><path d="M233.76635,161.05615c64.82178-17.31543,115.12402-.19678,115.625-.02246l.66016-1.8877c-.50586-.17676-51.35449-17.50244-116.80127-.02246l.51611,1.93262Z" fill="#3f3d56"/><path d="M246.74401,244.86805h89.34375v-66.20661l12.40885-10.72828c-38.14672-11.12717-76.76201-11.43174-115.81597-1.65451l14.06337,12.69546v65.89394Z" fill="#657b83"/><path d="M369.00512,238.97021h2v-33.73975l-.72803-.20605c-.82227-.23193-83.0752-22.97705-157.34863,.00732l-.70459,.21777v30.44629h2v-28.97021c69.79443-21.31152,146.50439-2.16113,154.78125,.02686v32.21777Z" fill="#3f3d56"/><path d="M213.48217,220.43018c87.56445-23.39014,155.5166-.25879,156.19287-.02246l.66016-1.8877c-.68164-.23877-69.17871-23.57813-157.36914-.02246l.51611,1.93262Z" fill="#3f3d56"/><path d="M213.48217,230.35742c87.56689-23.39014,155.51611-.25879,156.19287-.02246l.66016-1.8877c-.68164-.23828-69.17871-23.57764-157.36963-.02246l.5166,1.93262Z" fill="#3f3d56"/><path d="M240.95321,96.78906c0,15.53397,27.00976,.40367,48.94007,.40367s50.33076,15.13029,50.33076-.40367-26.05059-39.70833-47.9809-39.70833c-21.93031,0-51.28993,24.17436-51.28993,39.70833Z" fill="#657b83"/><rect x="270.73446" y="43.84462" width="43.01736" height="23.16319" transform="translate(584.48627 110.85243) rotate(-180)" fill="#657b83"/><rect x="288.10685" y="0" width="6.61806" height="47.9809" transform="translate(582.83176 47.9809) rotate(-180)" fill="#657b83"/><path d="M199.59036,667.59633h173.72395l-26.47222-380.53818,34.74479-46.32639c-59.18845-9.46943-119.14115-12.02188-180.34201-3.30903l24.81771,43.01736-26.47222,387.15623Z" fill="#e6e6e6"/><g><rect x="226.06258" y="594.79772" width="31.43576" height="72.79861" transform="translate(483.56093 1262.39405) rotate(-180)" fill="#fff"/><polyline points="280.66154 667.59633 282.31605 584.87064 263.40639 561.70744 242.60772 561.70744 257.49835 586.29047 258.97862 666.78245" fill="#ccc"/></g><g><rect x="301.06258" y="594.79772" width="31.43576" height="72.79861" transform="translate(633.56093 1262.39405) rotate(-180)" fill="#fff"/><polyline points="355.66154 667.59633 357.31605 584.87064 338.40639 561.70744 317.60772 561.70744 332.49835 586.29047 333.97862 666.78245" fill="#ccc"/></g><path d="M434.0852,668h2v-56.8208l-.72803-.20605c-.37207-.10498-37.84863-10.58545-91.42773-15.78418-49.46045-4.7998-123.16992-5.95557-193.44287,15.7915l-.70459,.21777v54.61084h2v-53.13525c69.74414-21.42383,142.84131-20.26025,191.95459-15.49414,49.30518,4.78418,84.88721,14.04346,90.34863,15.51855v55.30176Z" fill="#3f3d56"/><path d="M151.03979,637.34082c83.10986-22.19971,155.81982-21.02441,202.18115-16.12939,50.24316,5.30469,81.22705,15.99951,81.53418,16.10693l.66016-1.8877c-.30859-.10791-31.46045-10.8667-81.91406-16.20068-46.54443-4.92041-119.54102-6.10791-202.97754,16.17822l.51611,1.93262Z" fill="#3f3d56"/><path d="M151.03979,655.34229c83.10986-22.19922,155.81982-21.02441,202.18115-16.12939,50.24316,5.30469,81.22705,15.99951,81.53418,16.10693l.66016-1.8877c-.30859-.10791-31.46045-10.8667-81.91406-16.20068-46.54346-4.9209-119.54102-6.10791-202.97754,16.17822l.51611,1.93262Z" fill="#3f3d56"/><rect x="0" y="665.78223" width="581.17725" height="2" fill="#2f2e41"/></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="532" height="532" viewBox="0 0 532 532" xmlns:xlink="http://www.w3.org/1999/xlink"><circle cx="270.75986" cy="260.93427" r="86.34897" fill="#ffb6b6"/><polygon points="221.18982 360.05209 217.28876 320.6185 295.18982 306.05209 341.18982 418.05209 261.18982 510.05209 204.18982 398.05209 221.18982 360.05209" fill="#ffb6b6"/><path d="m216.0374,340.35736l17.03111,3.84802s-13.38821-42.45453-8.84396-46.50766c4.54427-4.05316,15.68007,2.33328,15.68007,2.33328l11.70201,13.1199,14.25394-14.51239s15.47495-19.2421,21.53397-24.6463-3.67319-25.46364-3.67319-25.46364c0,0,89.89185-24.23923,56.44299-67.83968,0,0-19.61093-34.18452-25.99734-23.04871-6.38641,11.1358-14.00162-6.55013-14.00162-6.55013l-23.25381,4.42198s-45.89429-27.06042-89.45331,30.82959c-43.55902,57.89003,28.57916,154.01572,28.57916,154.01572h-.00002Z" fill="#2f2e41"/><path d="m433.16003,472.95001c-47.19,38.26001-105.57001,59.04999-167.16003,59.04999-56.23999,0-109.81-17.33997-154.62-49.47998.08002-.84003.16003-1.66998.23004-2.5,1.19-13,2.25-25.64001,2.94995-36.12,2.71002-40.69,97.64001-67.81,97.64001-67.81,0,0,.42999.42999,1.29004,1.17999,5.23999,4.59998,26.50995,21.27997,63.81,25.94,33.25995,4.15997,44.20996-15.57001,47.51996-25.02002,1-2.88,1.30005-4.81,1.30005-4.81l97.63995,46.10999c6.37,9.10004,8.86005,28.70001,9.35004,50.73004.01996.90997.03998,1.81.04999,2.72998Z" fill="#657b83"/><path d="m454.09003,77.91003C403.85004,27.66998,337.05005,0,266,0S128.15002,27.66998,77.91003,77.91003C27.67004,128.15002,0,194.95001,0,266c0,64.85004,23.05005,126.16003,65.29004,174.57001,4.02997,4.63,8.23999,9.14001,12.62,13.52002,1.02997,1.02997,2.07001,2.06,3.12,3.06,2.79999,2.70996,5.65002,5.35999,8.54999,7.92999,1.76001,1.57001,3.54004,3.10999,5.34003,4.62,1.40997,1.19,2.82001,2.35999,4.25,3.51001.02997.02997.04999.04999.07996.07001,3.97003,3.19995,8.01001,6.27997,12.13,9.23999,44.81,32.14001,98.37999,49.47998,154.61998,49.47998,61.59003,0,119.97003-20.78998,167.16003-59.04999,3.84998-3.12,7.62-6.35999,11.32001-9.71002,3.26996-2.95996,6.46997-6.01001,9.60999-9.14996.98999-.98999,1.97998-1.98999,2.95001-3,2.70001-2.78003,5.32001-5.61005,7.88-8.48004,43.37-48.71997,67.07996-110.83997,67.07996-176.60999,0-71.04999-27.66998-137.84998-77.90997-188.08997Zm10.17999,362.20997c-2.5,2.84003-5.06,5.64001-7.67999,8.37-4.08002,4.25-8.28998,8.37-12.64001,12.34003-1.64996,1.52002-3.32001,3-5.01001,4.46997-1.91998,1.67004-3.85999,3.31-5.82996,4.92004-15.53003,12.75-32.54004,23.75-50.73004,32.70996-7.19,3.54999-14.56,6.78003-22.09998,9.67004-29.28998,11.23999-61.08002,17.39996-94.28003,17.39996-32.03998,0-62.75995-5.73999-91.19-16.23999-11.66998-4.29999-22.94995-9.40997-33.77997-15.26001-1.59003-.85999-3.16998-1.72998-4.73999-2.62-8.26001-4.67999-16.25-9.78998-23.91998-15.31-.25-.17999-.51001-.37-.76001-.54999-5.46002-3.94-10.77002-8.09003-15.90002-12.45001-1.88-1.59003-3.73999-3.20001-5.57001-4.84998-2.97998-2.65002-5.89996-5.38-8.75-8.18005-5.39996-5.28998-10.56-10.79999-15.48999-16.52997C26.09003,391.77002,2,331.65002,2,266,2,120.42999,120.43005,2,266,2s264,118.42999,264,264c0,66.66003-24.82996,127.62-65.72998,174.12Z" fill="#3f3d56"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="532" height="532" viewBox="0 0 532 532" xmlns:xlink="http://www.w3.org/1999/xlink"><g><g><circle cx="270.759" cy="260.92941" r="86.34897" fill="#a0616a"/><polygon points="199.2879 366.61365 217.2879 320.61365 310.2879 306.61365 320.28003 408.44043 226.28003 410.44043 199.2879 366.61365" fill="#a0616a"/></g><path d="M357.94449,276.8613c-1.12067,4.48965-3.38602,15.17972-6.9238,15.23233-2.89023,.04208-5.65668-46.33466-2.76953-54.00568,3.31638-8.81271-5.39886-19.96062-11.96411-25.6832-11.80423-10.2894-38.00696,11.80466-64.65118,1.79587-.70633-.26482-.56558-.23502-8.97934-3.59174-25.88966-10.32974-27.2506-10.62788-28.73386-10.77521-12.55046-1.24167-27.86705,9.02844-34.12146,21.55038-6.50168,13.01653-1.06937,24.18106-7.18346,55.67184-.71246,3.67065-1.83138,8.90216-3.59174,8.97934-3.21819,.14029-6.3605-17.04846-7.18346-21.55038-3.44792-18.86186-6.7722-37.04675,0-57.46771,.73878-2.22729,5.29158-10.49458,14.36693-26.93799,13.0744-23.68825,19.65018-35.57709,21.55038-37.7132,13.62859-15.32624,38.43575-29.30734,59.26357-23.34626,10.52704,3.01299,8.63953,7.85691,21.55038,12.57105,23.00821,8.40057,43.00476-1.87303,46.69254,5.3876,1.9537,3.84602-3.51236,7.01686-3.59174,14.36693-.13593,12.6114,15.81424,16.25575,25.14212,28.73386,5.01447,6.70819,13.59753,6.78012-8.87228,96.78212l.00003,.00003Z" fill="#2f2e41"/></g><path d="M464.92017,442.61035c-3.48022,3.91016-7.09009,7.74023-10.83008,11.48047-50.23999,50.23926-117.04004,77.90918-188.09009,77.90918-61.40991,0-119.63989-20.66992-166.75-58.71973-.03003-.01953-.05005-.04004-.07983-.07031-6.25-5.03906-12.30005-10.39941-18.14014-16.05957,.10986-.87988,.22998-1.75,.35986-2.61035,.82007-5.7998,1.73022-11.33008,2.75-16.41992,8.3501-41.71973,118.22021-85.51953,121.08008-86.66016,.04004-.00977,.06006-.01953,.06006-.01953,0,0,14.14014,52.12012,74.72998,51.4502,41.27002-.4502,33.27002-51.4502,33.27002-51.4502,0,0,.5,.09961,1.43994,.2998,11.91992,2.53027,94.68018,20.70996,127.33008,45.52051,9.94995,7.55957,17.08984,23.66016,22.21997,42.85938,.21997,.82031,.42993,1.66016,.65015,2.49023Z" fill="#657b83"/><path d="M454.09009,77.91016C403.8501,27.6709,337.05005,0,266,0S128.15015,27.6709,77.90991,77.91016C27.67017,128.15039,0,194.9502,0,266c0,64.85059,23.05005,126.16016,65.29004,174.57031,4.03003,4.62988,8.23999,9.13965,12.61987,13.52051,1.03003,1.0293,2.07007,2.05957,3.12012,3.05957,5.84009,5.66016,11.89014,11.02051,18.14014,16.05957,.02979,.03027,.0498,.05078,.07983,.07031,47.11012,38.0498,105.3401,58.71973,166.75001,58.71973,71.05005,0,137.8501-27.66992,188.09009-77.90918,3.73999-3.74023,7.34985-7.57031,10.83008-11.48047,43.36987-48.71973,67.07983-110.83984,67.07983-176.61035,0-71.0498-27.66992-137.84961-77.90991-188.08984Zm10.17993,362.20996c-7.86987,8.9502-16.33008,17.37012-25.33008,25.18066-17.06982,14.84961-36.06982,27.5293-56.55981,37.62988-7.19019,3.5498-14.56006,6.7793-22.1001,9.66992-29.29004,11.24023-61.08008,17.39941-94.28003,17.39941-32.04004,0-62.76001-5.73926-91.18994-16.23926-11.67017-4.30078-22.94995-9.41016-33.78003-15.26074-1.59009-.85938-3.16992-1.72949-4.73999-2.61914-8.26001-4.68066-16.25-9.79004-23.91992-15.31055-10.98999-7.87988-21.3501-16.58984-30.98022-26.03027-5.3999-5.29004-10.55981-10.7998-15.48975-16.5293C26.09009,391.77051,2,331.65039,2,266,2,120.43066,120.42993,2,266,2s264,118.43066,264,264c0,66.66016-24.82983,127.62012-65.72998,174.12012Z" fill="#3f3d56"/></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="537.64" height="577.45" viewBox="0 0 537.64 577.45" xmlns:xlink="http://www.w3.org/1999/xlink"><rect x="280.93" y="-24.02" width="4" height="352.38" transform="translate(-37.98 167.04) rotate(-30.93)" fill="#000019"/><polygon points="245.05 178.56 268.82 186.38 268.82 152.16 247.25 152.16 245.05 178.56" fill="#f3a3a6"/><circle cx="265.88" cy="137.94" r="23.69" fill="#f3a3a6"/><path d="m259.85,139.8l3.26,3.96,5.91-10.34s7.54.39,7.54-5.21c0-5.6,6.92-5.75,6.92-5.75,0,0,9.79-17.1-10.49-12.59,0,0-14.07-9.64-21.06-1.4,0,0-21.45,10.8-15.31,29.61l10.2,19.39,2.31-4.39s-1.4-18.42,10.73-13.29Z" fill="#2f2e43"/><rect x="280.32" y="528.57" width="20.94" height="29.71" transform="translate(581.58 1086.85) rotate(-180)" fill="#f3a3a6"/><path d="m298.94,575.3c-3.58.32-21.5,1.74-22.4-2.37-.82-3.77.39-7.71.56-8.25,1.72-17.14,2.36-17.33,2.75-17.44.61-.18,2.39.67,5.28,2.53l.18.12.04.21c.05.27,1.33,6.56,7.4,5.59,4.16-.66,5.51-1.58,5.94-2.03-.35-.16-.79-.44-1.1-.92-.45-.7-.53-1.6-.23-2.68.78-2.85,3.12-7.06,3.22-7.23l.27-.48,23.8,16.06,14.7,4.2c1.11.32,2,1.11,2.45,2.17h0c.62,1.48.24,3.2-.96,4.28-2.67,2.4-7.97,6.51-13.54,7.02-1.48.14-3.44.19-5.64.19-9.19,0-22.61-.95-22.71-.97Z" fill="#2f2e43"/><rect x="202.3" y="493.53" width="20.94" height="29.71" transform="translate(72.11 1041.25) rotate(-142.5)" fill="#f3a3a6"/><path d="m199.84,538.64c-3.04-1.92-18.12-11.71-16.33-15.51,1.64-3.49,5-5.89,5.47-6.2,11.8-12.55,12.42-12.31,12.8-12.17.6.23,1.49,1.98,2.65,5.22l.07.2-.1.19c-.12.24-2.93,6.02,2.46,8.94,3.7,2.01,5.33,2.1,5.95,2.01-.18-.34-.36-.83-.31-1.4.07-.83.55-1.59,1.45-2.27,2.35-1.78,6.77-3.7,6.96-3.78l.5-.22,9.11,27.23,9.11,12.28c.69.93.91,2.1.62,3.22h0c-.41,1.56-1.76,2.69-3.37,2.81-3.58.28-10.29.31-15.01-2.67-1.25-.79-2.84-1.94-4.59-3.28-7.29-5.6-17.36-14.52-17.43-14.59Z" fill="#2f2e43"/><path d="m0,576.26c0,.66.53,1.19,1.19,1.19h535.26c.66,0,1.19-.53,1.19-1.19s-.53-1.19-1.19-1.19H1.19c-.66,0-1.19.53-1.19,1.19Z" fill="#2f2e43"/><path d="m314.2,315.16l-79.06,8.07s-11.29,37.11,4.84,54.86l9.68,50.02-43.56,59.7,27.43,17.75,38.72-41.95v70.99l37.11-3.23,17.75-111.33-12.91-104.88Z" fill="#2f2e43"/><path d="m278.7,173.17s-6.45-11.29-33.88-9.68l-6.45,14.52s-19.36,4.84-19.36,33.88,9.68,116.17,9.68,116.17l94.39-5.65-43.66-136.47-.71-12.78Z" fill="#ccc"/><path d="m183.03,47.44c-3.34,22.1-1.81,44.89,4.34,66.36l103.82-54.67c-1.81-2.15-3.66-4.26-5.59-6.3-15.57-16.43-34.96-29.15-56.24-36.82-7.82,3.36-15.94,7.38-24.35,12.19-7.6,4.34-14.56,8.75-20.94,13.19-.39,2.01-.74,4.02-1.04,6.04Z" fill="#657b83"/><path d="m241.89,17.9c12,5.5,23.22,12.64,33.35,21.1,6.78,5.66,13.02,11.94,18.66,18.72l68.6-36.12s-47.65-40.3-129.12-7.25c2.87,1.1,5.71,2.28,8.5,3.56Z" fill="#657b83"/><path d="m182.33,106.3c-4.67-20.45-5.25-41.79-1.73-62.44-72.78,52.48-65.84,108.18-65.84,108.18l69.91-36.81c-.86-2.95-1.66-5.92-2.35-8.92Z" fill="#657b83"/><path id="uuid-215a2cca-fbee-4bbc-9bf2-8b7e67129ed8-5794" d="m364.5,276.19c6.17,2.84,9.62,8.42,7.71,12.47-1.91,4.05-8.47,5.03-14.64,2.2-2.48-1.1-4.65-2.79-6.32-4.95l-25.99-12.36,6.4-12.46,24.95,13.51c2.74-.12,5.46.42,7.91,1.59,0,0,0,0,0,0Z" fill="#f3a3a6"/><path d="m348.4,285.3l-62.74-20.49-.07-.07-47.79-44.22c-7.32-6.77-8.42-17.96-2.55-26.03,3.59-4.94,9.15-7.89,15.25-8.1,6.1-.21,11.85,2.36,15.77,7.04l35.89,42.86,51.69,33.58-5.45,15.43Z" fill="#ccc"/></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

30
hack/deploy-dev Executable file
View File

@@ -0,0 +1,30 @@
#! /bin/bash
#
set -euo pipefail
tmpdir="$(mktemp -d)"
finish() {
rm -rf "$tmpdir"
}
trap finish EXIT
set -euo pipefail
: ${GIT_DETAIL:=$(git describe --tags HEAD)}
: ${GIT_SUFFIX:=$(test -n "`git status --porcelain`" && echo "-dirty" || echo "")}
cd "$tmpdir"
git clone --depth 1 git@github.com:holos-run/holos-infra.git
cd holos-infra/saas
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
echo '{"components":{"dev-holos-app":{"stages":{"dev":{"images":{"quay.io/holos-run/holos":{"newTag":"'"${GIT_DETAIL}"'"}}}}}}}' > userdata/components/dev-holos-app/images.json
holos render platform ./platform
git add .
git commit -m "dev-holos-app: deploy ${GIT_DETAIL}${GIT_SUFFIX} [auto]"
git --no-pager show --stat
git push origin HEAD
echo
echo "https://argocd.admin.aws2.holos.run/applications/dev-holos-app"

View File

@@ -2,15 +2,16 @@
#
set -euo pipefail
prefix="$(git rev-parse --show-prefix)"
# Generate the documentation for the package the calls go:generate
package="$(git rev-parse --show-prefix)"
cd "$(git rev-parse --show-toplevel)"
mkdir -p "doc/md/$(dirname "${prefix}")"
gomarkdoc --output "doc/md/${prefix%/}.md" "./${prefix}"
mkdir -p "doc/md/$(dirname "${package}")"
gomarkdoc --output "doc/md/${package%/}.md" "./${package}"
# Fix heading anchors by making them explicit
# Refer to https://docusaurus.io/docs/markdown-features/toc#heading-ids
stamp=$RANDOM
# sed 's/^## type /## /' "doc/md/${prefix%/}.md" > "doc/md/${prefix%/}.md.${stamp}"
# sed 's/^## type /## /' "doc/md/${package%/}.md" > "doc/md/${package%/}.md.${stamp}"
sed -E 's/## type ([A-Za-z0-9_]+)/## type \1 {#\1}/' "doc/md/${prefix%/}.md" > "doc/md/${prefix%/}.md.${stamp}"
mv "doc/md/${prefix%/}.md.${stamp}" "doc/md/${prefix%/}.md"
sed -E 's/## type ([A-Za-z0-9_]+)/## type \1 {#\1}/' "doc/md/${package%/}.md" > "doc/md/${package%/}.md.${stamp}"
mv "doc/md/${package%/}.md.${stamp}" "doc/md/${package%/}.md"

View File

@@ -15,7 +15,7 @@ import (
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"github.com/holos-run/holos/api/core/v1alpha2"
v1 "github.com/holos-run/holos/api/core/v1alpha3"
"github.com/holos-run/holos/api/v1alpha1"
"github.com/holos-run/holos"
@@ -26,10 +26,10 @@ import (
)
const (
KubernetesObjects = v1alpha2.KubernetesObjectsKind
KubernetesObjects = v1.KubernetesObjectsKind
// Helm is the value of the kind field of holos build output indicating helm
// values and helm command information.
Helm = v1alpha2.HelmChartKind
Helm = v1.HelmChartKind
// Skip is the value when the instance should be skipped
Skip = "Skip"
// KustomizeBuild is the value of the kind field of cue output indicating
@@ -60,7 +60,7 @@ type BuildData struct {
}
type buildPlanWrapper struct {
buildPlan *v1alpha2.BuildPlan
buildPlan *v1.BuildPlan
}
func (b *buildPlanWrapper) validate() error {
@@ -72,14 +72,11 @@ func (b *buildPlanWrapper) validate() error {
return fmt.Errorf("invalid BuildPlan: is nil")
}
errs := make([]string, 0, 2)
if bp.Kind != v1alpha2.BuildPlanKind {
if bp.Kind != v1.BuildPlanKind {
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", v1alpha1.BuildPlanKind, bp.Kind))
}
if bp.APIVersion != v1alpha2.APIVersion {
errs = append(errs, fmt.Sprintf("apiVersion invalid: want: %s have: %s", v1alpha2.APIVersion, bp.APIVersion))
}
if len(errs) > 0 {
return fmt.Errorf("invalid BuildPlan: " + strings.Join(errs, ", "))
return errors.New("invalid BuildPlan: " + strings.Join(errs, ", "))
}
return nil
}
@@ -282,7 +279,7 @@ func (b Builder) build(ctx context.Context, bd BuildData) (results []*render.Res
switch tm.Kind {
case "BuildPlan":
var bp v1alpha2.BuildPlan
var bp v1.BuildPlan
if err = decoder.Decode(&bp); err != nil {
err = errors.Wrap(fmt.Errorf("could not decode BuildPlan %s: %w", bd.Dir, err))
return
@@ -298,7 +295,7 @@ func (b Builder) build(ctx context.Context, bd BuildData) (results []*render.Res
return results, err
}
func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1alpha2.BuildPlan, path holos.InstancePath) (results []*render.Result, err error) {
func (b *Builder) buildPlan(ctx context.Context, buildPlan *v1.BuildPlan, path holos.InstancePath) (results []*render.Result, err error) {
log := logger.FromContext(ctx)
bpw := buildPlanWrapper{buildPlan: buildPlan}

View File

@@ -7,7 +7,6 @@ import (
"strings"
"github.com/holos-run/holos/internal/cli/command"
"github.com/holos-run/holos/internal/client"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/generate"
"github.com/holos-run/holos/internal/holos"
@@ -35,11 +34,9 @@ func NewPlatform(cfg *holos.Config) *cobra.Command {
cmd.Args = cobra.ExactArgs(1)
cmd.RunE = func(cmd *cobra.Command, args []string) error {
ctx := cmd.Root().Context()
clientContext := holos.NewClientContext(ctx)
client := client.New(client.NewConfig(cfg))
for _, name := range args {
if err := generate.GeneratePlatform(ctx, client, clientContext.OrgID, name); err != nil {
if err := generate.GeneratePlatform(ctx, name); err != nil {
return errors.Wrap(err)
}
}

View File

@@ -41,7 +41,7 @@ func New(cfg *holos.Config) *cobra.Command {
if printClaims {
fmt.Fprintln(cmd.OutOrStdout(), token.Pretty)
} else {
fmt.Fprintf(cmd.OutOrStdout(), token.Bearer)
fmt.Fprintln(cmd.OutOrStdout(), token.Bearer)
}
return nil

File diff suppressed because one or more lines are too long

View File

@@ -131,8 +131,8 @@ func makeRenderFunc[T any](log *slog.Logger, path string, cfg T) func([]byte) *b
func GenerateComponent(ctx context.Context, kind string, name string, cfg *Schematic) error {
// use name from args to build the source path
path := filepath.Join(componentsRoot, kind, name)
// use cfg.Name from flags to build the destination path
dstPath := filepath.Join(getCwd(ctx), cfg.Name)
// write to the current directory.
dstPath := filepath.Join(getCwd(ctx))
log := logger.FromContext(ctx).With("name", cfg.Name, "path", dstPath)
log.DebugContext(ctx, "mkdir")
if err := os.MkdirAll(dstPath, os.ModePerm); err != nil {

View File

@@ -1,5 +1,8 @@
package holos
// Produce a helm chart build plan.
(#Helm & Chart).Output
let Chart = {
Name: "{{ .Name }}"
Version: "{{ .Version }}"
@@ -10,6 +13,3 @@ let Chart = {
Values: {}
}
// Produce a helm chart build plan.
(#Helm & Chart).Output

View File

@@ -0,0 +1,9 @@
package holos
// Manage podinfo on workload clusters only
for Cluster in #Fleets.workload.clusters {
#Platform: Components: "\(Cluster.name)/podinfo": {
path: "components/podinfo"
cluster: Cluster.name
}
}

View File

@@ -37,27 +37,9 @@ func Platforms() []string {
return dirs
}
func writePlatformMetadata(ctx context.Context, rpc *client.Client, orgID string, name string) error {
func initPlatformMetadata(ctx context.Context, name string) error {
log := logger.FromContext(ctx)
// Link the local platform the SaaS platform ID.
rpcPlatforms, err := rpc.Platforms(ctx, orgID)
if err != nil {
return errors.Wrap(err)
}
var rpcPlatform *platform.Platform
for _, p := range rpcPlatforms {
if p.GetName() == name {
rpcPlatform = p
break
}
log.DebugContext(ctx, "checking platform", "want", name, "have", p.GetName())
}
if rpcPlatform == nil {
return errors.Wrap(errors.New("cannot generate: platform not found in the holos server"))
}
rpcPlatform := &platform.Platform{Name: name}
// Write the platform data.
encoder := protojson.MarshalOptions{Indent: " "}
data, err := encoder.Marshal(rpcPlatform)
@@ -67,7 +49,7 @@ func writePlatformMetadata(ctx context.Context, rpc *client.Client, orgID string
if len(data) > 0 {
data = append(data, '\n')
}
log = log.With("platform_id", rpcPlatform.GetId())
if err := os.WriteFile(client.PlatformMetadataFile, data, 0644); err != nil {
return errors.Wrap(fmt.Errorf("could not write platform metadata: %w", err))
}
@@ -78,7 +60,7 @@ func writePlatformMetadata(ctx context.Context, rpc *client.Client, orgID string
// GeneratePlatform writes the cue code for a platform to the local working
// directory.
func GeneratePlatform(ctx context.Context, rpc *client.Client, orgID string, name string) error {
func GeneratePlatform(ctx context.Context, name string) error {
log := logger.FromContext(ctx)
// Check for a valid platform
platformPath := filepath.Join(platformsRoot, name)
@@ -90,7 +72,7 @@ func GeneratePlatform(ctx context.Context, rpc *client.Client, orgID string, nam
log.DebugContext(ctx, fmt.Sprintf("skipped write %s: already exists", client.PlatformConfigFile))
} else {
if os.IsNotExist(err) {
if err := writePlatformMetadata(ctx, rpc, orgID, name); err != nil {
if err := initPlatformMetadata(ctx, name); err != nil {
return errors.Wrap(err)
}
} else {

View File

@@ -0,0 +1,51 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha3
package v1alpha3
import "google.golang.org/protobuf/types/known/structpb"
// InternalLabel is an arbitrary unique identifier internal to holos itself.
// The holos cli is expected to never write a InternalLabel value to rendered
// output files, therefore use a [InternalLabel] when the identifier must be
// unique and internal. Defined as a type for clarity and type checking.
//
// A InternalLabel is useful to convert a CUE struct to a list, for example
// producing a list of [APIObject] resources from an [APIObjectMap]. A CUE
// struct using InternalLabel keys is guaranteed to not lose data when rendering
// output because a InternalLabel is expected to never be written to the final
// output.
#InternalLabel: string
// Kind is a kubernetes api object kind. Defined as a type for clarity and type
// checking.
#Kind: string
// APIObject represents the most basic generic form of a single kubernetes api
// object. Represented as a JSON object internally for compatibility between
// tools, for example loading from CUE.
#APIObject: structpb.#Struct
// APIObjectMap represents the marshalled yaml representation of kubernetes api
// objects. Do not produce an APIObjectMap directly, instead use [APIObjects]
// to produce the marshalled yaml representation from CUE data, then provide the
// result to [Component].
#APIObjectMap: {[string]: [string]: string}
// APIObjects represents Kubernetes API objects defined directly from CUE code.
// Useful to mix in resources to any kind of [Component], for example
// adding an ExternalSecret resource to a [HelmChart].
//
// [Kind] must be the resource kind, e.g. Deployment or Service.
//
// [InternalLabel] is an arbitrary internal identifier to uniquely identify the resource
// within the context of a `holos` command. Holos will never write the
// intermediate label to rendered output.
//
// Refer to [Component] which accepts an [APIObjectMap] field provided by
// [APIObjects].
#APIObjects: {
apiObjects: {[string]: [string]: #APIObject} @go(APIObjects,map[Kind]map[InternalLabel]APIObject)
apiObjectMap: #APIObjectMap @go(APIObjectMap)
}

View File

@@ -0,0 +1,58 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha3
package v1alpha3
// FilePath represents a file path.
#FilePath: string
// FileContent represents file contents.
#FileContent: string
// FileContentMap represents a mapping of file paths to file contents.
#FileContentMap: {[string]: #FileContent}
// BuildPlan represents a build plan for the holos cli to execute. The purpose
// of a BuildPlan is to define one or more [Component] kinds. For example a
// [HelmChart], [KustomizeBuild], or [KubernetesObjects].
//
// A BuildPlan usually has an additional empty [KubernetesObjects] for the
// purpose of using the [Component] DeployFiles field to deploy an ArgoCD
// or Flux gitops resource for the holos component.
#BuildPlan: {
kind: string & "BuildPlan" @go(Kind)
apiVersion: string & (string | *"v1alpha3") @go(APIVersion)
spec: #BuildPlanSpec @go(Spec)
}
// BuildPlanSpec represents the specification of the build plan.
#BuildPlanSpec: {
// Disabled causes the holos cli to take no action over the [BuildPlan].
disabled?: bool @go(Disabled)
// Components represents multiple [HolosComponent] kinds to manage.
components?: #BuildPlanComponents @go(Components)
}
#BuildPlanComponents: {
resources?: {[string]: #KubernetesObjects} @go(Resources,map[InternalLabel]KubernetesObjects)
kubernetesObjectsList?: [...#KubernetesObjects] @go(KubernetesObjectsList,[]KubernetesObjects)
helmChartList?: [...#HelmChart] @go(HelmChartList,[]HelmChart)
kustomizeBuildList?: [...#KustomizeBuild] @go(KustomizeBuildList,[]KustomizeBuild)
}
// Kustomize represents resources necessary to execute a kustomize build.
// Intended for at least two use cases:
//
// 1. Process a [KustomizeBuild] [Component] which represents raw yaml
// file resources in a holos component directory.
// 2. Post process a [HelmChart] [Component] to inject istio, patch jobs,
// add custom labels, etc...
#Kustomize: {
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
kustomizeFiles?: #FileContentMap @go(KustomizeFiles)
// ResourcesFile is the file name used for api objects in kustomization.yaml
resourcesFile?: string @go(ResourcesFile)
}

View File

@@ -0,0 +1,50 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/core/v1alpha3
package v1alpha3
// Component defines the fields common to all holos component kinds. Every
// holos component kind should embed Component.
#Component: {
// Kind is a string value representing the resource this object represents.
kind: string @go(Kind)
// APIVersion represents the versioned schema of this representation of an object.
apiVersion: string & "v1alpha3" @go(APIVersion)
// Metadata represents data about the holos component such as the Name.
metadata: #Metadata @go(Metadata)
// APIObjectMap holds the marshalled representation of api objects. Useful to
// mix in resources to each Component type, for example adding an
// ExternalSecret to a [HelmChart] Component. Refer to [APIObjects].
apiObjectMap?: #APIObjectMap @go(APIObjectMap)
// DeployFiles represents file paths relative to the cluster deploy directory
// with the value representing the file content. Intended for defining the
// ArgoCD Application resource or Flux Kustomization resource from within CUE,
// but may be used to render any file related to the build plan from CUE.
deployFiles?: #FileContentMap @go(DeployFiles)
// Kustomize represents a kubectl kustomize build post-processing step.
kustomize?: #Kustomize @go(Kustomize)
// Skip causes holos to take no action regarding this component.
skip: bool & (bool | *false) @go(Skip)
}
// Metadata represents data about the object such as the Name.
#Metadata: {
// Name represents the name of the holos component.
name: string @go(Name)
// Namespace is the primary namespace of the holos component. A holos
// component may manage resources in multiple namespaces, in this case
// consider setting the component namespace to default.
//
// This field is optional because not all resources require a namespace,
// particularly CRDs and DeployFiles functionality.
// +optional
namespace?: string @go(Namespace)
}

Some files were not shown because too many files have changed in this diff Show More