Compare commits

...

394 Commits

Author SHA1 Message Date
Jeff McCune
8bc7804a9c Merge pull request #190 from holos-run/jeff/189-reference-docs
(#189) v1alpha2 API for reference docs
2024-06-30 15:07:46 -07:00
Jeff McCune
a39807a858 (#189) go mod tidy 2024-06-30 15:04:39 -07:00
Jeff McCune
5170650760 (#189) Remove yaml tags for v1alpha2.
Unnecessary, json tags are sufficient for both yaml and json.
2024-06-30 14:50:50 -07:00
Jeff McCune
1d81b3c3b4 (#189) Clarify documentation of v1alpha2
Focusing on the purpose of #APIObjects
2024-06-30 14:36:04 -07:00
Jeff McCune
33970dafe8 (#189) Version 0.85.0 v1alpha2 2024-06-30 10:27:48 -07:00
Jeff McCune
faa46c54d8 (#189) Do not write empty files with gitops results
Previosly, the holos component Results for each ArgoCD Application
resource managed as part of each BuildPlan results in an empty file
being written for the empty list of k8s api objects.

This patch fixes the problem by skipping writing the accumulated output
of API objects with the Result metadata.name starts with `gitops/`.

This is kind of a hack, but it works well enough for now.
2024-06-30 10:15:28 -07:00
Jeff McCune
42509a34cf (#189) Fix the gitops Application component name
Previously components appeared to be duplicated, it was not clear to the
user one build plan results in two components: one for the k8s yaml and
one for the gitops argocd Application resource.

```
❯ holos render component --cluster-name aws1 components/login/zitadel-server
9:27AM INF result.go:195 wrote deploy file version=0.84.1 path=deploy/clusters/aws1/gitops/zitadel-server.application.gen.yaml bytes=338
9:27AM INF render.go:92 rendered zitadel-server version=0.84.1 cluster=aws1 name=zitadel-server status=ok action=rendered
9:27AM INF render.go:92 rendered zitadel-server version=0.84.1 cluster=aws1 name=zitadel-server status=ok action=rendered
```

This patch prefixes the ArgoCD Application resource, which is
implemented as a separate HolosComponent in the same BuildPlan.  The
result is more clear about what is going on:

```
❯ holos render component --cluster-name aws1 components/login/zitadel-server
9:39AM INF result.go:195 wrote deploy file version=0.84.1 path=deploy/clusters/aws1/gitops/zitadel-server.application.gen.yaml bytes=338
9:39AM INF render.go:92 rendered gitops/zitadel-server version=0.84.1 cluster=aws1 name=gitops/zitadel-server status=ok action=rendered
9:39AM INF render.go:92 rendered zitadel-server version=0.84.1 cluster=aws1 name=zitadel-server status=ok action=rendered
```
2024-06-30 09:37:14 -07:00
Jeff McCune
ef369d4860 (#189) Format cue code with make fmt
Previously the internal cue code was not formatted properly.  This patch
updates `make fmt` to automatically format the embedded internal
platforms.
2024-06-30 09:35:25 -07:00
Jeff McCune
747ed3462a (#189) Fix Helm + Kustomize post renderer for v1alpha2
Previously the `login/zitadel-server` component failed to render with
the following error.  This is a result of the kustomize config fileds
moving down one level to the `kustomize` field in v1alpha2 relative to
`v1alpha`.

```
spec.components.helmChartList.0.kustomizeFiles: field not allowed:
    ./buildplan.cue:106:9
    ./buildplan.cue:106:27
    ./buildplan.cue:118:3
    ./buildplan.cue:124:4
    ./buildplan.cue:125:4
    ./buildplan.cue:126:5
    ./buildplan.cue:162:10
    ./buildplan.cue:165:37
    ./buildplan.cue:206:13
    ./components/login/zitadel-server/zitadel.cue:9:1
    ./components/login/zitadel-server/zitadel.cue:18:9
    ./components/login/zitadel-server/zitadel.cue:19:9
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:31:8
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:36:15
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:42:19
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:42:22
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:48:18
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:12:13
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:13:2
spec.components.helmChartList.0.resourcesFile: field not allowed:
    ./buildplan.cue:106:9
    ./buildplan.cue:106:27
    ./buildplan.cue:118:3
    ./buildplan.cue:122:4
    ./buildplan.cue:125:4
    ./buildplan.cue:125:43
    ./buildplan.cue:162:10
    ./buildplan.cue:165:37
    ./buildplan.cue:206:13
    ./components/login/zitadel-server/zitadel.cue:9:1
    ./components/login/zitadel-server/zitadel.cue:18:9
    ./components/login/zitadel-server/zitadel.cue:19:9
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:31:8
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:36:15
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:42:19
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:42:22
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:48:18
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:12:13
    ./cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:13:2
_PlatformConfig: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./buildplan.cue:232:21
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./components/login/login.cue:6:18
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./components/login/zitadel.cue:8:18
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./platform.cue:61:17
    ./platform.cue:60:19
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./platform.cue:62:17
    ./platform.cue:60:19
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./platform.cue:79:17
    ./platform.cue:78:19
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./platform.cue:80:17
    ./platform.cue:78:19
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./platform.cue:100:25
    ./schema.cue:14:44
_PlatformConfig: invalid interpolation: invalid interpolation: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./platform.cue:102:22
    ./platform.cue:100:25
    ./schema.cue:14:44
_PlatformConfig: error in call to encoding/json.Unmarshal: json: invalid JSON:
    ./schema.cue:14:44
```

With this patch the component renders without any further modification:

```
❯ holos render component --cluster-name aws1 components/login/zitadel-server
9:24AM INF result.go:195 wrote deploy file version=0.84.1 path=deploy/clusters/aws1/gitops/zitadel-server.application.gen.yaml bytes=338
9:24AM INF render.go:92 rendered zitadel-server version=0.84.1 cluster=aws1 name=zitadel-server status=ok action=rendered
9:24AM INF render.go:92 rendered zitadel-server version=0.84.1 cluster=aws1 name=zitadel-server status=ok action=rendered
```
2024-06-30 09:23:01 -07:00
Jeff McCune
1fb1798f60 (#189) Make HolosComponent Metadata Namespace optional
Previously a metadata.namespace value was required for all holos
components.  This is a problem because not all resources require a
namespace, for example producing the ArgoCD Application resource for
each build plan does not need a namespace defined, particularly when
managing only CRDs.

With this patch we get pretty far:

```
❯ holos generate platform holos
9:14AM INF platform.go:79 wrote platform.metadata.json version=0.84.1 platform_id=018fa1cf-a609-7463-aa6e-fa53bfded1dc path=/Users/jeff/Holos/holos-infra/saas2/platform.metadata.json
9:14AM INF platform.go:91 generated platform holos version=0.84.1 platform_id=018fa1cf-a609-7463-aa6e-fa53bfded1dc path=/Users/jeff/Holos/holos-infra/saas2

❯ time holos render platform --concurrency 1 ./platform
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/eso-creds-manager cluster=management num=1 total=73 duration=212.546542ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/cert-letsencrypt cluster=management num=2 total=73 duration=110.363875ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/certificates cluster=management num=3 total=73 duration=154.642541ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/login/zitadel-certs cluster=management num=4 total=73 duration=115.132041ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/ecr-creds-manager cluster=management num=5 total=73 duration=162.559542ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/eks-pod-identity-webhook cluster=management num=6 total=73 duration=135.03ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/crossplane/crds cluster=management num=7 total=73 duration=296.536833ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/crossplane/controller cluster=management num=8 total=73 duration=146.730667ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/backstage/management/certs cluster=management num=9 total=73 duration=117.42625ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/external-secrets cluster=aws1 num=10 total=73 duration=170.574458ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/eso-creds-refresher cluster=aws1 num=11 total=73 duration=161.188625ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/secretstores cluster=aws1 num=12 total=73 duration=153.708458ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/ecr-creds-refresher cluster=aws1 num=13 total=73 duration=130.369166ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/gateway-api cluster=aws1 num=14 total=73 duration=2.078997458s
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/istio/base cluster=aws1 num=15 total=73 duration=145.869084ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/istio/mesh/cni cluster=aws1 num=16 total=73 duration=142.113125ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/istio/mesh/istiod cluster=aws1 num=17 total=73 duration=155.186375ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/istio/mesh/gateway cluster=aws1 num=18 total=73 duration=137.8775ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/istio/mesh/httpbin/backend cluster=aws1 num=19 total=73 duration=116.537458ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/istio/mesh/httpbin/routes cluster=aws1 num=20 total=73 duration=122.709875ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/pgo/crds cluster=aws1 num=21 total=73 duration=271.561666ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/pgo/controller cluster=aws1 num=22 total=73 duration=143.880292ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/login/zitadel-secrets cluster=aws1 num=23 total=73 duration=116.962167ms
9:14AM INF platform.go:52 ok render component version=0.84.1 path=components/login/zitadel-database cluster=aws1 num=24 total=73 duration=121.315875ms
9:14AM ERR could not execute version=0.84.1 code=unknown err="could not build /Users/jeff/Holos/holos-infra/saas2/components/login/zitadel-server: spec.components.helmChartList.0.resourcesFile: field not allowed" loc=builder.go:166
spec.components.helmChartList.0.resourcesFile: field not allowed:
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:106:9
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:106:27
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:118:3
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:122:4
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:125:4
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:125:43
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:162:10
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:165:37
    /Users/jeff/Holos/holos-infra/saas2/buildplan.cue:206:13
    /Users/jeff/Holos/holos-infra/saas2/components/login/zitadel-server/zitadel.cue:9:1
    /Users/jeff/Holos/holos-infra/saas2/components/login/zitadel-server/zitadel.cue:18:9
    /Users/jeff/Holos/holos-infra/saas2/components/login/zitadel-server/zitadel.cue:19:9
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:31:8
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:36:15
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:42:19
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:42:22
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:48:18
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:12:13
    /Users/jeff/Holos/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:13:2
9:14AM ERR could not execute version=0.84.1 code=unknown err="could not render component: exit status 1" loc=platform.go:48
holos render platform --concurrency 1 ./platform  6.62s user 1.22s system 133% cpu 5.878 total
```
2024-06-30 09:14:52 -07:00
Jeff McCune
accf80200f (#189) Fix pod-identity-webhook Helm chart for v1alpha2
The pod identity webhook component fails to render with v1alpha2.  This
patch fixes the problem by providing concrete values for enableHooks and
the namespace of the helm chart holos component.

The namespace is mainly necessary to render the ArgoCD Application
resource along side the helm chart output.
2024-06-30 08:18:58 -07:00
Jeff McCune
4522ee1d4e (#189) Working eso-creds-manager with v1alpha2
With this patch the eso-creds-manager component renders correctly.  This
is a `#Kubernetes` type build plan which uses the
spec.components.resources map to manage resources.

The only issue was needing to provide the namespace to the nested holos
component inside the BuildPlan.

The ArgoCD Application resource moves to the DeployFiles field of a
separate holos component in the same build plan at
spec.components.resources.argocd.  For this reason a separate Result
object is no longer necessary inside of the Holos cli for the purpose of
managing Flux or ArgoCD gitops.  The CUE code can simply inline whatever
gitops resources it wants and the holos cli will write the files
relative to the cluster specific deploy directory.

Result:

```
❯ holos render component --cluster-name management components/eso-creds-manager
2:55PM INF result.go:195 wrote deploy file version=0.84.1 path=deploy/clusters/management/gitops/eso-creds-manager.application.gen.yaml bytes=350
2:55PM INF render.go:92 rendered eso-creds-manager version=0.84.1 cluster=management name=eso-creds-manager status=ok action=rendered
```
2024-06-29 14:55:53 -07:00
Jeff McCune
313ebc6817 (#189) README 2024-06-29 08:04:51 -07:00
Jeff McCune
e0f439515f (#189) Fix holos render platform for v1alpha2
Previously holos render platform failed for the holos platform.  The issue was
caused by the deployFiles field moving from the BuildPlan down to
HolosComponent.

This patch fixes the problem by placing the ArgoCD Application resource into a
separate Resources entry of the BuildPlan.  The sole purpose of this additional
entry in the Resources map is to produce the Application resource along side
any other components which are part of the build plan.
2024-06-29 07:32:57 -07:00
Jeff McCune
caa7560ab9 (#189) Fix Helm.Chart.namespace: field not allowed
Fixes:

```
4:19PM ERR could not execute version=0.84.1 code=unknown err="could not build /home/jeff/workspace/holos-run/holos-infra/saas2/platform: #Helm.Chart.namespace: field not allowed" loc=platform.go:52
    /home/jeff/workspace/holos-run/holos-infra/saas2/buildplan.cue:106:9
    /home/jeff/workspace/holos-run/holos-infra/saas2/buildplan.cue:108:3
    /home/jeff/workspace/holos-run/holos-infra/saas2/buildplan.cue:118:3
    /home/jeff/workspace/holos-run/holos-infra/saas2/buildplan.cue:118:43
    /home/jeff/workspace/holos-run/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/buildplan_go_gen.cue:48:18
    /home/jeff/workspace/holos-run/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:12:13
    /home/jeff/workspace/holos-run/holos-infra/saas2/cue.mod/gen/github.com/holos-run/holos/api/core/v1alpha2/helm_go_gen.cue:13:2
```
2024-06-28 16:21:13 -07:00
Jeff McCune
bbcf280da7 (#189) Refactor v1alpha2 API
Previously methods were defined on the API objects in the v1alpha1 API.
The API should be data structures only.  This patch refactors the
methods responsible for orchestrating the build plan to pull them into
the internal render package.

The result is the API is cleaner and has no methods.  The render package
has corresponding data structures which simply wrap around the API
structure and implement the methods to render and return the result to
the CLI.

This commit compiles, but it has not been tested at all.  It's almost
surely broken completely.
2024-06-28 16:16:12 -07:00
Jeff McCune
6d2daacb7b (#189) Split api into meta and core groups
Previously in v1alpha1, all Holos structs are located in the same
package.  This makes it difficult to focus on only the structs necessary
to transfer configuration data from CUE to the `holos` cli.

This patch splits the structs into `meta` and `core` where the core
package holds the structs end users should refer to and focus on.  Only
the Platform resource is in core now, but other BuildPlan types will be
added shortly.
2024-06-28 13:02:44 -07:00
Jeff McCune
62f96a2d6c (#189) Add Go Documentation Server
Run it with:

    godoc -http=:6060
2024-06-28 12:42:34 -07:00
Jeff McCune
50f414d520 (#189) Platform v1alpha2
This patch moves the top level Platform API resource to v1alpha2 so it's
well documented using go docs.
2024-06-28 12:33:45 -07:00
Jeff McCune
882f3894f3 (#189) Clean up unused packages 2024-06-28 10:04:38 -07:00
Jeff McCune
30ddde7b49 (maint) Add make image to make help
Previously it wasn't clear how to build the image, wasn't showing up in
make help.
2024-06-24 20:48:47 -07:00
Jeff McCune
5cced6fb51 Version 0.84.0 2024-06-24 20:40:00 -07:00
Jeff McCune
a82ebf43b6 Merge pull request #187 from holos-run/jeff/180-backstage-component
(#180) Configure GitHub Apps Discovery
2024-06-24 20:38:17 -07:00
Jeff McCune
ebb6d6205a (#180) Configure GitHub Apps Discovery
Previously Backstage was not configured to integrate with GitHub.  The
integration is necessary for Backstage to automatically discover
resources in a GitHub organization and import them into the Catalog.

This patch adds a new platform model form field and section for the
primary GitHub organization name of the platform.  Additional GitHub
organizations can be added in the future, Backstage supports them.

The result is Backstage automatically scans public and private
repositories and adds the information in `catalog-info.yaml` to the UI.
2024-06-24 20:35:20 -07:00
Jeff McCune
58950c469a (#180) Manage default-istio ServiceAccount
Previosly the gateway ArogCD Application resource is out of sync because
the `default-istio` `ServiceAccount` is not in the git repository
source.  Argo would prune the service account on sync which is a problem.

This patch manages the service account so the Application can be synced
properly.
2024-06-13 06:04:10 -07:00
Jeff McCune
0eebdaf0c7 (#180) Fix authpolicy component after generate
Previously the holos render platform command fails with the following
error when giving a demo after the generate platform step.

This patch updates the internal generated holos platform to the latest
version.

Running through the demo is successful now.

```
holos logout
holos login
holos register user
holos generate platform holos
holos pull platform config .
holos render platform ./platform
```
2024-06-13 05:51:47 -07:00
Jeff McCune
54e2f28f4c (#179) Double check if the error group is done.
I'm not sure if we should check in the loop, in the go routine, or in
both places.  Double check in both cases just to be sure we're not doing
extra unnecessary work.
2024-06-06 15:51:16 -07:00
Jeff McCune
d4d50ef12b (#179) Use errorgroup SetLimit to limit concurrency
Previously a channel was used to limit concurrency.  This is more
difficult to read and comprehend than the inbuilt errorgroup.SetLimit
functionality.

This patch uses `errgroup.`[Group.SetLimit()][1] to limit concurrency,
avoid leaking go routines, and avoid unnecessary work.

[1]: https://pkg.go.dev/golang.org/x/sync/errgroup#Group.SetLimit
2024-06-06 15:23:49 -07:00
Jeff McCune
075f2b16a4 Merge pull request #179 from holos-run:nate/concurrency
Add concurrency to 'holos render platform'
2024-06-06 15:10:50 -07:00
Nate McCurdy
6f8008a53c Add concurrency to 'holos render platform'
This adds concurrency to the 'holos render platform' command so platform
components are rendered in less time than before.

Default concurrency is set to `min(runtime.NumCPU(), 8)`, which is the
lesser of 8 or the number of CPU cores. In testing, I found that past 8,
there are diminishing or negative returns due to memory usage or
rendering each component.

In practice, this reduced rendering of the saas platform components from
~90s to ~28s on my 12-core macbook pro.

This also changes the key name of the Helm Chart's version in log lines
from `version` to `chart_version` since `version` already exists and
shows the Holos CLI version.
2024-06-06 15:04:55 -07:00
Jeff McCune
0618b52bae (#181) Add AuthorizationPolicy resources for admin interfaces
Previously, when a user registered and logged into the holos app server,
they were able to reach admin interfaces like
https://argocd.admin.example.com

This patch adds AuthorizationPolicy resources governing the whole
cluster.  Users with the prod-cluster-{admin,edit,view} roles may access
admin services like argocd.

Users without these roles are blocked with RBAC: access denied.

In ZITADEL, the Holos Platform project is granted to the CIAM
organization without granting the prod-cluster-* roles, so there's no
possible way a CIAM user account can have these roles.
2024-06-06 14:57:48 -07:00
Jeff McCune
f1951c5db3 (#178) Add holos push platform model command
Previously there wasn't a good way to populate the platform model in the
database after building a new instance of holos server.

With this patch, the process to reset clean is:

```
export HOLOS_SERVER=https://dev.app.holos.run:443
grpcurl -H "x-oidc-id-token: $(holos token)" ${HOLOS_SERVER##*/} holos.user.v1alpha1.SystemService.DropTables
grpcurl -H "x-oidc-id-token: $(holos token)" ${HOLOS_SERVER##*/} holos.system.v1alpha1.SystemService.SeedDatabase
```

Then populate the form and model:

```
holos push platform form .
holos push platform model .
```

The `platform.config.json` file stored in version control is pushed to
the holos server and stored in the database.  This makes it nice and
easy to reset entirely, or move to another service url.
2024-06-05 15:38:55 -07:00
Jeff McCune
dad12acd8d (#178) Seed the Holos Platform itself
Previously this would have needed to be created in pgAdmin.
2024-06-05 14:17:31 -07:00
Jeff McCune
a4503e076f (#178) Add make image task to push the container image
Previously there wasn't an easy way to make the container image and
publish it.  This adds a simple `make image` task to build and push the
image.
2024-06-05 14:03:31 -07:00
Jeff McCune
09ddd339b8 (#178) Update user ids for SeedDatabase rpc
Need them to match the new login issuer.
2024-06-05 13:57:52 -07:00
Jeff McCune
bc94f4b6b8 (#178) Login to https://login.holos.run
Previously the default oidc issuer was to one of the kubernetes clusters
running in my basement.  This patch changes the issuer to the production
ready issuer running in EKS.
2024-06-05 13:42:37 -07:00
Jeff McCune
564406f60f (#178) Add app.example.com HTTPRoute for holos server
Previously the holos server Service was not exposed.

This patch exposes the holos service with an HTTPRoute behind the auth
proxy.  Holos successfully authenticates the user with the
x-oidc-id-token header set by the default Gateway.

---

Add dev-holos-infra and dev-holos-app

Previously the PostgresCluster and the holos server Deployment are not
managed on the aws2 cluster.

This patch is a start, but the Deployment does not yet start.  We need
to pass an option for the oidc issuer.

---

Add namespaces and cert for prod-holos, dev-holos, jeff-holos

Previously we didn't have a place to deploy holos server.  This patch
adds a namespace, creates a Gateway listener, and binds the tls certs
for app.example.com and *.app.example.com to the listeners.

In addition, cluster specific endpoints of *.app.aws2.example.com,
*.app.aws1.example.com, etc. are created to provide dev environment
urls. For example jeff.app.aws2.example.com is my personal dev hostname.
2024-06-05 13:15:11 -07:00
Jeff McCune
7845ce62e0 (#178) Update buf with make tools
Previously go releaser was failing because buf has been updated again.
2024-06-03 11:10:42 -07:00
Jeff McCune
a1542752b7 (#178) Add ArgoCD Application resources for each build plan
Previously holos render platform ./platform did not render any GitOps
resources for Flux or ArgoCD.

This patch uses the new DeployFiles field in holos v0.83.0 to write an
Application resource for every component BuildPlan listed in the
platform.
2024-06-03 10:33:05 -07:00
Jeff McCune
7956475363 (#178) Add BuildPlan deployFiles field
Previously, each BuildPlan has no clear way to produce an ArgoCD
Application resource.  This patch provides a general solution where each
BuildPlan can provide arbitrary files as a map[string]string where the
key is the file path relative to the gitops repository `deploy/` folder.
2024-06-03 10:00:35 -07:00
Jeff McCune
004ed56591 (#178) Add ArgoCD repository credentials
Previously ArgoCD has no ssh credentials to connect to GitHub.  This
patch adds an ssh ed25519 key as a secret in the management cluster.
The secret is synced to the workload clusters using an ExternalSecret
with the proper label for ArgoCD to find and load it for use with any
application that references the Git URL.
2024-06-02 15:58:35 -07:00
Jeff McCune
d497df3c27 (#178) Add ArgoCD RBAC Policy
Previously a logged in user could not modify anything in ArgoCD.  With
this patch users who have been granted the prod-cluster-admin role in
ZITADEL are granted the admin role in ArgoCD.
2024-06-02 15:07:27 -07:00
Jeff McCune
3a8d46234f (#178) Add ArgoCD
Previously ArgoCD was present in the platform configuration, but not
functional.  This patch brings ArgoCD fully up, integrated with the
service mesh, auth proxy, and SSO at
https://argocd.admin.clustername.example.com/

The upstream [helm chart][1] is used instead of the kustomize install
method.  We had existing prior art integrating the v6 helm chart with
the holos platform identity provider, so we continue with the helm
chart.

CRDs are still managed with the kustomize version.  The CRDs need to be
kept in sync.  It's possible to generate the kustomization.yaml file
from the same version value as is used by the helm chart, but we don't
for the time being.

[1]: https://github.com/argoproj/argo-helm/tree/argo-cd-7.1.1/charts/argo-cd
2024-06-02 14:35:36 -07:00
Jeff McCune
4d24dc5149 (#178) Add authpolicy component for RequestAuthentication
Previously, no RequestAuthentication or AuthorizationPolicy resources
govern the default Gateway.  This patch adds the resources and
configures the service mesh with the authproxy as an ExtAuthZ provider
for CUSTOM AuthorizationPolicy rules.

This patch also fixes a bug in the zitadel-server component where
resources from the upstream helm chart did not specify a namespace.
Kustomize is used as a post processor to force all resources into the
zitadel namespace.

Add multiple HTTPRoutes to validate http2 connection reuse

This patch adds multiple HTTPRoute resources which match
*.admin.example.com  The purpose is to validate http2 connections are
reused properly with Chrome.

With this patch no 404 no route errors are encountered when navigating
between the various httpbin{1,2,3,4} urls.

Add note backupRestore will trigger a restore

The process of configuring ZITADEL to provision from a datasource will
cause an in-place restore from S3.  This isn't a major issue, but users
should be aware data added since the most recent backup will be lost.
2024-06-02 09:41:57 -07:00
Jeff McCune
8eb7fbf7dc (#178) Move httpbin HTTPRoute resources to namespace istio-gateways
Previously, HTTPRoute resources were in the same namespace as the
backend service, httpbin in this case.  This doesn't follow the default
behavior of a Gateway listener only allowing attachment from HTTPRoute
resources in the same namespace as the Gateway.

This also complicates intercepting the authproxy path prefix and sending
it to the authproxy.  We'd need to add a ReferenceGrant in the authproxy
namespace, which seems backwards and dangerous because it would grant
the application developer the ability to route requests to all Services
in the istio-gateways namespace.

This patch enables Cluster Operators to manage the HTTPRoute resources
and direct the auth proxy path prefix of `/holos/authproxy` to the auth
proxy Service in the same namespace.

ReferenceGrant resources are used to enable the HTTPRoute backend
references.

When an application developer needs to manage their own HTTPRoute, as is
the case for ZITADEL, a label selector may be used and will override
less specific HTTPRoute hostsnames in the istio-gateways namespace.
2024-06-01 21:18:47 -07:00
Jeff McCune
ffeeb7c553 (#178) Add authproxy Deployment
With redis.  The auth proxy authenticates correctly against zitadel
running in the same cluster.  Validated by visiting
https://httpbin.admin.clustername.example.com/holos/authproxy

Visiting
https://httpbin.admin.clustername.example.com/holos/authproxy/auth
returns the id token in the response header, visible in the Chrome
network inspector.  The ID token works as expected from multiple orgs
with project grants in ZITADEL from the Holos org to the OIS org.

This patch doesn't fully implement the auth proxy feature.
AuthorizationPolicy and RequestAuthentication resources need to be
added.

Before we do so, we need to move the HTTPRoute resources into the
gateway namespace so all of the security policies are in one place and
to simplify the process of routing requests to two backends, the
authproxy and the backend server.
2024-06-01 20:12:35 -07:00
Jeff McCune
c3c174155c (#178) Add httpbin{1,2,3,4} HTTPRoutes to validate http2 connection reuse
This patch adds multiple HTTPRoute resources which match
*.admin.example.com  The purpose is to validate http2 connections are
reused properly with Chrome.

With this patch no 404 no route errors are encountered when navigating
between the various httpbin{1,2,3,4} urls.
2024-06-01 12:44:33 -07:00
Jeff McCune
2c2d2a9fd9 (#178) Add Namespaces documentation
Describe how to manage a new namespace to build a component in.
2024-06-01 09:43:32 -07:00
Jeff McCune
d692e2a6d5 (#178) Split subdomain certs into two certs
Problem:
Istio 1.22 with Gateway API and HTTPRoute is mis-routing HTTP2 requests
when the tls certificate has two dns names, for example
login.example.com and *.login.example.com.

When the user visits login.example.com and then tries to visit
other.login.example.com with Chrome, the connection is re-used and istio
returns a 404 route not found error even though there is a valid and
accepted HTTPRoute for *.login.example.com

This patch attempts to fix the problem by ensuring certificate dns names
map exactly to Gateway listeners.  When a wildcard cert is used, the
corresponding Gateway listener host field exactly matches the wildcard
cert dns name so Istio and envoy should not get confused.
2024-06-01 09:30:47 -07:00
Jeff McCune
e4cebddd0c (#178) Make aws2 the primary cluster 2024-05-31 14:01:11 -07:00
Jeff McCune
0e48537d65 (#178) Add zitadel-server component
This patch adds the ZITADEL server component, which deploys zitadel from
a helm chart.  Kustomize is used heavily to patch the output of helm to
make the configuration fit nicely with the holos platform.

With this patch the two Jobs that initialize the database and setup
ZITADEL run successfully.  The ZITADEL deployment starts successfully.

ZITADEL is accessible at https://login.example.com/ with the default
admin username of `zitadel-admin@zitadel.login.example.com` and password
`Password1!`.

Use grant.holos.run/subdomain.admin: "true" for HTTPRoute

This patch clarifies the label that grants httproute attachment for a
subdomain Gateway listener to a namespace.

Fix istio-base holos component name

Was named `base` which is the chart name, not the holos component name.
2024-05-31 13:47:03 -07:00
Jeff McCune
a461a96b9c (#178) Add ZITADEL crunchy pgo PostgresCluster
This patch adds the postgres clusters and a few console form controls to
configure how backups are taken and if the postgres cluster is
initialized from an existing backup or not.

The pgo-s3-creds file is manually created at this time.  It looks like:

    ❯ holos get secret -n zitadel pgo-s3-creds --print-key s3.conf
    [global]
    repo2-cipher-pass=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    repo2-s3-key=KKKKKKKKKKKKKKKKKKKK
    repo2-s3-key-secret=/SSSSSSS/SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
    repo3-cipher-pass=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    repo3-s3-key=KKKKKKKKKKKKKKKKKKKK
    repo3-s3-key-secret=/SSSSSSS/SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS

The s3 key and secret are credentials to read / write to the bucket.
The cipher pass is a random string for client side encryption.  Generate
it with `tr -dc A-Za-z0-9 </dev/urandom | head -c 64`
2024-05-30 11:33:00 -07:00
Jeff McCune
9524c4f7c3 (#178) Add crunchy postgres operator
Needed for ZITADEL and Holos Server.  Intended for ephemeral dev
environments, but may also try it in staging while we wait for RDS.
2024-05-29 12:03:05 -07:00
Jeff McCune
64b04d9cfd (#178) Add Gateway listener for login.example.com
This patch is foundational work for the ZITADEL login service.

This patch adds a tls certificate with names *.login.example.com and
login.example.com, a pair of listeners attached to the certificate in
the `default` Gateway, and the ExternalSecret to sync the secret from
the management cluster.

The zitadel namespace is managed and has the label
holos.run/login.grant: "true" to grant HTTPRoute attachment from the
zitadel namespace to the default Gateway in the istio-gateways
namespace.
2024-05-29 09:27:08 -07:00
Jeff McCune
b419ad8caf (#178) Add HTTPRoute for httpbin.admin.aws1.example.com
With this change, https://httpbin.admin.aws1.example.com works as
expected.

PROXY protocol is configured on the AWS load balancer and the istio
gateway.  The istio gateway logs have the correct client source ip
address and x-forwarded-for headers.

Namespaces must have the holos.run/admin.grant: "true" label in order to
attach an HTTPRoute to the admin section of the default Gateway.

The TLS certificate is working as expected and hopefully does not suffer
from the NR route not found issued encountered with the Istio Gateway
API.
2024-05-28 21:10:18 -07:00
Jeff McCune
8036c17916 (#178) Add istiod and gateway components
This patch gets the istio-ingressgateway up and running in AWS with
minimal configuration.  No authentication or authorization policies have
been migrated from previous iterations of the platform.  These will be
handled in subsequent iterations.

Connectivity to a backend service like httpbin has not yet been tested.
This will happen in a follow up as well using /httpbin path prefixes on
existing services like argocd to conserve certificate resources.
2024-05-28 14:37:25 -07:00
Jeff McCune
220d498be0 (#178) Define a #IngressCertificate
This is the standard way to issue public facing certificates.  Be aware
of the 50 cert limit per week from LetsEncrypt.  We map names to certs
1:1 to avoid http2 connection reuse issues with istio.
2024-05-28 13:15:14 -07:00
Jeff McCune
0f5b6a2d6e (#178) Add istio 1.22.0 base component 2024-05-28 13:08:34 -07:00
Jeff McCune
36369d75c7 (#178) Add argocd.admin.aws1.holos.run cert
Manage certificates on a project basis similar to how namespaces
associated with each project are managed.

Manage the Certificate resources on the management cluster in the
istio-ingress namespace so the tls certs can be synced to the workload
clusters.
2024-05-28 11:50:31 -07:00
Jeff McCune
059b8283fd (#178) Add cert-letsencrypt component for holos management cluster
The secret needs to be manually provisioned for this to work since the
management cluster does not sync secrets from any other external
cluster.
2024-05-26 09:56:46 -07:00
Jeff McCune
386eb2452a (#178) Add cert-manager to the holos platform
This patch adds cert-manager on all clusters.  On the management cluster
cert manager is scheduled on spot instances to reduce cost.
2024-05-26 09:29:15 -07:00
Jeff McCune
38e9a97fd2 (#178) Add secretstores holos platform component
The secretstores component is critical and provides the mechanism to
securely fetch Secret resources from the Management Cluster.
The holos server and configuration code stored in version control
contains only ExternalSecret references, no actual secrets.

This component adds a `default` `SecretStore` to each management
namespace which uses the `eso-reader` service account token to
authenticate to the management cluster.  This service account is limited
to reading secrets within the namespace it resides in.

For example:

```yaml
---
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: default
  namespace: external-secrets
spec:
  provider:
    kubernetes:
      auth:
        token:
          bearerToken:
            key: token
            name: eso-reader
      remoteNamespace: external-secrets
      server:
        caBundle: Long Base64 encoded string
        url: https://34.121.54.174
```
2024-05-25 15:02:06 -07:00
Jeff McCune
ecca40e9d5 (#178) Add holos platform eso-creds-manager
This patch adds the `eso-creds-manager` component which needs to be
applied to the management cluster prior to the `eso-creds-refreher`
component being applied to workload clusters.

The manager component configures rbac to allow the creds-refresher job
to complete.

This patch also adjusts the behavior to only create secrets for the
eso-reader account by default.

Namespaces with the label `holos.run/eso.writer=true` will also have an
eso-writer secret provisioned in their namespace, allowing secrets to be
written back to the management cluster.  This is intended for the
PushSecret resource.
2024-05-24 15:09:59 -07:00
Jeff McCune
9d08e27e31 (#178) Add cue.mod/gen/k8s.io/api/batch/v1 2024-05-23 16:33:58 -07:00
Jeff McCune
969bf5e867 (#178) Import k8s rbac api
cue get go k8s.io/api/rbac/v1beta1
cue get go k8s.io/api/rbac/v1
2024-05-23 16:26:24 -07:00
Jeff McCune
3b5f28f4df (#178) Fix holos generate writing executable files
Adhere to the umask to allow group writable or world writable, but do
not set the execute bit.
2024-05-23 11:37:04 -07:00
Jeff McCune
df5619f988 (#178) Add ArgoCD schematic and component to holos
Add the ArgoCD component which is a good example of how to wrap a plain
kustomize kustomization.yaml file with Holos.
2024-05-23 11:18:29 -07:00
Jeff McCune
a6d8383176 (#178) Do not write flux kustomization if empty
If the holos component returns no data for the flux kustomization, don't
bother writing an useless empty file.
2024-05-23 10:56:08 -07:00
Jeff McCune
dbc7e374cd (#178) Update buf 2024-05-23 09:37:46 -07:00
Jeff McCune
d81729857b (#178) v0.81.2 for holos
Use v0.81.2 to build out the holos platform.  Once we have the
components structured fairly well we can circle back around and copy the
components to schematics.  There's a bit of friction regenerating the
platform from schematic each time.
2024-05-23 09:14:27 -07:00
Jeff McCune
d3d8a7b73c (#178) Shape _Namespaces to corev1.#Namespace
Eliminate the need for a for loop by having _Namespaces be a struct of
name to k8s.io/api/core/v1.#Namespace
2024-05-23 09:12:08 -07:00
Jeff McCune
d9e6776b95 (#178) npm upgrade 2024-05-23 06:41:10 -07:00
Jeff McCune
bde98faffa (#178) Use private fields to store data
Using CUE definitions like #Platform to hold data is confusing.  Clarify
the use of fields, definitions like #Platform define the shape (schema)
of the data while private fields like _Platform represent and hold the
data.
2024-05-23 06:38:52 -07:00
Jeff McCune
c2847554e0 (#178) Add namespaces to holos platform 2024-05-22 17:04:47 -07:00
Jeff McCune
9411a65dd8 (#178) Add namespaces component schematic
The first thing most platforms need to do is come up with a strategy for
managing namespaces across multiple clusters.

This patch defines #Namespaces in the holos platform and adds a
namespaces component which loops over all values in the #Namespaces
struct and manages a kubernetes Namespace object.

The platform resource itself loops over all clusters in the platform to
manage all namespaces across all clusters.

From a blank slate:

```
❯ holos generate platform holos
4:26PM INF platform.go:79 wrote platform.metadata.json version=0.82.0 platform_id=018fa1cf-a609-7463-aa6e-fa53bfded1dc path=/home/jeff/workspace/holos-run/holos-infra/saas/platform.metadata.json
4:26PM INF platform.go:91 generated platform holos version=0.82.0 platform_id=018fa1cf-a609-7463-aa6e-fa53bfded1dc path=/home/jeff/workspace/holos-run/holos-infra/saas

❯ holos pull platform config .
4:26PM INF pull.go:64 pulled platform model version=0.82.0 server=https://jeff.app.dev.k2.holos.run:443 platform_id=018fa1cf-a609-7463-aa6e-fa53bfded1dc
4:26PM INF pull.go:75 saved platform config version=0.82.0 server=https://jeff.app.dev.k2.holos.run:443 platform_id=018fa1cf-a609-7463-aa6e-fa53bfded1dc path=platform.config.json

❯ (cd components && holos generate component cue namespaces)
4:26PM INF component.go:147 generated component version=0.82.0 name=namespaces path=/home/jeff/workspace/holos-run/holos-infra/saas/components/namespaces

❯ holos render platform ./platform/
4:26PM INF platform.go:29 ok render component version=0.82.0 path=components/namespaces cluster=management num=1 total=2 duration=464.055541ms
4:26PM INF platform.go:29 ok render component version=0.82.0 path=components/namespaces cluster=aws1 num=2 total=2 duration=467.978499ms
```

The result:

```sh
cat deploy/clusters/management/components/namespaces/namespaces.gen.yaml
```

```yaml
---
metadata:
  name: holos
  labels:
    kubernetes.io/metadata.name: holos
kind: Namespace
apiVersion: v1
```
2024-05-22 16:32:59 -07:00
Jeff McCune
9c1165e77e (#178) Save platform.config.json with multiple lines 2024-05-22 14:10:28 -07:00
Jeff McCune
a02c7a4015 (#178) Fix the PlatformService CreatePlatform rpc
Without this patch the
holos.platform.v1alpha1.PlatformService.CreatePlatform doesn't work as
expected.  The Platform message is used which incorrectly requires a
client supplied id which is ignored by the server.

This patch allows the creation of a new platform by reusing the update
operation as a mutation that applies to both create and update.  Only
modifiable fields are part of the PlatformMutation message.
2024-05-22 12:39:24 -07:00
Jeff McCune
bdcde88e6f (#175) Add git describe to --version output
Much easier to track changes between releases.
2024-05-21 13:21:27 -07:00
Jeff McCune
a32b100192 (#175) Output at the end
Flip the let definitions to before their use to avoid confusing /
distracting users who are just getting started.

User feedback from Nate.
2024-05-21 13:03:22 -07:00
Jeff McCune
670d716403 (#175) Add podinfo oci example
This patch adds to more example helm chart based components.  podinfo
installs as a normal https repository based helm chart.  podinfo-oci
uses an oci image to manage the helm chart.

The way holos handls OCI images is subtle, so it's good to include an
example right out of the chute.  Github actions uses OCI images for
example.
2024-05-21 12:36:45 -07:00
Jeff McCune
bba3895f35 (#175) Add holos generate component helm command
This patch adds a schematic to generate a holos component that wraps a
helm chart.  The cert-manager chart is the current example.

Usage:

```bash
set -euo pipefail

rm -rf ~/holos/dev/bare
mkdir ~/holos/dev/bare
cd ~/holos/dev/bare

holos generate platform bare
holos pull platform config .
holos render platform ./platform/
(cd components && holos generate component helm cert-manager)
```

The chart builds:

```bash
holos build ./components/cert-manager | yq .
```

And renders:

```bash
holos render component ./components/cert-manager --cluster-name k2
find deploy -type f
```

```txt
9:41PM INF render.go:83 rendered cert-manager version=0.81.1 cluster=k2 status=ok action=rendered name=cert-manager
deploy/clusters/k2/holos/components/cert-manager-kustomization.gen.yaml
deploy/clusters/k2/components/cert-manager/cert-manager.gen.yaml
```
2024-05-21 11:05:53 -07:00
Jeff McCune
9e60ddbe85 (#175) Add holos generate component cue command
This patch adds a command to generate CUE based holos components from
examples embedded in the executable.  The examples are passed through
the go template rendering engine with values pulled from flags.

Each directory in the embedded filesystem becomes a unique command for
nice tab completion.  The `--name` flag defaults to "example" and is the
resulting component name.

A follow up patch with more flags will set the stage for a Helm
component schematic.

```
holos generate component cue minimal
```

```txt
3:07PM INF component.go:91 generated component version=0.80.2 name=example path=/home/jeff/holos/dev/bare/components/example
```
2024-05-20 15:10:54 -07:00
Jeff McCune
44334fca52 (#175) Fix lint 2024-05-20 12:39:43 -07:00
Jeff McCune
2e2ed398c6 (#175) Fix tests 2024-05-20 11:32:29 -07:00
Jeff McCune
34f2a52cb7 (#175) Add holos render platform command
Split holos render into component and platform.

This patch splits the previous `holos render` command into subcommands.
`holos render component ./path/to/component/` behaves as the previous
`holos render` command and renders an individual component.

The new `holos render platform ./path/to/platform/` subcommand makes
space to render the entire platform using the platform model pulled from
the PlatformService.

Starting with an empty directory:

```sh
holos register user
holos generate platform bare
holos pull platform config .
holos render platform ./platform/
```

```txt
10:01AM INF platform.go:29 ok render component version=0.80.2 path=components/configmap cluster=k1 num=1 total=1 duration=448.133038ms
```

The bare platform has a single component which refers to the platform
model pulled from the PlatformService:

```sh
cat deploy/clusters/mycluster/components/platform-configmap/platform-configmap.gen.yaml
```

```yaml
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: platform
  namespace: default
data:
  platform: |
    spec:
      model:
        cloud:
          providers:
            - cloudflare
        cloudflare:
          email: platform@openinfrastructure.co
        org:
          displayName: Open Infrastructure Services
          name: ois
```
2024-05-20 10:41:24 -07:00
Jeff McCune
d3888a884f (#175) go mod tidy 2024-05-20 06:32:53 -07:00
Jeff McCune
3845871368 (#175) holos pull platform config
This patch adds a subcommand to pull the data necessary to construct a
PlatformConfig DTO.  The PlatformConfig message contains all of the
fields and values necessary to build a platform and the platform
components.  This is an alternative to holos passing multiple tags to
CUE.  The PlatformConfig is marshalled and passed once.

The platform config is also stored in the local filesystem in the root
directory of the platform.  This enables repeated local building and
rendering without making an rpc call.

The build / render pipeline is expected to cache the PlatformConfig once
at the start of the pipeline using the pull subcommand.
2024-05-19 08:27:21 -07:00
Jeff McCune
a3b2d19adb (#175) Render the platform with the model
The `holos render platform` command is unimplemented.  This patch
partially implements platform rendering by fetching the platform model
from the PlatformService and providing it to CUE using a tag.

CUE returns a `kind: Platform` resource to `holos` which will eventually
process a Buildlan for each platform component listed in the Platform
spec.

For now, however, it's sufficient to have the current platform model
available to CUE.
2024-05-18 11:40:30 -07:00
Jeff McCune
e4e7cd8c47 (#175) Make holos render --cluster-name flag optional
Problem:
Rendering the whole platform doesn't need a cluster name.

Solution:
Make the flag optional, do not set the cue tag if it's empty.

Result:
Holos renders the platform resource and proceeds to the point where we
need to implement the iteration over platform components, passing the
platform model to each one and rendering the component.
2024-05-17 15:48:36 -07:00
Jeff McCune
fb22e5521b (#175) Define the Platform resource in CUE
We need to output a kind: Platform resource from cue so holos can
iterate over each build plan.  The platform resource itself should also
contain a copy of the platform model obtained from the PlatformService
so holos can easily pass the model to each BuildPlan it needs to execute
to render the full platform.

This patch lays the groundwork for the Platform resource.  A future
patch will have the holos cli obtain the platform model and inject it as
a JSON encoded string to CUE.  CUE will return the Platform resource
which is a list of references to build plans.  Holos will then iterate
over each build plan, pass the model back in, and execute the build
plan.

To illustrate where we're headed, the `cue export` step will move into
`holos` with a future patch.

```
❯ holos register user
3:34PM INF register.go:77 user version=0.80.0 email=jeff@ois.run server=https://app.dev.k2.holos.run:443 user_id=018f8839-3d74-7e39-afe9-181ad2fc8abe org_id=018f8839-3d74-7e3a-918c-b36494da0115
❯ holos generate platform bare
3:34PM INF generate.go:79 wrote platform.metadata.json version=0.80.0 platform_id=018f8839-3d74-7e3b-8cb8-77a2c124d173 path=/home/jeff/holos/dev/bare/platform.metadata.json
3:34PM INF generate.go:91 generated platform bare version=0.80.0 platform_id=018f8839-3d74-7e3b-8cb8-77a2c124d173 path=/home/jeff/holos/dev/bare
❯ holos push platform form .
3:34PM INF push.go:70 pushed: https://app.dev.k2.holos.run:443/ui/platform/018f8839-3d74-7e3b-8cb8-77a2c124d173 version=0.80.0
❯ cue export ./platform/
{
    "metadata": {
        "name": "bare",
        "labels": {},
        "annotations": {}
    },
    "spec": {
        "model": {}
    },
    "kind": "Platform",
    "apiVersion": "holos.run/v1alpha1"
}
```
2024-05-17 15:34:56 -07:00
Jeff McCune
d2ae766ae3 Merge pull request #176 from holos-run/dependabot/go_modules/github.com/docker/docker-26.0.2incompatible
Bump github.com/docker/docker from 26.0.0+incompatible to 26.0.2+incompatible
2024-05-17 11:53:44 -07:00
dependabot[bot]
c0db949729 Bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.0.0+incompatible to 26.0.2+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.0.0...v26.0.2)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-17 18:52:51 +00:00
Jeff McCune
d2d4337ffd (#175) Improve url output
❯ holos push platform form .
11:49AM INF push.go:70 pushed: https://app.dev.k2.holos.run:443/ui/platform/018f87d1-7ca2-7e37-97ed-a06bcee9b442 version=0.79.0
2024-05-17 11:49:04 -07:00
Jeff McCune
b0ca04635e (#175) Update the client context when switching servers
When the holos server URL switches, we also need to update the client
context to get the correct org id.

Also improve quality of life by printing the url to the form when the
platform form is pushed to the server.

❯ holos push platform form .
11:41AM INF push.go:71 updated platform form version=0.79.0 server=https://app.dev.k2.holos.run:443 platform_id=018f87d1-7ca2-7e37-97ed-a06bcee9b442
11:41AM INF push.go:72 https://app.dev.k2.holos.run:443/ui/platform/018f87d1-7ca2-7e37-97ed-a06bcee9b442 version=0.79.0
2024-05-17 11:43:52 -07:00
Jeff McCune
198c66e6cd (#175) Fix tests
Not sure why this started failing, but it wasn't necessary.
2024-05-17 10:22:35 -07:00
Jeff McCune
24346b9a38 (#172) Deploy v0.79.0 to dev 2024-05-17 10:15:05 -07:00
Jeff McCune
0639562f1c (#175) go mod tidy 2024-05-17 10:09:40 -07:00
Jeff McCune
c1fa9cc531 (#175) Fix lint 2024-05-17 10:08:06 -07:00
Jeff McCune
18653534ad (#175) Add holos push platform form command
This sub-command renders the web app form from CUE code and updates the
form using the `holos.platform.v1alpha1.PlatformService/UpdatePlatform`
rpc method.

Example use case, starting fresh:

```
rm -rf ~/holos
mkdir ~/holos
cd ~/holos
```

Step 1: Login

```sh
holos login
```

```txt
9:53AM INF login.go:40 logged in as jeff@ois.run version=0.79.0 name="Jeff McCune" exp="2024-05-17 21:16:07 -0700 PDT" email=jeff@ois.run
```

Step 2: Register to create server side resources.

```sh
holos register user
```

```
9:52AM INF register.go:68 user version=0.79.0 email=jeff@ois.run user_id=018f826d-85a8-751d-81ee-64d0f2775b3f org_id=018f826d-85a8-751e-98dd-a6cddd9dd8f0
```

Step 3: Generate the bare platform in the local filesystem.

```sh
holos generate platform bare
```

```txt
9:52AM INF generate.go:79 wrote platform.metadata.json version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos/platform.metadata.json
9:52AM INF generate.go:91 generated platform bare version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos
```

Step 4: Push the platform form to the `holos server` web app.

```sh
holos push platform form .
```

```txt
9:52AM INF client.go:67 updated platform version=0.79.0 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 duration=73.62995ms
```

At this point the platform form is published and functions as expected
when visiting the platform web interface.
2024-05-17 09:51:36 -07:00
Jeff McCune
2b89c33067 (#175) Add holos orgid command
Makes it easier to work with grpcurl:

    grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"org_id":"'$(holos orgid)'"}' ${HOLOS_SERVER##*/} holos.platform.v1alpha1.PlatformService.ListPlatforms
2024-05-16 21:11:24 -07:00
Jeff McCune
aee26d9375 (#175) Set header User-Agent: holos/0.70.0 (go1.22.2)
Previously: User-Agent: connect-go/1.16.0 (go1.22.2)
2024-05-16 20:49:06 -07:00
Jeff McCune
7b04d492ab (#175) Set http.Server ReadHeaderTimeout
Upstream connectrpc recommends it.  Refer to
https://connectrpc.com/docs/faq#stream-error
2024-05-16 20:28:31 -07:00
Jeff McCune
8abd03e165 (#175) Log x-request-id and x-b3-trace headers
This patch logs the x-request-id header which makes it straight forward
to correlate the logs with the service mesh logs.

For example, select the request id from the gateway logs by copying the
log from the holos server logs.

```sh
kubectl -n istio-ingress logs -l app=istio-ingressgateway -f \
  | grep --line-buffered '^{' \
  | jq 'select(.request_id=="'d0867115-5795-4096-942e-5ac188cdf618'")'
```

```json
{
  "upstream_local_address": "10.244.1.51:44248",
  "x_forwarded_for": "192.168.2.21",
  "authority": "jeff.app.dev.k2.holos.run:443",
  "upstream_transport_failure_reason": null,
  "connection_termination_details": null,
  "response_code": 200,
  "duration": 6,
  "response_flags": "-",
  "upstream_service_time": "5",
  "upstream_cluster": "outbound|3000||holos.jeff-holos.svc.cluster.local",
  "upstream_host": "10.244.1.249:3000",
  "user_agent": "connect-go/1.16.0 (go1.22.2)",
  "requested_server_name": "jeff.app.dev.k2.holos.run",
  "request_id": "d0867115-5795-4096-942e-5ac188cdf618",
  "start_time": "2024-05-17T03:16:37.900Z",
  "method": "POST",
  "protocol": "HTTP/2",
  "downstream_local_address": "65.102.23.41:443",
  "path": "/holos.user.v1alpha1.UserService/GetUser",
  "bytes_sent": 159,
  "downstream_remote_address": "192.168.2.21:59564",
  "response_code_details": "via_upstream",
  "bytes_received": 0,
  "route_name": "holos-api"
}
```
2024-05-16 20:14:34 -07:00
Jeff McCune
2df843bc98 (#175) Link the generated platform to holos server
When the user generates a platform, we need to know the platform ID it's
linked to in the holos server.  If there is no platform with the same
name, the `holos generate platform` command should error out.

This is necessary because the first thing we want to show is pushing an
updated form to `holos server`.  To update the web ui the CLI needs to
know the platform ID to update.

This patch modifies the generate command to obtain a list of platforms
for the org and verify the generated name matches one of the platforms
  that already exists.

A future patch could have the `generate platform` command call the
`holos.platform.v1alpha1.PlatformService.CreatePlatform` method if the
platform isn't found.

Results:

```sh
holos generate platform bare
```

```txt
4:15PM INF generate.go:77 wrote platform.metadata.json version=0.77.1 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos/platform.metadata.json
4:15PM INF generate.go:89 generated platform bare version=0.77.1 platform_id=018f826d-85a8-751f-96d0-0d2bf70df909 path=/home/jeff/holos
```

```sh
cat platform.metadata.json
```

```json
{
  "id": "018f826d-85a8-751f-96d0-0d2bf70df909",
  "name": "bare",
  "display_name": "Bare Platform"
}
```
2024-05-16 16:18:38 -07:00
Jeff McCune
be4d2c29a5 (#175) Log info message when generating a platform
holos generate platform bare
    2:11PM INF generate.go:55 generated platform bare version=0.77.1 path=/home/jeff/holos
2024-05-16 14:26:51 -07:00
Jeff McCune
8ce88bf491 (#175) Fix goreleaser
Buf was being automatically updated in the pipeline.
2024-05-16 14:00:37 -07:00
Jeff McCune
b05571a595 (#175) Go tidy and update package.json
For goreleaser
2024-05-16 13:41:47 -07:00
Jeff McCune
4edfc71d68 (#175) Log the grpc procedure at info level
This patch logs the service and rpc method of every request at Info
level.  The error code and message is also logged.  This gives a good
indication of what rpc methods are being called and by whom.
2024-05-16 11:43:20 -07:00
Jeff McCune
3049694a0a (#175) holos register user
This patch adds a `holos register user` command.  Given an authenticated
id token and no other record of the user in the database, the cli tool
use the API to:

 1. User is registered in `holos server`
 2. User is linked to one Holos Organization.
 3. Holos Organization has the `bare` platform.
 4. Holos Organization has the `reference` platform.
 5. Ensure `~/.holos/client-context.json` contains the user id and an
    org id.

The `holos.ClientContext` struct is intended as a light weight way to
save and load the current organization id to the file system for further
API calls.

The assumption is most users will have only one single org.  We can add
a more complicated config context system like kubectl uses if and when
we need it.
2024-05-16 10:51:40 -07:00
Jeff McCune
5860c5747b (#87) generate sub-command with embedded platform
This patch adds a generate subcommand that copies a platform embedded
into the executable to the local filesystem.  The purpose is to
accelerate initial setup with canned example platforms.

Two platforms are intended to start, one bare and one reference
platform.  The number of platforms embedded into holos should be kept
small (2-3) to limit our support burden.
2024-05-14 15:03:21 -07:00
Jeff McCune
d3c2d55706 (#172) Deploy v0.76.0 to dev 2024-05-14 13:28:19 -07:00
Jeff McCune
ac2ff47a9c (#172) Wire Version Info in the UI
This patch adds the GetVersion rpc method to
holos.system.v1alpha1.SystemService and wires the version information up
to the Web UI.

This is a good example to crib from later regarding fetching and
refreshing data from the web ui using grpc and field masks.
2024-05-14 11:50:06 -07:00
Jeff McCune
9a2773c618 (#171) Refactor API to use FieldMasks
This patch refactors the API following the [API Best Practices][api]
documentation.  The UpdatePlatform method is modeled after a mutating
operation described [by Netflix][nflx] instead of using a REST resource
representation.  This makes it much easier to iterate over the fields
that need to be updated as the PlatformUpdateOperation is a flat data
structure while a Platform resource may have nested fields.  Nested
fields are more complicated and less clear to handle with a FieldMask.

This patch also adds a snapckbar message on save.  Previously, the save
button didn't give any indication of success or failure.  This patch
fixes the problem by adding a snackbar message that pop up at the bottom
of the screen nicely.

When the snackbar message is dismissed or times out the save button is
re-enabled.

[api]: https://protobuf.dev/programming-guides/api/
[nflx]: https://netflixtechblog.com/practical-api-design-at-netflix-part-2-protobuf-fieldmask-for-mutation-operations-2e75e1d230e4

Examples:

FieldMask for ListPlatforms

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d @ ${HOLOS_SERVER##*/} holos.platform.v1alpha1.PlatformService.ListPlatforms <<EOF
{
  "org_id": "018f36fb-e3f7-7f7f-a1c5-c85fb735d215",
  "field_mask": { "paths": ["id","name"] }
}
EOF
```

```json
{
 "platforms": [
   {
     "id": "018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94",
     "name": "bare"
   },
   {
     "id": "018f6b06-9e57-7223-91a9-784e145d998c",
     "name": "gary"
   },
   {
     "id": "018f6b06-9e53-7223-8ae1-1ad53d46b158",
     "name": "jeff"
   },
   {
     "id": "018f6b06-9e5b-7223-8b8b-ea62618e8200",
     "name": "nate"
   }
 ]
}
```

Closes: #171
2024-05-13 16:20:20 -07:00
Jeff McCune
51b6575d9f (#171) Refactor to API Best Practices
This patch refactors the API to be resource-oriented around one service
per resource type.  PlatformService, OrganizationService, UserService,
etc...

Validation is improved to use CEL rules provided by [protovalidate][1].

Place holders for FieldMask and other best practices are added, but are
unimplemented as per [API Best Practices][2].

The intent is to set us up well for copying and pasting solid existing
examples as we add features.

With this patch the server and web app client are both updated to use
the refactored API, however the following are not working:

 1. Update the model.
 2. Field Masks.

[1]: https://buf.build/bufbuild/protovalidate
[2]: https://protobuf.dev/programming-guides/api/
2024-05-10 15:55:41 -07:00
Jeff McCune
68a43f0682 (#167) Add holos rpc platform-model command
This command is just a prototype of how to fetch the platform model so
we can make it available to CUE.

The idea is we take the data from the holos server and write it into a
CUE `_Platform` struct.  This will probably involve converting the data
to CUE format and nesting it under the platform struct spec field.
2024-05-08 16:34:00 -07:00
Jeff McCune
9da88c4d1b (#169) ZITADEL ServerError - PGBouncer DNS
Add runbook notes.  Root cause and permanent solution have not been
identified yet.
2024-05-08 12:04:50 -07:00
Jeff McCune
19df2ec0fb (#167) Bump dev deployment to 0.74.0 2024-05-07 16:58:03 -07:00
Jeff McCune
bac7aec0ba (#167) Restructure the bare platform
This patch restructures the bare platform in preparation for a
`Platform` kind of output from CUE in addition to the existing
`BuildPlan` kind.

This patch establishes a pattern where our own CUE defined code goes
into the two CUE module paths:

1. `internal/platforms/cue.mod/gen/github.com/holos-run/holos/api/v1alpha1`
2. `internal/platforms/cue.mod/pkg/github.com/holos-run/holos/api/v1alpha1`
3. `internal/platforms/cue.mod/usr/github.com/holos-run/holos/api/v1alpha1`

The first path is automatically generated from Go structs.  The second
path is where we override and provide additional cue level integration.

The third path is reserved for the end user to further refine and
constrain our definitions.
2024-05-07 16:53:00 -07:00
Jeff McCune
42f916af41 (#164) Use quay.io/holos/oauth2-proxy:v7.6.0-1-g77a03ae2
Custom build to set samesite=none on the csrf cookie.
2024-05-06 16:18:32 -07:00
Jeff McCune
47a5e237e0 (#162) Lint go, typescript, and proto3 files
This patch adds lint coverage for proto3 and typescript to keep our code
reasonably clean.  The go linter was already enabled.
2024-05-06 14:17:08 -07:00
Jeff McCune
1279e2351a (#162) Move Platform back to holos.v1alpha1
No need to have a separate package for the PlatformService and related
protobuf messages.
2024-05-06 13:47:37 -07:00
Jeff McCune
adb8177026 Merge pull request #166 from holos-run/jeff/165-deploy-holos
(#165) Deploy Holos to Dev
2024-05-06 11:23:48 -07:00
Jeff McCune
4e8fa5abda (#165) Bump dev deployment to 0.73.1 2024-05-06 11:22:24 -07:00
Jeff McCune
6894f45b6c (#165) Deploy Holos to Dev
This patch deploys holos to the dev environment on the k2 cluster.  It's
accessible at https://app.dev.k2.holos.run/ behind the auth proxy by
default.
2024-05-06 11:10:29 -07:00
Jeff McCune
89d25be837 (#161) Wrap main router outlet in <main></main> 2024-05-06 09:16:15 -07:00
Jeff McCune
5b33e48552 (#161) Reasonably advanced form modeling the reference platform
This form goes a good way toward capturing what we need to configure the
entire reference platform.  Elements and sections are responsive to
which cloud providers are selected, which achieves my goal of modeling a
reasonably advanced form using only JSON data produced by CUE.

To write the form via the API:

    cue export ./forms/platform/ --out json \
      | jq '{platform_id: "'${platformId}'", fields: .spec.fields}' \
      | grpcurl -H "x-oidc-id-token: $(holos token)" -d @ ${host}:443 \
      holos.platform.v1alpha1.PlatformService.PutForm
2024-05-04 20:16:09 -07:00
Jeff McCune
79e8ab639a (#161) Fix the FormGroup & Refactor API
The way we were organizing fields into section broke Formly validation.
This patch fixes the problem by using the recommended approach of
[Nested Forms][1].

This patch also refactors the PlatformService API to clean it up.
GetForm / PutForm are separated from the Platform methods.  Similarly
GetModel / PutModel are separated out and are specific to get and put
the model data.

NOTE: I'm not sure we should have separated out the platform service
into it's own protobuf package.  Seems maybe unnecessary.

❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94"}' jeff.app.dev.k2.holos.run:443 holos.platform.v1alpha1.PlatformService.GetModel
{
  "model": {
    "org": {
      "contactEmail": "platform@openinfrastructure.co",
      "displayName": "Open Infrastructure Services LLC",
      "domain": "ois.run",
      "name": "ois"
    },
    "privacy": {
      "country": "earth",
      "regions": [
        "us-east-2",
        "us-west-2"
      ]
    },
    "terms": {
      "didAgree": true
    }
  }
}

[1]: https://formly.dev/docs/examples/other/nested-formly-forms
2024-05-04 10:14:37 -07:00
Jeff McCune
a0cc673736 (#150) Wire up select and multi select boxes
This patch wires up a Select and a Multi Select box.  This patch also
establishes a decision as it relates to Formly TypeScript / gRPC Proto3
/ CUE definitions of the form data structure.  The decision is to use
gRPC as a transport for any JSON to avoid friction trying to fit Formly
types into Proto3 messages.

Note when using google.protobuf.Value messages with bufbuild/connect-es,
we need to round trip them one last time through JSON to get the
original JSON on the other side.  This is because connect-es preserves
the type discriminators in the case and value fields of the message.

Refer to: [Accessing oneof
groups](https://github.com/bufbuild/protobuf-es/blob/main/docs/runtime_api.md#accessing-oneof-groups)

NOTE: On the wire, carry any JSON as field configs for expedience.  I
attempted to reflect FormlyFieldConfig in protobuf, but it was too time
consuming.  The loosely defined Formly json data API creates significant
friction when joined with a well defined protobuf API.  Therefore, we do
not specify anything about the Forms API, convey any valid JSON, and
leave it up to CUE and Formly on the sending and receiving side of the
API.

We use CUE to define our own holos form elements as a subset of the loose
Formly definitions.  We further hope Formly will move toward a better JSON
data API, but it's unlikely.  Consider replacing Formly entirely and
building on top of the strongly typed Angular Dyanmic Forms API.

Refer to: https://github.com/ngx-formly/ngx-formly/blob/v6.3.0/src/core/src/lib/models/fieldconfig.ts#L15
Consider: https://angular.io/guide/dynamic-form

Usage:

Generate the form from CUE

    cue export ./forms/platform/ --out json | jq -cM | pbcopy

Store the form JSON in the config_values column of the platforms table.

View the form, and submit some data. Then get the data back out for use rendering the platform:

    grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"'${platformId}'"}' $holos holos.v1alpha1.PlatformService.GetConfig

```json
{
  "platform": {
    "spec": {
      "config": {
        "user": {
          "sections": {
            "org": {
              "fields": {
                "contactEmail": "jeff@openinfrastructure.co",
                "displayName": "Open Infrastructure Services LLC",
                "domain": "ois.run",
                "name": "ois"
              }
            },
            "privacy": {
              "fields": {
                "country": "earth",
                "regions": [
                  "us-east-2",
                  "us-west-2"
                ]
              }
            },
            "terms": {
              "fields": {
                "didAgree": true
              }
            }
          }
        }
      }
    }
  }
}
```
2024-05-03 10:42:03 -07:00
Jeff McCune
d06ecfadc8 (#150) Refactor PlatformService.GetConfig for use with CUE
Problem:
The GetConfig response value isn't directly usable with CUE without some
gymnastics.

Solution:
Refactor the protobuf definition and response output to make the user
defined and supplied config values provided by the API directly usable
in the CUE code that defines the platform.

Result:

The top level platform config is directly usable in the
`internal/platforms/bare` directory:

    grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"'${platformID}'"}' $host \
      holos.v1alpha1.PlatformService.GetConfig \
      > platform.holos.json

Vet the user supplied data:

    cue vet ./ -d '#PlatformConfig' platform.holos.json

Build the holos component.  The ConfigMap consumes the user supplied
data:

    cue export --out yaml -t cluster=k2 ./components/configmap platform.holos.json \
      | yq .spec.components

Note the data provided by the input form is embedded into the
ConfigMap managed by Holos:

```yaml
KubernetesObjectsList:
  - metadata:
      name: platform-configmap
    apiObjectMap:
      ConfigMap:
        platform: |
          metadata:
            name: platform
            namespace: default
            labels:
              app.holos.run/managed: "true"
          data:
            platform: |
              kind: Platform
              spec:
                config:
                  user:
                    sections:
                      org:
                        fields:
                          contactEmail: jeff@openinfrastructure.co
                          displayName: Open Infrastructure Services LLC
                          domain: ois.run
                          name: ois
              apiVersion: app.holos.run/v1alpha1
              metadata:
                name: bare
                labels: {}
                annotations: {}
              holos:
                flags:
                  cluster: k2
          kind: ConfigMap
          apiVersion: v1
    Skip: false
```
2024-05-02 06:39:33 -07:00
Jeff McCune
64a117b0c3 (#150) Add PlatformService.GetConfig and refactor ConfigValues proto
Problem:
The use of google.protobuf.Any was making it awkward to work with the
data provided by the user.  The structure of the form data is defined by
the platform engineer, so the intent of Any was to wrap the data in a
way we can pass over the network and persist in the database.

The escaped JSON encoding was problematic and error prone to decode on
the other end.

Solution:
Define the Platform values as a two level map with string keys, but with
protobuf message fields "sections" and "fields" respectively.  Use
google.protobuf.Value from the struct package to encode the actual
value.

Result:
In TypeScript, google.protobuf.Value encodes and decodes easily to a
JSON value.  On the go side, connect correctly handles the value as
well.

No more ugly error prone escaping:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"'${platformId}'"}' $host holos.v1alpha1.PlatformService.GetConfig
{
  "sections": {
    "org": {
      "fields": {
        "contactEmail": "jeff@openinfrastructure.co",
        "displayName": "Open Infrastructure Services LLC",
        "domain": "ois.run",
        "name": "ois"
      }
    }
  }
}
```

This return value is intended to be directly usable in the CUE code, so
we may further nest the values into a platform.spec key.
2024-05-01 21:30:30 -07:00
Jeff McCune
cf006be9cf (#150) Add SystemService DropTables and SeedDatabase
Makes it easier to reset the database and give Gary and Nate access to
the same organization I'm in so they can provide feedback.
2024-05-01 14:30:13 -07:00
Jeff McCune
45ad3d8e63 (#150) Fix 500 error when config values aren't provided
AddPlatform was failing with a 500 error trying to decode a nil byte
slice when adding a platform without providing any values.
2024-05-01 11:31:25 -07:00
Jeff McCune
441c968c4f (#150) Look up user by iss sub, not email.
Also log when orgs are created.
2024-05-01 10:02:08 -07:00
Jeff McCune
99f2763fdf (#150) Store Platform Config Form and Values as JSON
This patch changes the backend to store the platform config form
definition and the config values supplied by the form as JSON in the
database.

The gRPC API does not change with this patch, but may need to depending
on how this works and how easy it is to evolve the data model and add
features.
2024-05-01 09:11:53 -07:00
Jeff McCune
1312395a11 (#150) Fix platforms page links
The links were hard to click.  This makes the links a much larger click
target following the example at https://material.angular.io/components/list/overview#navigation-lists
2024-05-01 08:51:29 -07:00
Jeff McCune
615f147bcb (#150) Add PutPlatformConfig to store the config values
This patch is a work in progress wiring up the form to put the values to
the holos server using grpc.

In an effort to simplify the platform configuration, the structure is a
two level map with the top level being configuration sections and the
second level being the fields associated with the config section.

To support multiple kinds of values and field controls, the values are
serialized to JSON for rpc over the network and for storage in the
database.  When they values are used, either by the UI or by the `holos
render` command, they're to be unmarshalled and in-lined into the
Platform Config data structure.

Pick back up ensuring the Platform rpc handler correctly encodes and
decodes the structure to the database.

Consider changing the config_form and config_values fields to JSON field
types in the database.  It will likely make working with this a lot
easier.

With this patch we're ready to wire up the holos render command to fetch
the platform configuration and create the end to end demo.

Here's essentially what the render command will fetch and lay down as a
json file for CUE:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"018f2c4e-ecde-7bcb-8b89-27a99e6cc7a1"}' jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.GetPlatform | jq .platform.config.values
{
  "sections": {
    "org": {
      "values": {
        "contactEmail": "\"platform@openinfrastructure.co\"",
        "displayName": "\"Open Infrastructure Services  LLC\"",
        "domain": "\"ois.run\"",
        "name": "\"ois\""
      }
    }
  }
}
```
2024-04-30 20:21:15 -07:00
Jeff McCune
d0ad3bfc69 (#150) Add Platform Detail to edit platform config
This patch adds a /platform/:id route path to a PlatformDetail
component.  The platform detail component calls the GetPlatform method
given the platform ID and renders the platform config form on the detail
tab.

The submit button is not yet wired up.

The API for adding platforms changes, allowing raw json bytes using the
RawConfig.  The raw bytes are not presented on the read path though,
calling GetPlatforms provides the platform and the config form inline in
the response.

Use the `raw_config` field instead of `config` when creating the form
data.

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d @ jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.AddPlatform <<EOF
{
  "platform": {
    "org_id": "018f27cd-e5ac-7f98-bfe1-2dbab208a48c",
    "name": "bare2",
    "raw_config": {
      "form": "$(cue export ./forms/platform/ --out json | jq -cM | base64 -w0)"
    }
  }
}
EOF
```
2024-04-30 14:02:49 -07:00
Jeff McCune
fe58a33747 (#150) Add holos.v1alpha1.PlatformService.GetForm
The GetForm method is intended for the Angular frontend to get
[FormlyFieldConfig][1] data for each section of the Platform config.

[1]: https://formly.dev/docs/api/core/#formlyfieldconfig

Steps to exercise for later testing:

Add the form definition to the database:

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d @ jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.AddPlatform <<EOF
{
  "platform": {
    "org_id": "018f27cd-e5ac-7f98-bfe1-2dbab208a48c",
    "name": "bare${RANDOM}",
    "config": {
      "form": "$(cue export ./forms/platform/ --out json | jq -cM | base64 -w0)"
    }
  }
}
EOF
```

Get the form definition back out:

```

❯ grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"platform_id":"018f2bc1-6590-7670-958a-9f3bc02b658f"}' jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.GetForm
{
  "apiVersion": "forms.holos.run/v1alpha1",
  "kind": "PlatformForm",
  "metadata": {
    "name": "bare"
  },
  "spec": {
    "sections": [
      {
        "name": "org",
        "displayName": "Organization",
        "description": "Organization config values are used to derive more specific configuration values throughout the platform.",
        "fieldConfigs": [
          {
            "key": "name",
            "type": "input",
            "props": {
              "label": "Name",
              "placeholder": "example",
              "description": "DNS label, e.g. 'example'",
              "required": true
            }
          },
          {
            "key": "domain",
            "type": "input",
            "props": {
              "label": "Domain",
              "placeholder": "example.com",
              "description": "DNS domain, e.g. 'example.com'",
              "required": true
            }
          },
          {
            "key": "displayName",
            "type": "input",
            "props": {
              "label": "Display Name",
              "placeholder": "Example Organization",
              "description": "Display name, e.g. 'Example Organization'",
              "required": true
            }
          },
          {
            "key": "contactEmail",
            "type": "input",
            "props": {
              "label": "Contact Email",
              "placeholder": "platform-team@example.com",
              "description": "Technical contact email address",
              "required": true
            }
          }
        ]
      }
    ]
  }
}
```

References

```
❯ cue export ./forms/platform/ --out yaml | yq
apiVersion: forms.holos.run/v1alpha1
kind: PlatformForm
metadata:
  name: bare
spec:
  sections:
    - name: org
      displayName: Organization
      description: Organization config values are used to derive more specific configuration values throughout the platform.
      fieldConfigs:
        - key: name
          type: input
          props:
            label: Name
            placeholder: example
            description: DNS label, e.g. 'example'
            required: true
        - key: domain
          type: input
          props:
            label: Domain
            placeholder: example.com
            description: DNS domain, e.g. 'example.com'
            required: true
        - key: displayName
          type: input
          props:
            label: Display Name
            placeholder: Example Organization
            description: Display name, e.g. 'Example Organization'
            required: true
        - key: contactEmail
          type: input
          props:
            label: Contact Email
            placeholder: platform-team@example.com
            description: Technical contact email address
            required: true
```
2024-04-29 14:24:16 -07:00
Jeff McCune
26e537e768 (#150) Add platform config form, values, cue
This patch adds 4 fields to the Platform table:

 1. Config Form represents the JSON FormlyFieldConfig for the UI.
 2. Config CUE represents the CUE file containing a definition the
    Config Values must unify with.
 3. Config Definition is the CUE definition variable name used to unify
    the values with the cue code.  Should be #PlatformSpec in most
    cases.
 4. Config Values represents the JSON values provided by the UI.

The use case is the platform engineer defines the #PlatformSpec in cue,
and provides the form field config.  The platform engineer then provides
1-3 above when adding or updating a Platform.

The UI then presents the form to the end user and provides values for 4
when the user submits the form.

This patch also refactors the AddPlatform method to accept a Platform
message.  To do so we make the id field optional since it is server
assigned.

The patch also adds a database constraint to ensure platform names are
unique within the scope of an organization.

Results:

Note how the CUE representation of the Platform Form is exported to JSON
then converted to a base64 encoded string, which is the protobuf JSON
representation of a bytes[] value.

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d @ jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.AddPlatform <<EOF
{
  "platform": {
    "id": "0d3dc0c0-bbc8-41f8-8c6e-75f0476509d6",
    "org_id": "018f27cd-e5ac-7f98-bfe1-2dbab208a48c",
    "name": "bare",
    "config": {
      "form": "$(cd internal/platforms/bare && cue export ./forms/platform/ --out json | jq -cM | base64 -w0)"
    }
  }
}
EOF
```

Note the requested platform ID is ignored.

```
{
  "platforms": [
    {
      "id": "018f2af9-f7ba-772a-9db6-f985ece8fed1",
      "timestamps": {
        "createdAt": "2024-04-29T17:49:36.058379Z",
        "updatedAt": "2024-04-29T17:49:36.058379Z"
      },
      "name": "bare",
      "creator": {
        "id": "018f27cd-e591-7f98-a9d2-416167282d37"
      },
      "config": {
        "form": "eyJhcGlWZXJzaW9uIjoiZm9ybXMuaG9sb3MucnVuL3YxYWxwaGExIiwia2luZCI6IlBsYXRmb3JtRm9ybSIsIm1ldGFkYXRhIjp7Im5hbWUiOiJiYXJlIn0sInNwZWMiOnsic2VjdGlvbnMiOlt7Im5hbWUiOiJvcmciLCJkaXNwbGF5TmFtZSI6Ik9yZ2FuaXphdGlvbiIsImRlc2NyaXB0aW9uIjoiT3JnYW5pemF0aW9uIGNvbmZpZyB2YWx1ZXMgYXJlIHVzZWQgdG8gZGVyaXZlIG1vcmUgc3BlY2lmaWMgY29uZmlndXJhdGlvbiB2YWx1ZXMgdGhyb3VnaG91dCB0aGUgcGxhdGZvcm0uIiwiZmllbGRDb25maWdzIjpbeyJrZXkiOiJuYW1lIiwidHlwZSI6ImlucHV0IiwicHJvcHMiOnsibGFiZWwiOiJOYW1lIiwicGxhY2Vob2xkZXIiOiJleGFtcGxlIiwiZGVzY3JpcHRpb24iOiJETlMgbGFiZWwsIGUuZy4gJ2V4YW1wbGUnIiwicmVxdWlyZWQiOnRydWV9fSx7ImtleSI6ImRvbWFpbiIsInR5cGUiOiJpbnB1dCIsInByb3BzIjp7ImxhYmVsIjoiRG9tYWluIiwicGxhY2Vob2xkZXIiOiJleGFtcGxlLmNvbSIsImRlc2NyaXB0aW9uIjoiRE5TIGRvbWFpbiwgZS5nLiAnZXhhbXBsZS5jb20nIiwicmVxdWlyZWQiOnRydWV9fSx7ImtleSI6ImRpc3BsYXlOYW1lIiwidHlwZSI6ImlucHV0IiwicHJvcHMiOnsibGFiZWwiOiJEaXNwbGF5IE5hbWUiLCJwbGFjZWhvbGRlciI6IkV4YW1wbGUgT3JnYW5pemF0aW9uIiwiZGVzY3JpcHRpb24iOiJEaXNwbGF5IG5hbWUsIGUuZy4gJ0V4YW1wbGUgT3JnYW5pemF0aW9uJyIsInJlcXVpcmVkIjp0cnVlfX0seyJrZXkiOiJjb250YWN0RW1haWwiLCJ0eXBlIjoiaW5wdXQiLCJwcm9wcyI6eyJsYWJlbCI6IkNvbnRhY3QgRW1haWwiLCJwbGFjZWhvbGRlciI6InBsYXRmb3JtLXRlYW1AZXhhbXBsZS5jb20iLCJkZXNjcmlwdGlvbiI6IlRlY2huaWNhbCBjb250YWN0IGVtYWlsIGFkZHJlc3MiLCJyZXF1aXJlZCI6dHJ1ZX19XX1dfX0K"
      }
    }
  ]
}
```
2024-04-29 10:53:23 -07:00
Jeff McCune
ad70a6c4fe (#150) Add holos.v1alpha1.PlatformService.AddPlatform
This patch adds a basic AddPlatform method that adds a platform with a
name and a display name.

Next steps are to add fields for the Platform Config Form definition and
the Platform Config values submitted from the form.
2024-04-29 09:35:49 -07:00
Jeff McCune
22a04da6bb (#150) Add holos.v1alpha1.PlatformService.GetPlatforms
Next step: AddPlatform

Also consider extracting the queries to get the requested org_id to a
helper function.  This will likely eventually move to an interceptor
because every request is org scoped and needs authorization checks
against the org.

```
grpcurl -H "x-oidc-id-token: $(holos token)" -d '{"org_id":"018f27cd-e5ac-7f98-bfe1-2dbab208a48c"}' jeff.app.dev.k2.holos.run:443 holos.v1alpha1.PlatformService.GetPlatforms
```
2024-04-28 20:21:32 -07:00
Jeff McCune
dc97fe0ff0 (#150) Define a PlatformForm for platform design
Problem:
Platform engineers need the ability to define custom input fields for
their own platform level configuration values.  The holos web UI needs
to present the platform config values in a clean way.  The values
entered on the form need to make their way into the top level
Platform.spec field for use across all components and clusters in the
platform.

Solution:
Define a Platform Form in a forms cue package.  The output of this
definition is intended to be sent to the holos server to provide to the
web UI.

Result:
Platform engineers can define their platform config input values in
their infrastructure repository.  For example, the bare platform form
inputs are defined at `platforms/bare/forms/platform/platform-form.cue`.

This cue file produces [FormlyFieldConfig][1] output.

```console
cue export ./forms/platform/ --out yaml
```

```yaml
apiVersion: forms.holos.run/v1alpha1
kind: PlatformForm
metadata:
  name: bare
spec:
  sections:
    - name: org
      displayName: Organization
      description: Organization config values are used to derive more specific configuration values throughout the platform.
      fieldConfigs:
        - key: name
          type: input
          props:
            label: Name
            placeholder: example
            description: DNS label, e.g. 'example'
            required: true
        - key: domain
          type: input
          props:
            label: Domain
            placeholder: example.com
            description: DNS domain, e.g. 'example.com'
            required: true
        - key: displayName
          type: input
          props:
            label: Display Name
            placeholder: Example Organization
            description: Display name, e.g. 'Example Organization'
            required: true
        - key: contactEmail
          type: input
          props:
            label: Contact Email
            placeholder: platform-team@example.com
            description: Technical contact email address
            required: true
```

Next Steps:
Add a holos subcommand to produce the output and store it in the
backend.  Wire the front end to fetch the form config from the backend.

[1]: https://formly.dev/docs/api/core#formlyfieldconfig
2024-04-28 11:25:06 -07:00
Jeff McCune
9ca97c6e01 Merge pull request #148 from holos-run/jeff/147-cue-oom
(#147) Add holos render --print-instances flag
2024-04-26 16:31:14 -07:00
Jeff McCune
924653e240 (#150) Bare Platform
This patch adds a bare platform that does nothing but render a configmap
containing the platform config structure itself.

The definition of the platform structure is firming up.  The platform
designer, which may be a holos customer, is responsible for defining the
structure of the `platform.spec` output field.

Us holos developers have a reserved namespace to add configuration
fields and data in the `platform.holos` output file.

Beyond these two fields, the platform config structure has TypeMeta and
ObjectMeta fields similar to a kubernetes api object to support
versioning the platform config data, naming the platform, annotating the
platform, and labeling the platform.

The path forward from here is to:

 1. Eventually move the stable definitions into a CUE module that gets
    imported into the user's package.
 2. As a platform designer, add the organization field to the
    #PlatformSpec definition as a CUE definition.
 3. As a platform designer, add the organization field Form data
    structure as a JSON file.
 4. Add an API to upload the #PlatformSpec cue file and the
    #PlatformSpec form json file to the saas backend.
 5. Wire up Angular to pull the form json from the API and render the
    form.
 6. Wire up Angular to write the form data to a gRPC service method.
 7. Wire up the `holos cli` to read the form data from a gRPC service
    method.
 8. Tie it all together where the holos cli renders the configmap.
2024-04-26 16:14:30 -07:00
Jeff McCune
59d48f8599 (#146) Platform Config Mock Up
This patch adds a mock up of the platform config.  The goal is to use
this to connect to an anemic example platform built from `holos init`.
2024-04-26 11:29:58 -07:00
Jeff McCune
90f8eab816 (#144) Tidy go.mod and package.json 2024-04-25 19:14:20 -07:00
Jeff McCune
9ae45e260d (#147) Add holos render --print-instances flag
To enumerate all of the instances that could be run in separate
processes with xargs instead of run in the for loop in the Builder Run
method.
2024-04-25 13:59:10 -07:00
Jeff McCune
aee15f95e2 Merge pull request #145 from holos-run/jeff/144-organization-selector
(#144) Profile Button
2024-04-25 09:55:55 -07:00
Jeff McCune
1c540ac375 (#144) Profile Button and Organization Selector
This patch adds an organization "selector" that's really just a place
holder.  The active organization is the last element in the list
returned by the GetCallerOrganizations method for now.

The purpose is to make sure we have the structure in place for more than
one organizations without needing to implement full support for the
feature at this early stage.

The Angular frontend is expected to call the activeOrg() method of the
OrganizationService.  In the future this could store the state of which
organization the user has selected.  The purpose is to return an org id
to send as a request parameter for other requests.

Note this patch also implements refresh behavior.  The list of orgs is
fetched once on application load.  If there is no user, or the user has
zero orgs, the user is created and an organization is added with them as
an owner.  This is accompished using observable pipes.

The pipe is tied to a refresh behavior.  Clicking the org button
triggers the refresh behavior, which executes the pipe again and
notifies all subscribers.

This works quite well and should be idiomatic angular / rxjs.  Clicking
the button automatically updates the UI after making the necessary API
calls.
2024-04-25 09:55:13 -07:00
Jeff McCune
5b0e883ac9 (#144) Get or Create the orgranization
This patch adds the OrganizationService to the Angular front end and
displays a simple list of the organizations the user is a member of in
the profile card.

There isn't a service yet to return the currently selected
organization, but that could be a simple method to return the most
recent entry in the list until we put something more complicated in
place like local storage of what the user has selected.

It may make sense to put a database constraint on the number of
organizations until we implement the feature later, it's too early to do
so now, I just want to make sure it's possible to add later.
2024-04-25 07:02:17 -07:00
Jeff McCune
9a2519af71 (#144) Make the linter happy 2024-04-24 13:41:45 -07:00
Jeff McCune
9b9ff601c0 (#144) Call GetCallerClaims once instead of multiple times
Problem:
When loading the page the GetCallerClaims rpc method is called multiple
times unnecessarily.

Solution:
Use [shareReplay][1] to replay the last observable event for all
subscribers, including subscribers coming late to the party.

Result:
Network inspector in chrome indicates GetCallerClaims is called once and
only once.

[1]: https://rxjs.dev/api/operators/shareReplay
2024-04-24 12:44:44 -07:00
Jeff McCune
2f798296dc (#144) Profile Button
This patch adds a ProfileButton component which makes a ConnectRPC gRPC
call to the `holos.v1alpha1.UserService.GetCallerClaims` method and
renders the profile button based on the claims.

Note, in the network inspector there are two API calls to
`holos.v1alpha1.UserService.GetCallerClaims` which is unfortunate.  A
follow up patch might be good to fix this.
2024-04-24 12:23:54 -07:00
Jeff McCune
2b2ff63cad (#144) Connect /ui to ng serve for hot reload
Problem:
It's slow to build the angular app, compile it into the go executable,
copy it to the pod, then restart the server.

Solution:
Configure the mesh to route /ui to `ng serve` running on my local
host.

Result:
Navigating to https://jeff.app.dev.k2.holos.run/ui gets responses from
the ng development server.

Use:

    ng serve --host 0.0.0.0
2024-04-23 20:30:02 -07:00
Jeff McCune
3b135c09f3 (#144) Make a ConnectRPC call to the GetUserClaims method
This patch wires up an Angular RxJS Observable to the result of a gRPC
call to the `holos.v1alpha1.UserService.GetCallerClaims` method.

The implementation is a combination of [this connect example][1] and the
official [angular data][2] guide.

[1]: https://github.com/connectrpc/examples-es/tree/main/angular
[2]: https://angular.io/start/start-data#configuring-the-shippingcomponent-to-use-cartservice
2024-04-23 17:18:35 -07:00
Jeff McCune
28813eba5b (#126) v0.69.0 2024-04-23 10:24:58 -07:00
Jeff McCune
02ff765f54 Merge pull request #143 from holos-run/jeff/126-registration
(#126) Minimal API to register users and organizations
2024-04-23 09:00:07 -07:00
Jeff McCune
fe8a806132 (#126) Refactor to GetCallerX / CreateCallerX
This patch simplifies the user and organization registration and query
for the UI.  The pattern clients are expected to follow is to create if
the get fails.  For example, the following pseudo-go-code is the
expected calling convention:

    var entity *ent.User
    entity, err := Get()
    if err != nil {
      if ent.MaskNotFound(err) == nil {
        entity = Create()
      } else {
        return err
      }
    }
    return entity

This patch adds the following service methods.  For initial
registration, all input data comes from the id token claims of the
authenticated user.

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 list | xargs -n1 grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 list
holos.v1alpha1.OrganizationService.CreateCallerOrganization
holos.v1alpha1.OrganizationService.GetCallerOrganizations
holos.v1alpha1.UserService.CreateCallerUser
holos.v1alpha1.UserService.GetCallerClaims
holos.v1alpha1.UserService.GetCallerUser
```
2024-04-23 08:43:23 -07:00
Jeff McCune
6626d58301 (#126) Add OrganizationService
Next step after this is to simplify the calling convention to a get
followed by a create if the get fails.
2024-04-23 05:28:07 -07:00
Jeff McCune
cb0911e890 (#126) Add holos.v1alpha1.UserService.GetUser
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.UserService.GetUser
{
  "user": {
    "id": "018f07f4-4f9c-7b69-9d9e-07bf7bb4fe33",
    "email": "jeff@openinfrastructure.co",
    "name": "Jeff McCune",
    "timestamps": {
      "createdAt": "2024-04-22T22:36:42.780492Z",
      "updatedAt": "2024-04-22T22:36:42.780492Z"
    }
  }
}
2024-04-22 16:49:25 -07:00
Jeff McCune
3745a68dc5 (#126) Add unique index on user iss sub fields
The server will frequently look up the user record given the iss and sub
claims from the id token, index them and make sure the combination of
the two is unique.
2024-04-22 16:14:40 -07:00
Jeff McCune
fd64830476 (#126) Rename HolosService to UserService
Organize services by the resource they manage.
2024-04-22 16:05:32 -07:00
Jeff McCune
1ee0fa9c1f (#126) User Registration via API
With this patch user registration works with grpcurl.  Nothing in the
web UI yet.

```
grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.HolosService.RegisterUser
```

Cannot register twice:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.HolosService.RegisterUser
ERROR:
  Code: FailedPrecondition
  Message: user.go:26: ent: constraint failed: ERROR: duplicate key value violates unique constraint "users_email_key" (SQLSTATE 23505)
```

GetUserClaims works though:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 holos.v1alpha1.HolosService.GetUserClaims
{
  "iss": "https://login.ois.run",
  "sub": "261773693724656988",
  "email": "jeff@openinfrastructure.co",
  "emailVerified": true,
  "name": "Jeff McCune"
}
```
2024-04-22 15:38:07 -07:00
Jeff McCune
8fab325b0a (#126) Add gRPC reflection
So grpcurl works as expected:

```
❯ grpcurl -H "x-oidc-id-token: $(holos token)" jeff.app.dev.k2.holos.run:443 list
holos.v1alpha1.HolosService
```
2024-04-22 15:02:08 -07:00
Jeff McCune
858ffad913 (#126) Add holos token command for grpcurl 2024-04-22 14:54:09 -07:00
Jeff McCune
62735b99e7 (#126) Update Tiltfile to use holos.run for dev
This patch updates the Tiltfile to use the holos.run domain which is
integrated with the default Gateway.
2024-04-22 13:42:18 -07:00
Jeff McCune
29ab9c6300 (#141) Install provisioner helper.rb from entrypoint
And add a script to reset the choria provisioner credentials and config.
2024-04-22 13:20:38 -07:00
Jeff McCune
debc01c7de (#141) Fix Incorrect Provisioning Token foo given
The `make-provisioner-jwt` incorrectly used the choria broker password
as the provisioning token.  In the reference [setup.sh][1] both the
token and the `broker_provisioning_password` are set to `s3cret` so I
confused the two, but they are actually different values.

This patch ensures the provisioning token configured in
`provisioner.yaml` matches the token embedded into the provisioning.jwt
file using `choria jwt provisioning` via the `make-provisioner-jwt`
script.

[1]: 6dbc8fd105/example/setup/templates/provisioner/provisioner.yaml (L6)
2024-04-22 12:31:10 -07:00
Jeff McCune
c07f35ecd6 (#141) Fix holos controller invalid websocket connection error
Problem:
When the ingress default Gateway AuthorizationPolicy/authpolicy-custom
rule is in place the choria machine room holos controller fails to
connect to the provisioner broker with the following error:

```
❯ holos controller run --config=agent.cfg
WARN[0000] Starting controller version 0.68.1 with config file /home/jeff/workspace/holos-run/holos/hack/choria/agent/agent.cfg  leader=false
WARN[0000] Switching to provisioning configuration due to build defaults and missing /home/jeff/workspace/holos-run/holos/hack/choria/agent/agent.cfg
WARN[0000] Setting anonymous TLS mode during provisioning  component=server connection=coffee.home identity=coffee.home
WARN[0000] Initial connection to the Broker failed on try 1: invalid websocket connection  component=server connection=coffee.home identity=coffee.home
WARN[0000] Initial connection to the Broker failed on try 2: invalid websocket connection  component=server connection=coffee.home identity=coffee.home
WARN[0002] Initial connection to the Broker failed on try 3: invalid websocket connection  component=server connection=coffee.home identity=coffee.home
```

This problem is caused because the provisioning token url is set to
`wss://jeff.provision.dev.k2.holos.run:443` which has the port number
specified.

Solution:
Follow the upstream istio guidance of [Writing Host Match Policies][1]
to match host headers with or without the port specified.

Result:
The controller is able to connect to the provisioner broker:

[1]: https://istio.io/latest/docs/ops/best-practices/security/#writing-host-match-policies
2024-04-22 12:31:10 -07:00
Jeff McCune
c8f528700c (#141) Fix error: do not know how to handle choria_provisioning purpose token
Solution:
remove the plugin.security.choria.ca setting
2024-04-22 12:30:16 -07:00
Jeff McCune
896248c237 (#141) Try and connect holos controller to the provisioner
Running into error:

time="2024-04-20T03:23:19Z" level=warning msg="Denying connection: verified error: do not know how to handle choria_provisioning purpose token, unverified error: <nil>" component=authentication remote="10.244.1.51:56338" stage=check
time="2024-04-20T03:23:19Z" level=error msg="192.168.2.21/10.244.1.51:56338 - wid:367 - authentication error" component=network_broker
2024-04-22 12:29:56 -07:00
Jeff McCune
74a181db21 (#133) Add missing Choria Provisioner deployment 2024-04-19 15:14:31 -07:00
Jeff McCune
ba10113342 (#133) Fix tls error when connecting to provisioner websocket
This problem fixes an error where the istio ingress gateway proxy failed
to verify the TLS certificate presented by the choria broker upstream
server.

    kubectl logs choria-broker-0

    level=error msg="websocket: TLS handshake error from 10.244.1.190:36142: remote error: tls: unknown certificate\n"

Istio ingress logs:

    kubectl -n istio-ingress logs -l app=istio-ingressgateway -f | grep --line-buffered '^{' | jq .

    "upstream_transport_failure_reason": "TLS_error:|268435581:SSL_routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED:TLS_error_end:TLS_error_end"

Client curl output:

    curl https://jeff.provision.dev.k2.holos.run

    upstream connect error or disconnect/reset before headers. retried and the latest reset reason: remote connection failure, transport failure reason: TLS_error:|268435581:SSL routines:OPENSSL_i
nternal:CERTIFICATE_VERIFY_FAILED:TLS_error_end:TLS_error_end

Explanation of error:

Istio defaults to expecting a tls certificate matching the downstream
host/authority which isn't how we've configured Choria.

Refer to [ClientTLSSettings][1]

> A list of alternate names to verify the subject identity in the
> certificate. If specified, the proxy will verify that the server
> certificate’s subject alt name matches one of the specified values. If
> specified, this list overrides the value of subject_alt_names from the
> ServiceEntry. If unspecified, automatic validation of upstream presented
> certificate for new upstream connections will be done based on the
> downstream HTTP host/authority header, provided
> VERIFY_CERTIFICATE_AT_CLIENT and ENABLE_AUTO_SNI environmental variables
> are set to true.

[1]: https://istio.io/latest/docs/reference/config/networking/destination-rule/#ClientTLSSettings
2024-04-19 13:13:09 -07:00
Jeff McCune
eb0207c92e (#133) Choria Provisioner
This patch is a work in progress to configure the provisioner to connect
to the broker.  Services and deployments are prefixed with choria for
clarity.
2024-04-19 13:13:08 -07:00
Jeff McCune
0fbcee8119 (#133) Extend the life of the Platform Issuer CA
The platform issuer root CA was set to expire after 90 days, the default
value.  This is too short.

Extend the life of the root CA beyond 100 years.
2024-04-19 11:29:17 -07:00
Jeff McCune
ce8bc798f6 (#133) Exclude nats and provision hosts from the auth proxy
Problem:
The identity aware auth proxy attached to the default gateway is
blocking access to NATS and the Choria Provisioner cluster.

Solution:
Add configuration that causes the project hosts to get added to the
exclusion list of the AuthorizationPolicy/authproxy-custom rule.

Result:
Requests bypass the auth proxy and go straight to the backend.  The
rules look like:

    kubectl get authorizationpolicy authproxy-custom -o yaml

```yaml
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: authproxy-custom
  namespace: istio-ingress
  labels:
    app.kubernetes.io/name: authproxy-custom
    app.kubernetes.io/part-of: istio-ingressgateway
spec:
  action: CUSTOM
  provider:
    name: ingressauth
  rules:
  - to:
    - operation:
        notHosts:
        - login.ois.run
        - vault.core.ois.run
        - provision.holos.run
        - nats.holos.run
        - provision.dev.holos.run
        - nats.dev.holos.run
        - jeff.provision.dev.holos.run
        - jeff.nats.dev.holos.run
        - gary.provision.dev.holos.run
        - gary.nats.dev.holos.run
        - nate.provision.dev.holos.run
        - nate.nats.dev.holos.run
        - provision.k2.holos.run
        - nats.k2.holos.run
        - provision.dev.k2.holos.run
        - nats.dev.k2.holos.run
        - jeff.provision.dev.k2.holos.run
        - jeff.nats.dev.k2.holos.run
        - gary.provision.dev.k2.holos.run
        - gary.nats.dev.k2.holos.run
        - nate.provision.dev.k2.holos.run
        - nate.nats.dev.k2.holos.run
    when:
    - key: request.headers[x-oidc-id-token]
      notValues:
      - '*'
  selector:
    matchLabels:
      istio: ingressgateway
```
2024-04-19 06:32:11 -07:00
Jeff McCune
996195d651 (#137) Fix ArgoCD PKCE login small comment 2024-04-18 14:39:13 -07:00
Jeff McCune
f00b29d3a3 (#137) Fix ArgoCD PKCE login
This patch configures ArgoCD to log in via PKCE.

Note the changes are primarily in platform.site.cue and ensuring the
emailDomain is set properly.  Note too the redirect URL needs to be
`/pkce/verify` when PKCE is enabled.  Finally, if the setting is
reconfigured make sure to clear cookies otherwise the incorrect
`/auth/callback` path may be used.
2024-04-18 14:37:06 -07:00
Jeff McCune
a6756ecf11 (#132) Update go deps to fix Machine Room 2024-04-18 13:35:58 -07:00
Jeff McCune
ef7ec30037 (#132) Use machine-room main branch
Our patch to use Args got merged.
2024-04-18 11:38:51 -07:00
Jeff McCune
1642787825 (#101) Fix port names in servers must be unique: duplicate name https
Problem:
Port names in the default Gateway.spec.servers.port field must be unique
across all servers associated with the workload.

Solution:
Append the fully qualified domain name with dots replaced with hyphens.

Result:
Port name is unique.
2024-04-18 11:21:05 -07:00
Jeff McCune
f83781480f (#101) Do not add Gateway.spec.servers for other clusters
Problem:
The default gateway in one cluster gets server entries for all hosts in
the problem.  This makes the list unnecessarily large with entries for
clusters that should not be handled on the current cluster.

For example, the k2 cluster has gateway entries to route hosts for k1,
k3, k4, k5, etc...

Solution:
Add a field to the CertInfo definition representing which clusters the
host is valid on.

Result:
Hosts which are valid on all clusters, e.g. login.ois.run, have all
project clusters added to the clusters field of the CertInfo.  Hosts
which are valid on a single cluster have the coresponding single entry
added.

When building resources, holos components should check if `#ClusterName`
is a valid field of the CertInfo.clusters field.  If so, the host is
valid for the current cluster.  If not, the host should be omitted from
the current cluster.
2024-04-18 11:10:16 -07:00
Jeff McCune
9b70205855 (#101) Use letsencrypt production instead of staging
Certificates issue OK from staging, switching to production.
2024-04-18 10:36:28 -07:00
Jeff McCune
0e4bf3c144 (#101) Manage certs on all clusters
We're going to do a big re-issue so might as well do it once so we don't
have to re-issue again to add more clusters to existing projects.
2024-04-18 10:16:55 -07:00
Jeff McCune
1241c74b41 (#101) Do not add the project name as a project host
Doing so forces unnecessary hosts for some projects.  For example,
iam.ois.run is useless for the iam project, the primary project host is
login to build login.ois.run.

Some projects may not need any hosts as well.

Better to let the user specify `project: foo: hosts: foo: _` if they
want it.
2024-04-18 09:59:21 -07:00
Jeff McCune
44fea098de (#101) Manage an ExternalSecret for every Server in the default Gateway
This patch loops over every Gateway.spec.servers entry in the default
gateway and manages an ExternalSecret to sync the credential from the
provisioner cluster.
2024-04-18 09:53:39 -07:00
Jeff McCune
52286efa25 (#101) Fix duplicate certs in holos components
Problem:
A Holos Component is created for each project stage, but all hosts for
all stages in the project are added.  This creates duplicates.

Solution:
Sort project hosts by their stage and map the holos component for a
stage to the hosts for that stage.

Result:
Duplicates are eliminated, the prod certs are not in the dev holos
component and vice-versa.
2024-04-18 09:17:49 -07:00
Jeff McCune
a1b2179442 (#101) Remove holos-saas-certs holos component
No longer needed now that project host certs are using wildcards and
organized nicely.
2024-04-18 06:32:06 -07:00
Jeff McCune
cffc430738 (#101) Provision wildcard certs for all Gateway servers
This patch provisions wildcard certs in the provisioning cluster.  The
CN matches the project stage host global hostname without any cluster
qualifiers.

The use of a wildcard in place of the environment name dns segment at
the leftmost position of the fully qualified dns name enables additional
environments to be configured without reissuing certificates.

This is to avoid the 100 name per cert limit in LetsEncrypt.
2024-04-18 06:26:29 -07:00
Jeff McCune
d76454272b (#101) Simplify the GatewayServers struct
Mapping each project host fqdn to the stage is unnecessary.  The list of
gateway servers is constructed from each FQDN in the project.

This patch removes the unnecessary struct mappings.
2024-04-18 05:32:19 -07:00
Jeff McCune
9d1e77c00f (#101) Define #ProjectHosts to manage project hosts
Problem:
It's difficult to map and reduce the collection of project hosts when
configuring related Certificate, Gateway.spec.servers, VirtualService,
and auth proxy cookie domain settings.

Solution:
Define #ProjectHosts which takes a project and provides Hosts which is a
struct with a fqdn key and a #CertInfo value.  The #CertInfo definition
is intended to provide everything need to reduce the Hosts property to
structs usful for the problematic resources mentioned previously.

Result:
Gateway.spec.servers are mapped using #ProjectHosts

Next step is to map the Certificate resources on the provisioner
cluster.
2024-04-17 21:59:04 -07:00
Jeff McCune
2050abdc6c (#101) Add wildcard support to project certs
Problem:
Adding environments to a project causes certs to be re-issued.

Solution:
Enable wildcard certs for per-environment namespaces like jeff, gary,
nate, etc...

Result:
Environments can be added to a project stage without needing the cert to
be re-issued.
2024-04-17 12:32:44 -07:00
Jeff McCune
3ea013c503 (#101) Consolidate certificates by project stage
This patch avoids LetsEncrypt rate limits by consolidating multiple dns
names into one certificate.

For each project host, create a certificate for each stage in the
project.  The certificate contains the dns names for all clusters and
environments associated with that stage and host.

This can become quite a list, the limit is 100 dnsNames.

For the Holos project which has 7 clusters and 4 dev environments, the
number of dns names is 32 (4 envs + 4 envs * 7 clusters = 32 dns names).

Still, a much needed improvement because we're limited to 50 certs per
week.

It may be worth considering wildcards for the per-developer
environments, which are the ones we'll likely spin up the most
frequently.
2024-04-17 11:58:46 -07:00
Jeff McCune
309db96138 (#133) Choria Broker for Holos Controller provisioning
This patch is a partial step toward getting the choria broker up
and running in my own namespace.  The choria broker is necessary for
provisioning machine room agents such as the holos controller.
2024-04-17 08:48:31 -07:00
Jeff McCune
283b4be71c (#132) Use forked version of machine-room
Until https://github.com/choria-io/machine-room/pull/12 gets merged
2024-04-16 19:46:36 -07:00
Jeff McCune
ab9bca0750 (#132) Controller Subcommand
This patch adds an initial holos controller subcommand.  The machine
room agent starts, but doesn't yet provision because we haven't deployed
the provisioning infrastructure yet.
2024-04-16 15:40:25 -07:00
Jeff McCune
ac2be67c3c (#130) NATS deployment with operator jwt
Configure NATS in a 3 Node deployment with resolver authentication using
an Operator JWT.

The operator secret nkeys are stored in the provisioner cluster.  Get
them with:

    holos get secret -n jeff-holos nats-nsc --print-key nsc.tgz | tar -tvzf-
2024-04-15 17:02:18 -07:00
Jeff McCune
6ffafb8cca (#127) Setup Routing using Dashboard Schematic
This patch sets up basic routing and a 404 not found page.  The Home and
Clusters page are generated from the [dashboard schematic][1]

    ng generate @angular/material:dashboard home
    ng generate @angular/material:dashboard cluster-list
    ng g c error-not-found

[1]: https://material.angular.io/guide/schematics#dashboard-schematic
2024-04-15 13:48:00 -07:00
Jeff McCune
590e6b556c (#127) Generate Angular Material navigation
Instead of trying to hand-craft a navigation sidebar and toolbar from
Youtube videos, use the [navigation schematic][1] to quickly get a "good
enough" UI.

    ng generate @angular/material:navigation nav

[1]: https://material.angular.io/guide/schematics#navigation-schematic
2024-04-15 10:43:24 -07:00
Jeff McCune
5dc5c6fbdf (#127) ng add @angular/material
And start working on the sidenav and toolbar.
2024-04-14 07:03:45 -07:00
Jeff McCune
cd8c9f2c32 (#127) ConnectRPC generated code 2024-04-13 11:03:19 -07:00
Jeff McCune
3490941d4c (#127) Frontend deps from make tools
Needed to generate the connectrpc bindings and build the holos
executable.
2024-04-12 20:09:41 -07:00
Jeff McCune
3f201df0c2 (#126) Configure Angular to align with frontend.go
Angular must build output into a path compatible with the Go
http.FileServer.  We cannot easily graft an fs.FS onto a sub-path, so we
need the `./ui/` path in the output.  This requires special
configuration from the Angular default application builder behavior.
2024-04-12 20:08:37 -07:00
Jeff McCune
4c22d515bd (#127) ng new holos
ng new holos --routing --skip-git --standalone
SCSS
No SSR
2024-04-12 20:07:17 -07:00
Jeff McCune
ec0ef1c4b3 (#127) Angular - Restart again
Restart again this time with SCSS instead of CSS.
2024-04-12 20:03:45 -07:00
Jeff McCune
1e51e2d49a (#127) Angular Navigation schematic
Following [Navigation schematic][1].

    ng generate @angular/material:navigation navigation

[1]: https://material.angular.io/guide/schematics#navigation-schematic
2024-04-12 19:45:26 -07:00
Jeff McCune
5186499b90 Revert "(#127) Angular - ng add ng-matero"
This reverts commit fc275e4164.

Yuck, don't like it.
2024-04-12 17:21:26 -07:00
Jeff McCune
fc275e4164 (#127) Angular - ng add ng-matero
Trying [ng-matero][1].  Seems to exceed the max prod budget of 1mb, but
worth trying anyway.

[1]: https://github.com/ng-matero/ng-matero
2024-04-12 17:18:33 -07:00
Jeff McCune
9fa466f7cf (#126) Build the front end app when building holos
Always build the front end app bundle when rebuilding the holos cli so
we're sure things are up to date.
2024-04-12 17:04:41 -07:00
Jeff McCune
efd6f256a5 (#126) Connect generated bindings for the frontend 2024-04-12 16:57:30 -07:00
Jeff McCune
f7f9d6b5f0 (#126) Angular Material - ng add @angular/material 2024-04-12 16:57:15 -07:00
Jeff McCune
0526062ab2 (#126) Configure Angular to align with frontend.go
Angular must build output into a path compatible with the Go
http.FileServer.  We cannot easily graft an fs.FS onto a sub-path, so we
need the `./ui/` path in the output.  This requires special
configuration from the Angular default application builder behavior.
2024-04-12 16:57:15 -07:00
Jeff McCune
a1ededa722 (#126) http.FileServer serves /ui instead of /app
This fixes Angular not being served up correctly.

Note, special configuration in Angular is necessary to get the build
output into the ui/ directory.  Refer to: [Output path configuration][1]
and [browser directory created in outputPath][2].

[1]: https://angular.io/guide/workspace-config#output-path-configuration
[2]: https://github.com/angular/angular-cli/issues/26304
2024-04-12 16:51:45 -07:00
Jeff McCune
9b09a02912 (#115) Angular new project with defaults
Setup angular with the defaults.  CSS, No SSR / Static Site Generation.

    npm install -g @angular/cli
    ng new holos

```
? Which stylesheet format would you like to use? CSS             [ https://developer.mozilla.org/docs/Web/CSS                     ]
? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No
```

```
CREATE holos/README.md (1059 bytes)
CREATE holos/.editorconfig (274 bytes)
CREATE holos/.gitignore (548 bytes)
CREATE holos/angular.json (2587 bytes)
CREATE holos/package.json (1036 bytes)
CREATE holos/tsconfig.json (857 bytes)
CREATE holos/tsconfig.app.json (263 bytes)
CREATE holos/tsconfig.spec.json (273 bytes)
CREATE holos/.vscode/extensions.json (130 bytes)
CREATE holos/.vscode/launch.json (470 bytes)
CREATE holos/.vscode/tasks.json (938 bytes)
CREATE holos/src/main.ts (250 bytes)
CREATE holos/src/favicon.ico (15086 bytes)
CREATE holos/src/index.html (291 bytes)
CREATE holos/src/styles.css (80 bytes)
CREATE holos/src/app/app.component.css (0 bytes)
CREATE holos/src/app/app.component.html (19903 bytes)
CREATE holos/src/app/app.component.spec.ts (913 bytes)
CREATE holos/src/app/app.component.ts (301 bytes)
CREATE holos/src/app/app.config.ts (227 bytes)
CREATE holos/src/app/app.routes.ts (77 bytes)
CREATE holos/src/assets/.gitkeep (0 bytes)
✔ Packages installed successfully.
```
2024-04-12 15:07:38 -07:00
Jeff McCune
657a5e82a5 (#115) Remove Angular SSR
We don't want Angular Server Side Rendering, we want plain old client
side angular.
2024-04-12 14:57:39 -07:00
Jeff McCune
1eece02254 (#126) Angular Material UI
ng add @angular/material

```
❯ ng add @angular/material
Skipping installation: Package already installed
? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink        [ Preview: https://material.angular.io?theme=indigo-pink ]
? Set up global Angular Material typography styles? Yes
? Include the Angular animations module? Include and enable animations Yes
```
2024-04-12 14:16:45 -07:00
Jeff McCune
c866b47dcb (#126) Check for errors decoding claims
Return an empty claims struct when there's an error.
2024-04-12 14:16:44 -07:00
Jeff McCune
ff52ec750b (#126) Try to fix golangci-lint
It's doing way too much, might want to consider something else.

Getting these errors:

```
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.dockerignore: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.envrc: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.gitattributes: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/CODEOWNERS: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/buf-logo.svg: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/dependabot.yml: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/workflows/add-to-project.yaml: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/workflows/back-to-development.yaml: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/workflows/buf-binary-size.yaml: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/workflows/buf-shadow-sync.yaml: Cannot open: File exists
/usr/bin/tar: ../../../go/pkg/mod/github.com/bufbuild/buf@v1.30.1/.github/workflows/buf.yaml: Cannot open: File exists
```
2024-04-12 14:01:16 -07:00
Jeff McCune
4184619afc (#126) Refactor pkg to internal
pkg folder is not needed.  Move everything internal for now.
2024-04-12 13:56:16 -07:00
Jeff McCune
954dbd1ec8 (#126) Refactor id token acquisition to token package
And add a logout command that deletes the token cache.

The token package is intended for subcommands that need to make API
calls to the holos api server, getting a token should be a simple matter
of calling the token.Get() method, which takes minimal dependencies.
2024-04-12 13:15:03 -07:00
Jeff McCune
30b70e76aa (#126) Add login command
This copies the login command from the previous holos cli.  Wire
dependency injection and all the rest of the unnecessary stuff from
kubelogin are removed, streamlined down into a single function that
takes a few oidc related parameters.

This will need to be extracted out into an infrastructure service so
multiple other command line tools can easily re-use it and get the ID
token into the x-oidc-id-token header.
2024-04-12 12:13:33 -07:00
Jeff McCune
ec6d112711 (#126) Remove hydra and kratos databases
No longer needed for dev.
2024-04-12 10:24:26 -07:00
Jeff McCune
e796c6a763 (#126) Default to DATABASE_URL env var 2024-04-12 10:20:13 -07:00
Jeff McCune
be32201294 (#126) Basic User and Organization Ent models
Get rid of the previous UserIdentity model, this is no longer part of
the core domain and instead handled within the context of ZITADEL.
2024-04-12 09:59:40 -07:00
Jeff McCune
5ebc54b5b7 (#124) Go Tools 2024-04-12 09:14:13 -07:00
Jeff McCune
2954a57872 (#120) Fix NATS target namespace
The upstream nats charts don't specify namespaces for each attribute.
This works with helm update, but not helm template which holos uses to
render the yaml.

The missing namespace causes flux to fail.

This patch uses the flux kustomization to add the target namespace to
all resources.
2024-04-10 21:54:58 -07:00
Jeff McCune
df705bd79f (#121) Fix Multiple Charts cause holos render to fail
When rendering a holos component which contains more than one helm chart, rendering fails.  It should succeed.

```
holos render --cluster-name=k2 /home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/holos/... --log-level debug
```

```
9:03PM ERR could not execute version=0.64.2 err="could not rename: rename /home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/holos/nats/envs/vendor553679311 /home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/holos/nats/envs/vendor: file exists" loc=helm.go:145
```

This patch fixes the problem by moving each child item of the temporary
directory charts are installed into.  This avoids the problem of moving
the parent when the parent target already exists.
2024-04-10 21:27:39 -07:00
Jeff McCune
4e8ce3585d (#115) Minor clean up of cue code 2024-04-10 21:21:16 -07:00
Jeff McCune
ab5f17c3d2 (#115) Fix goreleaser
Import modules to take the direct dependency and prevent go mod tidy
from modifying go.mod and go.sum which causes goreleaser to fail.
2024-04-10 19:09:30 -07:00
Jeff McCune
a8918c74d4 (#115) Angular spike - fix make frontend
And install frontend deps.
2024-04-09 21:03:26 -07:00
Jeff McCune
ae5738d82d (#115) Angular with SSR
Executed:

    ng new
    ng add @angular/ssr

Name: holos
Style: CSS
SSR and SSG?: No

ssr added using ng add following https://angular.io/guide/prerendering
2024-04-09 20:52:42 -07:00
Jeff McCune
bb99aedffa (#115) Remove frontend
Clean up for ng new in angular spike.
2024-04-09 20:35:43 -07:00
Jeff McCune
d6ee1864c8 (#116) Tilt for development
Add Tilt back from holos server

Note with this patch the ec-creds.yaml file needs to be applied to the
provisioner and an external secret used to sync the image pull creds.

With this patch the dev instance is accessible behind the auth proxy.
pgAdmin also works from the Tilt UI.

https://jeff.holos.dev.k2.ois.run/app/start
2024-04-09 20:26:37 -07:00
Jeff McCune
8a4be66277 (#113) Fix goreleaser try 4
Please check in your pipeline what can be changing the following files:
  M go.sum
2024-04-09 16:48:21 -07:00
Jeff McCune
79ce2f8458 (#113) Fix goreleaser try 3 2024-04-09 16:35:38 -07:00
Jeff McCune
3d4ae44ddd (#113) Fix goreleaser try 2
goreleaser fails with Failure: plugin connect-query: could not find protoc plugin for name connect-query - please make sure protoc-gen-connect-query is installed and present on your $PATH
2024-04-09 16:23:35 -07:00
Jeff McCune
1efb1faa40 (#113) Fix goreleaser
git executable must come before actions checkout
2024-04-09 16:04:42 -07:00
Jeff McCune
bfd6a56397 (#113) Fix actions workflows 2024-04-09 15:57:31 -07:00
Jeff McCune
a788f6d8e8 (#112) Refactor config flag handling
Remove the server.Config struct, not needed.  Remove the app struct and
move the configuration to the main holos.Config.ServerConfig.

Add flags specific to server configuration.

With this patch logging is simplified.  Subcommands have a handle on the
top level holos.Config and can get a fully configured logger from
cfg.Logger() after flag parsing happens.
2024-04-09 11:42:24 -07:00
Jeff McCune
80fa91d74d (#112) Rename wrapper package to errors
The wrapper package name doesn't indicate what it's for.  Rename to
errors and delegate to the standard library.
2024-04-08 20:53:58 -07:00
Jeff McCune
db34562e9a (#112) Get tests passing 2024-04-08 20:53:57 -07:00
Jeff McCune
d6af089ab3 (#112) Rename package core to app
Disambiguate the term `core` which should mean the core domain.  The app
is a supporting domain concerned with logging and configuration
initialization early in the life cycle.
2024-04-08 20:53:57 -07:00
Jeff McCune
b3a70c5911 (#112) Copy holos-server to holos server subcommand
From holos-server commit da35fe966ded2098fe069293ec30864775a6c4f0

Compiles but needs cleanup
2024-04-08 20:53:25 -07:00
Jeff McCune
bf5765c9cb (#110) Update ZITADEL to v2.49.1 from v2.46.0
Attempt to resolve issue where `/oauth/v2/keys` returns `{"keys": []}`
causing id token verification failures.

Closes: #110
2024-04-07 17:20:10 -07:00
Jeff McCune
6c7697648c (#110) Add runbook to take a full database backup
This runbook documents how to write a full database backup to a blank S3
bucket given an existing postgrescluster resource with a live, running
database.

The pgo controller needs to remove and re-create the repo for the backup
to succeed, otherwise it complains about a missing file expected from a
previous backup.
2024-04-07 17:20:07 -07:00
Jeff McCune
04158485c7 (#96) Do not expire ZITADEL signing public key
The public key needs to be configured along with the signing key.
2024-04-05 10:52:36 -07:00
Jeff McCune
cf83c77280 (#96) Do not expire ZITADEL signing private key
Without this patch users encounter an error from istio because it does
not have a valid Jwks from ZITADEL to verify the request when processing
a `RequestAuthentication` policy.

Fixes error `AuthProxy JWKS Error - Jwks doesn't have key to match kid or alg from Jwt`.

Occurs when accessing a protected URL for the first time after tokens have expired.
2024-04-04 15:56:00 -07:00
Jeff McCune
6e545b13dd (#104) Deploy crunchy monitoring stack for ZITADEL
Not exposed via the ingress gateway, but accessible via

    kubectl port-forward svc/crunchy-grafana 3000

Refer to [day two monitoring][1].  This is pretty much a straight copy
of the upstream kustomize configs at [2].

[1]: https://access.crunchydata.com/documentation/postgres-operator/5.5/tutorials/day-two/monitoring
[2]: https://github.com/CrunchyData/postgres-operator-examples/tree/main/kustomize/monitoring
2024-04-04 15:40:07 -07:00
Jeff McCune
bf258a1f41 (#104) Enable monitoring for ZITADEL postgres
This patch enables the monitoring configuration for the ZITADEL postgres
cluster.

Refer to: https://access.crunchydata.com/documentation/postgres-operator/5.5/tutorials/day-two/monitoring

Integrating with:
https://github.com/CrunchyData/postgres-operator-examples/tree/main/kustomize/monitoring
which will become a separate holos component instance.
2024-04-03 22:26:38 -07:00
Jeff McCune
6f06c73d6f (#85) Initial addition of kube-prometheus-stack
Grafana does not yet have the istio sidecar.  Prometheus is accessible
through the auth proxy.  Cert manager is added to the workload clusters
so tls certs can be issued for webhooks, the kube-prom-stack helm chart
uses cert manager for this purpose.

With this patch Grafana is integrated with OIDC and I'm able to log in
as an Administrator.
2024-04-03 21:29:26 -07:00
Jeff McCune
a689c53a9c (#47) v0.62.1 - Projects v1alpha1 milestone complete 2024-04-03 15:32:34 -07:00
Jeff McCune
58cdda1d35 Merge pull request #100 from holos-run/jeff/47-iam-v2
(#47) Remove the prod-iam-zitadel namespace
2024-04-03 15:23:48 -07:00
Jeff McCune
bcb02b5c5c (#47) Remove the prod-iam-zitadel namespace
No longer needed, cluster has moved to prod-iam namespace.
2024-04-03 15:10:30 -07:00
Jeff McCune
0736c7de1a (#47) Bind ALL VirtualServices to the default gateway
Problem:
The VirtualService that catches auth routes for paths, e.g.
`/holos/authproxy/istio-ingress` is bound to the default gateway which
no longer exists because it has no hosts.

Solution:
It's unnecessary and complicated to create a Gateway for every project.
Instead, put all server entries into one `default` gateway and
consolidate the list using CUE.

Result:
It's easier to reason about this system.  There is only one ingress
gateway, `default` and everything gets added to it.  VirtualServices
need only bind to this gateway, which has a hosts entry appropriately
namespaced for the project.
2024-04-03 14:56:40 -07:00
Jeff McCune
28be9f9fbb (#47) Use the project specific Gateway
The login service is unavailable because the wrong gateway is used.
When using projects the VS needs to attach to the correct Gateway.
2024-04-03 12:59:48 -07:00
Jeff McCune
647681de38 (#99) Restore backups from prod-iam namespace
This patch configures the standby cluster to restore backups from the
prod-iam namespace instead of the prod-iam-zitadel namespace.
2024-04-03 12:30:12 -07:00
Jeff McCune
81beb5c539 (#47) Restore ZITADEL from existing backups
Problem:
The ZITADEL database isn't restoring into the prod-iam namespace after
moving from prod-iam-zitadel because no backup exists at the bucket
path.

Solution:
Hard-code the path to the old namespace to restore the database.  We'll
figure out how to move the backups to the new location in a follow up
change.
2024-04-03 11:44:16 -07:00
Jeff McCune
5c1e0a29c8 (#47) Have Ceph depend on secret stores
Another kustomization reconciling too early.
2024-04-03 11:22:15 -07:00
Jeff McCune
01ac5276a9 (#47) Have Gateway depend on secret stores
The `prod-platform-gateway` kustomization is reconciling early:

ExternalSecret/istio-ingress/argocd.ois.run dry-run failed: failed to
get API group resources: unable to retrieve the complete list of server
APIs: external-secrets.io/v1beta1: the server could not find the
requested resource
2024-04-03 11:20:15 -07:00
Jeff McCune
e40594ad8e (#47) Move ZITADEL to prod-iam project namespace
This patch moves ZITADEL from the prod-iam-zitadel namespace to the
projects managed prod-iam namespace, which is the prod environment of
the prod stage of the iam project.
2024-04-03 11:06:55 -07:00
Jeff McCune
bc9c6a622a (#97) Increase ZITADEL pgdata volume to 20Gi
Problem:

```
❯ k exec zitadel-pgha1-4npq-0 -it -- bash
Defaulted container "database" out of: database, replication-cert-copy, pgbackrest, pgbackrest-config, postgres-startup (init), nss-wrapper-init (init)
bash-4.4$ df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay         119G   51G   68G  43% /
tmpfs            64M     0   64M   0% /dev
/dev/rbd3       9.8G  9.8G     0 100% /pgdata
/dev/sda6       119G   51G   68G  43% /tmp
tmpfs            16G   24K   16G   1% /pgconf/tls
tmpfs            16G   24K   16G   1% /etc/database-containerinfo
tmpfs            16G   16K   16G   1% /etc/patroni
tmpfs            16G     0   16G   0% /dev/shm
tmpfs            16G   28K   16G   1% /etc/pgbackrest/conf.d
tmpfs            16G   12K   16G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs           7.9G     0  7.9G   0% /proc/acpi
tmpfs           7.9G     0  7.9G   0% /proc/scsi
tmpfs           7.9G     0  7.9G   0% /sys/firmware
```
2024-04-03 10:09:49 -07:00
Jeff McCune
17f22199b7 (#86) ArgoCD - Disable Dex
Not needed
2024-04-02 15:47:22 -07:00
Jeff McCune
7e93fe4535 (#86) ArgoCD
Using the Helm chart so we can inject the istio sidecar with a kustomize
patch and tweak the configs for OIDC integration.

Login works, istio sidecar is injected.  ArgoCD can only be configured
with one domain unfortunately, it's not accessible at argocd.ois.run,
only argocd.k2.ois.run (or whatever cluster it's installed into).

Ideally it would use the Host header but it does not.

RBAC is not implemented but the User Info endpoint does have group
membership so this shouldn't be a problem to implement.
2024-04-02 15:33:47 -07:00
Jeff McCune
2e98df3572 (#86) ArgoCD in prod-platform project namespace
Deploys using the official release yaml.
2024-04-02 13:34:03 -07:00
Jeff McCune
3b561de413 (#93) Custom AuthPolicy rules for vault
This patch defines a #AuthPolicyRules struct which excludes hosts from
the blanket auth policy and includes them in specialized auth policies.
The purpose is to handle special cases like vault requests which have an
`X-Vault-Token` and `X-Vault-Request` header.

Vault does not use jwts so we cannot verify them in the mesh, have to
pass them along to the backend.

Closes: #93
2024-04-02 12:54:31 -07:00
Jeff McCune
0d0dae8742 (#89) Disable project auth proxies by default
Focus on the ingress gateway auth proxy for now and see how far it gets
us.
2024-04-01 21:48:08 -07:00
Jeff McCune
61b4b5bd17 (#89) Refactor auth proxy callbacks
The ingress gateway auth proxy callback conflicts with the project stage
auth proxy callback for the same backend Host: header value.

This patch disambiguates them by the namespace the auth proxy resides
in.
2024-04-01 21:37:52 -07:00
Jeff McCune
0060740b76 (#82) ingress gateway AuthorizationPolicy
This patch adds a `RequestAuthentication` and `AuthorizationPolicy` rule
to protect all requests flowing through the default ingress gateway.

Consider a browser request for httpbin.k2.example.com representing any
arbitrary host with a valid destination inside the service mesh.  The
default ingress gateway will check if there is already an
x-oidc-id-token header, and if so validate the token is issued by
ZITADEL and the aud value contains the ZITADEL project number.

If the header is not present, the request is forwarded to oauth2-proxy
in the istio-ingress namespace.  This auth proxy is configured to start
the oidc auth flow with a redirect back to /holos/oidc/callback of the
Host: value originally provided in the browser request.

Closes: #82
2024-04-01 20:37:34 -07:00
Jeff McCune
bf8a4af579 (#82) ingressgateway ExtAuthzHttp provider
This patch adds an ingress gateway extauthz provider.  Because ZITADEL
returns all applications associated with a ZITADEL project in the aud
claim, it makes sense to have one ingress auth proxy at the initial
ingress gateway so we can get the ID token in the request header for
backend namespaces to match using `RequestAuthentication` and
`AuthorizationPolicy`.

This change likely makes the additional per-stage auth proxies
unnecessary and over-engineered.  Backend namespaces will have access to
the ID token.
2024-04-01 16:53:11 -07:00
Jeff McCune
dc057fe39d (#89) Add platform project hosts for argocd, grafana, and prometheus
Certificates are issued by the provisioner and synced to the workload
clusters.
2024-04-01 13:09:46 -07:00
Jeff McCune
9877ab131a (#89) Platform Project
This patch manages a platform project to host platform level services
like ArgoCD, Kube Prom Stack, Kiali, etc...
2024-04-01 11:46:02 -07:00
Jeff McCune
13aba64cb7 (#66) Move CUSTOM AuthorizationPolicy to env namespace
It doesn't make sense to link the stage ext authz provider to the
ingress gateway because there can be only one provider per workload.

Link it instead to the backend environment and use the
`security.holos.run/authproxy` label to match the workload.
2024-03-31 18:56:14 -07:00
Jeff McCune
fe9bc2dbfc (#81) Istio 1.21.0 2024-03-31 12:51:56 -07:00
Jeff McCune
c53b682852 (#66) Use x-oidc-id-token instead of authorization header
Problem:
Backend services and web apps expect to place their own credentials into
the Authorization header.  oauth2-proxy writes over the authorization
header creating a conflict.

Solution:
Use the alpha configuration to place the id token into the
x-oidc-id-token header and configure the service mesh to authenticate
requests that have this header in place.

Note: ZITADEL does not use a JWT for an access token, unlike Keycloak
and Dex.  The access token is not compatible with a
RequestAuthentication jwt rule so we must use the id token.
2024-03-31 11:41:23 -07:00
Jeff McCune
3aca6a9e4c (#66) configure auth proxies to set Authorization: Bearer header
Without this patch the istio RequestAuthentication resources fail to
match because the access token from ZITADEL returned by oauth2-proxy in
the x-auth-request-access-token header is not a proper jwt.

The error is:

```
Jwt is not in the form of Header.Payload.Signature with two dots and 3 sections
```

This patch works around the problem by configuring oauth2-proxy to set
the ID token, which is guaranteed to be a proper JWT in the
authorization response headers.

Unfortunately, oauth2-proxy will only place the ID token in the
Authorization header response, which will write over any header set by a
client application.  This is likely to cause problems with single page
apps.

We'll probably need to work around this issue by using the alpha
configuration to set the id token in some out-of-the-way header.  We've
done this before, it'll just take some work to setup the ConfigMap and
translate the config again.
2024-03-30 16:15:27 -07:00
Jeff McCune
40fdfc0317 (#66) Fix auth proxy provider name, stage is always first
dev-holos-authproxy not authproxy-dev-holos
2024-03-30 14:05:50 -07:00
Jeff McCune
25d9415b0a (#66) Fix redis not able to write to /data
Without this patch redis cannot write to the /data directory, which
causes oauth2-proxy to fail with a 500 server error.
2024-03-30 13:40:34 -07:00
Jeff McCune
43c8702398 (#66) Configure an ExtAuthzProxy provider for each project stage
This patch configures an istio envoyExtAuthzHttp provider for each stage
in each project.  An example provider for the dev stage of the holos
project is `authproxy-dev-holos`
2024-03-30 11:28:23 -07:00
Jeff McCune
ce94776dbb (#66) Add ZITADEL project and client ids for iam project
core1 and core2 don't render without these resource identifiers in
place.
2024-03-30 09:18:54 -07:00
Jeff McCune
78ab6cd848 (#66) Match /holos/oidc for all hosts in the project stage
This has the same effect and makes the VirtualService much more
manageable, particularly when calling `kubectl get vs -A`.
2024-03-29 22:50:17 -07:00
Jeff McCune
0a7001f868 (#66) Configure the primary domain for zitadel
This bypasses the account selection screen and automatically redirects
back to the application without user interaction.
2024-03-29 22:44:52 -07:00
Jeff McCune
2db7be671b (#66) Route prefix /holos/oidc to authproxy
This patch configures the service mesh to route all requests with a uri
path prefix of `/holos/oidc` to the auth proxy associated with the
project stage.

Consider a request to https://jeff.holos.dev.k2.ois.run/holos/oidc/sign_in

This request is usually routed to the backend app, but
VirtualService/authproxy in the dev-holos-system namespace matches the
request and routes it to the auth proxy instead.

The auth proxy matches the request Host: header against the whitelist
and cookiedomain setting, which matches the suffix
`.holos.dev.k2.ois.run`.  The auth proxy redirects to the oidc issuer
with a callback url of the request Host for a url of
`https://jeff.holos.dev.k2.ois.run/holos/oidc/callback`.

ZITADEL matches the callback against those registered with the app and
the app client id.  A code is then sent back to the auth proxy.

The auth proxy sets a cookie named `__Secure-authproxy-dev-holos` with a
domain of `.holos.dev.k2.ois.run` from the suffix match of the
`--cookiedomain` flag.

Because this all works using paths, the `auth` prefix domains have been
removed.  They're unnecessary, oauth2-proxy is available for any host
routed to the project stage at path prefix `/holos/oidc`.

Refer to https://oauth2-proxy.github.io/oauth2-proxy/features/endpoints/
for good endpoints for debuggin, replacing `/oauth2` with `/holos/oidc`
2024-03-29 21:56:46 -07:00
Jeff McCune
b51870f7bf (#66) Deploy oauth2-proxy and redis to stage namespaces
This patch deploys oauth2-proxy and redis to the system namespace of
each stage in each project.  The plan is to redirect unauthenticated
requests to the request host at the /holos/oidc/callback endpoint.

This patch removes the --redirect-uri flag, which makes the auth domain
prefix moot, so a future patch should remove those if they really are
unnecessary.

The reason to remove the --redirect-uri flag is to make sure we set the
cookie to a domain suffix of the request Host: header.
2024-03-29 20:56:26 -07:00
Jeff McCune
0227dfa7e5 (#66) Add Gateway entries for oauth2-proxy
This patch adds entries to the project stage Gateway for oauth2-proxy.
Three entries for each stage are added, one for the global endpoint plus
one for each cluster.
2024-03-29 15:30:02 -07:00
Jeff McCune
05b59d9af0 (#66) Refactor project hosts for auth proxy cookies
Without this patch the auth proxy cookie domain is difficult to manage.
This patch refactors the hosts managed for each environment in a project
to better align with security domains and auth proxy session cookies.

The convention is: `<env?>.<host>.<stage?>.<cluster?>.<domain>` where
`host` can be 0..N entries with a default value of `[projectName]`.

env may be omitted for prod or the dev env of the dev stage.  stage may
be omitted for prod.  cluster may be omitted for the global endpoint.

For a project named `holos`:

| Project | Stage | Env  | Cluster | Host                      |
| ------- | ----- | ---  | ------- | ------                    |
| holos   | dev   | jeff | k2      | jeff.holos.dev.k2.ois.run |
| holos   | dev   | jeff | global  | jeff.holos.dev.ois.run    |
| holos   | dev   | -    | k2      | holos.dev.k2.ois.run      |
| holos   | dev   | -    | global  | holos.dev.ois.run         |
| holos   | prod  | -    | k2      | holos.k2.ois.run          |
| holos   | prod  | -    | global  | holos.ois.run             |

Auth proxy:

| Project | Stage | Auth Proxy Host           | Auth Cookie Domain   |
| ------- | ----- | ------                    | ------------------   |
| holos   | dev   | auth.holos.dev.ois.run    | holos.dev.ois.run    |
| holos   | dev   | auth.holos.dev.k1.ois.run | holos.dev.k1.ois.run |
| holos   | dev   | auth.holos.dev.k2.ois.run | holos.dev.k2.ois.run |
| holos   | prod  | auth.holos.ois.run        | holos.ois.run        |
| holos   | prod  | auth.holos.k1.ois.run     | holos.k1.ois.run     |
| holos   | prod  | auth.holos.k2.ois.run     | holos.k2.ois.run     |
2024-03-29 15:30:01 -07:00
Jeff McCune
04f9f3b3a8 Merge pull request #79 from holos-run/nate/makefile_version
Show the holos version in 'make install|build'
2024-03-29 15:04:48 -07:00
Nate McCurdy
b58be8b38c Show the holos version in 'make install|build'
Prior to this, when running the 'install' or 'build' Makefile target,
the version of holos being built was not shown even though the 'build'
target attempted to show the version.

```
.PHONY: build
build: generate ## Build holos executable.
	@echo "building ${BIN_NAME} ${VERSION}"
```

For example:
```
> make install
go generate ./...
building holos
...
```

Holo's version is stored in pkg/version/embedded/{major,minor,patch},
not the `Version` const. So the fix is to change the value of `VERSION`
so that it comes from those embedded files.

Now the version of holos is shown:

```
> make install
go generate ./...
building holos 0.61.1
...
```

This also adds a new Makefile target called `show-version` which shows
the full version string (i.e. the value of `$VERSION`).
2024-03-29 15:01:33 -07:00
Jeff McCune
10493d754a (#66) Add httpbin to each project environment
The goal of this patch is to verify each project environment is wired up
to the ingress Gateway for the project stage.

This is a necessary step to eventually configure the VirtualService and
AuthorizationPolicy to only match on the `/dump/request` path of each
endpoint for troubleshooting.
2024-03-28 21:51:34 -07:00
Jeff McCune
cf28516b8b (#66) Project managed namespaces
This patch uses the existing #ManagedNamespaces definition to create and
manage namespaces on the provisioner and workload clusters so that
SecretStore and eso-creds-refresher resources are managed in the project
environment namespaces and the project stage system namespace.
2024-03-28 15:09:57 -07:00
Jeff McCune
d81e25c4e4 (#66) Project Certificates
Provisioner cluster:

This patch creates a Certificate resource in the provisioner for each
host associated with the project.  By default, one host is created for
each stage with the short hostname set to the project name.

A namespace is also created for each project for eso creds refresher to
manage service accounts for SecretStore resources in the workload
clusters.

Workload cluster:

For each env, plus one system namespace per stage:

 - Namespace per env
 - SecretStore per env
 - ExternalSecret per host in the env

Common names for the holos project, prod stage:

- holos.k1.ois.run
- holos.k2.ois.run
- holos.ois.run

Common names for the holos project, dev stage:

- holos.dev.k1.ois.run
- holos.dev.k2.ois.run
- holos.dev.ois.run
- holos.gary.k1.ois.run
- holos.gary.k2.ois.run
- holos.gary.ois.run
- holos.jeff.k1.ois.run
- holos.jeff.k2.ois.run
- holos.jeff.ois.run
- holos.nate.k1.ois.run
- holos.nate.k2.ois.run
- holos.nate.ois.run

Usage:

    holos render --cluster-name=provisioner \
      ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/provisioner/projects/...
    holos render --cluster-name=k1 \
      ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/workload/projects/...
    holos render --cluster-name=k2 \
      ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/workload/projects/...
2024-03-27 20:54:51 -07:00
Jeff McCune
c4612ff5d2 (#64) Manage one system namespace per project
This patch introduces a new BuildPlan spec.components.resources
collection, which is a map version of
spec.components.kubernetesObjectsList.  The map version is much easier
to work with and produce in CUE than the list version.

The list version should be deprecated and removed prior to public
release.

The projects holos instance renders multiple holos components, each
containing kubernetes api objects defined directly in CUE.

<project>-system is intended for the ext auth proxy providers for all
stages.

<project>-namespaces is intended to create a namespace for each
environment in the project.

The intent is to expand the platform level definition of a project to
include the per-stage auth proxy and per-env role bindings.  Secret
Store and ESO creds refresher resources will also be defined by the
platform level definition of a project.
2024-03-26 12:23:01 -07:00
Jeff McCune
d70acbb47e ignore .vscode 2024-03-22 21:22:06 -07:00
Jeff McCune
3c977d22fe (#71) Final refactoring of example code to use BuildPlan
Need to test it on all the clusters now.  Will follow up with any
necessary fixes.
2024-03-22 16:58:52 -07:00
Jeff McCune
e34db2b583 (#71) Refactor provisioner to produce a BuildPlan 2024-03-22 16:42:57 -07:00
Jeff McCune
71de57ac88 (#71) Refactor optional vault service to BuildPlan 2024-03-22 15:54:52 -07:00
Jeff McCune
c7cc661018 (#71) Refactor Zitadel components for BuildPlan
❯ holos render --cluster-name k2  ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/accounts/iam/zitadel/...
3:04PM INF render.go:43 rendered prod-iam-postgres version=0.60.2 status=ok action=rendered name=prod-iam-postgres
3:04PM INF render.go:43 rendered prod-iam-postgres-certs version=0.60.2 status=ok action=rendered name=prod-iam-postgres-certs
3:04PM INF render.go:43 rendered prod-iam-zitadel version=0.60.2 status=ok action=rendered name=prod-iam-zitadel
2024-03-22 15:04:43 -07:00
Jeff McCune
09f39c02fe (#71) Refactor foundation/cloud/secrets components to BuildPlan 2024-03-22 13:50:34 -07:00
Jeff McCune
23c76a73e0 (#71) Refactor pgo components to BuildPlan 2024-03-22 13:29:38 -07:00
Jeff McCune
1cafe08237 (#71) Refactor prod-metal-ceph to use BuildPlan 2024-03-22 12:44:20 -07:00
Jeff McCune
45b07964ef (#71) Refactor the mesh collection to use BuildPlan
This patch refactors the example reference platform to use the new
BuildPlan API.

```
❯ holos render --cluster-name=k2 /home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/mesh/...
12:19PM INF render.go:43 rendered prod-mesh-cni version=0.60.2 status=ok action=rendered name=prod-mesh-cni
12:19PM INF render.go:43 rendered prod-mesh-gateway version=0.60.2 status=ok action=rendered name=prod-mesh-gateway
12:19PM INF render.go:43 rendered prod-mesh-httpbin version=0.60.2 status=ok action=rendered name=prod-mesh-httpbin
12:19PM INF render.go:43 rendered prod-mesh-ingress version=0.60.2 status=ok action=rendered name=prod-mesh-ingress
12:19PM INF render.go:43 rendered prod-mesh-istiod version=0.60.2 status=ok action=rendered name=prod-mesh-istiod
12:19PM INF render.go:43 rendered prod-mesh-istio-base version=0.60.2 status=ok action=rendered name=prod-mesh-istio-base
```
2024-03-22 12:44:20 -07:00
Jeff McCune
6cc4a57b62 (#72) BuildPlan DisallowUnknownFields
This patch disallows unknown fields from CUE.  The purpose is to fail
early if there is a typo in a nested field name and to speed up
refactoring the reference platform.

With this patch, refactoring the type definition of the Holos/CUE API is
a faster process:

 1. Change api/vX/*.go
 2. make gencue
 3. Render the reference platform
 4. Fix error with unknown fields
 5. Verify rendered output is the same as before

Closes: #72
2024-03-22 12:44:11 -07:00
Jeff McCune
31280acbae (#71) Add HelmChart BuildPlan support
This patch refactors the #HelmChart definition to a BuildPlan.HelmCharts,
which executes a collection of HelmCharts.  The same behavior is
preserved, helm template executes then a kustomize post processor
executes.

```
❯ holos render --cluster-name=k2 ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/... --log-level=debug
9:53PM DBG config.go:150 finalized config from flags version=0.60.1 state=finalized
9:53PM DBG builder.go:108 cue: building instances version=0.60.1
9:53PM DBG builder.go:95 cue: equivalent command: cue export --out yaml -t cluster=k2 ./platforms/reference/clusters/foundation/cloud/github/arc/... version=0.60.1
9:53PM DBG builder.go:100 cue: tags [cluster=k2] version=0.60.1
9:53PM DBG builder.go:122 cue: building instance version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc
9:53PM DBG builder.go:127 cue: validating instance version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc
9:53PM DBG builder.go:131 cue: decoding holos build plan version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc
9:53PM DBG builder.go:122 cue: building instance version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/runner
9:53PM DBG builder.go:127 cue: validating instance version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/runner
9:53PM DBG builder.go:131 cue: decoding holos build plan version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/runner
9:53PM DBG result.go:61 ExternalSecret/controller-manager version=0.60.1 kind=ExternalSecret name=controller-manager
9:53PM DBG builder.go:122 cue: building instance version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/system
9:53PM DBG builder.go:127 cue: validating instance version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/system
9:53PM DBG builder.go:131 cue: decoding holos build plan version=0.60.1 dir=/home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/system
9:53PM DBG helm.go:95 helm: wrote values version=0.60.1 chart=oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller path=/tmp/holos1163326896/values.yaml bytes=653
9:53PM DBG run.go:40 running: helm version=0.60.1 name=helm args="[template --no-hooks --include-crds --values /tmp/holos1163326896/values.yaml --namespace arc-system --kubeconfig /dev/null --version 0.8.3 gha-rs-controller /home/jeff/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/github/arc/system/vendor/gha-runner-scale-set-controller]"
9:53PM DBG remove.go:15 tmp: removed version=0.60.1 path=/tmp/holos1163326896
9:53PM DBG result.go:95 wrote: /tmp/holos.kustomize3569816247/resources.yaml version=0.60.1 op=write path=/tmp/holos.kustomize3569816247/resources.yaml bytes=2019229
9:53PM DBG result.go:108 wrote: /tmp/holos.kustomize3569816247/kustomization.yaml version=0.60.1 op=write path=/tmp/holos.kustomize3569816247/kustomization.yaml bytes=94
9:53PM DBG run.go:40 running: kubectl version=0.60.1 name=kubectl args="[kustomize /tmp/holos.kustomize3569816247]"
9:53PM DBG remove.go:15 tmp: removed version=0.60.1 path=/tmp/holos.kustomize3569816247
9:53PM DBG result.go:135 out: wrote deploy/clusters/k2/components/prod-github-arc-runner/prod-github-arc-runner.gen.yaml version=0.60.1 action=write path=deploy/clusters/k2/components/prod-github-arc-runner/prod-github-arc-runner.gen.yaml status=ok
9:53PM DBG result.go:135 out: wrote deploy/clusters/k2/holos/components/prod-github-arc-runner-kustomization.gen.yaml version=0.60.1 action=write path=deploy/clusters/k2/holos/components/prod-github-arc-runner-kustomization.gen.yaml status=ok
9:53PM INF render.go:43 rendered prod-github-arc-runner version=0.60.1 status=ok action=rendered name=prod-github-arc-runner
9:53PM DBG result.go:135 out: wrote deploy/clusters/k2/components/prod-github-arc-system/prod-github-arc-system.gen.yaml version=0.60.1 action=write path=deploy/clusters/k2/components/prod-github-arc-system/prod-github-arc-system.gen.yaml status=ok
9:53PM DBG result.go:135 out: wrote deploy/clusters/k2/holos/components/prod-github-arc-system-kustomization.gen.yaml version=0.60.1 action=write path=deploy/clusters/k2/holos/components/prod-github-arc-system-kustomization.gen.yaml status=ok
9:53PM INF render.go:43 rendered prod-github-arc-system version=0.60.1 status=ok action=rendered name=prod-github-arc-system
```
2024-03-22 10:14:04 -07:00
Jeff McCune
6f0928b12c (#71) Add go BuildPlan type as the CUE<->Holos API
This patch establishes the BuildPlan struct as the single API contract
between CUE and Holos.  A BuildPlan spec contains a list of each of the
support holos component types.

The purpose of this data structure is to support the use case of one CUE
instance generating 1 build plan that contains 0..N of each type of
holos component.

The need for multiple components per one CUE instance is to support the
generation of a collection of N~4 flux kustomization resources per
project and P~6 projects built from one CUE instance.

Tested with:

    holos render --cluster-name=k2 ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/foundation/cloud/init/namespaces/...

Common labels are removed because they're too tightly coupled to the
model of one component per one cue instance.
2024-03-21 16:13:36 -07:00
Jeff McCune
c6e9250d60 (#69) Refactor clean up go types
Separate out the Kustomization and Kustomize types commonly used in
holos components.  Embed HolosComponent into Result.
2024-03-21 08:57:02 -07:00
Jeff McCune
104bda459f (#69) Go Types for CUE/Holos API contract
This patch refactors the go structs used to decode cue output for
processing by the holos cli.  For context, the purpose of the structs
are to inform holos how the data from cue should be modeled and
processed as a rendering pipeline that provides rendered yaml to
configure kubernetes api objects.

The structs share common fields in the form of the HolosComponent
embedded struct.  The three main holos component kinds today are:

 1. KubernetesObjects - CUE outputs a nested map where each value is a
    single rendered api object (resource).
 2. HelmChart - CUE outputs the chart name and values.  Holos calls helm
    template to render the chart.  Additional api objects may be
    overlaid into the rendered output.  Kustomize may also optionally be
    called at the end of the render pipeline.
 3. KustomizeBuild - CUE outputs data to construct a kustomize
    kustomization build.  The holos component contains raw yaml files to
    use as kustomization resources.  CUE optionally defines additional
    patches, common labels, etc.

With the Go structs, cue may directly import the definitions to more
easily keep the CUE definitions in sync with what the holos cli expects
to receive.

The holos component types may be imported into cue using:

    cue get go github.com/holos-run/holos/api/v1alpha1/...
2024-03-20 17:21:10 -07:00
Jeff McCune
bd2effa183 (#61) Improve ks prod-iam-zitadel robustness with flux health checks
Without this patch ks/prod-iam-zitadel often gets blocked waiting for
jobs that will never complete.  In addition, flux should not manage the
zitadel-test-connection Pod which is an unnecessary artifact of the
upstream helm chart.

We'd disable helm hooks, but they're necessary to create the init and
setup jobs.

This patch also changes the default behavior of Kustomizations from
wait: true to wait: false.  Waiting is expensive for the api server and
slows down the reconciliation process considerably.

Component authors should use ks.spec.healthChecks to target specific
important resources to watch and wait for.
2024-03-15 15:56:43 -07:00
Jeff McCune
562412fbe7 (#57) Run gha-rs scale set only on the primary cluster
This patch fixes the problem of the actions runner scale set listener
pod failing every 3 seconds.  See
https://github.com/actions/actions-runner-controller/issues/3351

The solution is not ideal, if the primary cluster is down workflows will
not execute.  The primary cluster shouldn't go down though so this is
the trade off.  Lower log spam and resource usage by eliminating the
failing pods on other clusters for lower availability if the primary
cluster is not available.

We could let the pods loop and if the primary is unavailable another
would quickly pick up the role, but it doesn't seem worth it.
2024-03-15 13:13:25 -07:00
Jeff McCune
fd6fbe5598 (#57) Allow gha-rs scale set to fail on all but one clusters
The effect of this patch is limited to refreshing credentials only for
namespaces that exist in the local cluster.  There is structure in place
in the CUE code to allow for namespaces bound to specific clusters, but
this is used only by the optional Vault component.

This patch was an attempt to work around
https://github.com/actions/actions-runner-controller/issues/3351 by
deploying the runner scale sets into unique namespaces.

This effort was a waste of time, only one listener pod successfully
registered for a given scale set name / group combination.

Because we have only one group named Default we can only have one
listener pod globally for a given scale set name.

Because we want our workflows to execute regardless of the availability
of a single cluster, we're going to let this fail for now.  The pod
retries every 3 seconds.  When a cluster is destroyed, another cluster
will quickly register.

A follow up patch will look to expand this retry behavior.
2024-03-15 12:53:16 -07:00
Jeff McCune
67472e1e1c (#60) Disable flux reconciliation of deployment/zitadel on standby clusters 2024-03-14 21:58:32 -07:00
Jeff McCune
d64c3e8c66 (#58) Zitadel Failover RunBook 2024-03-14 15:25:38 -07:00
Jeff McCune
f344f97374 (#58) Restore last zitadel database backup
When the cluster is provisioned, restore the most recent backup instead
of a fixed point in time.
2024-03-14 11:40:17 -07:00
Jeff McCune
770088b912 (#53) Clean up nested if statements with && 2024-03-13 10:35:20 -07:00
Jeff McCune
cb9b39c3ca (#53) Add Vault as an optional service on the core clusters
This patch migrates the vault component from [holos-infra][1] to a cue
based component.  Vault is optional in the reference platform, so this
patch also defines an `#OptionalServices` struct to conditionally manage
a service across multiple clusters in the platform.

The primary use case for optional services is managing a namespace to
provision and provide secrets across clusters.

[1]: https://github.com/holos-run/holos-infra/tree/v0.5.0/components/core/core/vault
2024-03-12 17:18:38 -07:00
Jeff McCune
0f34b20546 (#54) Disable helm hooks when rendering components
Pods are unnecessarily created when deploying helm based holos
components and often fail.  Prevent these test pods by disabling helm
hooks with the `--no-hooks` flag.

Closes: #54
2024-03-12 14:14:20 -07:00
Jeff McCune
0d7bbbb659 (#48) Disable pg spec.dataSource for standby cluster
Problem:
The standby cluster on k2 fails to start.  A pgbackrest pod first
restores the database from S3, then the pgha nodes try to replay the WAL
as part of the standby initialization process.  This fails because the
PGDATA directory is not empty.

Solution:
Specify the spec.dataSource field only when the cluster is configured as
a primary cluster.

Result:
Non-primary clusters are standby, they skip the pgbackrest job to
restore from S3 and move straight to patroni replaying the WAL from S3
as part of the pgha pods.

One of the two pgha pods becomes the "standby leader" and restores the
WAL from S3.  The other is a cascading standby and then restores the
same WAL from the standby leader.

After 8 minutes both pods are ready.

```
❯ k get pods
NAME                               READY   STATUS    RESTARTS   AGE
zitadel-pgbouncer-d9f8cffc-j469g   2/2     Running   0          11m
zitadel-pgbouncer-d9f8cffc-xq29g   2/2     Running   0          11m
zitadel-pgha1-27w7-0               4/4     Running   0          11m
zitadel-pgha1-c5qj-0               4/4     Running   0          11m
zitadel-repo-host-0                2/2     Running   0          11m
```
2024-03-11 17:56:47 -07:00
Jeff McCune
3f3e36bbe9 (#48) Split workload into foundation and accounts
Problem:
The k3 and k4 clusters are getting the Zitadel components which are
really only intended for the core cluster pair.

Solution:
Split the workload subtree into two, named foundation and accounts.  The
core cluster pair gets foundation+accounts while the kX clusters get
just the foundation subtree.

Result:
prod-zitadel-iam is no longer managed on k3 and k4
2024-03-11 15:20:35 -07:00
Jeff McCune
9f41478d33 (#48) Restore from Monday morning after Gary and Nate registered
Set the restore point to time="2024-03-11T17:08:58Z" level=info
msg="crunchy-pgbackrest ends" which is just after Gary and Nate
registered and were granted the cluster-admin role.
2024-03-11 10:18:45 -07:00
Jeff McCune
b86fee04fc (#48) v0.55.4 to rebuild k3, k4, k5 2024-03-11 08:48:07 -07:00
Jeff McCune
c78da6949f Merge pull request #51 from holos-run/jeff/48-zitadel-backups
(#48) Custom PGO Certs for Zitadel
2024-03-10 23:08:29 -07:00
Jeff McCune
7b215bb8f1 (#48) Custom PGO Certs for Zitadel
The [Streaming Standby][standby] architecture requires custom tls certs
for two clusters in two regions to connect to each other.

This patch manages the custom certs following the configuration
described in the article [Using Cert Manager to Deploy TLS for Postgres
on Kubernetes][article].

NOTE: One thing not mentioned anywhere in the crunchy documentation is
how custom tls certs work with pgbouncer.  The pgbouncer service uses a
tls certificate issued by the pgo root cert, not by the custom
certificate authority.

For this reason, we use kustomize to patch the zitadel Deployment and
the zitadel-init and zitadel-setup Jobs.  The patch projects the ca
bundle from the `zitadel-pgbouncer` secret into the zitadel pods at
/pgbouncer/ca.crt

[standby]: https://access.crunchydata.com/documentation/postgres-operator/latest/architecture/disaster-recovery#streaming-standby-with-an-external-repo
[article]: https://www.crunchydata.com/blog/using-cert-manager-to-deploy-tls-for-postgres-on-kubernetes
2024-03-10 22:54:06 -07:00
Jeff McCune
78cec76a96 (#48) Restore ZITADEL from point in time full backup
A full backup was taken using:

```
kubectl annotate postgrescluster zitadel postgres-operator.crunchydata.com/pgbackrest-backup="$(date)"
```

And completed with:

```
❯ k logs -f zitadel-backup-5r6v-v5jnm
time="2024-03-10T21:52:15Z" level=info msg="crunchy-pgbackrest starts"
time="2024-03-10T21:52:15Z" level=info msg="debug flag set to false"
time="2024-03-10T21:52:15Z" level=info msg="backrest backup command requested"
time="2024-03-10T21:52:15Z" level=info msg="command to execute is [pgbackrest backup --stanza=db --repo=2 --type=full]"
time="2024-03-10T21:55:18Z" level=info msg="crunchy-pgbackrest ends"
```

This patch verifies the point in time backup is robust in the face of
the following operations:

1. pg cluster zitadel was deleted (whole namespace emptied)
2. pg cluster zitadel was re-created _without_ a `dataSource`
3. pgo initailized a new database and backed up the blank database to
   S3.
4. pg cluster zitadel was deleted again.
5. pg cluster zitadel was re-created with `dataSource` `options: ["--type=time", "--target=\"2024-03-10 21:56:00+00\""]` (Just after the full backup completed)
6. Restore completed successfully.
7. Applied the holos zitadel component.
8. Zitadel came up successfully and user login worked as expected.

- [x] Perform an in place [restore][restore] from [s3][bucket].
- [x] Set repo1-retention-full to clear warning

[restore]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/disaster-recovery#restore-properties
[bucket]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/disaster-recovery#cloud-based-data-source
2024-03-10 17:42:54 -07:00
Jeff McCune
0e98ad2ecb (#48) Zitadel Backups
This patch configures backups suitable to support the [Streaming Standby
with an External Repo][0] architecture.

- [x] PGO [Multiple Backup Repositories][1] to k8s pv and s3.
- [x] [Encryption][2] of backups to S3.
- [x] [Remove SUPERUSER][3] role from zitadel-admin pg user to work with pgbouncer.  Resolves zitadel-init job failure.
- [x] Take a [Manual Backup][5]

[0]: https://access.crunchydata.com/documentation/postgres-operator/latest/architecture/disaster-recovery#streaming-standby-with-an-external-repo
[1]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/backups#set-up-multiple-backup-repositories
[2]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/backups#encryption
[3]: https://github.com/CrunchyData/postgres-operator/issues/3095#issuecomment-1904712211
[4]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/disaster-recovery#streaming-standby-with-an-external-repo
[5]: https://access.crunchydata.com/documentation/postgres-operator/latest/tutorials/backups-disaster-recovery/backup-management#taking-a-one-off-backup
2024-03-10 16:38:56 -07:00
Jeff McCune
30bb3f183a (#50) Describe type as strings to match others 2024-03-10 11:29:19 -07:00
Jeff McCune
1369338f3c (#50) Add -n shorthand for --namespace for secrets
It's annoying holos get secret -n foo doesn't work like kubectl get
secret -n foo works.

Closes: #50
2024-03-10 10:45:49 -07:00
Jeff McCune
ac03f64724 (#45) Configure ZITADEL to use pgbouncer 2024-03-09 09:44:33 -08:00
Jeff McCune
bea4468972 (#42) Remove cert manager db ca components
Simpler to let postgres manage the certs.  TLS is in verify-full mode
with the pgo configured certs.
2024-03-08 21:34:26 -08:00
Jeff McCune
224adffa15 (#42) Add holos components for zitadel with postgres
To establish the canonical https://login.ois.run identity issuer on the
core cluster pair.

Custom resources for PGO have been imported with:

    timoni mod vendor crds -f deploy/clusters/core2/components/prod-pgo-crds/prod-pgo-crds.gen.yaml

Note, the zitadel tls connection took some considerable effort to get
working.  We intentionally use pgo issued certs to reduce the toil of
managing certs issued by cert manager.

The default tls configuration of pgo is pretty good with verify full
enabled.
2024-03-08 21:29:25 -08:00
Jeff McCune
b4d34ffdbc (#42) Fix incorrect ceph pool for core2 cluster
The core2 cluster cannot provision pvcs because it's using the k8s-dev
pool when it has credentials valid only for the k8s-prod pool.

This patch adds an entry to the platform cluster map to configure the
pool for each cluster, with a default of k8s-dev.
2024-03-08 13:14:27 -08:00
Jeff McCune
a85db9cf5e (#42) Add KustomizeBuild holos component type to install pgo
PGO uses plain yaml and kustomize as the recommended installation
method.  Holos supports upstream by adding a new PlainFiles component
kind, which simply copies files into place and lets kustomize handle the
generation of the api objects.

Cue is responsible for very little in this kind of component, basically
allowing overlay resources if needed and deferring everything else to
the holos cli.

The holos cli in turn is responsible for executing kubectl kustomize
build on the input directory to produce the rendered output, then writes
the rendered output into place.
2024-03-08 11:27:42 -08:00
Jeff McCune
990c82432c (#40) Fix go releaser with standard arc runners
Standard arc runner image is missing gpg and git.
2024-03-07 22:59:15 -08:00
Jeff McCune
e3673b594c Merge pull request #41 from holos-run/jeff/40-actions-runners
(#40) Actions Runner Controller (Runner Scale Sets)
2024-03-07 22:43:16 -08:00
Jeff McCune
f8cf278a24 (#40) bump to v0.54.0 2024-03-07 22:37:51 -08:00
Jeff McCune
b0bc596a49 (#40) Update workflow to run on arc runner set
Matches the value of the github/arc/runner component helm release, which
is the installation name.
2024-03-07 22:37:51 -08:00
Jeff McCune
4501ceec05 (#40) Use baseline security context for GitHub arc
Without this patch the arc controller fails to create a listener.  The
template for the listener doesn't appear to be configurable from the
chart.

Could patch the listener pod template with kustomize, do this as a
follow up feature.

With this patch we get the expected two pods in the runner system
namespace:

```
❯ k get pods
NAME                                 READY   STATUS    RESTARTS   AGE
gha-rs-7db9c9f7-listener             1/1     Running   0          43s
gha-rs-controller-56bb9c77d9-6tjch   1/1     Running   0          8s
```
2024-03-07 22:37:50 -08:00
Jeff McCune
4183fdfd42 (#40) Note the helm release name is the installation name
Which is the value of the `runs-on` field in workflows.
2024-03-07 22:37:50 -08:00
Jeff McCune
2595793019 (#40) Do not force the namespace with kustomize
To avoid confining the custom resource definitions to a namespace.
2024-03-07 22:37:50 -08:00
Jeff McCune
aa3d1914b1 (#40) Manage the actions runner scale sets 2024-03-07 22:37:49 -08:00
Jeff McCune
679ddbb6bf (#40) Use Restricted pod security for arc runners
Might as well put the restriction in place before deploying the runners
to see what breaks.
2024-03-07 22:37:49 -08:00
Jeff McCune
b1d7d07a04 (#40) Add field for helm chart release name
The resource names for the arc controller are too long:

❯ k get pods -n arc-systems
NAME                                                              READY   STATUS    RESTARTS   AGE
gha-runner-scale-set-controller-gha-rs-controller-6bdf45bd6jx5n   1/1     Running   0          59m

Solve the problem by allowing components to set the release name to
`gha-rs-controller` which requires an additional field from the cue code
to differentiate from the chart name.
2024-03-07 20:40:31 -08:00
Jeff McCune
5f58263232 (#40) Create arc namespaces
Named after the upstream install guide, though arc-systems makes me
twitch for arc-system.
2024-03-07 20:37:35 -08:00
Jeff McCune
b6bdd072f7 (#40) Include crds when running helm template
Might need to make this a configurable option, but for now just always
do it.
2024-03-07 20:37:35 -08:00
Jeff McCune
509f2141ac (#40) Actions Runner Controller
This patch adds support for helm oci images which are used by the
gha-runner-scale-set-controller.

For example, arc is installed normally with:

```
NAMESPACE="arc-systems"
helm install arc \
    --namespace "${NAMESPACE}" \
    --create-namespace \
    oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
```

This patch caches the oci image in the same way as the repository based
method.

Refer to: https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/quickstart-for-actions-runner-controller
2024-03-07 20:37:35 -08:00
Jeff McCune
4c2bc34d58 (#32) SecretStore Component
Separate the SecretStore resources from the namespaces component because
it creates a deadlock.  The secretstore crds don't get applied until the
eso component is managed.

The namespaces component should have nothing but core api objects, no
custom resources.
2024-03-07 16:01:22 -08:00
Jeff McCune
d831070f53 Trim trailing newlines from files when creating secrets
Without this patch, the pattern of echoing data (without -n) or editing
files in a directory to represent the keys of a secret results in a
trailing newline in the kubernetes Secret.

This patch trims off the trailing newline by default, with the option to
preserve it with the --trim-trailing-newlines=false flag.
2024-03-06 11:21:32 -08:00
Jeff McCune
340715f76c (#36) Provide certs to Cockroach DB and Zitadel with ExternalSecrets
This patch switches CockroachDB to use certs provided by ExternalSecrets
instead of managing Certificate resources in-cluster from the upstream
helm chart.

This paves the way for multi-cluster replication by moving certificates
outside of the lifecycle of the workload cluster cockroach db operates
within.

Closes: #36
2024-03-06 10:38:47 -08:00
Jeff McCune
64ffacfc7a (#36) Add Cockroach Issuer for Zitadel to provisioner cluster
Issuing mtls certs for cockroach db moves to the provisioner cluster so
we can more easily support cross cluster replication in the future.
crdb certs will be synced same as public tls certs, using ExternalSecret
resources.
2024-03-06 09:36:20 -08:00
Nate McCurdy
54acea42cb Merge pull request #37 from holos-run/nate/preflight
Add 'holos preflight' command, check for GitHub CLI
2024-03-06 09:32:54 -08:00
Nate McCurdy
5ef8e75194 Fix Actions warning during Lint by updating golangci-lint-action
Warning:
> Node.js 16 actions are deprecated. Please update the following actions to use Node.js 20: golangci/golangci-lint-action@v3. For more information see: https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/.
2024-03-05 17:42:30 -08:00
Nate McCurdy
cb2b5c0f49 Add the 'preflight' subcommand; check for GitHub access
This adds a new holos subcommand: preflight

Initially, this just checks that the GitHub CLI is installed and
authenticated.

The preflight command will be used to validate that the user has the
neccessary CLI tools, access, and authorization to start using Holos and
setup a Holos cluster.
2024-03-05 17:40:08 -08:00
Jeff McCune
fd5a2fdbc1 (#36) Sync certs as ExternalSecrets from workload clusters
This patch replaces the httpbin and login cert on the workload clusters
with an ExternalSecret to sync the tls cert from the provisioner
cluster.
2024-03-05 17:05:10 -08:00
Jeff McCune
eb3e272612 (#36) Dynamically generate cluster certs from Platform spec
Each cluster should be more or less identical, configure certs from the
dynamic list of platform clusters.
2024-03-05 16:44:35 -08:00
Nate McCurdy
9f2a51bde8 Move the RunCmd function to the util package
More than one Holos package needs to execute commands, so pull out the
runCmd from builder and move it to the util package.

This commits adds the following to the util package:
* util.RunCmd func
* util.runResult struct
2024-03-05 15:12:14 -08:00
Jeff McCune
2b3b5a4887 (#36) Issue login and httpbin certs
This patch uses cert manager in the provisioner cluster to provision tls
certs for https://login.example.com and https://httpbin.k2.example.com

The certs are not yet synced to the clusters.  Next step is to replace
the Certificate resources with ExternalSecret resources, then remove
cert manager from the workload clusters.
2024-03-05 14:27:37 -08:00
Jeff McCune
7426e8f867 (#36) Move cert-manager to the provisioner cluster
This patch moves certificate management to the provisioner cluster to
centralize all secrets into the highly secured cluster.  This change
also simplifies the architecture in a number of ways:

1. Certificate lives are now completely independent of cluster
   lifecycle.
2. Remove the need for bi-directional sync to save cert secrets.
3. Workload clusters no longer need access to DNS.
2024-03-05 12:51:58 -08:00
Jeff McCune
cf0c455aa2 (#34) Add test for print secret data 2024-03-05 11:14:37 -08:00
Jeff McCune
752a3f912d (#34) Remove debug info logs 2024-03-05 11:05:51 -08:00
Jeff McCune
7d5852d675 (#34) Print secret data as json
Closes: #34
2024-03-05 11:03:47 -08:00
Jeff McCune
66b4ca0e6c (#31) Fix helm missing in actions workflow
Causing test failures that should pass.
2024-03-05 10:11:43 -08:00
Jeff McCune
b3f682453d (#31) Inject istio sidecar into Deployment zitadel using Kustomize
Multiple holos components rely on kustomize to modify the output of the
upstream helm chart, for example patching a Deployment to inject the
istio sidecar.

The new holos cue based component system did not support running
kustomize after helm template.  This patch adds the kustomize execution
if two fields are defined in the helm chart kind of cue output.

The API spec is pretty loose in this patch but I'm proceeding for
expedience and to inform the final API with more use cases as more
components are migrated to cue.
2024-03-05 09:56:39 -08:00
Jeff McCune
0c3181ae05 (#31) Add VirtualService for Zitadel
Also import the Kustomize types using:

    cue get go sigs.k8s.io/kustomize/api/types/...
2024-03-04 17:18:46 -08:00
Jeff McCune
18cbff0c13 (#31) Add tls cert for zitadel to connect to cockroach db
Cockroach DB uses tls certs for client authentication.  Issue one for
Zitadel.

With this patch Zitadel starts up bit is not yet exposted with a
VirtualService.

Refer to https://zitadel.com/docs/self-hosting/manage/configure
2024-03-04 14:46:49 -08:00
Jeff McCune
b4fca0929c (#31) ExternalSecret for zitadel-masterkey 2024-03-04 14:31:27 -08:00
Jeff McCune
911d65bdc6 (#31) Setup login.ois.run with basic istio default Gateway
The istio default Gateway is the basis for what will become a dynamic
set of server entries specified from cue project data integrated with
extauthz.

For now we simply need to get the identity provider up and running as
the first step toward identity and access management.
2024-03-04 13:59:17 -08:00
Jeff McCune
2a5eccf0c1 (#33) Helm stderr logging
Log error messages from helm when building and rendering holos
components.

Closes: #33
2024-03-04 13:16:51 -08:00
Jeff McCune
9db4873205 (#31) Add Cockroach DB for Zitadel
Following https://github.com/zitadel/zitadel-charts/blob/main/examples/4-cockroach-secure/README.md
2024-03-04 10:31:39 -08:00
Jeff McCune
f90e83e142 (#30) Add httpbin Gateway and VirtualService
There isn't a default Gateway yet, so use a specific `httpbin` gateway
to test istio instead.
2024-03-02 21:12:03 -08:00
Jeff McCune
bdd2964edb (#30) Add httpbin Service for ns istio-ingress 2024-03-02 20:39:55 -08:00
Jeff McCune
56375b82d8 (#30) Fix httpbin Deployment selector match labels
Without this patch the deployment fails with:

```
Deployment/istio-ingress/httpbin dry-run failed, reason: Invalid:
Deployment.apps "httpbin" is invalid: spec.template.metadata.labels:
Invalid value:
map[string]string{"app.kubernetes.io/component":"httpbin",
"app.kubernetes.io/instance":"prod-mesh-httpbin",
"app.kubernetes.io/name":"mesh", "app .kubernetes.io/part-of":"prod",
"holos.run/component.name":"httpbin", "holos.run/project.name":"mesh",
"holos.run/stage.name":"prod", "sidecar.istio.io/inject":"true"}:
`selector` does not match template `labels`
```
2024-03-02 20:23:23 -08:00
Jeff McCune
dc27489249 (#30) Add httpbin Deployment in istio-ingress namespace
This patch gets the Deployment running with a restricted seccomp
profile.
2024-03-02 20:17:16 -08:00
Jeff McCune
7d8a618e25 (#30) Add httpbin Certificate to verify the mesh
Also fix certmanager which was not installing role bindings correctly
because the flux kustomization was writing over the metadata namespace
field.
2024-03-02 17:16:42 -08:00
Jeff McCune
646f6fcdb0 (#30) Add https redirect overlay resources
This patch migrates the https redirect and the
istio-ingressgateway-loopback Service from
`holos-infra/components/core/istio/ingress/templates/deployment`
2024-03-02 15:01:58 -08:00
Jeff McCune
4ce39db745 (#30) Enforce restricted pod security profile on istio-ingress namespace
This patch enforces the restricted pod security profile on the istio
ingress namespace. The istio cni to move the traffic redirection from
the init container to a cni daemon set pod.

Refer to:

 - https://istio.io/latest/docs/setup/additional-setup/pod-security-admission/
 - https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
2024-03-02 11:16:55 -08:00
Jeff McCune
eba58d1639 (#30) Add ingress component and istio-ingressgateway Deployment
Migrated from holos-infra/components/core/istio/ingress
2024-03-02 10:22:21 -08:00
Jeff McCune
765832d90d (#30) Trim istiod 2024-03-01 16:27:49 -08:00
Jeff McCune
d1163d689a (#30) Add istiod istio controller and meshconfig
This patch adds the standard istiod controller, which depends on
istio-base.

The holos reference platform heavily customizes the meshconfig, so the
upstream istio ConfigMap is disabled in the helm chart values.  The mesh
config is generated from cue data defined in the controller holos
component.

Note: This patch adds a static configuration for the istio meshconfig in
the meshconfig.cue file.  The extauthz providers are a core piece of
functionality in the holos reference platform and a key motivation of
moving to CUE from Helm is the need to dynamically generate the
meshconfig from a platform scoped set of projects and services across
multiple clusters.

For expedience this dynamic generation is not part of this patch but is
expected to replace the static meshconfig once the cluster is more fully
configured with the new cue based holos command line interface.
2024-03-01 16:13:19 -08:00
Jeff McCune
63009ba419 (#30) Fix cue formatting 2024-03-01 10:35:32 -08:00
Jeff McCune
9c42cf9109 (#30) Import istio crds into cue definitions
❯ timoni mod vendor crds -f ~/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
10:30AM INF schemas vendored: extensions.istio.io/wasmplugin/v1alpha1
10:30AM INF schemas vendored: install.istio.io/istiooperator/v1alpha1
10:30AM INF schemas vendored: networking.istio.io/destinationrule/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/destinationrule/v1beta1
10:30AM INF schemas vendored: networking.istio.io/envoyfilter/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/gateway/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/gateway/v1beta1
10:30AM INF schemas vendored: networking.istio.io/proxyconfig/v1beta1
10:30AM INF schemas vendored: networking.istio.io/serviceentry/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/serviceentry/v1beta1
10:30AM INF schemas vendored: networking.istio.io/sidecar/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/sidecar/v1beta1
10:30AM INF schemas vendored: networking.istio.io/virtualservice/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/virtualservice/v1beta1
10:30AM INF schemas vendored: networking.istio.io/workloadentry/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/workloadentry/v1beta1
10:30AM INF schemas vendored: networking.istio.io/workloadgroup/v1alpha3
10:30AM INF schemas vendored: networking.istio.io/workloadgroup/v1beta1
10:30AM INF schemas vendored: security.istio.io/authorizationpolicy/v1
10:30AM INF schemas vendored: security.istio.io/authorizationpolicy/v1beta1
10:30AM INF schemas vendored: security.istio.io/peerauthentication/v1beta1
10:30AM INF schemas vendored: security.istio.io/requestauthentication/v1
10:30AM INF schemas vendored: security.istio.io/requestauthentication/v1beta1
10:30AM INF schemas vendored: telemetry.istio.io/telemetry/v1alpha1
2024-03-01 10:31:52 -08:00
Jeff McCune
3fce5188a2 (#30) Add holos cue instance prod-mesh-istio-base
This patch installs the istio base helm chart from upstream which
includes the custom resource definitions.
2024-03-01 10:28:54 -08:00
Jeff McCune
fde88ad5eb (#30) Add #DependsOn struct to unify dependencies
Using a list to merge dependencies through the tree from root to leaf is
challenging.  This patch uses a #DependsOn struct instead then builds
the list of dependencies for flux from the struct field values.
2024-03-01 10:13:55 -08:00
Jeff McCune
7a8d30f833 (#30) Mesh istio-system istio-ingress namespaces
Need to be in place with privileged pod security policies.
2024-03-01 09:35:57 -08:00
Jeff McCune
8987442b91 (#27) Add cert-manager ExternalSecret cloudflare-api-token-secret
This enables the dns01 letsencrypt acme solver and is heavily used in
the reference platform.

Secret migrated from Vault using:

```bash
vault kv get -format=json -field data kv/k8s/ns/cert-manager/cloudflare-api-token-secret \
  | holos create secret --namespace cert-manager cloudflare-api-token-secret --data-stdin --append-hash=false
```
2024-03-01 08:44:06 -08:00
Jeff McCune
a6af3a46cf (#27) Manage SecretStore with platform namespaces
It makes sense to manage the SecretStore along with the Namespace in the
platform namespaces holos component.  Otherwise, the first component
that needs an ExternalSecret also needs to manage a SecretStore, which
creates an artificial dependency for subesequent components that also
need a SecretStore in the same namespace.

Best to just have all components depend on the namespaces component.
2024-03-01 08:05:00 -08:00
Jeff McCune
71d545a883 (#27) Add cert-manager LetsEncrypt issuers
This patch partially adds the Let's Encrypt issuers.  The platform data
expands to take a contact email and a cloudflare login email.

The external secret needs to be added next.
2024-02-29 21:40:55 -08:00
Jeff McCune
044d3082d9 (#27) Add cert-manager custom resource definitions
Without this patch the cert-manager component is missing the custom
resource definitions.

This patch adds them using the helm installCRDs value.
2024-02-29 20:46:42 -08:00
Jeff McCune
c2d5c4ad36 (#27) Add cert-manager to the mesh collection
Straight-forward helm install with no customization.

This patch also adds a "Skip" output kind which allows intermediate cue
files in the tree to signal holos to skip over the instance.  This
enables constraints to be added at intermediate layers without build
errors.
2024-02-29 16:50:27 -08:00
Jeff McCune
ab03ef1052 (#27) Refactor top level schema
Remove content and contentType top level keys, deprecated in favor of
apiObjects.

Clarify toward the use of #CollectionName instead of project name.
2024-02-29 15:48:54 -08:00
Jeff McCune
8c76061b0d (#27) Add recommended labels and sort output
Add the recommended labels mapping to holos stage, project, and
component names.  Project will eventually be renamed to "collection" or
something.

Example:

    app.kubernetes.io/part-of: prod
    app.kubernetes.io/name: secrets
    app.kubernetes.io/component: validate
    app.kubernetes.io/instance: prod-secrets-validate

Also sort the api objects produced from cue so the output of the `holos
render` command is stable for git commits.
2024-02-29 15:12:19 -08:00
Jeff McCune
f60db8fa1f (#25) Show name of api object in errors
This patch changes the interface between CUE and Holos to remove the
content field and replace it with an api object map.  The map is a
`map[string]map[string]string` with the rendered yaml as the value of a
kind/name nesting.

This structure enables better error messages, cue disjunction errors
indicate the type and the name of the resource instead of just the list
index number.
2024-02-29 11:23:49 -08:00
Jeff McCune
eefc092ea9 (#22) Copy external secret data files one for one
Without this patch the secret data was nested under a key with the same
name as the secret name.  This caused the ceph controller to not find
the values.

This patch changes the golden path for #ExternalSecret to copy all data
keys 1:1 from the external to the target in the cluster.
2024-02-28 16:51:26 -08:00
Jeff McCune
0860ac3409 (#22) Rename ceph secret to include ClusterName
Without this patch all clusters would use the same ceph secret from the
provisioner cluster.  This is a problem because ceph credentials are
unique per cluster.

This patch renames the ceph secret to have a cluster name prefix.

The secret is created with:

```bash
vault kv get -format=json -field data kv/k2/kube-namespace/ceph-csi-rbd/csi-rbd-secret \
  | holos create secret --namespace ceph-system k2-ceph-csi-rbd --cluster-name=k2 --data-stdin --append-hash=false
```
2024-02-28 16:14:22 -08:00
Jeff McCune
6b156e9883 (#22) Label ns ceph-system with pod-security enforce: privileged
This patch adds the `pod-security.kubernetes.io/enforce: privileged`
label to the ceph-system namespace.

The Namespace resources are managed all over the map, it would be a good
idea to consolidate the PlatformNamespaces data into one well known
place for the entire platform.  Eschewing for now.
2024-02-28 15:57:01 -08:00
Jeff McCune
4de9f77fbf (#22) Add holos create secret --data-stdin flag
This patch enables quickly copying secrets from vault to the provisioner
cluster.  For example:

    vault kv get -format=json -field data kv/k2/kube-namespace/ceph-csi-rbd/csi-rbd-secret \
      | holos create secret --namespace ceph-system csi-rbd-secret --data-stdin --append-hash=false
2024-02-28 15:29:32 -08:00
Jeff McCune
4c5429b64a (#22) Ceph CSI for Metal clusters
This patch adds the ceph-csi-rbd helm chart component to the metal
cluster type.  The purpose is to enable PersistentVolumeClaims on ois
metal clusters.

Cloud clusters like GKE and EKS are expected to skip rendering the metal
type.

Helm values are handled with CUE.  The ceph secret is managed as an
ExternalSecret resource, appended to the rendered output by cue and the
holos cli.

Use:

    ❯ holos render --cluster-name=k2 ~/workspace/holos-run/holos/docs/examples/platforms/reference/clusters/metal/...
    2:45PM INF render.go:40 rendered prod-metal-ceph version=0.47.0 status=ok action=rendered name=prod-metal-ceph
2024-02-28 14:46:03 -08:00
Jeff McCune
ac5bff4b32 (#20) Error if secret is not found
Without this patch scripts incorrectly proceeded without detecting a
secret was not fetched.

    holos get secret notfound

    8:34AM ERR could not execute version=0.46.3 err="not found: notfound" loc=get.go:66
2024-02-28 08:33:55 -08:00
938 changed files with 263311 additions and 1252 deletions

View File

@@ -1,6 +1,7 @@
---
# https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#how-to-use
name: Lint
on:
"on":
push:
branches:
- main
@@ -14,14 +15,35 @@ permissions:
jobs:
golangci:
name: lint
runs-on: [self-hosted, k8s]
runs-on: gha-rs
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
cache: false
- 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
make buf
go generate ./...
make frontend
go mod tidy
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v4
with:
version: latest
skip-pkg-cache: true

View File

@@ -2,32 +2,61 @@ name: Release
on:
push:
# Run only against tags
tags:
- '*'
branches:
- release
permissions:
contents: write
jobs:
goreleaser:
runs-on: [self-hosted, k8s]
runs-on: gha-rs
steps:
# 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
# Must come after git executable is provided
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
# Necessary to run these outside of goreleaser, otherwise
# /home/runner/_work/holos/holos/internal/frontend/node_modules/.bin/protoc-gen-connect-query is not in PATH
- name: Install Tools
run: |
set -x
make tools
make buf
go generate ./...
make frontend
go mod tidy
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_CODE_SIGNING_SECRETKEY }}
passphrase: ${{ secrets.GPG_CODE_SIGNING_PASSPHRASE }}
- name: List keys
run: gpg -K
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
- name: Git diff
run: git diff
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:

View File

@@ -13,15 +13,38 @@ permissions:
jobs:
test:
runs-on: [self-hosted, k8s]
runs-on: gha-rs
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
- name: Install Packages
run: sudo apt update && sudo apt -qq -y install git curl zip unzip tar bzip2 make
- name: Set up Helm
uses: azure/setup-helm@v4
- name: Set up Kubectl
uses: azure/setup-kubectl@v3
- name: Install Tools
run: |
set -x
make tools
make buf
go generate ./...
make frontend
go mod tidy
- name: Test
run: ./scripts/test

6
.gitignore vendored
View File

@@ -1,7 +1,9 @@
bin/
/bin/
vendor/
.idea/
coverage.out
dist/
/dist/
*.hold/
/deploy/
.vscode/
tmp/

2
.golangci.yaml Normal file
View File

@@ -0,0 +1,2 @@
run:
timeout: 5m

View File

@@ -10,10 +10,8 @@ version: 1
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
- go mod tidy
builds:
- main: ./cmd/holos
@@ -23,6 +21,9 @@ builds:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
signs:
- artifacts: checksum

8
Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
FROM quay.io/holos-run/debian:bullseye AS final
USER root
WORKDIR /app
ADD bin bin
RUN chown -R app: /app
# Kubernetes requires the user to be numeric
USER 8192
ENTRYPOINT bin/holos server

View File

@@ -4,19 +4,24 @@ PROJ=holos
ORG_PATH=github.com/holos-run
REPO_PATH=$(ORG_PATH)/$(PROJ)
VERSION := $(shell grep "const Version " pkg/version/version.go | sed -E 's/.*"(.+)"$$/\1/')
VERSION := $(shell cat version/embedded/major version/embedded/minor version/embedded/patch | xargs printf "%s.%s.%s")
BIN_NAME := holos
DOCKER_REPO=quay.io/openinfrastructure/holos
DOCKER_REPO=quay.io/holos-run/holos
IMAGE_NAME=$(DOCKER_REPO)
$( shell mkdir -p bin)
# For buf plugin protoc-gen-connect-es
export PATH := $(PWD)/internal/frontend/holos/node_modules/.bin:$(PATH)
GIT_COMMIT=$(shell git rev-parse HEAD)
GIT_SUFFIX=$(shell test -n "`git status --porcelain`" && echo "-dirty" || echo "")
GIT_DETAIL=$(shell git describe --tags HEAD)
GIT_TREE_STATE=$(shell test -n "`git status --porcelain`" && echo "dirty" || echo "clean")
BUILD_DATE=$(shell date -Iseconds)
LD_FLAGS="-w -X ${ORG_PATH}/${PROJ}/pkg/version.GitCommit=${GIT_COMMIT} -X ${ORG_PATH}/${PROJ}/pkg/version.GitTreeState=${GIT_TREE_STATE} -X ${ORG_PATH}/${PROJ}/pkg/version.BuildDate=${BUILD_DATE}"
LD_FLAGS="-w -X ${ORG_PATH}/${PROJ}/version.GitDescribe=${GIT_DETAIL}${GIT_SUFFIX} -X ${ORG_PATH}/${PROJ}/version.GitCommit=${GIT_COMMIT} -X ${ORG_PATH}/${PROJ}/version.GitTreeState=${GIT_TREE_STATE} -X ${ORG_PATH}/${PROJ}/version.BuildDate=${BUILD_DATE}"
.PHONY: default
default: test
@@ -39,24 +44,48 @@ bumpmajor: ## Bump the major version.
scripts/bump minor 0
scripts/bump patch 0
.PHONY: show-version
show-version: ## Print the full version.
@echo $(VERSION)
.PHONY: tidy
tidy: ## Tidy go module.
go mod tidy
.PHONY: fmt
fmt: ## Format Go code.
fmt: ## Format code.
cd docs/examples && cue fmt ./...
cd internal/generate/platforms && cue fmt ./...
go fmt ./...
.PHONY: vet
vet: ## Vet Go code.
go vet ./...
.PHONY: gencue
gencue: ## Generate CUE definitions
cd internal/generate/platforms && cue get go github.com/holos-run/holos/api/v1alpha1/...
cd internal/generate/platforms && cue get go github.com/holos-run/holos/api/core/...
cd internal/generate/platforms && cue get go github.com/holos-run/holos/api/meta/...
.PHONY: rmgen
rmgen: ## Remove generated code
git rm -rf service/gen/ internal/frontend/holos/src/app/gen/ || true
rm -rf service/gen/ internal/frontend/holos/src/app/gen/
git rm -rf internal/ent/
rm -rf internal/ent/
git restore --staged internal/ent/generate.go internal/ent/schema/
git restore internal/ent/generate.go internal/ent/schema/
.PHONY: regenerate
regenerate: generate ## Re-generate code (delete and re-create)
.PHONY: generate
generate: ## Generate code.
generate: buf gencue ## Generate code.
go generate ./...
.PHONY: build
build: generate ## Build holos executable.
build: generate frontend ## Build holos executable.
@echo "building ${BIN_NAME} ${VERSION}"
@echo "GOPATH=${GOPATH}"
go build -trimpath -o bin/$(BIN_NAME) -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/$(BIN_NAME)
@@ -75,6 +104,8 @@ test: ## Run tests.
.PHONY: lint
lint: ## Run linters.
buf lint
cd internal/frontend/holos && ng lint
golangci-lint run
.PHONY: coverage
@@ -85,6 +116,47 @@ coverage: test ## Test coverage profile.
snapshot: ## Go release snapshot
goreleaser release --snapshot --clean
.PHONY: buf
buf: ## buf generate
cd service && buf dep update
buf generate
.PHONY: tools
tools: go-deps frontend-deps ## install tool dependencies
.PHONY: go-deps
go-deps: ## tool versions pinned in tools.go
go install cuelang.org/go/cmd/cue
go install github.com/bufbuild/buf/cmd/buf
go install github.com/fullstorydev/grpcurl/cmd/grpcurl
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install connectrpc.com/connect/cmd/protoc-gen-connect-go
go install honnef.co/go/tools/cmd/staticcheck
go install golang.org/x/tools/cmd/godoc
# curl https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash
.PHONY: frontend-deps
frontend-deps: ## Setup npm and vite
cd internal/frontend/holos && npm install
cd internal/frontend/holos && npm install --save-dev @bufbuild/buf @connectrpc/protoc-gen-connect-es
cd internal/frontend/holos && npm install @connectrpc/connect @connectrpc/connect-web @bufbuild/protobuf
# https://github.com/connectrpc/connect-query-es/blob/1350b6f07b6aead81793917954bdb1cc3ce09df9/packages/protoc-gen-connect-query/README.md?plain=1#L23
cd internal/frontend/holos && npm install --save-dev @connectrpc/protoc-gen-connect-query @bufbuild/protoc-gen-es
cd internal/frontend/holos && npm install @connectrpc/connect-query @bufbuild/protobuf
.PHONY: frontend
frontend: buf
cd internal/frontend/holos && rm -rf dist
mkdir -p internal/frontend/holos/dist
cd internal/frontend/holos && ng build
touch internal/frontend/frontend.go
.PHONY: image
image: build ## Docker image build
docker build . -t ${DOCKER_REPO}:v$(shell ./bin/holos --version)
docker push ${DOCKER_REPO}:v$(shell ./bin/holos --version)
.PHONY: help
help: ## Display this help menu.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

1
README.md Normal file
View File

@@ -0,0 +1 @@
# Holos

311
Tiltfile Normal file
View File

@@ -0,0 +1,311 @@
# -*- mode: Python -*-
# This Tiltfile manages a Go project with live leload in Kubernetes
listen_port = 3000
metrics_port = 9090
# Use our wrapper to set the kube namespace
if os.getenv('TILT_WRAPPER') != '1':
fail("could not run, ./hack/tilt/bin/tilt was not used to start tilt")
# AWS Account to work in
aws_account = '271053619184'
aws_region = 'us-east-2'
# Resource ids
holos_backend = 'Holos Backend'
pg_admin = 'pgAdmin'
pg_cluster = 'PostgresCluster'
pg_svc = 'Database Pod'
compile_id = 'Go Build'
auth_id = 'Auth Policy'
lint_id = 'Run Linters'
tests_id = 'Run Tests'
# PostgresCluster resource name in k8s
pg_cluster_name = 'holos'
# Database name inside the PostgresCluster
pg_database_name = 'holos'
# PGAdmin name
pg_admin_name = 'pgadmin'
# Default Registry.
# See: https://github.com/tilt-dev/tilt.build/blob/master/docs/choosing_clusters.md#manual-configuration
# Note, Tilt will append the image name to the registry uri path
default_registry('{account}.dkr.ecr.{region}.amazonaws.com/holos-run/holos-server'.format(account=aws_account, region=aws_region))
# Set a name prefix specific to the user. Multiple developers share the tilt-holos namespace.
developer = os.getenv('USER')
holos_server = 'holos'
# See ./hack/tilt/bin/tilt
namespace = os.getenv('NAMESPACE')
# We always develop against the k1 cluster.
os.putenv('KUBECONFIG', os.path.abspath('./hack/tilt/kubeconfig'))
# The context defined in ./hack/tilt/kubeconfig
allow_k8s_contexts('sso@k1')
allow_k8s_contexts('sso@k2')
allow_k8s_contexts('sso@k3')
allow_k8s_contexts('sso@k4')
allow_k8s_contexts('sso@k5')
# PG db connection for localhost -> k8s port-forward
os.putenv('PGHOST', 'localhost')
os.putenv('PGPORT', '15432')
# We always develop in the dev aws account.
os.putenv('AWS_CONFIG_FILE', os.path.abspath('./hack/tilt/aws.config'))
os.putenv('AWS_ACCOUNT', aws_account)
os.putenv('AWS_DEFAULT_REGION', aws_region)
os.putenv('AWS_PROFILE', 'dev-holos')
os.putenv('AWS_SDK_LOAD_CONFIG', '1')
# Authenticate to AWS ECR when tilt up is run by the developer
local_resource('AWS Credentials', './hack/tilt/aws-login.sh', auto_init=True)
# Extensions are open-source, pre-packaged functions that extend Tilt
#
# More info: https://github.com/tilt-dev/tilt-extensions
# More info: https://docs.tilt.dev/extensions.html
load('ext://restart_process', 'docker_build_with_restart')
load('ext://k8s_attach', 'k8s_attach')
load('ext://git_resource', 'git_checkout')
load('ext://uibutton', 'cmd_button')
# Paths edited by the developer Tilt watches to trigger compilation.
# Generated files should be excluded to avoid an infinite build loop.
developer_paths = [
'./cmd',
'./internal/server',
'./internal/ent/schema',
'./frontend/package-lock.json',
'./frontend/src',
'./go.mod',
'./pkg',
'./service/holos',
]
# Builds the holos-server executable
local_resource(compile_id, 'make build', deps=developer_paths)
# Build Docker image
# Tilt will automatically associate image builds with the resource(s)
# that reference them (e.g. via Kubernetes or Docker Compose YAML).
#
# More info: https://docs.tilt.dev/api.html#api.docker_build
#
docker_build_with_restart(
'holos',
context='.',
entrypoint=[
'/app/bin/holos',
'server',
'--listen-port={}'.format(listen_port),
'--oidc-issuer=https://login.ois.run',
'--oidc-audience=262096764402729854@holos_platform',
'--log-level=debug',
'--metrics-port={}'.format(metrics_port),
],
dockerfile='./hack/tilt/Dockerfile',
only=['./bin'],
# (Recommended) Updating a running container in-place
# https://docs.tilt.dev/live_update_reference.html
live_update=[
# Sync files from host to container
sync('./bin', '/app/bin'),
# Wait for aws-login https://github.com/tilt-dev/tilt/issues/3048
sync('./tilt/aws-login.last', '/dev/null'),
# Execute commands in the container when paths change
# run('/app/hack/codegen.sh', trigger=['./app/api'])
],
)
# Run local commands
# Local commands can be helpful for one-time tasks like installing
# project prerequisites. They can also manage long-lived processes
# for non-containerized services or dependencies.
#
# More info: https://docs.tilt.dev/local_resource.html
#
# local_resource('install-helm',
# cmd='which helm > /dev/null || brew install helm',
# # `cmd_bat`, when present, is used instead of `cmd` on Windows.
# cmd_bat=[
# 'powershell.exe',
# '-Noninteractive',
# '-Command',
# '& {if (!(Get-Command helm -ErrorAction SilentlyContinue)) {scoop install helm}}'
# ]
# )
# Teach tilt about our custom resources (Note, this may be intended for workloads)
# k8s_kind('authorizationpolicy')
# k8s_kind('requestauthentication')
# k8s_kind('virtualservice')
k8s_kind('pgadmin')
# Troubleshooting
def resource_name(id):
print('resource: {}'.format(id))
return id.name
workload_to_resource_function(resource_name)
# Apply Kubernetes manifests
# Tilt will build & push any necessary images, re-deploying your
# resources as they change.
#
# More info: https://docs.tilt.dev/api.html#api.k8s_yaml
#
def holos_yaml():
"""Return a k8s Deployment personalized for the developer."""
k8s_yaml_template = str(read_file('./hack/tilt/k8s.yaml'))
return k8s_yaml_template.format(
name=holos_server,
developer=developer,
namespace=namespace,
listen_port=listen_port,
metrics_port=metrics_port,
tz=os.getenv('TZ'),
)
# Customize a Kubernetes resource
# By default, Kubernetes resource names are automatically assigned
# based on objects in the YAML manifests, e.g. Deployment name.
#
# Tilt strives for sane defaults, so calling k8s_resource is
# optional, and you only need to pass the arguments you want to
# override.
#
# More info: https://docs.tilt.dev/api.html#api.k8s_resource
#
k8s_yaml(blob(holos_yaml()))
# Backend server process
k8s_resource(
workload=holos_server,
new_name=holos_backend,
objects=[
'{}:serviceaccount'.format(holos_server),
'{}:servicemonitor'.format(holos_server),
],
resource_deps=[compile_id],
links=[
link('https://{}.app.dev.k2.holos.run/ui/'.format(developer), "Holos Web UI")
],
)
# AuthorizationPolicy - Beyond Corp functionality
k8s_resource(
new_name=auth_id,
objects=[
'{}:virtualservice'.format(holos_server),
],
)
# Database
# Note: Tilt confuses the backup pods with the database server pods, so this code is careful to tease the pods
# apart so logs are streamed correctly.
# See: https://github.com/tilt-dev/tilt.specs/blob/master/resource_assembly.md
# pgAdmin Web UI
k8s_resource(
workload=pg_admin_name,
new_name=pg_admin,
port_forwards=[
port_forward(15050, 5050, pg_admin),
],
)
# Disabled because these don't group resources nicely
# k8s_kind('postgrescluster')
# Postgres database in-cluster
k8s_resource(
new_name=pg_cluster,
objects=['holos:postgrescluster'],
)
# Needed to select the database by label
# https://docs.tilt.dev/api.html#api.k8s_custom_deploy
k8s_custom_deploy(
pg_svc,
apply_cmd=['./hack/tilt/k8s-get-db-sts', pg_cluster_name],
delete_cmd=['echo', 'Skipping delete. Object managed by custom resource.'],
deps=[],
)
k8s_resource(
pg_svc,
port_forwards=[
port_forward(15432, 5432, 'psql'),
],
resource_deps=[pg_cluster]
)
# Run tests
local_resource(
tests_id,
'make test',
allow_parallel=True,
auto_init=False,
deps=developer_paths,
)
# Run linter
local_resource(
lint_id,
'make lint',
allow_parallel=True,
auto_init=False,
deps=developer_paths,
)
# UI Buttons for helpful things.
# Icons: https://fonts.google.com/icons
os.putenv("GH_FORCE_TTY", "80%")
cmd_button(
'{}:go-test-failfast'.format(tests_id),
argv=['./hack/tilt/go-test-failfast'],
resource=tests_id,
icon_name='quiz',
text='Fail Fast',
)
cmd_button(
'{}:issues'.format(holos_server),
argv=['./hack/tilt/gh-issues'],
resource=holos_backend,
icon_name='folder_data',
text='Issues',
)
cmd_button(
'{}:gh-issue-view'.format(holos_server),
argv=['./hack/tilt/gh-issue-view'],
resource=holos_backend,
icon_name='task',
text='View Issue',
)
cmd_button(
'{}:get-pgdb-creds'.format(holos_server),
argv=['./hack/tilt/get-pgdb-creds', pg_cluster_name, pg_database_name],
resource=pg_svc,
icon_name='lock_open_right',
text='DB Creds',
)
cmd_button(
'{}:get-pgdb-creds'.format(pg_admin_name),
argv=['./hack/tilt/get-pgdb-creds', pg_cluster_name, pg_database_name],
resource=pg_admin,
icon_name='lock_open_right',
text='DB Creds',
)
cmd_button(
'{}:get-pgadmin-creds'.format(pg_admin_name),
argv=['./hack/tilt/get-pgadmin-creds', pg_admin_name],
resource=pg_admin,
icon_name='lock_open_right',
text='pgAdmin Login',
)
print("✨ Tiltfile evaluated")

View File

@@ -0,0 +1,38 @@
package v1alpha2
import "google.golang.org/protobuf/types/known/structpb"
// Label is an arbitrary unique identifier. Defined as a type for clarity and type checking.
type Label string
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
type Kind string
// 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 [HolosComponent].
type APIObjectMap map[Kind]map[Label]string
// APIObjects represents kubernetes api objects to apply to the api server.
// Useful to mix in resources to each HolosComponent type, for example adding an
// ExternalSecret to a HelmChart HolosComponent.
//
// Kind must be the resource kind, e.g. Deployment or Service.
//
// Label 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 [HolosComponent] which accepts an [APIObjectMap] field provided by
// [APIObjects].
type APIObjects struct {
// APIObjects represents Kubernetes API objects defined directly from CUE
// code. Useful to mix in resources, for example adding an ExternalSecret
// resource to a HelmChart HolosComponent.
APIObjects map[Kind]map[Label]structpb.Struct `json:"apiObjects"`
// APIObjectMap represents the marshalled yaml representation of APIObjects,
// useful to inspect the rendered representation of the resource which will be
// sent to the kubernetes API server.
APIObjectMap APIObjectMap `json:"apiObjectMap"`
}

View File

@@ -0,0 +1,116 @@
package v1alpha2
import (
"fmt"
"strings"
)
// FileContentMap represents a mapping of file names to file content.
type FileContentMap map[string]string
// BuildPlan represents a build plan for the holos cli to execute. A build plan
// is a set of zero or more holos components. The purpose of a BuildPlan is to
// define one or more [HolosComponent] kinds, for example a [HelmChart] or
// [KustomizeBuild].
//
// A BuildPlan usually has an additional empty [KubernetesObjects] for the
// purpose of using the [HolosComponent] 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 | *\"v1alpha2\""`
Spec BuildPlanSpec `json:"spec"`
}
func (bp *BuildPlan) Validate() error {
errs := make([]string, 0, 2)
if bp.Kind != BuildPlanKind {
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", BuildPlanKind, bp.Kind))
}
if bp.APIVersion != APIVersion {
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 nil
}
func (bp *BuildPlan) ResultCapacity() (count int) {
if bp == nil {
return 0
}
count = len(bp.Spec.Components.HelmChartList) +
len(bp.Spec.Components.KubernetesObjectsList) +
len(bp.Spec.Components.KustomizeBuildList) +
len(bp.Spec.Components.Resources)
return count
}
type BuildPlanSpec struct {
Disabled bool `json:"disabled,omitempty"`
Components BuildPlanComponents `json:"components,omitempty"`
}
type BuildPlanComponents struct {
Resources map[string]KubernetesObjects `json:"resources,omitempty"`
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty"`
HelmChartList []HelmChart `json:"helmChartList,omitempty"`
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty"`
}
// HolosComponent defines the fields common to all holos component kinds. Every
// holos component kind should embed HolosComponent.
type HolosComponent 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:"string | *\"v1alpha2\""`
// 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 HolosComponent type, for example adding an
// ExternalSecret to a HelmChart HolosComponent. 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 holos component 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 CRD's and DeployFiles functionality.
// +optional
Namespace string `json:"namespace,omitempty"`
}
// Kustomize represents resources necessary to execute a kustomize build.
// Intended for at least two use cases:
//
// 1. Process a [KustomizeBuild] [HolosComponent] which represents raw yaml
// file resources in a holos component directory.
// 2. Post process a [HelmChart] [HolosComponent] 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,11 @@
package v1alpha2
const (
APIVersion = "v1alpha2"
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"
)

49
api/core/v1alpha2/core.go Normal file
View File

@@ -0,0 +1,49 @@
// Package v1alpha2 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.
package v1alpha2
import "google.golang.org/protobuf/types/known/structpb"
type PlatformMetadata struct {
// Name represents the Platform name.
Name string `json:"name"`
}
// 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 | *\"v1alpha2\""`
// Metadata represents data about the object such as the Name.
Metadata PlatformMetadata `json:"metadata"`
// Spec represents the specification.
Spec PlatformSpec `json:"spec"`
}
// 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"`
// 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"`
}

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

@@ -0,0 +1,38 @@
package v1alpha2
// 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 [HolosComponent], for
// example [Kustomize] post-rendering and mixing in additional kubernetes api
// objects.
type HelmChart struct {
HolosComponent `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 v1alpha2
const KubernetesObjectsKind = "KubernetesObjects"
// KubernetesObjects represents a [HolosComponent] composed of kubernetes api
// objects provided directly from CUE using [APIObjects].
type KubernetesObjects struct {
HolosComponent `json:",inline"`
Kind string `json:"kind" cue:"\"KubernetesObjects\""`
}

View File

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

37
api/meta/v1alpha2/meta.go Normal file
View File

@@ -0,0 +1,37 @@
package v1alpha2
// TypeMeta describes an individual object in an API response or request with
// strings representing the type of the object and its API schema version.
// Structures that are versioned or persisted should inline TypeMeta.
type TypeMeta struct {
// Kind is a string value representing the resource this object represents.
Kind string `json:"kind"`
// APIVersion defines the versioned schema of this representation of an object.
APIVersion string `json:"apiVersion" cue:"string | *\"v1alpha2\""`
}
func (tm *TypeMeta) GetKind() string {
return tm.Kind
}
func (tm *TypeMeta) GetAPIVersion() string {
return tm.APIVersion
}
// Discriminator discriminates the kind of an api object.
type Discriminator interface {
// GetKind returns Kind.
GetKind() string
// GetAPIVersion returns APIVersion.
GetAPIVersion() string
}
// ObjectMeta represents metadata of a holos component object. The fields are a
// copy of upstream kubernetes api machinery but are holos objects distinct from
// kubernetes api objects.
type ObjectMeta struct {
// Name uniquely identifies the holos component instance and must be suitable as a file name.
Name string `json:"name,omitempty"`
// Namespace confines a holos component to a single namespace via kustomize if set.
Namespace string `json:"namespace,omitempty"`
}

55
api/v1alpha1/buildplan.go Normal file
View File

@@ -0,0 +1,55 @@
package v1alpha1
import (
"fmt"
"strings"
)
// BuildPlan is the primary interface between CUE and the Holos cli.
type BuildPlan struct {
TypeMeta `json:",inline" yaml:",inline"`
// Metadata represents the holos component name
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Spec BuildPlanSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
}
type BuildPlanSpec struct {
Disabled bool `json:"disabled,omitempty" yaml:"disabled,omitempty"`
Components BuildPlanComponents `json:"components,omitempty" yaml:"components,omitempty"`
// DeployFiles keys represent file paths relative to the cluster deploy
// directory. Map values represent the string encoded file contents. Used to
// write the argocd Application, but may be used to render any file from CUE.
DeployFiles FileContentMap `json:"deployFiles,omitempty" yaml:"deployFiles,omitempty"`
}
type BuildPlanComponents struct {
HelmChartList []HelmChart `json:"helmChartList,omitempty" yaml:"helmChartList,omitempty"`
KubernetesObjectsList []KubernetesObjects `json:"kubernetesObjectsList,omitempty" yaml:"kubernetesObjectsList,omitempty"`
KustomizeBuildList []KustomizeBuild `json:"kustomizeBuildList,omitempty" yaml:"kustomizeBuildList,omitempty"`
Resources map[string]KubernetesObjects `json:"resources,omitempty" yaml:"resources,omitempty"`
}
func (bp *BuildPlan) Validate() error {
errs := make([]string, 0, 2)
if bp.Kind != BuildPlanKind {
errs = append(errs, fmt.Sprintf("kind invalid: want: %s have: %s", BuildPlanKind, bp.Kind))
}
if bp.APIVersion != APIVersion {
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 nil
}
func (bp *BuildPlan) ResultCapacity() (count int) {
if bp == nil {
return 0
}
count = len(bp.Spec.Components.HelmChartList) +
len(bp.Spec.Components.KubernetesObjectsList) +
len(bp.Spec.Components.KustomizeBuildList) +
len(bp.Spec.Components.Resources)
return count
}

30
api/v1alpha1/component.go Normal file
View File

@@ -0,0 +1,30 @@
package v1alpha1
// HolosComponent defines the fields common to all holos component kinds including the Render Result.
type HolosComponent struct {
TypeMeta `json:",inline" yaml:",inline"`
// Metadata represents the holos component name
Metadata ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
// APIObjectMap holds the marshalled representation of api objects. Think of
// these as resources overlaid at the back of the render pipeline.
APIObjectMap APIObjectMap `json:"apiObjectMap,omitempty" yaml:"apiObjectMap,omitempty"`
// Kustomization holds the marshalled representation of the flux kustomization
// which reconciles resources in git with the api server.
Kustomization `json:",inline" yaml:",inline"`
// Kustomize represents a kubectl kustomize build post-processing step.
Kustomize `json:",inline" yaml:",inline"`
// Skip causes holos to take no action regarding the component.
Skip bool
}
func (hc *HolosComponent) NewResult() *Result {
return &Result{HolosComponent: *hc}
}
func (hc *HolosComponent) GetAPIVersion() string {
return hc.APIVersion
}
func (hc *HolosComponent) GetKind() string {
return hc.Kind
}

11
api/v1alpha1/constants.go Normal file
View File

@@ -0,0 +1,11 @@
package v1alpha1
const (
APIVersion = "holos.run/v1alpha1"
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"
)

2
api/v1alpha1/doc.go Normal file
View File

@@ -0,0 +1,2 @@
// Package v1alpha1 defines the api boundary between CUE and Holos.
package v1alpha1

13
api/v1alpha1/form.go Normal file
View File

@@ -0,0 +1,13 @@
package v1alpha1
import object "github.com/holos-run/holos/service/gen/holos/object/v1alpha1"
// Form represents a collection of Formly json powered form.
type Form struct {
TypeMeta `json:",inline" yaml:",inline"`
Spec FormSpec `json:"spec" yaml:"spec"`
}
type FormSpec struct {
Form object.Form `json:"form" yaml:"form"`
}

184
api/v1alpha1/helm.go Normal file
View File

@@ -0,0 +1,184 @@
package v1alpha1
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/holos-run/holos"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/logger"
"github.com/holos-run/holos/internal/util"
)
// A HelmChart represents a helm command to provide chart values in order to render kubernetes api objects.
type HelmChart struct {
HolosComponent `json:",inline" yaml:",inline"`
// Namespace is the namespace to install into. TODO: Use metadata.namespace instead.
Namespace string `json:"namespace"`
Chart Chart `json:"chart"`
ValuesContent string `json:"valuesContent"`
EnableHooks bool `json:"enableHooks"`
}
type Chart struct {
Name string `json:"name"`
Version string `json:"version"`
Release string `json:"release"`
Repository Repository `json:"repository,omitempty"`
}
type Repository struct {
Name string `json:"name"`
URL string `json:"url"`
}
func (hc *HelmChart) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
result := Result{HolosComponent: hc.HolosComponent}
if err := hc.helm(ctx, &result, path); err != nil {
return nil, err
}
result.addObjectMap(ctx, hc.APIObjectMap)
if err := result.kustomize(ctx); err != nil {
return nil, errors.Wrap(fmt.Errorf("could not kustomize: %w", err))
}
return &result, nil
}
// runHelm provides the values produced by CUE to helm template and returns
// the rendered kubernetes api objects in the result.
func (hc *HelmChart) helm(ctx context.Context, r *Result, path holos.InstancePath) error {
log := logger.FromContext(ctx).With("chart", hc.Chart.Name)
if hc.Chart.Name == "" {
log.WarnContext(ctx, "skipping helm: no chart name specified, use a different component type")
return nil
}
cachedChartPath := filepath.Join(string(path), ChartDir, filepath.Base(hc.Chart.Name))
if isNotExist(cachedChartPath) {
// Add repositories
repo := hc.Chart.Repository
if repo.URL != "" {
out, err := util.RunCmd(ctx, "helm", "repo", "add", repo.Name, repo.URL)
if err != nil {
log.ErrorContext(ctx, "could not run helm", "stderr", out.Stderr.String(), "stdout", out.Stdout.String())
return errors.Wrap(fmt.Errorf("could not run helm repo add: %w", err))
}
// Update repository
out, err = util.RunCmd(ctx, "helm", "repo", "update", repo.Name)
if err != nil {
log.ErrorContext(ctx, "could not run helm", "stderr", out.Stderr.String(), "stdout", out.Stdout.String())
return errors.Wrap(fmt.Errorf("could not run helm repo update: %w", err))
}
} else {
log.DebugContext(ctx, "no chart repository url proceeding assuming oci chart")
}
// Cache the chart
if err := cacheChart(ctx, path, ChartDir, hc.Chart); err != nil {
return fmt.Errorf("could not cache chart: %w", err)
}
}
// Write values file
tempDir, err := os.MkdirTemp("", "holos")
if err != nil {
return errors.Wrap(fmt.Errorf("could not make temp dir: %w", err))
}
defer util.Remove(ctx, tempDir)
valuesPath := filepath.Join(tempDir, "values.yaml")
if err := os.WriteFile(valuesPath, []byte(hc.ValuesContent), 0644); err != nil {
return errors.Wrap(fmt.Errorf("could not write values: %w", err))
}
log.DebugContext(ctx, "helm: wrote values", "path", valuesPath, "bytes", len(hc.ValuesContent))
// Run charts
chart := hc.Chart
args := []string{"template"}
if !hc.EnableHooks {
args = append(args, "--no-hooks")
}
namespace := hc.Namespace
args = append(args, "--include-crds", "--values", valuesPath, "--namespace", namespace, "--kubeconfig", "/dev/null", "--version", chart.Version, chart.Release, cachedChartPath)
helmOut, err := util.RunCmd(ctx, "helm", args...)
if err != nil {
stderr := helmOut.Stderr.String()
lines := strings.Split(stderr, "\n")
for _, line := range lines {
if strings.HasPrefix(line, "Error:") {
err = fmt.Errorf("%s: %w", line, err)
}
}
return errors.Wrap(fmt.Errorf("could not run helm template: %w", err))
}
r.accumulatedOutput = helmOut.Stdout.String()
return nil
}
// cacheChart stores a cached copy of Chart in the chart subdirectory of path.
//
// It is assumed that the only method responsible for writing to chartDir is
// cacheChart itself.
//
// This relies on the atomicity of moving temporary directories into place on
// the same filesystem via os.Rename. If a syscall.EEXIST error occurs during
// renaming, it indicates that the cached chart already exists, which is an
// expected scenario when this function is called concurrently.
func cacheChart(ctx context.Context, path holos.InstancePath, chartDir string, chart Chart) error {
log := logger.FromContext(ctx)
cacheTemp, err := os.MkdirTemp(string(path), chartDir)
if err != nil {
return errors.Wrap(fmt.Errorf("could not make temp dir: %w", err))
}
defer util.Remove(ctx, cacheTemp)
chartName := chart.Name
if chart.Repository.Name != "" {
chartName = fmt.Sprintf("%s/%s", chart.Repository.Name, chart.Name)
}
helmOut, err := util.RunCmd(ctx, "helm", "pull", "--destination", cacheTemp, "--untar=true", "--version", chart.Version, chartName)
if err != nil {
return errors.Wrap(fmt.Errorf("could not run helm pull: %w", err))
}
log.Debug("helm pull", "stdout", helmOut.Stdout, "stderr", helmOut.Stderr)
cachePath := filepath.Join(string(path), chartDir)
if err := os.MkdirAll(cachePath, 0777); err != nil {
return errors.Wrap(fmt.Errorf("could not mkdir: %w", err))
}
items, err := os.ReadDir(cacheTemp)
if err != nil {
return errors.Wrap(fmt.Errorf("could not read directory: %w", err))
}
for _, item := range items {
src := filepath.Join(cacheTemp, item.Name())
dst := filepath.Join(cachePath, item.Name())
log.DebugContext(ctx, "rename", "src", src, "dst", dst)
if err := os.Rename(src, dst); err != nil {
var linkErr *os.LinkError
if errors.As(err, &linkErr) && errors.Is(linkErr.Err, syscall.EEXIST) {
log.DebugContext(ctx, "cache already exists", "chart", chart.Name, "chart_version", chart.Version, "path", cachePath)
} else {
return errors.Wrap(fmt.Errorf("could not rename: %w", err))
}
}
}
log.InfoContext(ctx, "cached", "chart", chart.Name, "chart_version", chart.Version, "path", cachePath)
return nil
}
func isNotExist(path string) bool {
_, err := os.Stat(path)
return os.IsNotExist(err)
}

View File

@@ -0,0 +1,21 @@
package v1alpha1
import (
"context"
"github.com/holos-run/holos"
)
const KubernetesObjectsKind = "KubernetesObjects"
// KubernetesObjects represents CUE output which directly provides Kubernetes api objects to holos.
type KubernetesObjects struct {
HolosComponent `json:",inline" yaml:",inline"`
}
// Render produces kubernetes api objects from the APIObjectMap
func (o *KubernetesObjects) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
result := Result{HolosComponent: o.HolosComponent}
result.addObjectMap(ctx, o.APIObjectMap)
return &result, nil
}

View File

@@ -0,0 +1,7 @@
package v1alpha1
// Kustomization holds the rendered flux kustomization api object content for git ops.
type Kustomization struct {
// KsContent is the yaml representation of the flux kustomization for gitops.
KsContent string `json:"ksContent,omitempty" yaml:"ksContent,omitempty"`
}

47
api/v1alpha1/kustomize.go Normal file
View File

@@ -0,0 +1,47 @@
package v1alpha1
import (
"context"
"github.com/holos-run/holos"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/logger"
"github.com/holos-run/holos/internal/util"
)
const KustomizeBuildKind = "KustomizeBuild"
// Kustomize represents resources necessary to execute a kustomize build.
// Intended for at least two use cases:
//
// 1. Process raw yaml file resources in a holos component directory.
// 2. Post process a HelmChart to inject istio, add custom labels, etc...
type Kustomize struct {
// KustomizeFiles holds file contents for kustomize, e.g. patch files.
KustomizeFiles FileContentMap `json:"kustomizeFiles,omitempty" yaml:"kustomizeFiles,omitempty"`
// ResourcesFile is the file name used for api objects in kustomization.yaml
ResourcesFile string `json:"resourcesFile,omitempty" yaml:"resourcesFile,omitempty"`
}
// KustomizeBuild renders plain yaml files in the holos component directory using kubectl kustomize build.
type KustomizeBuild struct {
HolosComponent `json:",inline" yaml:",inline"`
}
// Render produces a Result by executing kubectl kustomize on the holos
// component path. Useful for processing raw yaml files.
func (kb *KustomizeBuild) Render(ctx context.Context, path holos.InstancePath) (*Result, error) {
log := logger.FromContext(ctx)
result := Result{HolosComponent: kb.HolosComponent}
// Run kustomize.
kOut, err := util.RunCmd(ctx, "kubectl", "kustomize", string(path))
if err != nil {
log.ErrorContext(ctx, kOut.Stderr.String())
return nil, errors.Wrap(err)
}
// Replace the accumulated output
result.accumulatedOutput = kOut.Stdout.String()
// Add CUE based api objects.
result.addObjectMap(ctx, kb.APIObjectMap)
return &result, nil
}

14
api/v1alpha1/objectmap.go Normal file
View File

@@ -0,0 +1,14 @@
package v1alpha1
// Label is an arbitrary unique identifier. Defined as a type for clarity and type checking.
type Label string
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
type Kind string
// APIObjectMap is the shape of marshalled api objects returned from cue to the
// holos cli. A map is used to improve the clarity of error messages from cue.
type APIObjectMap map[Kind]map[Label]string
// FileContentMap is a map of file names to file contents.
type FileContentMap map[string]string

View File

@@ -0,0 +1,15 @@
package v1alpha1
// ObjectMeta represents metadata of a holos component object. The fields are a
// copy of upstream kubernetes api machinery but are by holos objects distinct
// from kubernetes api objects.
type ObjectMeta struct {
// Name uniquely identifies the holos component instance and must be suitable as a file name.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Namespace confines a holos component to a single namespace via kustomize if set.
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
// Labels are not used but are copied from api machinery ObjectMeta for completeness.
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
// Annotations are not used but are copied from api machinery ObjectMeta for completeness.
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
}

32
api/v1alpha1/platform.go Normal file
View File

@@ -0,0 +1,32 @@
package v1alpha1
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 {
TypeMeta `json:",inline" yaml:",inline"`
Metadata ObjectMeta `json:"metadata" yaml:"metadata"`
Spec PlatformSpec `json:"spec" yaml:"spec"`
}
// PlatformSpec represents the platform build plan specification.
type PlatformSpec struct {
// Model represents the platform model holos gets from from the
// holos.platform.v1alpha1.PlatformService.GetPlatform method and provides to
// CUE using a tag.
Model structpb.Struct `json:"model" yaml:"model"`
Components []PlatformSpecComponent `json:"components" yaml:"components"`
}
// PlatformSpecComponent represents a component to build or render with flags to
// pass, for example the cluster name.
type PlatformSpecComponent struct {
// Path is the path of the component relative to the platform root.
Path string `json:"path" yaml:"path"`
// Cluster is the cluster name to use when building the component.
Cluster string `json:"cluster" yaml:"cluster"`
}

22
api/v1alpha1/render.go Normal file
View File

@@ -0,0 +1,22 @@
package v1alpha1
import (
"context"
"github.com/holos-run/holos"
)
type Renderer interface {
GetKind() string
Render(ctx context.Context, path holos.InstancePath) (*Result, error)
}
// Render produces a Result representing the kubernetes api objects to
// configure. Each of the various holos component types, e.g. Helm, Kustomize,
// et al, should implement the Renderer interface. This process is best
// conceptualized as a data pipeline, for example a component may render a
// result by first calling helm template, then passing the result through
// kustomize, then mixing in overlay api objects.
func Render(ctx context.Context, r Renderer, path holos.InstancePath) (*Result, error) {
return r.Render(ctx, path)
}

165
api/v1alpha1/result.go Normal file
View File

@@ -0,0 +1,165 @@
package v1alpha1
import (
"context"
"fmt"
"os"
"path/filepath"
"slices"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/logger"
"github.com/holos-run/holos/internal/util"
)
// Result is the build result for display or writing. Holos components Render the Result as a data pipeline.
type Result struct {
HolosComponent
// accumulatedOutput accumulates rendered api objects.
accumulatedOutput string
// DeployFiles keys represent file paths relative to the cluster deploy
// directory. Map values represent the string encoded file contents. Used to
// write the argocd Application, but may be used to render any file from CUE.
DeployFiles FileContentMap `json:"deployFiles,omitempty" yaml:"deployFiles,omitempty"`
}
// Continue returns true if Skip is true indicating the result is to be skipped over.
func (r *Result) Continue() bool {
if r == nil {
return false
}
return r.Skip
}
func (r *Result) Name() string {
return r.Metadata.Name
}
func (r *Result) Filename(writeTo string, cluster string) string {
name := r.Metadata.Name
return filepath.Join(writeTo, "clusters", cluster, "components", name, name+".gen.yaml")
}
func (r *Result) KustomizationFilename(writeTo string, cluster string) string {
return filepath.Join(writeTo, "clusters", cluster, "holos", "components", r.Metadata.Name+"-kustomization.gen.yaml")
}
// AccumulatedOutput returns the accumulated rendered output.
func (r *Result) AccumulatedOutput() string {
return r.accumulatedOutput
}
// addObjectMap renders the provided APIObjectMap into the accumulated output.
func (r *Result) addObjectMap(ctx context.Context, objectMap APIObjectMap) {
log := logger.FromContext(ctx)
b := []byte(r.AccumulatedOutput())
kinds := make([]Kind, 0, len(objectMap))
// Sort the keys
for kind := range objectMap {
kinds = append(kinds, kind)
}
slices.Sort(kinds)
for _, kind := range kinds {
v := objectMap[kind]
// Sort the keys
names := make([]Label, 0, len(v))
for name := range v {
names = append(names, name)
}
slices.Sort(names)
for _, name := range names {
yamlString := v[name]
log.Debug(fmt.Sprintf("%s/%s", kind, name), "kind", kind, "name", name)
b = util.EnsureNewline(b)
header := fmt.Sprintf("---\n# Source: CUE apiObjects.%s.%s\n", kind, name)
b = append(b, []byte(header+yamlString)...)
b = util.EnsureNewline(b)
}
}
r.accumulatedOutput = string(b)
}
// kustomize replaces the accumulated output with the output of kustomize build
func (r *Result) kustomize(ctx context.Context) error {
log := logger.FromContext(ctx)
if r.ResourcesFile == "" {
log.DebugContext(ctx, "skipping kustomize: no resourcesFile")
return nil
}
if len(r.KustomizeFiles) < 1 {
log.DebugContext(ctx, "skipping kustomize: no kustomizeFiles")
return nil
}
tempDir, err := os.MkdirTemp("", "holos.kustomize")
if err != nil {
return errors.Wrap(err)
}
defer util.Remove(ctx, tempDir)
// Write the main api object resources file for kustomize.
target := filepath.Join(tempDir, r.ResourcesFile)
b := []byte(r.AccumulatedOutput())
b = util.EnsureNewline(b)
if err := os.WriteFile(target, b, 0644); err != nil {
return errors.Wrap(fmt.Errorf("could not write resources: %w", err))
}
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
// Write the kustomization tree, kustomization.yaml must be in this map for kustomize to work.
for file, content := range r.KustomizeFiles {
target := filepath.Join(tempDir, file)
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
return errors.Wrap(err)
}
b := []byte(content)
b = util.EnsureNewline(b)
if err := os.WriteFile(target, b, 0644); err != nil {
return errors.Wrap(fmt.Errorf("could not write: %w", err))
}
log.DebugContext(ctx, "wrote: "+target, "op", "write", "path", target, "bytes", len(b))
}
// Run kustomize.
kOut, err := util.RunCmd(ctx, "kubectl", "kustomize", tempDir)
if err != nil {
log.ErrorContext(ctx, kOut.Stderr.String())
return errors.Wrap(err)
}
// Replace the accumulated output
r.accumulatedOutput = kOut.Stdout.String()
return nil
}
func (r *Result) WriteDeployFiles(ctx context.Context, path string) error {
log := logger.FromContext(ctx)
if len(r.DeployFiles) == 0 {
return nil
}
for k, content := range r.DeployFiles {
path := filepath.Join(path, k)
if err := r.Save(ctx, path, content); err != nil {
return errors.Wrap(err)
}
log.InfoContext(ctx, "wrote deploy file", "path", path, "bytes", len(content))
}
return nil
}
// Save writes the content to the filesystem for git ops.
func (r *Result) Save(ctx context.Context, path string, content string) error {
log := logger.FromContext(ctx)
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, os.FileMode(0775)); err != nil {
log.WarnContext(ctx, "could not mkdir", "path", dir, "err", err)
return errors.Wrap(err)
}
// Write the file content
if err := os.WriteFile(path, []byte(content), os.FileMode(0644)); err != nil {
log.WarnContext(ctx, "could not write", "path", path, "err", err)
return errors.Wrap(err)
}
log.DebugContext(ctx, "out: wrote "+path, "action", "write", "path", path, "status", "ok")
return nil
}

20
api/v1alpha1/typemeta.go Normal file
View File

@@ -0,0 +1,20 @@
package v1alpha1
type TypeMeta struct {
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
}
func (tm *TypeMeta) GetKind() string {
return tm.Kind
}
func (tm *TypeMeta) GetAPIVersion() string {
return tm.APIVersion
}
// Discriminator is an interface to discriminate the kind api object.
type Discriminator interface {
GetKind() string
GetAPIVersion() string
}

20
buf.gen.yaml Normal file
View File

@@ -0,0 +1,20 @@
# Generates gRPC and ConnectRPC bindings for Go and TypeScript
#
# Note: protoc-gen-connect-query is the primary method of wiring up the React
# frontend.
version: v1
plugins:
- plugin: go
out: service/gen
opt: paths=source_relative
- plugin: connect-go
out: service/gen
opt: paths=source_relative
- plugin: es
out: internal/frontend/holos/src/app/gen
opt:
- target=ts
- plugin: connect-es
out: internal/frontend/holos/src/app/gen
opt:
- target=ts

8
buf.lock Normal file
View File

@@ -0,0 +1,8 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: bufbuild
repository: protovalidate
commit: b983156c5e994cc9892e0ce3e64e17e0
digest: shake256:fb47a62989d38c2529bcc5cd86ded43d800eb84cee82b42b9e8a9e815d4ee8134a0fb9d0ce8299b27c2d2bbb7d6ade0c4ad5a8a4d467e1e2c7ca619ae9f634e2

3
buf.work.yaml Normal file
View File

@@ -0,0 +1,3 @@
version: v1
directories:
- service

View File

@@ -1,8 +1,9 @@
package main
import (
"github.com/holos-run/holos/pkg/cli"
"os"
"github.com/holos-run/holos/internal/cli"
)
func main() {

View File

@@ -1,10 +1,11 @@
package main
import (
"github.com/holos-run/holos/pkg/cli"
"github.com/rogpeppe/go-internal/testscript"
"os"
"testing"
"github.com/holos-run/holos/internal/cli"
"github.com/rogpeppe/go-internal/testscript"
)
func TestMain(m *testing.M) {

34
cmd/holos/testdata/constraints.txt vendored Normal file
View File

@@ -0,0 +1,34 @@
# Want support for intermediary constraints
exec holos build ./foo/... --log-level debug
stdout '^bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b$'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- foo/constraints.cue --
package holos
metadata: name: "jeff"
-- foo/bar/bar.cue --
package holos
spec: components: KubernetesObjectsList: [
#KubernetesObjects & {
apiObjectMap: foo: bar: "bf2bc7f9-9ba0-4f9e-9bd2-9a205627eb0b"
}
]
-- schema.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#KubernetesObjects: {
apiVersion: "holos.run/v1alpha1"
kind: "KubernetesObjects"
apiObjectMap: {...}
}
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"

View File

@@ -1,15 +1,20 @@
# Want cue errors to show files and lines
! exec holos build .
stderr 'could not decode: content: cannot convert non-concrete value string'
stderr '/component.cue:6:1$'
stderr 'apiObjectMap.foo.bar: cannot convert incomplete value'
stderr '/component.cue:\d+:\d+$'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
apiVersion: "holos.run/v1alpha1"
kind: "KubernetesObjects"
cluster: string @tag(cluster, string)
content: foo
foo: string
kind: "BuildPlan"
spec: components: KubernetesObjectsList: [{apiObjectMap: foo: bar: _baz}]
_baz: string

View File

@@ -0,0 +1,61 @@
# Want kube api objects in the apiObjects output.
exec holos build .
stdout '^kind: SecretStore$'
stdout '# Source: CUE apiObjects.SecretStore.default'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: KubernetesObjectsList: [{apiObjectMap: #APIObjects.apiObjectMap}]
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#SecretStore: {
kind: string
metadata: name: string
}
#APIObjects: {
apiObjects: {
SecretStore: {
default: #SecretStore & { metadata: name: "default" }
}
}
}
-- schema.cue --
package holos
// #APIObjects is the output type for api objects produced by cue. A map is used to aid debugging and clarity.
import "encoding/yaml"
#APIObjects: {
// apiObjects holds each the api objects produced by cue.
apiObjects: {
[Kind=_]: {
[Name=_]: {
kind: Kind
metadata: name: Name
}
}
}
// apiObjectsContent holds the marshalled representation of apiObjects
apiObjectMap: {
for kind, v in apiObjects {
"\(kind)": {
for name, obj in v {
"\(name)": yaml.Marshal(obj)
}
}
}
}
}

View File

@@ -0,0 +1,62 @@
# Want kube api objects in the apiObjects output.
exec holos build .
stdout '^kind: SecretStore$'
stdout '# Source: CUE apiObjects.SecretStore.default'
stderr 'skipping helm: no chart name specified'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: HelmChartList: [{apiObjectMap: #APIObjects.apiObjectMap}]
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#SecretStore: {
kind: string
metadata: name: string
}
#APIObjects: {
apiObjects: {
SecretStore: {
default: #SecretStore & { metadata: name: "default" }
}
}
}
-- schema.cue --
package holos
// #APIObjects is the output type for api objects produced by cue. A map is used to aid debugging and clarity.
import "encoding/yaml"
#APIObjects: {
// apiObjects holds each the api objects produced by cue.
apiObjects: {
[Kind=_]: {
[Name=_]: {
kind: Kind
metadata: name: Name
}
}
}
// apiObjectsContent holds the marshalled representation of apiObjects
apiObjectMap: {
for kind, v in apiObjects {
"\(kind)": {
for name, obj in v {
"\(name)": yaml.Marshal(obj)
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
# Want api object kind and name in errors
! exec holos build .
stderr 'apiObjects.secretstore.default.foo: field not allowed'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "KubernetesObjects"
cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
#SecretStore: {
metadata: name: string
}
apiObjects: {
secretstore: {
default: #SecretStore & { foo: "not allowed" }
}
}

View File

@@ -0,0 +1,289 @@
# Want helm errors to show up
! exec holos build .
stderr 'Error: execution error at \(zitadel/templates/secret_zitadel-masterkey.yaml:2:4\): Either set .Values.zitadel.masterkey xor .Values.zitadel.masterkeySecretName'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- zitadel.cue --
package holos
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: HelmChartList: [_HelmChart]
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
_HelmChart: {
apiVersion: "holos.run/v1alpha1"
kind: "HelmChart"
metadata: name: "zitadel"
namespace: "zitadel"
chart: {
name: "zitadel"
version: "7.9.0"
release: name
repository: {
name: "zitadel"
url: "https://charts.zitadel.com"
}
}
}
-- vendor/zitadel/templates/secret_zitadel-masterkey.yaml --
{{- if (or (and .Values.zitadel.masterkey .Values.zitadel.masterkeySecretName) (and (not .Values.zitadel.masterkey) (not .Values.zitadel.masterkeySecretName)) ) }}
{{- fail "Either set .Values.zitadel.masterkey xor .Values.zitadel.masterkeySecretName" }}
{{- end }}
{{- if .Values.zitadel.masterkey -}}
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: zitadel-masterkey
{{- with .Values.zitadel.masterkeyAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "zitadel.labels" . | nindent 4 }}
stringData:
masterkey: {{ .Values.zitadel.masterkey }}
{{- end -}}
-- vendor/zitadel/Chart.yaml --
apiVersion: v2
appVersion: v2.46.0
description: A Helm chart for ZITADEL
icon: https://zitadel.com/zitadel-logo-dark.svg
kubeVersion: '>= 1.21.0-0'
maintainers:
- email: support@zitadel.com
name: zitadel
url: https://zitadel.com
name: zitadel
type: application
version: 7.9.0
-- vendor/zitadel/values.yaml --
# Default values for zitadel.
zitadel:
# The ZITADEL config under configmapConfig is written to a Kubernetes ConfigMap
# See all defaults here:
# https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
configmapConfig:
ExternalSecure: true
Machine:
Identification:
Hostname:
Enabled: true
Webhook:
Enabled: false
# The ZITADEL config under secretConfig is written to a Kubernetes Secret
# See all defaults here:
# https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
secretConfig:
# Annotations set on secretConfig secret
secretConfigAnnotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
# Reference the name of a secret that contains ZITADEL configuration.
configSecretName:
# The key under which the ZITADEL configuration is located in the secret.
configSecretKey: config-yaml
# ZITADEL uses the masterkey for symmetric encryption.
# You can generate it for example with tr -dc A-Za-z0-9 </dev/urandom | head -c 32
masterkey: ""
# Reference the name of the secret that contains the masterkey. The key should be named "masterkey".
# Note: Either zitadel.masterkey or zitadel.masterkeySecretName must be set
masterkeySecretName: ""
# Annotations set on masterkey secret
masterkeyAnnotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
# The CA Certificate needed for establishing secure database connections
dbSslCaCrt: ""
# The Secret containing the CA certificate at key ca.crt needed for establishing secure database connections
dbSslCaCrtSecret: ""
# The db admins secret containing the client certificate and key at tls.crt and tls.key needed for establishing secure database connections
dbSslAdminCrtSecret: ""
# The db users secret containing the client certificate and key at tls.crt and tls.key needed for establishing secure database connections
dbSslUserCrtSecret: ""
# Generate a self-signed certificate using an init container
# This will also mount the generated files to /etc/tls/ so that you can reference them in the pod.
# E.G. KeyPath: /etc/tls/tls.key CertPath: /etc/tls/tls.crt
# By default, the SAN DNS names include, localhost, the POD IP address and the POD name. You may include one more by using additionalDnsName like "my.zitadel.fqdn".
selfSignedCert:
enabled: false
additionalDnsName:
replicaCount: 3
image:
repository: ghcr.io/zitadel/zitadel
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
chownImage:
repository: alpine
pullPolicy: IfNotPresent
tag: "3.19"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# Annotations to add to the deployment
annotations: {}
# Annotations to add to the configMap
configMap:
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "0"
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podAdditionalLabels: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
securityContext: {}
# Additional environment variables
env:
[]
# - name: ZITADEL_DATABASE_POSTGRES_HOST
# valueFrom:
# secretKeyRef:
# name: postgres-pguser-postgres
# key: host
service:
type: ClusterIP
# If service type is "ClusterIP", this can optionally be set to a fixed IP address.
clusterIP: ""
port: 8080
protocol: http2
annotations: {}
scheme: HTTP
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: localhost
paths:
- path: /
pathType: Prefix
tls: []
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
topologySpreadConstraints: []
initJob:
# Once ZITADEL is installed, the initJob can be disabled.
enabled: true
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "1"
resources: {}
backoffLimit: 5
activeDeadlineSeconds: 300
extraContainers: []
podAnnotations: {}
# Available init commands :
# "": initialize ZITADEL instance (without skip anything)
# database: initialize only the database
# grant: set ALL grant to user
# user: initialize only the database user
# zitadel: initialize ZITADEL internals (skip "create user" and "create database")
command: ""
setupJob:
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation
helm.sh/hook-weight: "2"
resources: {}
activeDeadlineSeconds: 300
extraContainers: []
podAnnotations: {}
additionalArgs:
- "--init-projections=true"
machinekeyWriter:
image:
repository: bitnami/kubectl
tag: ""
resources: {}
readinessProbe:
enabled: true
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3
livenessProbe:
enabled: true
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3
startupProbe:
enabled: true
periodSeconds: 1
failureThreshold: 30
metrics:
enabled: false
serviceMonitor:
# If true, the chart creates a ServiceMonitor that is compatible with Prometheus Operator
# https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.ServiceMonitor.
# The Prometheus community Helm chart installs this operator
# https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack#kube-prometheus-stack
enabled: false
honorLabels: false
honorTimestamps: true
pdb:
enabled: false
# these values are used for the PDB and are mutally exclusive
minAvailable: 1
# maxUnavailable: 1
annotations: {}

View File

@@ -0,0 +1,39 @@
# Kustomize is a supported holos component kind
exec holos render component --cluster-name=mycluster . --log-level=debug
# Want generated output
cmp want.yaml deploy/clusters/mycluster/components/kstest/kstest.gen.yaml
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: KustomizeBuildList: [{metadata: name: "kstest"}]
-- kustomization.yaml --
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mynamespace
resources:
- serviceaccount.yaml
-- serviceaccount.yaml --
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
-- want.yaml --
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
namespace: mynamespace

View File

@@ -0,0 +1,17 @@
# https://github.com/holos-run/holos/issues/72
# Want holos to fail on unknown fields to catch typos and aid refactors
! exec holos build .
stderr 'unknown field \\"TypoKubernetesObjectsList\\"'
-- platform.config.json --
{}
-- cue.mod --
package holos
-- component.cue --
package holos
_cluster: string @tag(cluster, string)
_platform_config: string @tag(platform_config, string)
apiVersion: "holos.run/v1alpha1"
kind: "BuildPlan"
spec: components: TypoKubernetesObjectsList: []

View File

@@ -1,5 +1,3 @@
exec holos --version
# want version with no v on stdout
stdout -count=1 '^\d+\.\d+\.\d+$'
# want nothing on stderr
! stderr .

View File

@@ -0,0 +1,10 @@
{
"org_id": "018f36fb-e3f7-7f7f-a1c5-c85fb735d215",
"field_mask": {
"paths": [
"id",
"name",
"displayName"
]
}
}

View File

@@ -0,0 +1,8 @@
{
"update_mask": {
"paths": ["form"]
},
"update": {
"platform_id": "018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94"
}
}

View File

@@ -0,0 +1,11 @@
{
"update_mask": {
"paths": ["model","name","display_name"]
},
"update": {
"platform_id": "018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94",
"name": "bareplatform",
"display_name": "Bare Platform",
"model": {}
}
}

View File

@@ -0,0 +1,6 @@
{
"update": {
"platform_id": "018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94",
"model": {}
}
}

View File

@@ -0,0 +1,45 @@
package holos
import ap "security.istio.io/authorizationpolicy/v1"
// #AuthPolicyRules represents AuthorizationPolicy rules for hosts that need
// specialized treatment. Entries in this struct are excluded from
// AuthorizationPolicy/authproxy-custom in the istio-ingress namespace. Entries
// are added to their own AuthorizationPolicy.
#AuthPolicyRules: {
// AuthProxySpec represents the identity provider configuration
AuthProxySpec: #AuthProxySpec & #Platform.authproxy
// Hosts are hosts that need specialized treatment
hosts: {
[Name=_]: {
// name is the fully qualifed hostname, a Host: header value.
name: Name
// slug is the resource name prefix
slug: string
// NoAuthorizationPolicy disables an AuthorizationPolicy for the host
NoAuthorizationPolicy: true | *false
// Refer to https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule
spec: ap.#AuthorizationPolicySpec & {
action: "CUSTOM"
provider: name: AuthProxySpec.provider
selector: matchLabels: istio: "ingressgateway"
}
}
}
objects: #APIObjects & {
for Host in hosts {
if Host.NoAuthorizationPolicy == false {
apiObjects: {
AuthorizationPolicy: "\(Host.slug)-custom": {
metadata: namespace: "istio-ingress"
metadata: name: "\(Host.slug)-custom"
spec: Host.spec
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-certmanager/prod-mesh-certmanager.gen.yaml
package v1
import "strings"
// Order is a type to represent an Order with an ACME server
#Order: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "acme.cert-manager.io/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "Order"
metadata: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
spec!: #OrderSpec
}
#OrderSpec: {
// CommonName is the common name as specified on the DER encoded
// CSR. If specified, this value must also be present in
// `dnsNames` or `ipAddresses`. This field must match the
// corresponding field on the DER encoded CSR.
commonName?: string
// DNSNames is a list of DNS names that should be included as part
// of the Order validation process. This field must match the
// corresponding field on the DER encoded CSR.
dnsNames?: [...string]
// Duration is the duration for the not after date for the
// requested certificate. this is set on order creation as pe the
// ACME spec.
duration?: string
// IPAddresses is a list of IP addresses that should be included
// as part of the Order validation process. This field must match
// the corresponding field on the DER encoded CSR.
ipAddresses?: [...string]
// IssuerRef references a properly configured ACME-type Issuer
// which should be used to create this Order. If the Issuer does
// not exist, processing will be retried. If the Issuer is not an
// 'ACME' Issuer, an error will be returned and the Order will be
// marked as failed.
issuerRef: {
// Group of the resource being referred to.
group?: string
// Kind of the resource being referred to.
kind?: string
// Name of the resource being referred to.
name: string
}
// Certificate signing request bytes in DER encoding. This will be
// used when finalizing the order. This field must be set on the
// order.
request: string
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-platform-argocd/prod-platform-argocd.gen.yaml
package v1alpha1
import "strings"
// AppProject provides a logical grouping of applications,
// providing controls for: * where the apps may deploy to
// (cluster whitelist) * what may be deployed (repository
// whitelist, resource whitelist/blacklist) * who can access
// these applications (roles, OIDC group claims bindings) * and
// what they can do (RBAC policies) * automation access to these
// roles (JWT tokens)
#AppProject: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "argoproj.io/v1alpha1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "AppProject"
metadata: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// AppProjectSpec is the specification of an AppProject
spec!: #AppProjectSpec
}
// AppProjectSpec is the specification of an AppProject
#AppProjectSpec: {
// ClusterResourceBlacklist contains list of blacklisted cluster
// level resources
clusterResourceBlacklist?: [...{
group: string
kind: string
}]
// ClusterResourceWhitelist contains list of whitelisted cluster
// level resources
clusterResourceWhitelist?: [...{
group: string
kind: string
}]
// Description contains optional project description
description?: string
// Destinations contains list of destinations available for
// deployment
destinations?: [...{
// Name is an alternate way of specifying the target cluster by
// its symbolic name. This must be set if Server is not set.
name?: string
// Namespace specifies the target namespace for the application's
// resources. The namespace will only be set for namespace-scoped
// resources that have not set a value for .metadata.namespace
namespace?: string
// Server specifies the URL of the target cluster's Kubernetes
// control plane API. This must be set if Name is not set.
server?: string
}]
// NamespaceResourceBlacklist contains list of blacklisted
// namespace level resources
namespaceResourceBlacklist?: [...{
group: string
kind: string
}]
// NamespaceResourceWhitelist contains list of whitelisted
// namespace level resources
namespaceResourceWhitelist?: [...{
group: string
kind: string
}]
// OrphanedResources specifies if controller should monitor
// orphaned resources of apps in this project
orphanedResources?: {
// Ignore contains a list of resources that are to be excluded
// from orphaned resources monitoring
ignore?: [...{
group?: string
kind?: string
name?: string
}]
// Warn indicates if warning condition should be created for apps
// which have orphaned resources
warn?: bool
}
// PermitOnlyProjectScopedClusters determines whether destinations
// can only reference clusters which are project-scoped
permitOnlyProjectScopedClusters?: bool
// Roles are user defined RBAC roles associated with this project
roles?: [...{
// Description is a description of the role
description?: string
// Groups are a list of OIDC group claims bound to this role
groups?: [...string]
// JWTTokens are a list of generated JWT tokens bound to this role
jwtTokens?: [...{
exp?: int
iat: int
id?: string
}]
// Name is a name for this role
name: string
// Policies Stores a list of casbin formatted strings that define
// access policies for the role in the project
policies?: [...string]
}]
// SignatureKeys contains a list of PGP key IDs that commits in
// Git must be signed with in order to be allowed for sync
signatureKeys?: [...{
// The ID of the key in hexadecimal notation
keyID: string
}]
// SourceNamespaces defines the namespaces application resources
// are allowed to be created in
sourceNamespaces?: [...string]
// SourceRepos contains list of repository URLs which can be used
// for deployment
sourceRepos?: [...string]
// SyncWindows controls when syncs can be run for apps in this
// project
syncWindows?: [...{
// Applications contains a list of applications that the window
// will apply to
applications?: [...string]
// Clusters contains a list of clusters that the window will apply
// to
clusters?: [...string]
// Duration is the amount of time the sync window will be open
duration?: string
// Kind defines if the window allows or blocks syncs
kind?: string
// ManualSync enables manual syncs when they would otherwise be
// blocked
manualSync?: bool
// Namespaces contains a list of namespaces that the window will
// apply to
namespaces?: [...string]
// Schedule is the time the window will begin, specified in cron
// format
schedule?: string
// TimeZone of the sync that will be applied to the schedule
timeZone?: string
}]
}

View File

@@ -0,0 +1,422 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-certmanager/prod-mesh-certmanager.gen.yaml
package v1
import "strings"
// A Certificate resource should be created to ensure an up to
// date and signed X.509 certificate is stored in the Kubernetes
// Secret resource named in `spec.secretName`.
// The stored certificate will be renewed before it expires (as
// configured by `spec.renewBefore`).
#Certificate: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "cert-manager.io/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "Certificate"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// Specification of the desired state of the Certificate resource.
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
spec!: #CertificateSpec
}
// Specification of the desired state of the Certificate resource.
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
#CertificateSpec: {
// Defines extra output formats of the private key and signed
// certificate chain to be written to this Certificate's target
// Secret.
// This is an Alpha Feature and is only enabled with the
// `--feature-gates=AdditionalCertificateOutputFormats=true`
// option set on both the controller and webhook components.
additionalOutputFormats?: [...{
// Type is the name of the format type that should be written to
// the Certificate's target Secret.
type: "DER" | "CombinedPEM"
}]
// Requested common name X509 certificate subject attribute. More
// info:
// https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6
// NOTE: TLS clients will ignore this value when any subject
// alternative name is set (see
// https://tools.ietf.org/html/rfc6125#section-6.4.4).
// Should have a length of 64 characters or fewer to avoid
// generating invalid CSRs. Cannot be set if the `literalSubject`
// field is set.
commonName?: string
// Requested DNS subject alternative names.
dnsNames?: [...string]
// Requested 'duration' (i.e. lifetime) of the Certificate. Note
// that the issuer may choose to ignore the requested duration,
// just like any other requested attribute.
// If unset, this defaults to 90 days. Minimum accepted duration
// is 1 hour. Value must be in units accepted by Go
// time.ParseDuration https://golang.org/pkg/time/#ParseDuration.
duration?: string
// Requested email subject alternative names.
emailAddresses?: [...string]
// Whether the KeyUsage and ExtKeyUsage extensions should be set
// in the encoded CSR.
// This option defaults to true, and should only be disabled if
// the target issuer does not support CSRs with these X509
// KeyUsage/ ExtKeyUsage extensions.
encodeUsagesInRequest?: bool
// Requested IP address subject alternative names.
ipAddresses?: [...string]
// Requested basic constraints isCA value. The isCA value is used
// to set the `isCA` field on the created CertificateRequest
// resources. Note that the issuer may choose to ignore the
// requested isCA value, just like any other requested attribute.
// If true, this will automatically add the `cert sign` usage to
// the list of requested `usages`.
isCA?: bool
// Reference to the issuer responsible for issuing the
// certificate. If the issuer is namespace-scoped, it must be in
// the same namespace as the Certificate. If the issuer is
// cluster-scoped, it can be used from any namespace.
// The `name` field of the reference must always be specified.
issuerRef: {
// Group of the resource being referred to.
group?: string
// Kind of the resource being referred to.
kind?: string
// Name of the resource being referred to.
name: string
}
// Additional keystore output formats to be stored in the
// Certificate's Secret.
keystores?: {
// JKS configures options for storing a JKS keystore in the
// `spec.secretName` Secret resource.
jks?: {
// Create enables JKS keystore creation for the Certificate. If
// true, a file named `keystore.jks` will be created in the
// target Secret resource, encrypted using the password stored in
// `passwordSecretRef`. The keystore file will be updated
// immediately. If the issuer provided a CA certificate, a file
// named `truststore.jks` will also be created in the target
// Secret resource, encrypted using the password stored in
// `passwordSecretRef` containing the issuing Certificate
// Authority
create: bool
// PasswordSecretRef is a reference to a key in a Secret resource
// containing the password used to encrypt the JKS keystore.
passwordSecretRef: {
// The key of the entry in the Secret resource's `data` field to
// be used. Some instances of this field may be defaulted, in
// others it may be required.
key?: string
// Name of the resource being referred to. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
name: string
}
}
// PKCS12 configures options for storing a PKCS12 keystore in the
// `spec.secretName` Secret resource.
pkcs12?: {
// Create enables PKCS12 keystore creation for the Certificate. If
// true, a file named `keystore.p12` will be created in the
// target Secret resource, encrypted using the password stored in
// `passwordSecretRef`. The keystore file will be updated
// immediately. If the issuer provided a CA certificate, a file
// named `truststore.p12` will also be created in the target
// Secret resource, encrypted using the password stored in
// `passwordSecretRef` containing the issuing Certificate
// Authority
create: bool
// PasswordSecretRef is a reference to a key in a Secret resource
// containing the password used to encrypt the PKCS12 keystore.
passwordSecretRef: {
// The key of the entry in the Secret resource's `data` field to
// be used. Some instances of this field may be defaulted, in
// others it may be required.
key?: string
// Name of the resource being referred to. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
name: string
}
// Profile specifies the key and certificate encryption algorithms
// and the HMAC algorithm used to create the PKCS12 keystore.
// Default value is `LegacyRC2` for backward compatibility.
// If provided, allowed values are: `LegacyRC2`: Deprecated. Not
// supported by default in OpenSSL 3 or Java 20. `LegacyDES`:
// Less secure algorithm. Use this option for maximal
// compatibility. `Modern2023`: Secure algorithm. Use this option
// in case you have to always use secure algorithms (eg. because
// of company policy). Please note that the security of the
// algorithm is not that important in reality, because the
// unencrypted certificate and private key are also stored in the
// Secret.
profile?: "LegacyRC2" | "LegacyDES" | "Modern2023"
}
}
// Requested X.509 certificate subject, represented using the LDAP
// "String Representation of a Distinguished Name" [1].
// Important: the LDAP string format also specifies the order of
// the attributes in the subject, this is important when issuing
// certs for LDAP authentication. Example:
// `CN=foo,DC=corp,DC=example,DC=com` More info [1]:
// https://datatracker.ietf.org/doc/html/rfc4514 More info:
// https://github.com/cert-manager/cert-manager/issues/3203 More
// info: https://github.com/cert-manager/cert-manager/issues/4424
// Cannot be set if the `subject` or `commonName` field is set.
// This is an Alpha Feature and is only enabled with the
// `--feature-gates=LiteralCertificateSubject=true` option set on
// both the controller and webhook components.
literalSubject?: string
// x.509 certificate NameConstraint extension which MUST NOT be
// used in a non-CA certificate. More Info:
// https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10
// This is an Alpha Feature and is only enabled with the
// `--feature-gates=NameConstraints=true` option set on both the
// controller and webhook components.
nameConstraints?: {
// if true then the name constraints are marked critical.
critical?: bool
// Excluded contains the constraints which must be disallowed. Any
// name matching a restriction in the excluded field is invalid
// regardless of information appearing in the permitted
excluded?: {
// DNSDomains is a list of DNS domains that are permitted or
// excluded.
dnsDomains?: [...string]
// EmailAddresses is a list of Email Addresses that are permitted
// or excluded.
emailAddresses?: [...string]
// IPRanges is a list of IP Ranges that are permitted or excluded.
// This should be a valid CIDR notation.
ipRanges?: [...string]
// URIDomains is a list of URI domains that are permitted or
// excluded.
uriDomains?: [...string]
}
// Permitted contains the constraints in which the names must be
// located.
permitted?: {
// DNSDomains is a list of DNS domains that are permitted or
// excluded.
dnsDomains?: [...string]
// EmailAddresses is a list of Email Addresses that are permitted
// or excluded.
emailAddresses?: [...string]
// IPRanges is a list of IP Ranges that are permitted or excluded.
// This should be a valid CIDR notation.
ipRanges?: [...string]
// URIDomains is a list of URI domains that are permitted or
// excluded.
uriDomains?: [...string]
}
}
// `otherNames` is an escape hatch for SAN that allows any type.
// We currently restrict the support to string like otherNames,
// cf RFC 5280 p 37 Any UTF8 String valued otherName can be
// passed with by setting the keys oid: x.x.x.x and UTF8Value:
// somevalue for `otherName`. Most commonly this would be UPN set
// with oid: 1.3.6.1.4.1.311.20.2.3 You should ensure that any
// OID passed is valid for the UTF8String type as we do not
// explicitly validate this.
otherNames?: [...{
// OID is the object identifier for the otherName SAN. The object
// identifier must be expressed as a dotted string, for example,
// "1.2.840.113556.1.4.221".
oid?: string
// utf8Value is the string value of the otherName SAN. The
// utf8Value accepts any valid UTF8 string to set as value for
// the otherName SAN.
utf8Value?: string
}]
// Private key options. These include the key algorithm and size,
// the used encoding and the rotation policy.
privateKey?: {
// Algorithm is the private key algorithm of the corresponding
// private key for this certificate.
// If provided, allowed values are either `RSA`, `ECDSA` or
// `Ed25519`. If `algorithm` is specified and `size` is not
// provided, key size of 2048 will be used for `RSA` key
// algorithm and key size of 256 will be used for `ECDSA` key
// algorithm. key size is ignored when using the `Ed25519` key
// algorithm.
algorithm?: "RSA" | "ECDSA" | "Ed25519"
// The private key cryptography standards (PKCS) encoding for this
// certificate's private key to be encoded in.
// If provided, allowed values are `PKCS1` and `PKCS8` standing
// for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if
// not specified.
encoding?: "PKCS1" | "PKCS8"
// RotationPolicy controls how private keys should be regenerated
// when a re-issuance is being processed.
// If set to `Never`, a private key will only be generated if one
// does not already exist in the target `spec.secretName`. If one
// does exists but it does not have the correct algorithm or
// size, a warning will be raised to await user intervention. If
// set to `Always`, a private key matching the specified
// requirements will be generated whenever a re-issuance occurs.
// Default is `Never` for backward compatibility.
rotationPolicy?: "Never" | "Always"
// Size is the key bit size of the corresponding private key for
// this certificate.
// If `algorithm` is set to `RSA`, valid values are `2048`, `4096`
// or `8192`, and will default to `2048` if not specified. If
// `algorithm` is set to `ECDSA`, valid values are `256`, `384`
// or `521`, and will default to `256` if not specified. If
// `algorithm` is set to `Ed25519`, Size is ignored. No other
// values are allowed.
size?: int
}
// How long before the currently issued certificate's expiry
// cert-manager should renew the certificate. For example, if a
// certificate is valid for 60 minutes, and `renewBefore=10m`,
// cert-manager will begin to attempt to renew the certificate 50
// minutes after it was issued (i.e. when there are 10 minutes
// remaining until the certificate is no longer valid).
// NOTE: The actual lifetime of the issued certificate is used to
// determine the renewal time. If an issuer returns a certificate
// with a different lifetime than the one requested, cert-manager
// will use the lifetime of the issued certificate.
// If unset, this defaults to 1/3 of the issued certificate's
// lifetime. Minimum accepted value is 5 minutes. Value must be
// in units accepted by Go time.ParseDuration
// https://golang.org/pkg/time/#ParseDuration.
renewBefore?: string
// The maximum number of CertificateRequest revisions that are
// maintained in the Certificate's history. Each revision
// represents a single `CertificateRequest` created by this
// Certificate, either when it was created, renewed, or Spec was
// changed. Revisions will be removed by oldest first if the
// number of revisions exceeds this number.
// If set, revisionHistoryLimit must be a value of `1` or greater.
// If unset (`nil`), revisions will not be garbage collected.
// Default value is `nil`.
revisionHistoryLimit?: int
// Name of the Secret resource that will be automatically created
// and managed by this Certificate resource. It will be populated
// with a private key and certificate, signed by the denoted
// issuer. The Secret resource lives in the same namespace as the
// Certificate resource.
secretName: string
// Defines annotations and labels to be copied to the
// Certificate's Secret. Labels and annotations on the Secret
// will be changed as they appear on the SecretTemplate when
// added or removed. SecretTemplate annotations are added in
// conjunction with, and cannot overwrite, the base set of
// annotations cert-manager sets on the Certificate's Secret.
secretTemplate?: {
// Annotations is a key value map to be copied to the target
// Kubernetes Secret.
annotations?: {
[string]: string
}
// Labels is a key value map to be copied to the target Kubernetes
// Secret.
labels?: {
[string]: string
}
}
// Requested set of X509 certificate subject attributes. More
// info:
// https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6
// The common name attribute is specified separately in the
// `commonName` field. Cannot be set if the `literalSubject`
// field is set.
subject?: {
// Countries to be used on the Certificate.
countries?: [...string]
// Cities to be used on the Certificate.
localities?: [...string]
// Organizational Units to be used on the Certificate.
organizationalUnits?: [...string]
// Organizations to be used on the Certificate.
organizations?: [...string]
// Postal codes to be used on the Certificate.
postalCodes?: [...string]
// State/Provinces to be used on the Certificate.
provinces?: [...string]
// Serial number to be used on the Certificate.
serialNumber?: string
// Street addresses to be used on the Certificate.
streetAddresses?: [...string]
}
// Requested URI subject alternative names.
uris?: [...string]
// Requested key usages and extended key usages. These usages are
// used to set the `usages` field on the created
// CertificateRequest resources. If `encodeUsagesInRequest` is
// unset or set to `true`, the usages will additionally be
// encoded in the `request` field which contains the CSR blob.
// If unset, defaults to `digital signature` and `key
// encipherment`.
usages?: [..."signing" | "digital signature" | "content commitment" | "key encipherment" | "key agreement" | "data encipherment" | "cert sign" | "crl sign" | "encipher only" | "decipher only" | "any" | "server auth" | "client auth" | "code signing" | "email protection" | "s/mime" | "ipsec end system" | "ipsec tunnel" | "ipsec user" | "timestamping" | "ocsp signing" | "microsoft sgc" | "netscape sgc"]
}

View File

@@ -0,0 +1,127 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-certmanager/prod-mesh-certmanager.gen.yaml
package v1
import "strings"
// A CertificateRequest is used to request a signed certificate
// from one of the configured issuers.
// All fields within the CertificateRequest's `spec` are immutable
// after creation. A CertificateRequest will either succeed or
// fail, as denoted by its `Ready` status condition and its
// `status.failureTime` field.
// A CertificateRequest is a one-shot resource, meaning it
// represents a single point in time request for a certificate
// and cannot be re-used.
#CertificateRequest: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "cert-manager.io/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "CertificateRequest"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// Specification of the desired state of the CertificateRequest
// resource.
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
spec!: #CertificateRequestSpec
}
// Specification of the desired state of the CertificateRequest
// resource.
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
#CertificateRequestSpec: {
// Requested 'duration' (i.e. lifetime) of the Certificate. Note
// that the issuer may choose to ignore the requested duration,
// just like any other requested attribute.
duration?: string
// Extra contains extra attributes of the user that created the
// CertificateRequest. Populated by the cert-manager webhook on
// creation and immutable.
extra?: {
[string]: [...string]
}
// Groups contains group membership of the user that created the
// CertificateRequest. Populated by the cert-manager webhook on
// creation and immutable.
groups?: [...string]
// Requested basic constraints isCA value. Note that the issuer
// may choose to ignore the requested isCA value, just like any
// other requested attribute.
// NOTE: If the CSR in the `Request` field has a BasicConstraints
// extension, it must have the same isCA value as specified here.
// If true, this will automatically add the `cert sign` usage to
// the list of requested `usages`.
isCA?: bool
// Reference to the issuer responsible for issuing the
// certificate. If the issuer is namespace-scoped, it must be in
// the same namespace as the Certificate. If the issuer is
// cluster-scoped, it can be used from any namespace.
// The `name` field of the reference must always be specified.
issuerRef: {
// Group of the resource being referred to.
group?: string
// Kind of the resource being referred to.
kind?: string
// Name of the resource being referred to.
name: string
}
// The PEM-encoded X.509 certificate signing request to be
// submitted to the issuer for signing.
// If the CSR has a BasicConstraints extension, its isCA attribute
// must match the `isCA` value of this CertificateRequest. If the
// CSR has a KeyUsage extension, its key usages must match the
// key usages in the `usages` field of this CertificateRequest.
// If the CSR has a ExtKeyUsage extension, its extended key
// usages must match the extended key usages in the `usages`
// field of this CertificateRequest.
request: string
// UID contains the uid of the user that created the
// CertificateRequest. Populated by the cert-manager webhook on
// creation and immutable.
uid?: string
// Requested key usages and extended key usages.
// NOTE: If the CSR in the `Request` field has uses the KeyUsage
// or ExtKeyUsage extension, these extensions must have the same
// values as specified here without any additional values.
// If unset, defaults to `digital signature` and `key
// encipherment`.
usages?: [..."signing" | "digital signature" | "content commitment" | "key encipherment" | "key agreement" | "data encipherment" | "cert sign" | "crl sign" | "encipher only" | "decipher only" | "any" | "server auth" | "client auth" | "code signing" | "email protection" | "s/mime" | "ipsec end system" | "ipsec tunnel" | "ipsec user" | "timestamping" | "ocsp signing" | "microsoft sgc" | "netscape sgc"]
// Username contains the name of the user that created the
// CertificateRequest. Populated by the cert-manager webhook on
// creation and immutable.
username?: string
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha1
import (
"strings"
"list"
)
#WasmPlugin: {
// Extend the functionality provided by the Istio proxy through
// WebAssembly filters. See more details at:
// https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html
spec!: #WasmPluginSpec
apiVersion: "extensions.istio.io/v1alpha1"
kind: "WasmPlugin"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Extend the functionality provided by the Istio proxy through
// WebAssembly filters. See more details at:
// https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html
#WasmPluginSpec: {
// Specifies the failure behavior for the plugin due to fatal
// errors.
failStrategy?: "FAIL_CLOSE" | "FAIL_OPEN"
// The pull behaviour to be applied when fetching Wasm module by
// either OCI image or http/https.
imagePullPolicy?: "UNSPECIFIED_POLICY" | "IfNotPresent" | "Always"
// Credentials to use for OCI image pulling.
imagePullSecret?: strings.MaxRunes(253) & strings.MinRunes(1)
// Specifies the criteria to determine which traffic is passed to
// WasmPlugin.
match?: [...{
// Criteria for selecting traffic by their direction.
mode?: "UNDEFINED" | "CLIENT" | "SERVER" | "CLIENT_AND_SERVER"
// Criteria for selecting traffic by their destination port.
ports?: [...{
number: uint16 & >=1
}]
}]
// Determines where in the filter chain this `WasmPlugin` is to be
// injected.
phase?: "UNSPECIFIED_PHASE" | "AUTHN" | "AUTHZ" | "STATS"
// The configuration that will be passed on to the plugin.
pluginConfig?: {
...
}
// The plugin name to be used in the Envoy configuration (used to
// be called `rootID`).
pluginName?: strings.MaxRunes(256) & strings.MinRunes(1)
// Determines ordering of `WasmPlugins` in the same `phase`.
priority?: null | int
selector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which a policy should be applied.
matchLabels?: {
[string]: string
}
}
// SHA256 checksum that will be used to verify Wasm module or OCI
// container.
sha256?: =~"(^$|^[a-f0-9]{64}$)"
// Optional.
targetRef?: {
// group is the group of the target resource.
group?: string
// kind is kind of the target resource.
kind?: string
// name is the name of the target resource.
name?: string
// namespace is the namespace of the referent.
namespace?: string
}
// Specifies the type of Wasm Extension to be used.
type?: "UNSPECIFIED_PLUGIN_TYPE" | "HTTP" | "NETWORK"
// URL of a Wasm module or OCI container.
url: strings.MinRunes(1)
verificationKey?: string
vmConfig?: {
// Specifies environment variables to be injected to this VM.
env?: list.MaxItems(256) & [...{
// Name of the environment variable.
name: strings.MaxRunes(256) & strings.MinRunes(1)
// Value for the environment variable.
value?: strings.MaxRunes(2048)
// Source for the environment variable's value.
valueFrom?: "INLINE" | "HOST"
}]
}
}

View File

@@ -0,0 +1,26 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// BuildPlan is the primary interface between CUE and the Holos cli.
#BuildPlan: {
#TypeMeta
// Metadata represents the holos component name
metadata?: #ObjectMeta @go(Metadata)
spec?: #BuildPlanSpec @go(Spec)
}
#BuildPlanSpec: {
disabled?: bool @go(Disabled)
components?: #BuildPlanComponents @go(Components)
}
#BuildPlanComponents: {
helmChartList?: [...#HelmChart] @go(HelmChartList,[]HelmChart)
kubernetesObjectsList?: [...#KubernetesObjects] @go(KubernetesObjectsList,[]KubernetesObjects)
kustomizeBuildList?: [...#KustomizeBuild] @go(KustomizeBuildList,[]KustomizeBuild)
resources?: {[string]: #KubernetesObjects} @go(Resources,map[string]KubernetesObjects)
}

View File

@@ -0,0 +1,24 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// HolosComponent defines the fields common to all holos component kinds including the Render Result.
#HolosComponent: {
#TypeMeta
// Metadata represents the holos component name
metadata?: #ObjectMeta @go(Metadata)
// APIObjectMap holds the marshalled representation of api objects. Think of
// these as resources overlaid at the back of the render pipeline.
apiObjectMap?: #APIObjectMap @go(APIObjectMap)
#Kustomization
#Kustomize
// Skip causes holos to take no action regarding the component.
Skip: bool
}

View File

@@ -0,0 +1,15 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
#APIVersion: "holos.run/v1alpha1"
#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"

View File

@@ -0,0 +1,6 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
// Package v1alpha1 defines the api boundary between CUE and Holos.
package v1alpha1

View File

@@ -0,0 +1,28 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// A HelmChart represents a helm command to provide chart values in order to render kubernetes api objects.
#HelmChart: {
#HolosComponent
// Namespace is the namespace to install into. TODO: Use metadata.namespace instead.
namespace: string @go(Namespace)
chart: #Chart @go(Chart)
valuesContent: string @go(ValuesContent)
enableHooks: bool @go(EnableHooks)
}
#Chart: {
name: string @go(Name)
version: string @go(Version)
release: string @go(Release)
repository?: #Repository @go(Repository)
}
#Repository: {
name: string @go(Name)
url: string @go(URL)
}

View File

@@ -0,0 +1,12 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
#KubernetesObjectsKind: "KubernetesObjects"
// KubernetesObjects represents CUE output which directly provides Kubernetes api objects to holos.
#KubernetesObjects: {
#HolosComponent
}

View File

@@ -0,0 +1,11 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// Kustomization holds the rendered flux kustomization api object content for git ops.
#Kustomization: {
// KsContent is the yaml representation of the flux kustomization for gitops.
ksContent?: string @go(KsContent)
}

View File

@@ -0,0 +1,25 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
#KustomizeBuildKind: "KustomizeBuild"
// Kustomize represents resources necessary to execute a kustomize build.
// Intended for at least two use cases:
//
// 1. Process raw yaml file resources in a holos component directory.
// 2. Post process a HelmChart to inject istio, 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)
}
// KustomizeBuild renders plain yaml files in the holos component directory using kubectl kustomize build.
#KustomizeBuild: {
#HolosComponent
}

View File

@@ -0,0 +1,12 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
#KustomizeBuildKind: "KustomizeBuild"
// KustomizeBuild
#KustomizeBuild: {
#HolosComponent
}

View File

@@ -0,0 +1,18 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// Label is an arbitrary unique identifier. Defined as a type for clarity and type checking.
#Label: string
// Kind is a kubernetes api object kind. Defined as a type for clarity and type checking.
#Kind: string
// APIObjectMap is the shape of marshalled api objects returned from cue to the
// holos cli. A map is used to improve the clarity of error messages from cue.
#APIObjectMap: {[string]: [string]: string}
// FileContentMap is a map of file names to file contents.
#FileContentMap: {[string]: string}

View File

@@ -0,0 +1,22 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// ObjectMeta represents metadata of a holos component object. The fields are a
// copy of upstream kubernetes api machinery but are by holos objects distinct
// from kubernetes api objects.
#ObjectMeta: {
// Name uniquely identifies the holos component instance and must be suitable as a file name.
name?: string @go(Name)
// Namespace confines a holos component to a single namespace via kustomize if set.
namespace?: string @go(Namespace)
// Labels are not used but are copied from api machinery ObjectMeta for completeness.
labels?: {[string]: string} @go(Labels,map[string]string)
// Annotations are not used but are copied from api machinery ObjectMeta for completeness.
annotations?: {[string]: string} @go(Annotations,map[string]string)
}

View File

@@ -0,0 +1,7 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
#Renderer: _

View File

@@ -0,0 +1,10 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
// Result is the build result for display or writing. Holos components Render the Result as a data pipeline.
#Result: {
HolosComponent: #HolosComponent
}

View File

@@ -0,0 +1,10 @@
// Code generated by cue get go. DO NOT EDIT.
//cue:generate cue get go github.com/holos-run/holos/api/v1alpha1
package v1alpha1
#TypeMeta: {
kind?: string @go(Kind)
apiVersion?: string @go(APIVersion)
}

View File

@@ -0,0 +1,27 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha1
import "strings"
#IstioOperator: {
apiVersion: "install.istio.io/v1alpha1"
kind: "IstioOperator"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
...
}

View File

@@ -3066,7 +3066,7 @@ import (
// If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.
// More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
// +optional
securityContext?: null | #SecurityContext @go(SecurityContext,*SecurityContext) @protobuf(15,bytes,opt)
securityContext?: #SecurityContext @go(SecurityContext,*SecurityContext) @protobuf(15,bytes,opt)
// Whether this container should allocate a buffer for stdin in the container runtime. If this
// is not set, reads from stdin in the container will always result in EOF.
@@ -3982,7 +3982,7 @@ import (
// SecurityContext holds pod-level security attributes and common container settings.
// Optional: Defaults to empty. See type description for default values of each field.
// +optional
securityContext?: null | #PodSecurityContext @go(SecurityContext,*PodSecurityContext) @protobuf(14,bytes,opt)
securityContext?: #PodSecurityContext @go(SecurityContext,*PodSecurityContext) @protobuf(14,bytes,opt)
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,546 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-platform-monitoring/prod-platform-monitoring.gen.yaml
package v1
import "strings"
// PodMonitor defines monitoring for a set of pods.
#PodMonitor: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "monitoring.coreos.com/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "PodMonitor"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// Specification of desired Pod selection for target discovery by
// Prometheus.
spec!: #PodMonitorSpec
}
// Specification of desired Pod selection for target discovery by
// Prometheus.
#PodMonitorSpec: {
attachMetadata?: {
// When set to true, Prometheus must have the `get` permission on
// the `Nodes` objects.
node?: bool
}
// The label to use to retrieve the job name from. `jobLabel`
// selects the label from the associated Kubernetes `Pod` object
// which will be used as the `job` label for all metrics.
// For example if `jobLabel` is set to `foo` and the Kubernetes
// `Pod` object is labeled with `foo: bar`, then Prometheus adds
// the `job="bar"` label to all ingested metrics.
// If the value of this field is empty, the `job` label of the
// metrics defaults to the namespace and name of the PodMonitor
// object (e.g. `<namespace>/<name>`).
jobLabel?: string
// Per-scrape limit on the number of targets dropped by relabeling
// that will be kept in memory. 0 means no limit.
// It requires Prometheus >= v2.47.0.
keepDroppedTargets?: int
// Per-scrape limit on number of labels that will be accepted for
// a sample.
// It requires Prometheus >= v2.27.0.
labelLimit?: int
// Per-scrape limit on length of labels name that will be accepted
// for a sample.
// It requires Prometheus >= v2.27.0.
labelNameLengthLimit?: int
// Per-scrape limit on length of labels value that will be
// accepted for a sample.
// It requires Prometheus >= v2.27.0.
labelValueLengthLimit?: int
// Selector to select which namespaces the Kubernetes `Pods`
// objects are discovered from.
namespaceSelector?: {
// Boolean describing whether all namespaces are selected in
// contrast to a list restricting them.
any?: bool
// List of namespace names to select from.
matchNames?: [...string]
}
// List of endpoints part of this PodMonitor.
podMetricsEndpoints?: [...{
// `authorization` configures the Authorization header credentials
// to use when scraping the target.
// Cannot be set at the same time as `basicAuth`, or `oauth2`.
authorization?: {
// Selects a key of a Secret in the namespace that contains the
// credentials for authentication.
credentials?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Defines the authentication type. The value is case-insensitive.
// "Basic" is not a supported value.
// Default: "Bearer"
type?: string
}
// `basicAuth` configures the Basic Authentication credentials to
// use when scraping the target.
// Cannot be set at the same time as `authorization`, or `oauth2`.
basicAuth?: {
// `password` specifies a key of a Secret containing the password
// for authentication.
password?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `username` specifies a key of a Secret containing the username
// for authentication.
username?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// `bearerTokenSecret` specifies a key of a Secret containing the
// bearer token for scraping targets. The secret needs to be in
// the same namespace as the PodMonitor object and readable by
// the Prometheus Operator.
// Deprecated: use `authorization` instead.
bearerTokenSecret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `enableHttp2` can be used to disable HTTP2 when scraping the
// target.
enableHttp2?: bool
// When true, the pods which are not running (e.g. either in
// Failed or Succeeded state) are dropped during the target
// discovery.
// If unset, the filtering is enabled.
// More info:
// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
filterRunning?: bool
// `followRedirects` defines whether the scrape requests should
// follow HTTP 3xx redirects.
followRedirects?: bool
// When true, `honorLabels` preserves the metric's labels when
// they collide with the target's labels.
honorLabels?: bool
// `honorTimestamps` controls whether Prometheus preserves the
// timestamps when exposed by the target.
honorTimestamps?: bool
// Interval at which Prometheus scrapes the metrics from the
// target.
// If empty, Prometheus uses the global scrape interval.
interval?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// `metricRelabelings` configures the relabeling rules to apply to
// the samples before ingestion.
metricRelabelings?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// `oauth2` configures the OAuth2 settings to use when scraping
// the target.
// It requires Prometheus >= 2.27.0.
// Cannot be set at the same time as `authorization`, or
// `basicAuth`.
oauth2?: {
// `clientId` specifies a key of a Secret or ConfigMap containing
// the OAuth2 client's ID.
clientId: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// `clientSecret` specifies a key of a Secret containing the
// OAuth2 client's secret.
clientSecret: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `endpointParams` configures the HTTP parameters to append to
// the token URL.
endpointParams?: {
[string]: string
}
// `scopes` defines the OAuth2 scopes used for the token request.
scopes?: [...string]
// `tokenURL` configures the URL to fetch the token from.
tokenUrl: strings.MinRunes(1)
}
// `params` define optional HTTP URL parameters.
params?: {
[string]: [...string]
}
// HTTP path from which to scrape for metrics.
// If empty, Prometheus uses the default value (e.g. `/metrics`).
path?: string
// Name of the Pod port which this endpoint refers to.
// It takes precedence over `targetPort`.
port?: string
// `proxyURL` configures the HTTP Proxy URL (e.g.
// "http://proxyserver:2195") to go through when scraping the
// target.
proxyUrl?: string
// `relabelings` configures the relabeling rules to apply the
// target's metadata labels.
// The Operator automatically adds relabelings for a few standard
// Kubernetes fields.
// The original scrape job's name is available via the
// `__tmp_prometheus_job_name` label.
// More info:
// https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
relabelings?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// HTTP scheme to use for scraping.
// `http` and `https` are the expected values unless you rewrite
// the `__scheme__` label via relabeling.
// If empty, Prometheus uses the default value `http`.
scheme?: "http" | "https"
// Timeout after which Prometheus considers the scrape to be
// failed.
// If empty, Prometheus uses the global scrape timeout unless it
// is less than the target's scrape interval value in which the
// latter is used.
scrapeTimeout?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// Name or number of the target port of the `Pod` object behind
// the Service, the port must be specified with container port
// property.
// Deprecated: use 'port' instead.
targetPort?: (int | string) & {
string
}
// TLS configuration to use when scraping the target.
tlsConfig?: {
// Certificate authority used when verifying server certificates.
ca?: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Client certificate to present when doing client-authentication.
cert?: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Disable target certificate validation.
insecureSkipVerify?: bool
// Secret containing the client key file for the targets.
keySecret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Used to verify the hostname for the targets.
serverName?: string
}
// `trackTimestampsStaleness` defines whether Prometheus tracks
// staleness of the metrics that have an explicit timestamp
// present in scraped data. Has no effect if `honorTimestamps` is
// false.
// It requires Prometheus >= v2.48.0.
trackTimestampsStaleness?: bool
}]
// `podTargetLabels` defines the labels which are transferred from
// the associated Kubernetes `Pod` object onto the ingested
// metrics.
podTargetLabels?: [...string]
// `sampleLimit` defines a per-scrape limit on the number of
// scraped samples that will be accepted.
sampleLimit?: int
// The scrape class to apply.
scrapeClass?: strings.MinRunes(1)
// `scrapeProtocols` defines the protocols to negotiate during a
// scrape. It tells clients the protocols supported by Prometheus
// in order of preference (from most to least preferred).
// If unset, Prometheus uses its default value.
// It requires Prometheus >= v2.49.0.
scrapeProtocols?: [..."PrometheusProto" | "OpenMetricsText0.0.1" | "OpenMetricsText1.0.0" | "PrometheusText0.0.4"]
// Label selector to select the Kubernetes `Pod` objects.
selector: {
// matchExpressions is a list of label selector requirements. The
// requirements are ANDed.
matchExpressions?: [...{
// key is the label key that the selector applies to.
key: string
// operator represents a key's relationship to a set of values.
// Valid operators are In, NotIn, Exists and DoesNotExist.
operator: string
// values is an array of string values. If the operator is In or
// NotIn, the values array must be non-empty. If the operator is
// Exists or DoesNotExist, the values array must be empty. This
// array is replaced during a strategic merge patch.
values?: [...string]
}]
// matchLabels is a map of {key,value} pairs. A single {key,value}
// in the matchLabels map is equivalent to an element of
// matchExpressions, whose key field is "key", the operator is
// "In", and the values array contains only "value". The
// requirements are ANDed.
matchLabels?: {
[string]: string
}
}
// `targetLimit` defines a limit on the number of scraped targets
// that will be accepted.
targetLimit?: int
}

View File

@@ -0,0 +1,536 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-platform-monitoring/prod-platform-monitoring.gen.yaml
package v1
import "strings"
// Probe defines monitoring for a set of static targets or
// ingresses.
#Probe: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "monitoring.coreos.com/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "Probe"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// Specification of desired Ingress selection for target discovery
// by Prometheus.
spec!: #ProbeSpec
}
// Specification of desired Ingress selection for target discovery
// by Prometheus.
#ProbeSpec: {
// Authorization section for this endpoint
authorization?: {
// Selects a key of a Secret in the namespace that contains the
// credentials for authentication.
credentials?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Defines the authentication type. The value is case-insensitive.
// "Basic" is not a supported value.
// Default: "Bearer"
type?: string
}
// BasicAuth allow an endpoint to authenticate over basic
// authentication. More info:
// https://prometheus.io/docs/operating/configuration/#endpoint
basicAuth?: {
// `password` specifies a key of a Secret containing the password
// for authentication.
password?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `username` specifies a key of a Secret containing the username
// for authentication.
username?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Secret to mount to read bearer token for scraping targets. The
// secret needs to be in the same namespace as the probe and
// accessible by the Prometheus Operator.
bearerTokenSecret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Interval at which targets are probed using the configured
// prober. If not specified Prometheus' global scrape interval is
// used.
interval?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// The job name assigned to scraped metrics by default.
jobName?: string
// Per-scrape limit on the number of targets dropped by relabeling
// that will be kept in memory. 0 means no limit.
// It requires Prometheus >= v2.47.0.
keepDroppedTargets?: int
// Per-scrape limit on number of labels that will be accepted for
// a sample. Only valid in Prometheus versions 2.27.0 and newer.
labelLimit?: int
// Per-scrape limit on length of labels name that will be accepted
// for a sample. Only valid in Prometheus versions 2.27.0 and
// newer.
labelNameLengthLimit?: int
// Per-scrape limit on length of labels value that will be
// accepted for a sample. Only valid in Prometheus versions
// 2.27.0 and newer.
labelValueLengthLimit?: int
// MetricRelabelConfigs to apply to samples before ingestion.
metricRelabelings?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// The module to use for probing specifying how to probe the
// target. Example module configuring in the blackbox exporter:
// https://github.com/prometheus/blackbox_exporter/blob/master/example.yml
module?: string
// OAuth2 for the URL. Only valid in Prometheus versions 2.27.0
// and newer.
oauth2?: {
// `clientId` specifies a key of a Secret or ConfigMap containing
// the OAuth2 client's ID.
clientId: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// `clientSecret` specifies a key of a Secret containing the
// OAuth2 client's secret.
clientSecret: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `endpointParams` configures the HTTP parameters to append to
// the token URL.
endpointParams?: {
[string]: string
}
// `scopes` defines the OAuth2 scopes used for the token request.
scopes?: [...string]
// `tokenURL` configures the URL to fetch the token from.
tokenUrl: strings.MinRunes(1)
}
// Specification for the prober to use for probing targets. The
// prober.URL parameter is required. Targets cannot be probed if
// left empty.
prober?: {
// Path to collect metrics from. Defaults to `/probe`.
path?: string | *"/probe"
// Optional ProxyURL.
proxyUrl?: string
// HTTP scheme to use for scraping. `http` and `https` are the
// expected values unless you rewrite the `__scheme__` label via
// relabeling. If empty, Prometheus uses the default value
// `http`.
scheme?: "http" | "https"
// Mandatory URL of the prober.
url: string
}
// SampleLimit defines per-scrape limit on number of scraped
// samples that will be accepted.
sampleLimit?: int
// The scrape class to apply.
scrapeClass?: strings.MinRunes(1)
// `scrapeProtocols` defines the protocols to negotiate during a
// scrape. It tells clients the protocols supported by Prometheus
// in order of preference (from most to least preferred).
// If unset, Prometheus uses its default value.
// It requires Prometheus >= v2.49.0.
scrapeProtocols?: [..."PrometheusProto" | "OpenMetricsText0.0.1" | "OpenMetricsText1.0.0" | "PrometheusText0.0.4"]
// Timeout for scraping metrics from the Prometheus exporter. If
// not specified, the Prometheus global scrape timeout is used.
scrapeTimeout?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// TargetLimit defines a limit on the number of scraped targets
// that will be accepted.
targetLimit?: int
// Targets defines a set of static or dynamically discovered
// targets to probe.
targets?: {
// ingress defines the Ingress objects to probe and the relabeling
// configuration. If `staticConfig` is also defined,
// `staticConfig` takes precedence.
ingress?: {
// From which namespaces to select Ingress objects.
namespaceSelector?: {
// Boolean describing whether all namespaces are selected in
// contrast to a list restricting them.
any?: bool
// List of namespace names to select from.
matchNames?: [...string]
}
// RelabelConfigs to apply to the label set of the target before
// it gets scraped. The original ingress address is available via
// the `__tmp_prometheus_ingress_address` label. It can be used
// to customize the probed URL. The original scrape job's name is
// available via the `__tmp_prometheus_job_name` label. More
// info:
// https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
relabelingConfigs?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// Selector to select the Ingress objects.
selector?: {
// matchExpressions is a list of label selector requirements. The
// requirements are ANDed.
matchExpressions?: [...{
// key is the label key that the selector applies to.
key: string
// operator represents a key's relationship to a set of values.
// Valid operators are In, NotIn, Exists and DoesNotExist.
operator: string
// values is an array of string values. If the operator is In or
// NotIn, the values array must be non-empty. If the operator is
// Exists or DoesNotExist, the values array must be empty. This
// array is replaced during a strategic merge patch.
values?: [...string]
}]
// matchLabels is a map of {key,value} pairs. A single {key,value}
// in the matchLabels map is equivalent to an element of
// matchExpressions, whose key field is "key", the operator is
// "In", and the values array contains only "value". The
// requirements are ANDed.
matchLabels?: {
[string]: string
}
}
}
// staticConfig defines the static list of targets to probe and
// the relabeling configuration. If `ingress` is also defined,
// `staticConfig` takes precedence. More info:
// https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config.
staticConfig?: {
// Labels assigned to all metrics scraped from the targets.
labels?: {
[string]: string
}
// RelabelConfigs to apply to the label set of the targets before
// it gets scraped. More info:
// https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
relabelingConfigs?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// The list of hosts to probe.
static?: [...string]
}
}
// TLS configuration to use when scraping the endpoint.
tlsConfig?: {
// Certificate authority used when verifying server certificates.
ca?: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Client certificate to present when doing client-authentication.
cert?: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Disable target certificate validation.
insecureSkipVerify?: bool
// Secret containing the client key file for the targets.
keySecret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Used to verify the hostname for the targets.
serverName?: string
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-platform-monitoring/prod-platform-monitoring.gen.yaml
package v1
import "strings"
// PrometheusRule defines recording and alerting rules for a
// Prometheus instance
#PrometheusRule: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "monitoring.coreos.com/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "PrometheusRule"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// Specification of desired alerting rule definitions for
// Prometheus.
spec!: #PrometheusRuleSpec
}
#PrometheusRuleSpec: {
// Content of Prometheus rule file
groups?: [...{
// Interval determines how often rules in the group are evaluated.
interval?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// Limit the number of alerts an alerting rule and series a
// recording rule can produce. Limit is supported starting with
// Prometheus >= 2.31 and Thanos Ruler >= 0.24.
limit?: int
// Name of the rule group.
name: strings.MinRunes(1)
// PartialResponseStrategy is only used by ThanosRuler and will be
// ignored by Prometheus instances. More info:
// https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response
partial_response_strategy?: =~"^(?i)(abort|warn)?$"
// List of alerting and recording rules.
rules?: [...{
// Name of the alert. Must be a valid label value. Only one of
// `record` and `alert` must be set.
alert?: string
// Annotations to add to each alert. Only valid for alerting
// rules.
annotations?: {
[string]: string
}
// PromQL expression to evaluate.
expr: (int | string) & {
string
}
// Alerts are considered firing once they have been returned for
// this long.
for?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// KeepFiringFor defines how long an alert will continue firing
// after the condition that triggered it has cleared.
keep_firing_for?: strings.MinRunes(1) & {
=~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
}
// Labels to add or overwrite.
labels?: {
[string]: string
}
// Name of the time series to output to. Must be a valid metric
// name. Only one of `record` and `alert` must be set.
record?: string
}]
}]
}

View File

@@ -0,0 +1,566 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-platform-monitoring/prod-platform-monitoring.gen.yaml
package v1
import "strings"
// ServiceMonitor defines monitoring for a set of services.
#ServiceMonitor: {
// APIVersion defines the versioned schema of this representation
// of an object. Servers should convert recognized schemas to the
// latest internal value, and may reject unrecognized values.
// More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
apiVersion: "monitoring.coreos.com/v1"
// Kind is a string value representing the REST resource this
// object represents. Servers may infer this from the endpoint
// the client submits requests to. Cannot be updated. In
// CamelCase. More info:
// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
kind: "ServiceMonitor"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
// Specification of desired Service selection for target discovery
// by Prometheus.
spec!: #ServiceMonitorSpec
}
// Specification of desired Service selection for target discovery
// by Prometheus.
#ServiceMonitorSpec: {
attachMetadata?: {
// When set to true, Prometheus must have the `get` permission on
// the `Nodes` objects.
node?: bool
}
// List of endpoints part of this ServiceMonitor.
endpoints?: [...{
// `authorization` configures the Authorization header credentials
// to use when scraping the target.
// Cannot be set at the same time as `basicAuth`, or `oauth2`.
authorization?: {
// Selects a key of a Secret in the namespace that contains the
// credentials for authentication.
credentials?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Defines the authentication type. The value is case-insensitive.
// "Basic" is not a supported value.
// Default: "Bearer"
type?: string
}
// `basicAuth` configures the Basic Authentication credentials to
// use when scraping the target.
// Cannot be set at the same time as `authorization`, or `oauth2`.
basicAuth?: {
// `password` specifies a key of a Secret containing the password
// for authentication.
password?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `username` specifies a key of a Secret containing the username
// for authentication.
username?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// File to read bearer token for scraping the target.
// Deprecated: use `authorization` instead.
bearerTokenFile?: string
// `bearerTokenSecret` specifies a key of a Secret containing the
// bearer token for scraping targets. The secret needs to be in
// the same namespace as the ServiceMonitor object and readable
// by the Prometheus Operator.
// Deprecated: use `authorization` instead.
bearerTokenSecret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `enableHttp2` can be used to disable HTTP2 when scraping the
// target.
enableHttp2?: bool
// When true, the pods which are not running (e.g. either in
// Failed or Succeeded state) are dropped during the target
// discovery.
// If unset, the filtering is enabled.
// More info:
// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
filterRunning?: bool
// `followRedirects` defines whether the scrape requests should
// follow HTTP 3xx redirects.
followRedirects?: bool
// When true, `honorLabels` preserves the metric's labels when
// they collide with the target's labels.
honorLabels?: bool
// `honorTimestamps` controls whether Prometheus preserves the
// timestamps when exposed by the target.
honorTimestamps?: bool
// Interval at which Prometheus scrapes the metrics from the
// target.
// If empty, Prometheus uses the global scrape interval.
interval?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// `metricRelabelings` configures the relabeling rules to apply to
// the samples before ingestion.
metricRelabelings?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// `oauth2` configures the OAuth2 settings to use when scraping
// the target.
// It requires Prometheus >= 2.27.0.
// Cannot be set at the same time as `authorization`, or
// `basicAuth`.
oauth2?: {
// `clientId` specifies a key of a Secret or ConfigMap containing
// the OAuth2 client's ID.
clientId: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// `clientSecret` specifies a key of a Secret containing the
// OAuth2 client's secret.
clientSecret: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// `endpointParams` configures the HTTP parameters to append to
// the token URL.
endpointParams?: {
[string]: string
}
// `scopes` defines the OAuth2 scopes used for the token request.
scopes?: [...string]
// `tokenURL` configures the URL to fetch the token from.
tokenUrl: strings.MinRunes(1)
}
// params define optional HTTP URL parameters.
params?: {
[string]: [...string]
}
// HTTP path from which to scrape for metrics.
// If empty, Prometheus uses the default value (e.g. `/metrics`).
path?: string
// Name of the Service port which this endpoint refers to.
// It takes precedence over `targetPort`.
port?: string
// `proxyURL` configures the HTTP Proxy URL (e.g.
// "http://proxyserver:2195") to go through when scraping the
// target.
proxyUrl?: string
// `relabelings` configures the relabeling rules to apply the
// target's metadata labels.
// The Operator automatically adds relabelings for a few standard
// Kubernetes fields.
// The original scrape job's name is available via the
// `__tmp_prometheus_job_name` label.
// More info:
// https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
relabelings?: [...{
// Action to perform based on the regex matching.
// `Uppercase` and `Lowercase` actions require Prometheus >=
// v2.36.0. `DropEqual` and `KeepEqual` actions require
// Prometheus >= v2.41.0.
// Default: "Replace"
action?: "replace" | "Replace" | "keep" | "Keep" | "drop" | "Drop" | "hashmod" | "HashMod" | "labelmap" | "LabelMap" | "labeldrop" | "LabelDrop" | "labelkeep" | "LabelKeep" | "lowercase" | "Lowercase" | "uppercase" | "Uppercase" | "keepequal" | "KeepEqual" | "dropequal" | "DropEqual" | *"replace"
// Modulus to take of the hash of the source label values.
// Only applicable when the action is `HashMod`.
modulus?: int
// Regular expression against which the extracted value is
// matched.
regex?: string
// Replacement value against which a Replace action is performed
// if the regular expression matches.
// Regex capture groups are available.
replacement?: string
// Separator is the string between concatenated SourceLabels.
separator?: string
// The source labels select values from existing labels. Their
// content is concatenated using the configured Separator and
// matched against the configured regular expression.
sourceLabels?: [...=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]
// Label to which the resulting string is written in a
// replacement.
// It is mandatory for `Replace`, `HashMod`, `Lowercase`,
// `Uppercase`, `KeepEqual` and `DropEqual` actions.
// Regex capture groups are available.
targetLabel?: string
}]
// HTTP scheme to use for scraping.
// `http` and `https` are the expected values unless you rewrite
// the `__scheme__` label via relabeling.
// If empty, Prometheus uses the default value `http`.
scheme?: "http" | "https"
// Timeout after which Prometheus considers the scrape to be
// failed.
// If empty, Prometheus uses the global scrape timeout unless it
// is less than the target's scrape interval value in which the
// latter is used.
scrapeTimeout?: =~"^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$"
// Name or number of the target port of the `Pod` object behind
// the Service. The port must be specified with the container's
// port property.
targetPort?: (int | string) & {
string
}
// TLS configuration to use when scraping the target.
tlsConfig?: {
// Certificate authority used when verifying server certificates.
ca?: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Path to the CA cert in the Prometheus container to use for the
// targets.
caFile?: string
// Client certificate to present when doing client-authentication.
cert?: {
// ConfigMap containing data to use for the targets.
configMap?: {
// The key to select.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the ConfigMap or its key must be defined
optional?: bool
}
// Secret containing data to use for the targets.
secret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
}
// Path to the client cert file in the Prometheus container for
// the targets.
certFile?: string
// Disable target certificate validation.
insecureSkipVerify?: bool
// Path to the client key file in the Prometheus container for the
// targets.
keyFile?: string
// Secret containing the client key file for the targets.
keySecret?: {
// The key of the secret to select from. Must be a valid secret
// key.
key: string
// Name of the referent. More info:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// TODO: Add other useful fields. apiVersion, kind, uid?
name?: string
// Specify whether the Secret or its key must be defined
optional?: bool
}
// Used to verify the hostname for the targets.
serverName?: string
}
// `trackTimestampsStaleness` defines whether Prometheus tracks
// staleness of the metrics that have an explicit timestamp
// present in scraped data. Has no effect if `honorTimestamps` is
// false.
// It requires Prometheus >= v2.48.0.
trackTimestampsStaleness?: bool
}]
// `jobLabel` selects the label from the associated Kubernetes
// `Service` object which will be used as the `job` label for all
// metrics.
// For example if `jobLabel` is set to `foo` and the Kubernetes
// `Service` object is labeled with `foo: bar`, then Prometheus
// adds the `job="bar"` label to all ingested metrics.
// If the value of this field is empty or if the label doesn't
// exist for the given Service, the `job` label of the metrics
// defaults to the name of the associated Kubernetes `Service`.
jobLabel?: string
// Per-scrape limit on the number of targets dropped by relabeling
// that will be kept in memory. 0 means no limit.
// It requires Prometheus >= v2.47.0.
keepDroppedTargets?: int
// Per-scrape limit on number of labels that will be accepted for
// a sample.
// It requires Prometheus >= v2.27.0.
labelLimit?: int
// Per-scrape limit on length of labels name that will be accepted
// for a sample.
// It requires Prometheus >= v2.27.0.
labelNameLengthLimit?: int
// Per-scrape limit on length of labels value that will be
// accepted for a sample.
// It requires Prometheus >= v2.27.0.
labelValueLengthLimit?: int
// Selector to select which namespaces the Kubernetes `Endpoints`
// objects are discovered from.
namespaceSelector?: {
// Boolean describing whether all namespaces are selected in
// contrast to a list restricting them.
any?: bool
// List of namespace names to select from.
matchNames?: [...string]
}
// `podTargetLabels` defines the labels which are transferred from
// the associated Kubernetes `Pod` object onto the ingested
// metrics.
podTargetLabels?: [...string]
// `sampleLimit` defines a per-scrape limit on the number of
// scraped samples that will be accepted.
sampleLimit?: int
// The scrape class to apply.
scrapeClass?: strings.MinRunes(1)
// `scrapeProtocols` defines the protocols to negotiate during a
// scrape. It tells clients the protocols supported by Prometheus
// in order of preference (from most to least preferred).
// If unset, Prometheus uses its default value.
// It requires Prometheus >= v2.49.0.
scrapeProtocols?: [..."PrometheusProto" | "OpenMetricsText0.0.1" | "OpenMetricsText1.0.0" | "PrometheusText0.0.4"]
// Label selector to select the Kubernetes `Endpoints` objects.
selector: {
// matchExpressions is a list of label selector requirements. The
// requirements are ANDed.
matchExpressions?: [...{
// key is the label key that the selector applies to.
key: string
// operator represents a key's relationship to a set of values.
// Valid operators are In, NotIn, Exists and DoesNotExist.
operator: string
// values is an array of string values. If the operator is In or
// NotIn, the values array must be non-empty. If the operator is
// Exists or DoesNotExist, the values array must be empty. This
// array is replaced during a strategic merge patch.
values?: [...string]
}]
// matchLabels is a map of {key,value} pairs. A single {key,value}
// in the matchLabels map is equivalent to an element of
// matchExpressions, whose key field is "key", the operator is
// "In", and the values array contains only "value". The
// requirements are ANDed.
matchLabels?: {
[string]: string
}
}
// `targetLabels` defines the labels which are transferred from
// the associated Kubernetes `Service` object onto the ingested
// metrics.
targetLabels?: [...string]
// `targetLimit` defines a limit on the number of scraped targets
// that will be accepted.
targetLimit?: int
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,967 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha3
import "strings"
#DestinationRule: {
// Configuration affecting load balancing, outlier detection, etc.
// See more details at:
// https://istio.io/docs/reference/config/networking/destination-rule.html
spec!: #DestinationRuleSpec
apiVersion: "networking.istio.io/v1alpha3"
kind: "DestinationRule"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting load balancing, outlier detection, etc.
// See more details at:
// https://istio.io/docs/reference/config/networking/destination-rule.html
#DestinationRuleSpec: {
// A list of namespaces to which this destination rule is
// exported.
exportTo?: [...string]
// The name of a service from the service registry.
host: string
// One or more named sets that represent individual versions of a
// service.
subsets?: [...{
// Labels apply a filter over the endpoints of a service in the
// service registry.
labels?: {
[string]: string
}
// Name of the subset.
name: string
// Traffic policies that apply to this subset.
trafficPolicy?: {
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
// Traffic policies specific to individual ports.
portLevelSettings?: [...{
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
port?: {
number?: int
}
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
}]
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
// Configuration of tunneling TCP over other transport or
// application layers for the host configured in the
// DestinationRule.
tunnel?: {
// Specifies which protocol to use for tunneling the downstream
// connection.
protocol?: string
// Specifies a host to which the downstream connection is
// tunneled.
targetHost: string
// Specifies a port to which the downstream connection is
// tunneled.
targetPort: int
}
}
}]
// Traffic policies to apply (load balancing policy, connection
// pool sizes, outlier detection).
trafficPolicy?: {
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
// Traffic policies specific to individual ports.
portLevelSettings?: [...{
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
port?: {
number?: int
}
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
}]
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
// Configuration of tunneling TCP over other transport or
// application layers for the host configured in the
// DestinationRule.
tunnel?: {
// Specifies which protocol to use for tunneling the downstream
// connection.
protocol?: string
// Specifies a host to which the downstream connection is
// tunneled.
targetHost: string
// Specifies a port to which the downstream connection is
// tunneled.
targetPort: int
}
}
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which a policy should be applied.
matchLabels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,967 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1beta1
import "strings"
#DestinationRule: {
// Configuration affecting load balancing, outlier detection, etc.
// See more details at:
// https://istio.io/docs/reference/config/networking/destination-rule.html
spec!: #DestinationRuleSpec
apiVersion: "networking.istio.io/v1beta1"
kind: "DestinationRule"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting load balancing, outlier detection, etc.
// See more details at:
// https://istio.io/docs/reference/config/networking/destination-rule.html
#DestinationRuleSpec: {
// A list of namespaces to which this destination rule is
// exported.
exportTo?: [...string]
// The name of a service from the service registry.
host: string
// One or more named sets that represent individual versions of a
// service.
subsets?: [...{
// Labels apply a filter over the endpoints of a service in the
// service registry.
labels?: {
[string]: string
}
// Name of the subset.
name: string
// Traffic policies that apply to this subset.
trafficPolicy?: {
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
// Traffic policies specific to individual ports.
portLevelSettings?: [...{
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
port?: {
number?: int
}
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
}]
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
// Configuration of tunneling TCP over other transport or
// application layers for the host configured in the
// DestinationRule.
tunnel?: {
// Specifies which protocol to use for tunneling the downstream
// connection.
protocol?: string
// Specifies a host to which the downstream connection is
// tunneled.
targetHost: string
// Specifies a port to which the downstream connection is
// tunneled.
targetPort: int
}
}
}]
// Traffic policies to apply (load balancing policy, connection
// pool sizes, outlier detection).
trafficPolicy?: {
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
// Traffic policies specific to individual ports.
portLevelSettings?: [...{
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Settings controlling the load balancer algorithms.
loadBalancer?: ({} | {
simple: _
} | {
consistentHash: _
}) & {
consistentHash?: ({} | {
httpHeaderName: _
} | {
httpCookie: _
} | {
useSourceIp: _
} | {
httpQueryParameterName: _
}) & ({} | {
ringHash: _
} | {
maglev: _
}) & {
// Hash based on HTTP cookie.
httpCookie?: {
// Name of the cookie.
name: string
// Path to set for the cookie.
path?: string
// Lifetime of the cookie.
ttl?: string
}
// Hash based on a specific HTTP header.
httpHeaderName?: string
// Hash based on a specific HTTP query parameter.
httpQueryParameterName?: string
maglev?: {
// The table size for Maglev hashing.
tableSize?: int
}
// Deprecated.
minimumRingSize?: int
ringHash?: {
// The minimum number of virtual nodes to use for the hash ring.
minimumRingSize?: int
}
// Hash based on the source IP address.
useSourceIp?: bool
}
localityLbSetting?: {
// Optional: only one of distribute, failover or failoverPriority
// can be set.
distribute?: [...{
// Originating locality, '/' separated, e.g.
from?: string
// Map of upstream localities to traffic distribution weights.
to?: {
[string]: int
}
}]
// enable locality load balancing, this is DestinationRule-level
// and will override mesh wide settings in entirety.
enabled?: null | bool
// Optional: only one of distribute, failover or failoverPriority
// can be set.
failover?: [...{
// Originating region.
from?: string
// Destination region the traffic will fail over to when endpoints
// in the 'from' region becomes unhealthy.
to?: string
}]
// failoverPriority is an ordered list of labels used to sort
// endpoints to do priority based load balancing.
failoverPriority?: [...string]
}
simple?: "UNSPECIFIED" | "LEAST_CONN" | "RANDOM" | "PASSTHROUGH" | "ROUND_ROBIN" | "LEAST_REQUEST"
// Represents the warmup duration of Service.
warmupDurationSecs?: string
}
outlierDetection?: {
// Minimum ejection duration.
baseEjectionTime?: string
// Number of 5xx errors before a host is ejected from the
// connection pool.
consecutive5xxErrors?: null | int
consecutiveErrors?: int
// Number of gateway errors before a host is ejected from the
// connection pool.
consecutiveGatewayErrors?: null | int
// The number of consecutive locally originated failures before
// ejection occurs.
consecutiveLocalOriginFailures?: null | int
// Time interval between ejection sweep analysis.
interval?: string
// Maximum % of hosts in the load balancing pool for the upstream
// service that can be ejected.
maxEjectionPercent?: int
// Outlier detection will be enabled as long as the associated
// load balancing pool has at least min_health_percent hosts in
// healthy mode.
minHealthPercent?: int
// Determines whether to distinguish local origin failures from
// external errors.
splitExternalLocalOriginErrors?: bool
}
port?: {
number?: int
}
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
}]
// TLS related settings for connections to the upstream service.
tls?: {
// OPTIONAL: The path to the file containing certificate authority
// certificates to use in verifying a presented server
// certificate.
caCertificates?: string
// REQUIRED if mode is `MUTUAL`.
clientCertificate?: string
// The name of the secret that holds the TLS certs for the client
// including the CA certificates.
credentialName?: string
// `insecureSkipVerify` specifies whether the proxy should skip
// verifying the CA signature and SAN for the server certificate
// corresponding to the host.
insecureSkipVerify?: null | bool
// Indicates whether connections to this port should be secured
// using TLS.
mode?: "DISABLE" | "SIMPLE" | "MUTUAL" | "ISTIO_MUTUAL"
// REQUIRED if mode is `MUTUAL`.
privateKey?: string
// SNI string to present to the server during TLS handshake.
sni?: string
// A list of alternate names to verify the subject identity in the
// certificate.
subjectAltNames?: [...string]
}
// Configuration of tunneling TCP over other transport or
// application layers for the host configured in the
// DestinationRule.
tunnel?: {
// Specifies which protocol to use for tunneling the downstream
// connection.
protocol?: string
// Specifies a host to which the downstream connection is
// tunneled.
targetHost: string
// Specifies a port to which the downstream connection is
// tunneled.
targetPort: int
}
}
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which a policy should be applied.
matchLabels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,185 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha3
import "strings"
#EnvoyFilter: {
// Customizing Envoy configuration generated by Istio. See more
// details at:
// https://istio.io/docs/reference/config/networking/envoy-filter.html
spec!: #EnvoyFilterSpec
apiVersion: "networking.istio.io/v1alpha3"
kind: "EnvoyFilter"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Customizing Envoy configuration generated by Istio. See more
// details at:
// https://istio.io/docs/reference/config/networking/envoy-filter.html
#EnvoyFilterSpec: {
// One or more patches with match conditions.
configPatches?: [...{
// Specifies where in the Envoy configuration, the patch should be
// applied.
applyTo?: "INVALID" | "LISTENER" | "FILTER_CHAIN" | "NETWORK_FILTER" | "HTTP_FILTER" | "ROUTE_CONFIGURATION" | "VIRTUAL_HOST" | "HTTP_ROUTE" | "CLUSTER" | "EXTENSION_CONFIG" | "BOOTSTRAP" | "LISTENER_FILTER"
// Match on listener/route configuration/cluster.
match?: ({} | {
listener: _
} | {
routeConfiguration: _
} | {
cluster: _
}) & {
// Match on envoy cluster attributes.
cluster?: {
// The exact name of the cluster to match.
name?: string
// The service port for which this cluster was generated.
portNumber?: int
// The fully qualified service name for this cluster.
service?: string
// The subset associated with the service.
subset?: string
}
// The specific config generation context to match on.
context?: "ANY" | "SIDECAR_INBOUND" | "SIDECAR_OUTBOUND" | "GATEWAY"
// Match on envoy listener attributes.
listener?: {
// Match a specific filter chain in a listener.
filterChain?: {
// Applies only to sidecars.
applicationProtocols?: string
// The destination_port value used by a filter chain's match
// condition.
destinationPort?: int
// The name of a specific filter to apply the patch to.
filter?: {
// The filter name to match on.
name?: string
subFilter?: {
// The filter name to match on.
name?: string
}
}
// The name assigned to the filter chain.
name?: string
// The SNI value used by a filter chain's match condition.
sni?: string
// Applies only to `SIDECAR_INBOUND` context.
transportProtocol?: string
}
// Match a specific listener filter.
listenerFilter?: string
// Match a specific listener by its name.
name?: string
portName?: string
// The service port/gateway port to which traffic is being
// sent/received.
portNumber?: int
}
// Match on properties associated with a proxy.
proxy?: {
// Match on the node metadata supplied by a proxy when connecting
// to Istio Pilot.
metadata?: {
[string]: string
}
// A regular expression in golang regex format (RE2) that can be
// used to select proxies using a specific version of istio
// proxy.
proxyVersion?: string
}
// Match on envoy HTTP route configuration attributes.
routeConfiguration?: {
// The Istio gateway config's namespace/name for which this route
// configuration was generated.
gateway?: string
// Route configuration name to match on.
name?: string
// Applicable only for GATEWAY context.
portName?: string
// The service port number or gateway server port number for which
// this route configuration was generated.
portNumber?: int
// Match a specific virtual host in a route configuration and
// apply the patch to the virtual host.
vhost?: {
// The VirtualHosts objects generated by Istio are named as
// host:port, where the host typically corresponds to the
// VirtualService's host field or the hostname of a service in
// the registry.
name?: string
// Match a specific route within the virtual host.
route?: {
// Match a route with specific action type.
action?: "ANY" | "ROUTE" | "REDIRECT" | "DIRECT_RESPONSE"
// The Route objects generated by default are named as default.
name?: string
}
}
}
}
// The patch to apply along with the operation.
patch?: {
// Determines the filter insertion order.
filterClass?: "UNSPECIFIED" | "AUTHN" | "AUTHZ" | "STATS"
// Determines how the patch should be applied.
operation?: "INVALID" | "MERGE" | "ADD" | "REMOVE" | "INSERT_BEFORE" | "INSERT_AFTER" | "INSERT_FIRST" | "REPLACE"
// The JSON config of the object being patched.
value?: {}
}
}]
// Priority defines the order in which patch sets are applied
// within a context.
priority?: int
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which the configuration should be applied.
labels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,115 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha3
import "strings"
#Gateway: {
// Configuration affecting edge load balancer. See more details
// at:
// https://istio.io/docs/reference/config/networking/gateway.html
spec!: #GatewaySpec
apiVersion: "networking.istio.io/v1alpha3"
kind: "Gateway"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting edge load balancer. See more details
// at:
// https://istio.io/docs/reference/config/networking/gateway.html
#GatewaySpec: {
// One or more labels that indicate a specific set of pods/VMs on
// which this gateway configuration should be applied.
selector?: {
[string]: string
}
// A list of server specifications.
servers?: [...{
// The ip or the Unix domain socket to which the listener should
// be bound to.
bind?: string
defaultEndpoint?: string
// One or more hosts exposed by this gateway.
hosts: [...string]
// An optional name of the server, when set must be unique across
// all servers.
name?: string
// The Port on which the proxy should listen for incoming
// connections.
port: {
// Label assigned to the port.
name: string
// A valid non-negative integer port number.
number: int
// The protocol exposed on the port.
protocol: string
targetPort?: int
}
// Set of TLS related options that govern the server's behavior.
tls?: {
// REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
caCertificates?: string
// Optional: If specified, only support the specified cipher list.
cipherSuites?: [...string]
// For gateways running on Kubernetes, the name of the secret that
// holds the TLS certs including the CA certificates.
credentialName?: string
// If set to true, the load balancer will send a 301 redirect for
// all http connections, asking the clients to use HTTPS.
httpsRedirect?: bool
// Optional: Maximum TLS protocol version.
maxProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Minimum TLS protocol version.
minProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Indicates whether connections to this port should be
// secured using TLS.
mode?: "PASSTHROUGH" | "SIMPLE" | "MUTUAL" | "AUTO_PASSTHROUGH" | "ISTIO_MUTUAL" | "OPTIONAL_MUTUAL"
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
privateKey?: string
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
serverCertificate?: string
// A list of alternate names to verify the subject identity in the
// certificate presented by the client.
subjectAltNames?: [...string]
// An optional list of hex-encoded SHA-256 hashes of the
// authorized client certificates.
verifyCertificateHash?: [...string]
// An optional list of base64-encoded SHA-256 hashes of the SPKIs
// of authorized client certificates.
verifyCertificateSpki?: [...string]
}
}]
}

View File

@@ -0,0 +1,115 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1beta1
import "strings"
#Gateway: {
// Configuration affecting edge load balancer. See more details
// at:
// https://istio.io/docs/reference/config/networking/gateway.html
spec!: #GatewaySpec
apiVersion: "networking.istio.io/v1beta1"
kind: "Gateway"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting edge load balancer. See more details
// at:
// https://istio.io/docs/reference/config/networking/gateway.html
#GatewaySpec: {
// One or more labels that indicate a specific set of pods/VMs on
// which this gateway configuration should be applied.
selector?: {
[string]: string
}
// A list of server specifications.
servers?: [...{
// The ip or the Unix domain socket to which the listener should
// be bound to.
bind?: string
defaultEndpoint?: string
// One or more hosts exposed by this gateway.
hosts: [...string]
// An optional name of the server, when set must be unique across
// all servers.
name?: string
// The Port on which the proxy should listen for incoming
// connections.
port: {
// Label assigned to the port.
name: string
// A valid non-negative integer port number.
number: int
// The protocol exposed on the port.
protocol: string
targetPort?: int
}
// Set of TLS related options that govern the server's behavior.
tls?: {
// REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
caCertificates?: string
// Optional: If specified, only support the specified cipher list.
cipherSuites?: [...string]
// For gateways running on Kubernetes, the name of the secret that
// holds the TLS certs including the CA certificates.
credentialName?: string
// If set to true, the load balancer will send a 301 redirect for
// all http connections, asking the clients to use HTTPS.
httpsRedirect?: bool
// Optional: Maximum TLS protocol version.
maxProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Minimum TLS protocol version.
minProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Indicates whether connections to this port should be
// secured using TLS.
mode?: "PASSTHROUGH" | "SIMPLE" | "MUTUAL" | "AUTO_PASSTHROUGH" | "ISTIO_MUTUAL" | "OPTIONAL_MUTUAL"
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
privateKey?: string
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
serverCertificate?: string
// A list of alternate names to verify the subject identity in the
// certificate presented by the client.
subjectAltNames?: [...string]
// An optional list of hex-encoded SHA-256 hashes of the
// authorized client certificates.
verifyCertificateHash?: [...string]
// An optional list of base64-encoded SHA-256 hashes of the SPKIs
// of authorized client certificates.
verifyCertificateSpki?: [...string]
}
}]
}

View File

@@ -0,0 +1,54 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1beta1
import "strings"
#ProxyConfig: {
// Provides configuration for individual workloads. See more
// details at:
// https://istio.io/docs/reference/config/networking/proxy-config.html
spec!: #ProxyConfigSpec
apiVersion: "networking.istio.io/v1beta1"
kind: "ProxyConfig"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Provides configuration for individual workloads. See more
// details at:
// https://istio.io/docs/reference/config/networking/proxy-config.html
#ProxyConfigSpec: {
// The number of worker threads to run.
concurrency?: null | int
// Additional environment variables for the proxy.
environmentVariables?: {
[string]: string
}
image?: {
// The image type of the image.
imageType?: string
}
selector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which a policy should be applied.
matchLabels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,107 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha3
import "strings"
#ServiceEntry: {
// Configuration affecting service registry. See more details at:
// https://istio.io/docs/reference/config/networking/service-entry.html
spec!: #ServiceEntrySpec
apiVersion: "networking.istio.io/v1alpha3"
kind: "ServiceEntry"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting service registry. See more details at:
// https://istio.io/docs/reference/config/networking/service-entry.html
#ServiceEntrySpec: {
// The virtual IP addresses associated with the service.
addresses?: [...string]
// One or more endpoints associated with the service.
endpoints?: [...{
// Address associated with the network endpoint without the port.
address?: string
// One or more labels associated with the endpoint.
labels?: {
[string]: string
}
// The locality associated with the endpoint.
locality?: string
// Network enables Istio to group endpoints resident in the same
// L3 domain/network.
network?: string
// Set of ports associated with the endpoint.
ports?: {
[string]: int
}
// The service account associated with the workload if a sidecar
// is present in the workload.
serviceAccount?: string
// The load balancing weight associated with the endpoint.
weight?: int
}]
// A list of namespaces to which this service is exported.
exportTo?: [...string]
// The hosts associated with the ServiceEntry.
hosts: [...string]
// Specify whether the service should be considered external to
// the mesh or part of the mesh.
location?: "MESH_EXTERNAL" | "MESH_INTERNAL"
// The ports associated with the external service.
ports?: [...{
// Label assigned to the port.
name: string
// A valid non-negative integer port number.
number: int
// The protocol exposed on the port.
protocol?: string
// The port number on the endpoint where the traffic will be
// received.
targetPort?: int
}]
// Service resolution mode for the hosts.
resolution?: "NONE" | "STATIC" | "DNS" | "DNS_ROUND_ROBIN"
// If specified, the proxy will verify that the server
// certificate's subject alternate name matches one of the
// specified values.
subjectAltNames?: [...string]
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which the configuration should be applied.
labels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,107 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1beta1
import "strings"
#ServiceEntry: {
// Configuration affecting service registry. See more details at:
// https://istio.io/docs/reference/config/networking/service-entry.html
spec!: #ServiceEntrySpec
apiVersion: "networking.istio.io/v1beta1"
kind: "ServiceEntry"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting service registry. See more details at:
// https://istio.io/docs/reference/config/networking/service-entry.html
#ServiceEntrySpec: {
// The virtual IP addresses associated with the service.
addresses?: [...string]
// One or more endpoints associated with the service.
endpoints?: [...{
// Address associated with the network endpoint without the port.
address?: string
// One or more labels associated with the endpoint.
labels?: {
[string]: string
}
// The locality associated with the endpoint.
locality?: string
// Network enables Istio to group endpoints resident in the same
// L3 domain/network.
network?: string
// Set of ports associated with the endpoint.
ports?: {
[string]: int
}
// The service account associated with the workload if a sidecar
// is present in the workload.
serviceAccount?: string
// The load balancing weight associated with the endpoint.
weight?: int
}]
// A list of namespaces to which this service is exported.
exportTo?: [...string]
// The hosts associated with the ServiceEntry.
hosts: [...string]
// Specify whether the service should be considered external to
// the mesh or part of the mesh.
location?: "MESH_EXTERNAL" | "MESH_INTERNAL"
// The ports associated with the external service.
ports?: [...{
// Label assigned to the port.
name: string
// A valid non-negative integer port number.
number: int
// The protocol exposed on the port.
protocol?: string
// The port number on the endpoint where the traffic will be
// received.
targetPort?: int
}]
// Service resolution mode for the hosts.
resolution?: "NONE" | "STATIC" | "DNS" | "DNS_ROUND_ROBIN"
// If specified, the proxy will verify that the server
// certificate's subject alternate name matches one of the
// specified values.
subjectAltNames?: [...string]
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which the configuration should be applied.
labels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,280 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha3
import "strings"
#Sidecar: {
// Configuration affecting network reachability of a sidecar. See
// more details at:
// https://istio.io/docs/reference/config/networking/sidecar.html
spec!: #SidecarSpec
apiVersion: "networking.istio.io/v1alpha3"
kind: "Sidecar"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting network reachability of a sidecar. See
// more details at:
// https://istio.io/docs/reference/config/networking/sidecar.html
#SidecarSpec: {
// Egress specifies the configuration of the sidecar for
// processing outbound traffic from the attached workload
// instance to other services in the mesh.
egress?: [...{
// The IP(IPv4 or IPv6) or the Unix domain socket to which the
// listener should be bound to.
bind?: string
// When the bind address is an IP, the captureMode option dictates
// how traffic to the listener is expected to be captured (or
// not).
captureMode?: "DEFAULT" | "IPTABLES" | "NONE"
// One or more service hosts exposed by the listener in
// `namespace/dnsName` format.
hosts: [...string]
// The port associated with the listener.
port?: {
// Label assigned to the port.
name?: string
// A valid non-negative integer port number.
number?: int
// The protocol exposed on the port.
protocol?: string
targetPort?: int
}
}]
// Settings controlling the volume of connections Envoy will
// accept from the network.
inboundConnectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Ingress specifies the configuration of the sidecar for
// processing inbound traffic to the attached workload instance.
ingress?: [...{
// The IP(IPv4 or IPv6) to which the listener should be bound.
bind?: string
// The captureMode option dictates how traffic to the listener is
// expected to be captured (or not).
captureMode?: "DEFAULT" | "IPTABLES" | "NONE"
// Settings controlling the volume of connections Envoy will
// accept from the network.
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// The IP endpoint or Unix domain socket to which traffic should
// be forwarded to.
defaultEndpoint?: string
// The port associated with the listener.
port: {
// Label assigned to the port.
name?: string
// A valid non-negative integer port number.
number?: int
// The protocol exposed on the port.
protocol?: string
targetPort?: int
}
// Set of TLS related options that will enable TLS termination on
// the sidecar for requests originating from outside the mesh.
tls?: {
// REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
caCertificates?: string
// Optional: If specified, only support the specified cipher list.
cipherSuites?: [...string]
// For gateways running on Kubernetes, the name of the secret that
// holds the TLS certs including the CA certificates.
credentialName?: string
// If set to true, the load balancer will send a 301 redirect for
// all http connections, asking the clients to use HTTPS.
httpsRedirect?: bool
// Optional: Maximum TLS protocol version.
maxProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Minimum TLS protocol version.
minProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Indicates whether connections to this port should be
// secured using TLS.
mode?: "PASSTHROUGH" | "SIMPLE" | "MUTUAL" | "AUTO_PASSTHROUGH" | "ISTIO_MUTUAL" | "OPTIONAL_MUTUAL"
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
privateKey?: string
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
serverCertificate?: string
// A list of alternate names to verify the subject identity in the
// certificate presented by the client.
subjectAltNames?: [...string]
// An optional list of hex-encoded SHA-256 hashes of the
// authorized client certificates.
verifyCertificateHash?: [...string]
// An optional list of base64-encoded SHA-256 hashes of the SPKIs
// of authorized client certificates.
verifyCertificateSpki?: [...string]
}
}]
// Configuration for the outbound traffic policy.
outboundTrafficPolicy?: {
egressProxy?: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
mode?: "REGISTRY_ONLY" | "ALLOW_ANY"
}
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which the configuration should be applied.
labels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,280 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1beta1
import "strings"
#Sidecar: {
// Configuration affecting network reachability of a sidecar. See
// more details at:
// https://istio.io/docs/reference/config/networking/sidecar.html
spec!: #SidecarSpec
apiVersion: "networking.istio.io/v1beta1"
kind: "Sidecar"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting network reachability of a sidecar. See
// more details at:
// https://istio.io/docs/reference/config/networking/sidecar.html
#SidecarSpec: {
// Egress specifies the configuration of the sidecar for
// processing outbound traffic from the attached workload
// instance to other services in the mesh.
egress?: [...{
// The IP(IPv4 or IPv6) or the Unix domain socket to which the
// listener should be bound to.
bind?: string
// When the bind address is an IP, the captureMode option dictates
// how traffic to the listener is expected to be captured (or
// not).
captureMode?: "DEFAULT" | "IPTABLES" | "NONE"
// One or more service hosts exposed by the listener in
// `namespace/dnsName` format.
hosts: [...string]
// The port associated with the listener.
port?: {
// Label assigned to the port.
name?: string
// A valid non-negative integer port number.
number?: int
// The protocol exposed on the port.
protocol?: string
targetPort?: int
}
}]
// Settings controlling the volume of connections Envoy will
// accept from the network.
inboundConnectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// Ingress specifies the configuration of the sidecar for
// processing inbound traffic to the attached workload instance.
ingress?: [...{
// The IP(IPv4 or IPv6) to which the listener should be bound.
bind?: string
// The captureMode option dictates how traffic to the listener is
// expected to be captured (or not).
captureMode?: "DEFAULT" | "IPTABLES" | "NONE"
// Settings controlling the volume of connections Envoy will
// accept from the network.
connectionPool?: {
// HTTP connection pool settings.
http?: {
// Specify if http1.1 connection should be upgraded to http2 for
// the associated destination.
h2UpgradePolicy?: "DEFAULT" | "DO_NOT_UPGRADE" | "UPGRADE"
// Maximum number of requests that will be queued while waiting
// for a ready connection pool connection.
http1MaxPendingRequests?: int
// Maximum number of active requests to a destination.
http2MaxRequests?: int
// The idle timeout for upstream connection pool connections.
idleTimeout?: string
// Maximum number of requests per connection to a backend.
maxRequestsPerConnection?: int
// Maximum number of retries that can be outstanding to all hosts
// in a cluster at a given time.
maxRetries?: int
// If set to true, client protocol will be preserved while
// initiating connection to backend.
useClientProtocol?: bool
}
// Settings common to both HTTP and TCP upstream connections.
tcp?: {
// TCP connection timeout.
connectTimeout?: string
// The maximum duration of a connection.
maxConnectionDuration?: string
// Maximum number of HTTP1 /TCP connections to a destination host.
maxConnections?: int
// If set then set SO_KEEPALIVE on the socket to enable TCP
// Keepalives.
tcpKeepalive?: {
// The time duration between keep-alive probes.
interval?: string
// Maximum number of keepalive probes to send without response
// before deciding the connection is dead.
probes?: int
// The time duration a connection needs to be idle before
// keep-alive probes start being sent.
time?: string
}
}
}
// The IP endpoint or Unix domain socket to which traffic should
// be forwarded to.
defaultEndpoint?: string
// The port associated with the listener.
port: {
// Label assigned to the port.
name?: string
// A valid non-negative integer port number.
number?: int
// The protocol exposed on the port.
protocol?: string
targetPort?: int
}
// Set of TLS related options that will enable TLS termination on
// the sidecar for requests originating from outside the mesh.
tls?: {
// REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
caCertificates?: string
// Optional: If specified, only support the specified cipher list.
cipherSuites?: [...string]
// For gateways running on Kubernetes, the name of the secret that
// holds the TLS certs including the CA certificates.
credentialName?: string
// If set to true, the load balancer will send a 301 redirect for
// all http connections, asking the clients to use HTTPS.
httpsRedirect?: bool
// Optional: Maximum TLS protocol version.
maxProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Minimum TLS protocol version.
minProtocolVersion?: "TLS_AUTO" | "TLSV1_0" | "TLSV1_1" | "TLSV1_2" | "TLSV1_3"
// Optional: Indicates whether connections to this port should be
// secured using TLS.
mode?: "PASSTHROUGH" | "SIMPLE" | "MUTUAL" | "AUTO_PASSTHROUGH" | "ISTIO_MUTUAL" | "OPTIONAL_MUTUAL"
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
privateKey?: string
// REQUIRED if mode is `SIMPLE` or `MUTUAL`.
serverCertificate?: string
// A list of alternate names to verify the subject identity in the
// certificate presented by the client.
subjectAltNames?: [...string]
// An optional list of hex-encoded SHA-256 hashes of the
// authorized client certificates.
verifyCertificateHash?: [...string]
// An optional list of base64-encoded SHA-256 hashes of the SPKIs
// of authorized client certificates.
verifyCertificateSpki?: [...string]
}
}]
// Configuration for the outbound traffic policy.
outboundTrafficPolicy?: {
egressProxy?: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
mode?: "REGISTRY_ONLY" | "ALLOW_ANY"
}
workloadSelector?: {
// One or more labels that indicate a specific set of pods/VMs on
// which the configuration should be applied.
labels?: {
[string]: string
}
}
}

View File

@@ -0,0 +1,594 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1alpha3
import "strings"
#VirtualService: {
// Configuration affecting label/content routing, sni routing,
// etc. See more details at:
// https://istio.io/docs/reference/config/networking/virtual-service.html
spec!: #VirtualServiceSpec
apiVersion: "networking.istio.io/v1alpha3"
kind: "VirtualService"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting label/content routing, sni routing,
// etc. See more details at:
// https://istio.io/docs/reference/config/networking/virtual-service.html
#VirtualServiceSpec: {
// A list of namespaces to which this virtual service is exported.
exportTo?: [...string]
// The names of gateways and sidecars that should apply these
// routes.
gateways?: [...string]
// The destination hosts to which traffic is being sent.
hosts?: [...string]
// An ordered list of route rules for HTTP traffic.
http?: [...{
// Cross-Origin Resource Sharing policy (CORS).
corsPolicy?: {
// Indicates whether the caller is allowed to send the actual
// request (not the preflight) using credentials.
allowCredentials?: null | bool
// List of HTTP headers that can be used when requesting the
// resource.
allowHeaders?: [...string]
// List of HTTP methods allowed to access the resource.
allowMethods?: [...string]
allowOrigin?: [...string]
// String patterns that match allowed origins.
allowOrigins?: [...({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}]
// A list of HTTP headers that the browsers are allowed to access.
exposeHeaders?: [...string]
// Specifies how long the results of a preflight request can be
// cached.
maxAge?: string
}
// Delegate is used to specify the particular VirtualService which
// can be used to define delegate HTTPRoute.
delegate?: {
// Name specifies the name of the delegate VirtualService.
name?: string
// Namespace specifies the namespace where the delegate
// VirtualService resides.
namespace?: string
}
// A HTTP rule can either return a direct_response, redirect or
// forward (default) traffic.
directResponse?: {
// Specifies the content of the response body.
body?: ({} | {
string: _
} | {
bytes: _
}) & {
// response body as base64 encoded bytes.
bytes?: string
string?: string
}
// Specifies the HTTP response status to be returned.
status: int
}
// Fault injection policy to apply on HTTP traffic at the client
// side.
fault?: {
// Abort Http request attempts and return error codes back to
// downstream service, giving the impression that the upstream
// service is faulty.
abort?: ({} | {
httpStatus: _
} | {
grpcStatus: _
} | {
http2Error: _
}) & {
// GRPC status code to use to abort the request.
grpcStatus?: string
http2Error?: string
// HTTP status code to use to abort the Http request.
httpStatus?: int
percentage?: {
value?: number
}
}
// Delay requests before forwarding, emulating various failures
// such as network issues, overloaded upstream service, etc.
delay?: ({} | {
fixedDelay: _
} | {
exponentialDelay: _
}) & {
exponentialDelay?: string
// Add a fixed delay before forwarding the request.
fixedDelay?: string
// Percentage of requests on which the delay will be injected
// (0-100).
percent?: int
percentage?: {
value?: number
}
}
}
headers?: {
request?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
response?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
}
// Match conditions to be satisfied for the rule to be activated.
match?: [...{
// HTTP Authority values are case-sensitive and formatted as
// follows: - `exact: "value"` for exact string match - `prefix:
// "value"` for prefix-based match - `regex: "value"` for RE2
// style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
authority?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// Names of gateways where the rule should be applied.
gateways?: [...string]
// The header keys must be lowercase and use hyphen as the
// separator, e.g.
headers?: {
[string]: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
}
// Flag to specify whether the URI matching should be
// case-insensitive.
ignoreUriCase?: bool
// HTTP Method values are case-sensitive and formatted as follows:
// - `exact: "value"` for exact string match - `prefix: "value"`
// for prefix-based match - `regex: "value"` for RE2 style
// regex-based match (https://github.com/google/re2/wiki/Syntax).
method?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// The name assigned to a match.
name?: string
// Specifies the ports on the host that is being addressed.
port?: int
// Query parameters for matching.
queryParams?: {
[string]: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
}
// URI Scheme values are case-sensitive and formatted as follows:
// - `exact: "value"` for exact string match - `prefix: "value"`
// for prefix-based match - `regex: "value"` for RE2 style
// regex-based match (https://github.com/google/re2/wiki/Syntax).
scheme?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// One or more labels that constrain the applicability of a rule
// to source (client) workloads with the given labels.
sourceLabels?: {
[string]: string
}
// Source namespace constraining the applicability of a rule to
// workloads in that namespace.
sourceNamespace?: string
// The human readable prefix to use when emitting statistics for
// this route.
statPrefix?: string
// URI to match values are case-sensitive and formatted as
// follows: - `exact: "value"` for exact string match - `prefix:
// "value"` for prefix-based match - `regex: "value"` for RE2
// style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
uri?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// withoutHeader has the same syntax with the header, but has
// opposite meaning.
withoutHeaders?: {
[string]: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
}
}]
// Mirror HTTP traffic to a another destination in addition to
// forwarding the requests to the intended destination.
mirror?: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
mirror_percent?: null | int
mirrorPercent?: null | int
mirrorPercentage?: {
value?: number
}
// Specifies the destinations to mirror HTTP traffic in addition
// to the original destination.
mirrors?: [...{
// Destination specifies the target of the mirror operation.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
percentage?: {
value?: number
}
}]
// The name assigned to the route for debugging purposes.
name?: string
// A HTTP rule can either return a direct_response, redirect or
// forward (default) traffic.
redirect?: ({} | {
port: _
} | {
derivePort: _
}) & {
// On a redirect, overwrite the Authority/Host portion of the URL
// with this value.
authority?: string
// On a redirect, dynamically set the port: *
// FROM_PROTOCOL_DEFAULT: automatically set to 80 for HTTP and
// 443 for HTTPS.
derivePort?: "FROM_PROTOCOL_DEFAULT" | "FROM_REQUEST_PORT"
// On a redirect, overwrite the port portion of the URL with this
// value.
port?: int
// On a redirect, Specifies the HTTP status code to use in the
// redirect response.
redirectCode?: int
// On a redirect, overwrite the scheme portion of the URL with
// this value.
scheme?: string
// On a redirect, overwrite the Path portion of the URL with this
// value.
uri?: string
}
// Retry policy for HTTP requests.
retries?: {
// Number of retries to be allowed for a given request.
attempts?: int
// Timeout per attempt for a given request, including the initial
// call and any retries.
perTryTimeout?: string
// Specifies the conditions under which retry takes place.
retryOn?: string
// Flag to specify whether the retries should retry to other
// localities.
retryRemoteLocalities?: null | bool
}
// Rewrite HTTP URIs and Authority headers.
rewrite?: {
// rewrite the Authority/Host header with this value.
authority?: string
// rewrite the path (or the prefix) portion of the URI with this
// value.
uri?: string
// rewrite the path portion of the URI with the specified regex.
uriRegexRewrite?: {
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
match?: string
// The string that should replace into matching portions of
// original URI.
rewrite?: string
}
}
// A HTTP rule can either return a direct_response, redirect or
// forward (default) traffic.
route?: [...{
// Destination uniquely identifies the instances of a service to
// which the request/connection should be forwarded to.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
headers?: {
request?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
response?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
}
// Weight specifies the relative proportion of traffic to be
// forwarded to the destination.
weight?: int
}]
// Timeout for HTTP requests, default is disabled.
timeout?: string
}]
// An ordered list of route rules for opaque TCP traffic.
tcp?: [...{
// Match conditions to be satisfied for the rule to be activated.
match?: [...{
// IPv4 or IPv6 ip addresses of destination with optional subnet.
destinationSubnets?: [...string]
// Names of gateways where the rule should be applied.
gateways?: [...string]
// Specifies the port on the host that is being addressed.
port?: int
// One or more labels that constrain the applicability of a rule
// to workloads with the given labels.
sourceLabels?: {
[string]: string
}
// Source namespace constraining the applicability of a rule to
// workloads in that namespace.
sourceNamespace?: string
sourceSubnet?: string
}]
// The destination to which the connection should be forwarded to.
route?: [...{
// Destination uniquely identifies the instances of a service to
// which the request/connection should be forwarded to.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
// Weight specifies the relative proportion of traffic to be
// forwarded to the destination.
weight?: int
}]
}]
// An ordered list of route rule for non-terminated TLS & HTTPS
// traffic.
tls?: [...{
// Match conditions to be satisfied for the rule to be activated.
match: [...{
// IPv4 or IPv6 ip addresses of destination with optional subnet.
destinationSubnets?: [...string]
// Names of gateways where the rule should be applied.
gateways?: [...string]
// Specifies the port on the host that is being addressed.
port?: int
// SNI (server name indicator) to match on.
sniHosts: [...string]
// One or more labels that constrain the applicability of a rule
// to workloads with the given labels.
sourceLabels?: {
[string]: string
}
// Source namespace constraining the applicability of a rule to
// workloads in that namespace.
sourceNamespace?: string
}]
// The destination to which the connection should be forwarded to.
route?: [...{
// Destination uniquely identifies the instances of a service to
// which the request/connection should be forwarded to.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
// Weight specifies the relative proportion of traffic to be
// forwarded to the destination.
weight?: int
}]
}]
}

View File

@@ -0,0 +1,575 @@
// Code generated by timoni. DO NOT EDIT.
//timoni:generate timoni vendor crd -f /home/jeff/workspace/holos-run/holos-infra/deploy/clusters/k2/components/prod-mesh-istio-base/prod-mesh-istio-base.gen.yaml
package v1beta1
import "strings"
#VirtualService: {
// Configuration affecting label/content routing, sni routing,
// etc. See more details at:
// https://istio.io/docs/reference/config/networking/virtual-service.html
spec!: #VirtualServiceSpec
apiVersion: "networking.istio.io/v1beta1"
kind: "VirtualService"
metadata!: {
name!: strings.MaxRunes(253) & strings.MinRunes(1) & {
string
}
namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & {
string
}
labels?: {
[string]: string
}
annotations?: {
[string]: string
}
}
}
// Configuration affecting label/content routing, sni routing,
// etc. See more details at:
// https://istio.io/docs/reference/config/networking/virtual-service.html
#VirtualServiceSpec: {
// A list of namespaces to which this virtual service is exported.
exportTo?: [...string]
// The names of gateways and sidecars that should apply these
// routes.
gateways?: [...string]
// The destination hosts to which traffic is being sent.
hosts?: [...string]
// An ordered list of route rules for HTTP traffic.
http?: [...{
// Cross-Origin Resource Sharing policy (CORS).
corsPolicy?: {
// Indicates whether the caller is allowed to send the actual
// request (not the preflight) using credentials.
allowCredentials?: null | bool
// List of HTTP headers that can be used when requesting the
// resource.
allowHeaders?: [...string]
// List of HTTP methods allowed to access the resource.
allowMethods?: [...string]
allowOrigin?: [...string]
// String patterns that match allowed origins.
allowOrigins?: [...({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}]
// A list of HTTP headers that the browsers are allowed to access.
exposeHeaders?: [...string]
// Specifies how long the results of a preflight request can be
// cached.
maxAge?: string
}
// Delegate is used to specify the particular VirtualService which
// can be used to define delegate HTTPRoute.
delegate?: {
// Name specifies the name of the delegate VirtualService.
name?: string
// Namespace specifies the namespace where the delegate
// VirtualService resides.
namespace?: string
}
// A HTTP rule can either return a direct_response, redirect or
// forward (default) traffic.
directResponse?: {
// Specifies the content of the response body.
body?: ({} | {
string: _
} | {
bytes: _
}) & {
// response body as base64 encoded bytes.
bytes?: string
string?: string
}
// Specifies the HTTP response status to be returned.
status: int
}
// Fault injection policy to apply on HTTP traffic at the client
// side.
fault?: {
// Abort Http request attempts and return error codes back to
// downstream service, giving the impression that the upstream
// service is faulty.
abort?: ({} | {
httpStatus: _
} | {
grpcStatus: _
} | {
http2Error: _
}) & {
// GRPC status code to use to abort the request.
grpcStatus?: string
http2Error?: string
// HTTP status code to use to abort the Http request.
httpStatus?: int
percentage?: {
value?: number
}
}
// Delay requests before forwarding, emulating various failures
// such as network issues, overloaded upstream service, etc.
delay?: ({} | {
fixedDelay: _
} | {
exponentialDelay: _
}) & {
exponentialDelay?: string
// Add a fixed delay before forwarding the request.
fixedDelay?: string
// Percentage of requests on which the delay will be injected
// (0-100).
percent?: int
percentage?: {
value?: number
}
}
}
headers?: {
request?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
response?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
}
// Match conditions to be satisfied for the rule to be activated.
match?: [...{
// HTTP Authority values are case-sensitive and formatted as
// follows: - `exact: "value"` for exact string match - `prefix:
// "value"` for prefix-based match - `regex: "value"` for RE2
// style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
authority?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// Names of gateways where the rule should be applied.
gateways?: [...string]
// The header keys must be lowercase and use hyphen as the
// separator, e.g.
headers?: {
[string]: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
}
// Flag to specify whether the URI matching should be
// case-insensitive.
ignoreUriCase?: bool
// HTTP Method values are case-sensitive and formatted as follows:
// - `exact: "value"` for exact string match - `prefix: "value"`
// for prefix-based match - `regex: "value"` for RE2 style
// regex-based match (https://github.com/google/re2/wiki/Syntax).
method?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// The name assigned to a match.
name?: string
// Specifies the ports on the host that is being addressed.
port?: int
// Query parameters for matching.
queryParams?: {
[string]: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
}
// URI Scheme values are case-sensitive and formatted as follows:
// - `exact: "value"` for exact string match - `prefix: "value"`
// for prefix-based match - `regex: "value"` for RE2 style
// regex-based match (https://github.com/google/re2/wiki/Syntax).
scheme?: ({} | {
exact: _
} | {
prefix: _
} | {
regex: _
}) & {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
// One or more labels that constrain the applicability of a rule
// to source (client) workloads with the given labels.
sourceLabels?: {
[string]: string
}
// Source namespace constraining the applicability of a rule to
// workloads in that namespace.
sourceNamespace?: string
// The human readable prefix to use when emitting statistics for
// this route.
statPrefix?: string
// URI to match values are case-sensitive and formatted as
// follows: - `exact: "value"` for exact string match - `prefix:
// "value"` for prefix-based match - `regex: "value"` for RE2
// style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
uri?: {
exact?: string
prefix?: string
regex?: string
}
// withoutHeader has the same syntax with the header, but has
// opposite meaning.
withoutHeaders?: {
[string]: {
exact?: string
prefix?: string
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
regex?: string
}
}
}]
// Mirror HTTP traffic to a another destination in addition to
// forwarding the requests to the intended destination.
mirror?: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
mirror_percent?: null | int
mirrorPercent?: null | int
mirrorPercentage?: {
value?: number
}
// Specifies the destinations to mirror HTTP traffic in addition
// to the original destination.
mirrors?: [...{
// Destination specifies the target of the mirror operation.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
percentage?: {
value?: number
}
}]
// The name assigned to the route for debugging purposes.
name?: string
// A HTTP rule can either return a direct_response, redirect or
// forward (default) traffic.
redirect?: {
// On a redirect, overwrite the Authority/Host portion of the URL
// with this value.
authority?: string
// On a redirect, dynamically set the port: *
// FROM_PROTOCOL_DEFAULT: automatically set to 80 for HTTP and
// 443 for HTTPS.
derivePort?: "FROM_PROTOCOL_DEFAULT" | "FROM_REQUEST_PORT"
// On a redirect, overwrite the port portion of the URL with this
// value.
port?: int
// On a redirect, Specifies the HTTP status code to use in the
// redirect response.
redirectCode?: int
// On a redirect, overwrite the scheme portion of the URL with
// this value.
scheme?: string
// On a redirect, overwrite the Path portion of the URL with this
// value.
uri?: string
}
// Retry policy for HTTP requests.
retries?: {
// Number of retries to be allowed for a given request.
attempts?: int
// Timeout per attempt for a given request, including the initial
// call and any retries.
perTryTimeout?: string
// Specifies the conditions under which retry takes place.
retryOn?: string
// Flag to specify whether the retries should retry to other
// localities.
retryRemoteLocalities?: null | bool
}
// Rewrite HTTP URIs and Authority headers.
rewrite?: {
// rewrite the Authority/Host header with this value.
authority?: string
// rewrite the path (or the prefix) portion of the URI with this
// value.
uri?: string
// rewrite the path portion of the URI with the specified regex.
uriRegexRewrite?: {
// RE2 style regex-based match
// (https://github.com/google/re2/wiki/Syntax).
match?: string
// The string that should replace into matching portions of
// original URI.
rewrite?: string
}
}
// A HTTP rule can either return a direct_response, redirect or
// forward (default) traffic.
route?: [...{
// Destination uniquely identifies the instances of a service to
// which the request/connection should be forwarded to.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
headers?: {
request?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
response?: {
add?: {
[string]: string
}
remove?: [...string]
set?: {
[string]: string
}
}
}
// Weight specifies the relative proportion of traffic to be
// forwarded to the destination.
weight?: int
}]
// Timeout for HTTP requests, default is disabled.
timeout?: string
}]
// An ordered list of route rules for opaque TCP traffic.
tcp?: [...{
// Match conditions to be satisfied for the rule to be activated.
match?: [...{
// IPv4 or IPv6 ip addresses of destination with optional subnet.
destinationSubnets?: [...string]
// Names of gateways where the rule should be applied.
gateways?: [...string]
// Specifies the port on the host that is being addressed.
port?: int
// One or more labels that constrain the applicability of a rule
// to workloads with the given labels.
sourceLabels?: {
[string]: string
}
// Source namespace constraining the applicability of a rule to
// workloads in that namespace.
sourceNamespace?: string
sourceSubnet?: string
}]
// The destination to which the connection should be forwarded to.
route?: [...{
// Destination uniquely identifies the instances of a service to
// which the request/connection should be forwarded to.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
// Weight specifies the relative proportion of traffic to be
// forwarded to the destination.
weight?: int
}]
}]
// An ordered list of route rule for non-terminated TLS & HTTPS
// traffic.
tls?: [...{
// Match conditions to be satisfied for the rule to be activated.
match: [...{
// IPv4 or IPv6 ip addresses of destination with optional subnet.
destinationSubnets?: [...string]
// Names of gateways where the rule should be applied.
gateways?: [...string]
// Specifies the port on the host that is being addressed.
port?: int
// SNI (server name indicator) to match on.
sniHosts: [...string]
// One or more labels that constrain the applicability of a rule
// to workloads with the given labels.
sourceLabels?: {
[string]: string
}
// Source namespace constraining the applicability of a rule to
// workloads in that namespace.
sourceNamespace?: string
}]
// The destination to which the connection should be forwarded to.
route?: [...{
// Destination uniquely identifies the instances of a service to
// which the request/connection should be forwarded to.
destination: {
// The name of a service from the service registry.
host: string
port?: {
number?: int
}
// The name of a subset within the service.
subset?: string
}
// Weight specifies the relative proportion of traffic to be
// forwarded to the destination.
weight?: int
}]
}]
}

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