├── .github
├── actions
│ ├── builder
│ │ ├── Dockerfile
│ │ ├── action.yaml
│ │ └── builder
│ │ │ ├── README.md.tpl
│ │ │ └── main.py
│ └── updater
│ │ ├── Dockerfile
│ │ ├── Pipfile
│ │ ├── Pipfile.lock
│ │ ├── action.yaml
│ │ ├── repos
│ │ └── .gitignore
│ │ └── updater
│ │ ├── catalog.py
│ │ ├── entry.py
│ │ ├── main.py
│ │ ├── repo.py
│ │ └── settings.py
└── workflows
│ ├── main.yml
│ ├── promote.yml
│ └── updater.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Makefile
├── README.md
├── assets
└── favicon.png
├── repositories
├── .terraform.lock.hcl
├── README.md.tpl
├── main.tf
├── providers.tf
├── state.tf
└── variables.tf
├── src
├── _terraform_module
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── main._tf
│ ├── test_default_variant.tf
│ ├── test_kustomization
│ │ ├── Kustomization
│ │ ├── configmap.yaml
│ │ ├── deployment.yaml
│ │ └── namespace.yaml
│ ├── test_outputs.tf
│ ├── test_provider.tf
│ ├── tests
│ │ ├── common_annotations
│ │ │ └── test.tf
│ │ ├── common_labels
│ │ │ └── test.tf
│ │ ├── config_map_generator
│ │ │ ├── env
│ │ │ └── test.tf
│ │ ├── generator_options
│ │ │ └── test.tf
│ │ ├── images
│ │ │ └── test.tf
│ │ ├── inheritance
│ │ │ └── test.tf
│ │ ├── patches
│ │ │ ├── patch_deployment_resources.yaml
│ │ │ └── test.tf
│ │ ├── replicas
│ │ │ └── test.tf
│ │ └── secret_generator
│ │ │ ├── env
│ │ │ └── test.tf
│ ├── variables.tf
│ └── versions.tf
├── argo-cd
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── ha
│ │ ├── install.yaml
│ │ ├── kustomization.yaml
│ │ └── namespace.yaml
│ ├── main.tf
│ ├── normal
│ │ ├── install.yaml
│ │ ├── kustomization.yaml
│ │ └── namespace.yaml
│ ├── variables.tf
│ └── versions.tf
├── cert-manager
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── cert-manager.yaml
│ │ └── kustomization.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── custom-manifests
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── empty
│ │ └── Kustomization
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── flux
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── flux-account.yaml
│ │ ├── flux-deployment.yaml
│ │ ├── flux-ns.yaml
│ │ ├── flux-secret.yaml
│ │ ├── kustomization.yaml
│ │ ├── memcache-dep.yaml
│ │ └── memcache-svc.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── nginx
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── kustomization.yaml
│ │ └── mandatory.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default-ingress
│ │ ├── kustomization.yaml
│ │ └── patch-namespace.yaml
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── opa-gatekeeper
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── gatekeeper.yaml
│ │ └── kustomization.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── pinniped
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── concierge-base
│ │ ├── crds.yaml
│ │ ├── kustomization.yaml
│ │ └── resources.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── supervisor-base
│ │ ├── kustomization.yaml
│ │ └── resources.yaml
│ ├── variables.tf
│ └── versions.tf
├── postgresql
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── configmap.yaml
│ │ ├── kustomization.yaml
│ │ └── postgres-operator.yaml
│ ├── clusterwide
│ │ ├── kustomization.yaml
│ │ ├── namespace.yaml
│ │ ├── patch-deployment-env.yaml
│ │ └── rbac.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── prometheus
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── bundle.yaml
│ │ └── kustomization.yaml
│ ├── clusterwide
│ │ ├── instance-cluster-role.yaml
│ │ ├── kustomization.yaml
│ │ └── namespace.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── sealed-secrets
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── controller.yaml
│ │ └── kustomization.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── tektoncd
│ ├── _updater
│ │ ├── metadata.yaml
│ │ └── run.sh
│ ├── base
│ │ ├── kustomization.yaml
│ │ └── release.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
└── test
│ ├── base
│ ├── Kustomization
│ ├── configmap.yaml
│ ├── deployment.yaml
│ └── namespace.yaml
│ ├── configuration.tf
│ ├── data_source.tf
│ ├── default_variant.tf
│ ├── main.tf
│ ├── overlay
│ ├── Kustomization
│ └── patch-namespace.yaml
│ ├── variables.tf
│ └── versions.tf
└── test
└── k3d
├── Dockerfile
├── Pipfile
├── Pipfile.lock
├── main.py
└── main.tf.tpl
/.github/actions/builder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3
2 |
3 | COPY builder/ /opt/builder/
4 |
5 | CMD ["python", "/opt/builder/main.py"]
6 |
--------------------------------------------------------------------------------
/.github/actions/builder/action.yaml:
--------------------------------------------------------------------------------
1 | name: "Catalog Builder"
2 | description: "Build artifacts from catalog entries."
3 | runs:
4 | using: 'docker'
5 | image: 'Dockerfile'
6 |
--------------------------------------------------------------------------------
/.github/actions/builder/builder/README.md.tpl:
--------------------------------------------------------------------------------
1 | # $title Terraform Module
2 |
3 | This module installs $title on Kubernetes.
4 | It is maintained as part of [Kubestack, the Terraform framework for Kubernetes platform engineering](https://www.kubestack.com/).
5 | The module bundles an upstream release of $title and makes it fully configurable with Kustomizations set as input attributes.
6 |
7 | ## Usage with Kubestack
8 |
9 | Kubestack leverages configuration inheritance to avoid drift between environments.
10 | The example below shows how to use the module with Kubestack's default environment names `ops` and `apps`.
11 | You can learn more about [Kubestack's inheritance model in the documentation](https://www.kubestack.com/framework/documentation/inheritance-model/).
12 | For usage instructions without Kubestack see below.
13 |
14 | ```hcl
15 | terraform {
16 | required_providers {
17 | kustomization = {
18 | source = "kbst/kustomization"
19 | }
20 | }
21 | }
22 |
23 | provider "kustomization" {
24 | alias = "local"
25 |
26 | kubeconfig_path = "~/.kube/config"
27 | }
28 |
29 | module "example_$module_name" {
30 | providers = {
31 | kustomization = kustomization.local
32 | }
33 |
34 | source = "kubestack-modules/$name/kustomization"
35 | version = "v0.0.0-kbst.0"
36 |
37 | configuration = {
38 | apps = {
39 | # change the namespace of all resources
40 | namespace = var.example_argo_cd_namespace
41 |
42 | # or add an annotation
43 | common_annotations = {
44 | "terraform-workspace" = terraform.workspace
45 | }
46 |
47 | # use images to pull from an internal proxy
48 | # and avoid being rate limited
49 | images = [{
50 | # refers to the 'pod.spec.container.name' to modify the 'image' attribute of
51 | name = "container-name"
52 |
53 | # customize the 'registry/name' part of the image
54 | new_name = "reg.example.com/nginx"
55 | }]
56 | }
57 |
58 | ops = {
59 | # scale down replicas in ops
60 | replicas = [{
61 | # refers to the 'metadata.name' of the resource to scale
62 | name = "example"
63 |
64 | # sets the desired number of replicas
65 | count = 1
66 | }]
67 | }
68 | }
69 | }
70 | ```
71 |
72 | The Kubestack website has more documentation and examples on the available [Kustomization attributes](https://www.kubestack.com/framework/documentation/services/#configuration).
73 |
74 | ## Usage without Kubestack
75 |
76 | Modules are fully usable without Kubestack and without inheritance by setting `configuration_base_key` and a `configuration` with a single key matching your workspace name, e.g. `default`.
77 | The Kubestack website has a complete guide on [how to use the Kubestack modules without the Kubestack framework](https://www.kubestack.com/guides/catalog-using-kubestack-catalog-modules-standalone/).
78 |
79 | ```hcl
80 | terraform {
81 | required_providers {
82 | kustomization = {
83 | source = "kbst/kustomization"
84 | }
85 | }
86 | }
87 |
88 | provider "kustomization" {
89 | alias = "local"
90 |
91 | kubeconfig_path = "~/.kube/config"
92 | }
93 |
94 | module "example_$module_name" {
95 | providers = {
96 | # we're using the alias provider we configured above
97 | kustomization = kustomization.local
98 | }
99 |
100 | source = "kubestack-modules/$name/kustomization"
101 | version = "v0.0.0-kbst.0"
102 |
103 | # the configuration here assumes you're using Terraform's default workspace
104 | # use `terraform workspace list` to see the workspaces
105 | configuration_base_key = "default"
106 | configuration = {
107 | default = {
108 | replicas = [{
109 | name = "example"
110 | count = 5
111 | }]
112 | }
113 | }
114 | }
115 | ```
116 |
117 | ## Versions
118 |
119 | The module versions are the upstream release version (e.g. `v0.0.0`) plus a packaging suffix (e.g. `-kbst.0`).
120 | Should a new module release be necessary without changing the upstream version, the packaging suffix is incremented by one.
121 | Due to the packaging suffix, [Terraform version constraints](https://developer.hashicorp.com/terraform/language/expressions/version-constraints) can not be used for Kubestack modules.
122 |
123 | ## Contributing
124 |
125 | All Kubestack modules are built from the https://github.com/kbst/catalog/ repository.
126 | To contribute please head over to GitHub.
127 |
--------------------------------------------------------------------------------
/.github/actions/builder/builder/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from json import dumps
4 | from os import environ, listdir, mkdir
5 | from os.path import isdir, isfile, join, dirname
6 | from shutil import copytree, ignore_patterns, make_archive, rmtree, unpack_archive
7 | from sys import exit
8 | from tempfile import TemporaryDirectory
9 | from string import Template, capwords
10 |
11 |
12 | def create_archive(name, version):
13 | src = join(SRCDIR, name)
14 |
15 | module_dist = join(DISTDIR, f'module-{name}')
16 | module = join(DISTDIR, f'module-{name}-{version}')
17 |
18 | copytree(src, module_dist, ignore=ignore_patterns('_*'))
19 |
20 | with open(join(dirname(__file__), 'README.md.tpl'), 'r') as tf:
21 | t = Template(tf.read())
22 | md = t.substitute({
23 | "title": capwords(name),
24 | "name": name,
25 | "module_name": name.replace("-", "_"),
26 | })
27 | tf.close()
28 |
29 | with open(join(module_dist, "README.md"), 'w') as f:
30 | f.write(md)
31 | f.close()
32 |
33 | make_archive(module, 'zip', module_dist)
34 |
35 |
36 | def get_build_targets(ref):
37 | """ Returns build targets
38 |
39 | Returns a list of name and version tuples.
40 |
41 | If the ref name is prefixed with one of the available names,
42 | it returns a list of length one.
43 |
44 | If the ref is a branch, a short commit hash will be appended
45 | to the version.
46 |
47 | Refuse to build multiple artifacts for tags. Releases need
48 | to be for a single entry.
49 | """
50 | name = None
51 | version = None
52 |
53 | if ref.startswith('refs/tags/'):
54 | ref_name = ref.replace('refs/tags/', '')
55 | is_tag = True
56 |
57 | if ref.startswith('refs/heads/'):
58 | ref_name = ref.replace('refs/heads/', '')
59 | is_tag = False
60 |
61 | if ref.startswith('refs/heads/release-'):
62 | ref_name = ref.replace('refs/heads/release-', '')
63 | is_tag = False
64 |
65 | available_names = [n for n in listdir(SRCDIR) if not n.startswith('_')]
66 |
67 | targets = []
68 | for name in available_names:
69 | prefix = f'{name}-'
70 |
71 | # Version based on tag (e.g. refs/tags/nginx-v0.43.1-kbst.0)
72 | version = ref_name.replace(prefix, '')
73 |
74 | # Version based on branch (e.g. refs/heads/nginx-mychange)
75 | if not is_tag:
76 | hash = environ.get('GITHUB_SHA', None)
77 | if not hash:
78 | exit(f"[ERROR] `GITHUB_SHA` env var not set")
79 | version = hash
80 |
81 | if ref_name.startswith(prefix):
82 | # We're building a specific target
83 | return [(name, version)]
84 | else:
85 | # We build all entries
86 | targets.append((name, version))
87 |
88 | if ref.startswith('refs/tags/') and len(targets) != 1:
89 | exit(f"[ERROR] Invalid `GITHUB_REF` '{ref}'. " +
90 | f"Tags must be prefixed with one of {available_names}")
91 |
92 | if ref.startswith('refs/heads/all-'):
93 | # Building all targets takes very long, we only do so
94 | # when the branch name starts with `all-`
95 | return targets
96 |
97 | # if neither a specifc nor all entries were requested
98 | # we default to the test entry
99 | return [("test", hash)]
100 |
101 | if __name__ == "__main__":
102 | SRCDIR = 'src'
103 | DISTDIR = '_dist'
104 | OUTPUTSFILE = environ.get('GITHUB_OUTPUT')
105 |
106 | #
107 | #
108 | # Clean DISTDIR
109 | if isdir(DISTDIR):
110 | rmtree(DISTDIR)
111 | mkdir(DISTDIR)
112 |
113 | #
114 | #
115 | # Build artifacts
116 | ref = environ.get('GITHUB_REF', None)
117 | if not ref:
118 | exit(f"[ERROR] `GITHUB_REF` env var not set")
119 |
120 | if not ref.startswith('refs/tags/') and not ref.startswith('refs/heads/'):
121 | exit(f"[ERROR] unexpected `GITHUB_REF`: {ref}")
122 |
123 | build_targets = get_build_targets(ref)
124 |
125 | for name, version in build_targets:
126 | create_archive(name, version)
127 |
128 | #
129 | #
130 | # Generate all entries output for publish-gh job
131 | all_targets = get_build_targets("refs/heads/all-targets")
132 |
133 | names = []
134 | for name, _ in all_targets:
135 | names.append(f'"{name}"')
136 |
137 | tf_var_names_output = f'TF_VAR_names=[{",".join(names)}]'
138 |
139 | #
140 | #
141 | # Generate matrix output for test job
142 | matrix_output_data = {
143 | "include": []
144 | }
145 |
146 | for name in listdir(DISTDIR):
147 | if not isfile(name) and (not name.startswith('module-') or not name.endswith('.zip')):
148 | continue
149 |
150 | with TemporaryDirectory() as root:
151 | mut = join(root, "mut")
152 | archive = join(DISTDIR, name)
153 | unpack_archive(archive, mut, "zip")
154 | for variant in listdir(mut):
155 | variant_path = join(mut, variant)
156 | if not isdir(variant_path):
157 | continue
158 |
159 | matrix_output_data["include"].append({
160 | "variant": variant,
161 | "name": name
162 | })
163 |
164 | matrix_output = f'matrix={dumps(matrix_output_data)}'
165 |
166 |
167 | #
168 | #
169 | # Write or print outputs
170 | if OUTPUTSFILE:
171 | with open(OUTPUTSFILE, 'a') as f:
172 | f.write(f'{tf_var_names_output}\n')
173 | f.write(f'{matrix_output}\n')
174 | f.close()
175 | exit(0)
176 |
177 | print(tf_var_names_output)
178 | print(matrix_output)
179 | exit(0)
180 |
--------------------------------------------------------------------------------
/.github/actions/updater/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3
2 |
3 | ARG KUSTOMIZE_VERSION=3.8.1
4 |
5 | RUN KUSTOMIZE_BINARY_PATH="https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz"; \
6 | curl -LOs ${KUSTOMIZE_BINARY_PATH} && \
7 | tar -xf kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz && \
8 | mv kustomize /usr/local/bin/kustomize && \
9 | chmod +x /usr/local/bin/kustomize && \
10 | kustomize version;
11 |
12 | COPY Pipfile Pipfile.lock /opt/
13 |
14 | WORKDIR /opt
15 | RUN pip install --no-cache-dir pipenv &&\
16 | PIPENV_VENV_IN_PROJECT=true pipenv install
17 |
18 | COPY repos /opt/repos
19 | COPY updater /opt/updater
20 |
21 | ENV PATH=/opt/.venv/bin:$PATH
22 | CMD ["python", "/opt/updater/main.py"]
23 |
--------------------------------------------------------------------------------
/.github/actions/updater/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | verify_ssl = true
5 |
6 | [dev-packages]
7 |
8 | [packages]
9 | gitpython = "*"
10 | pyyaml = "*"
11 |
12 | [requires]
13 | python_version = "3"
14 |
--------------------------------------------------------------------------------
/.github/actions/updater/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "008de50a8b083b9a1d065913b0718c3e1ec16e5da0416d5a8a51cdf3e6635ad1"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "gitdb": {
20 | "hashes": [
21 | "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4",
22 | "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"
23 | ],
24 | "markers": "python_version >= '3.7'",
25 | "version": "==4.0.11"
26 | },
27 | "gitpython": {
28 | "hashes": [
29 | "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c",
30 | "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"
31 | ],
32 | "index": "pypi",
33 | "markers": "python_version >= '3.7'",
34 | "version": "==3.1.41"
35 | },
36 | "pyyaml": {
37 | "hashes": [
38 | "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5",
39 | "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc",
40 | "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df",
41 | "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741",
42 | "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206",
43 | "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27",
44 | "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595",
45 | "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62",
46 | "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98",
47 | "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696",
48 | "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290",
49 | "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9",
50 | "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d",
51 | "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6",
52 | "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867",
53 | "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47",
54 | "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486",
55 | "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6",
56 | "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3",
57 | "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007",
58 | "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938",
59 | "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0",
60 | "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c",
61 | "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735",
62 | "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d",
63 | "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28",
64 | "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4",
65 | "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba",
66 | "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8",
67 | "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5",
68 | "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd",
69 | "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3",
70 | "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0",
71 | "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515",
72 | "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c",
73 | "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c",
74 | "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924",
75 | "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34",
76 | "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43",
77 | "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859",
78 | "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673",
79 | "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54",
80 | "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a",
81 | "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b",
82 | "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab",
83 | "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa",
84 | "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c",
85 | "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585",
86 | "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d",
87 | "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"
88 | ],
89 | "index": "pypi",
90 | "markers": "python_version >= '3.6'",
91 | "version": "==6.0.1"
92 | },
93 | "smmap": {
94 | "hashes": [
95 | "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62",
96 | "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"
97 | ],
98 | "markers": "python_version >= '3.7'",
99 | "version": "==5.0.1"
100 | }
101 | },
102 | "develop": {}
103 | }
104 |
--------------------------------------------------------------------------------
/.github/actions/updater/action.yaml:
--------------------------------------------------------------------------------
1 | name: "Catalog Updater"
2 | description: "Update catalog entries with latest upstream releases."
3 | inputs:
4 | github_token:
5 | description: 'GitHub token used to push branches'
6 | required: true
7 | runs:
8 | using: 'docker'
9 | image: 'Dockerfile'
10 |
--------------------------------------------------------------------------------
/.github/actions/updater/repos/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore contents of repos directory
2 | *
3 |
4 | # Except this .gitignore
5 | !.gitignore
6 |
--------------------------------------------------------------------------------
/.github/actions/updater/updater/catalog.py:
--------------------------------------------------------------------------------
1 | import re
2 | import logging
3 | import subprocess
4 | from os import listdir, path
5 |
6 | from git.exc import GitCommandError
7 |
8 | from repo import clone_or_reset_repo
9 |
10 | import settings
11 |
12 | import yaml
13 |
14 |
15 | class Catalog():
16 | def __init__(self):
17 | self.clone_or_reset()
18 |
19 | def clone_or_reset(self):
20 | self.repo = clone_or_reset_repo(settings.CATALOG_NAME,
21 | settings.CATALOG_URL,
22 | settings.CATALOG_REF)
23 |
24 | # set git identity for commits
25 | self.repo.git.config('user.name', settings.GIT_USER_NAME)
26 | self.repo.git.config('user.email', settings.GIT_USER_EMAIL)
27 |
28 | def get_src_dir(self):
29 | return path.join(self.repo.working_tree_dir, 'src')
30 |
31 | def get_entries(self):
32 | src_dir = self.get_src_dir()
33 | return sorted([n for n in listdir(src_dir) if not n.startswith('_')])
34 |
35 | def get_variants(self, entry):
36 | entry_dir = path.join(self.get_src_dir(), entry.name)
37 | variants = []
38 | for v in listdir(entry_dir):
39 | if path.isdir(v) and not v.startswith('_'):
40 | variants.append(v)
41 | return sorted(variants)
42 |
43 | def run_script(self, entry, target_path):
44 | run_script_path = path.join(target_path, '_updater', 'run.sh')
45 |
46 | cmd = ['/bin/sh',
47 | run_script_path,
48 | entry.repo.working_tree_dir,
49 | target_path,
50 | str(entry.tag)]
51 |
52 | try:
53 | subprocess.run(cmd,
54 | check=True,
55 | capture_output=True,
56 | text=True)
57 | except subprocess.CalledProcessError as e:
58 | logging.error(f'updating {entry.name} failed, '
59 | f'stderr: "{e.stderr}"')
60 | self.clone_or_reset()
61 | self.repo.git.branch('-d', self.branch_name)
62 | return False
63 | else:
64 | logging.info(f'updated {entry.name} successfully')
65 | return True
66 |
67 | def update_version_annotation(self, kpath, version):
68 | kustomization_path = path.join(kpath, 'kustomization.yaml')
69 | with open(kustomization_path, 'r+') as stream:
70 | try:
71 | kf = yaml.safe_load(stream)
72 | except yaml.YAMLError as e:
73 | logging.exception(e)
74 | if 'commonAnnotations' not in kf:
75 | kf['commonAnnotations'] = {}
76 | kf['commonAnnotations']['app.kubernetes.io/version'] = version
77 | yaml.dump(kf,
78 | default_flow_style=False,
79 | indent=2,
80 | sort_keys=False)
81 | stream.seek(0)
82 | stream.write(yaml.dump(kf,
83 | default_flow_style=False,
84 | indent=2,
85 | sort_keys=False))
86 | stream.truncate()
87 |
88 | def update_entry(self, entry):
89 | current_version = str(entry.tag)
90 |
91 | # skip tags not matching regex
92 | if 'filter_tags' in entry.metadata:
93 | regex = entry.metadata['filter_tags']
94 | match = re.match(regex, current_version)
95 | if match:
96 | current_version = match.group(1)
97 | else:
98 | # if the regex does not match, we skip this tag
99 | return
100 |
101 | # in case upstream prefixes v, remove it
102 | # because we always prefix v for our tags
103 | current_version = current_version.lstrip('v')
104 | release_version = f'v{current_version}'
105 | release_tag = f'{entry.name}-{release_version}-kbst.0'
106 |
107 | if release_tag in entry.releases:
108 | # skip the upstream tag, if we already have a kbst.0 release for it
109 | logging.debug(f'skipping {release_tag}, already exists')
110 | return
111 |
112 | # checkout tag to build in source repo
113 | entry.repo.git.checkout('-f', entry.tag)
114 |
115 | self.branch_name = f'release-{release_tag}'
116 | self.repo.git.checkout(settings.CATALOG_REF)
117 | self.repo.git.clean('-xdf')
118 | self.repo.git.checkout('-B', self.branch_name)
119 |
120 | target_path = path.join(self.get_src_dir(), entry.name)
121 |
122 | # run entry updater script
123 | script_success = self.run_script(entry, target_path)
124 | if not script_success:
125 | return
126 |
127 | # update or set version annotation on all variants
128 | for variant in self.get_variants(entry):
129 | variant_path = path.join(target_path, variant)
130 | self.update_version_annotation(variant_path, release_version)
131 |
132 | self.repo.git.add('.')
133 | self.repo.git.commit('-m', f'Release {release_tag}')
134 | try:
135 | self.repo.git.push('origin', self.branch_name)
136 | except GitCommandError as e:
137 | logging.error(f'push of {self.branch_name} branch rejected')
138 | logging.error(f'git error: {e}')
139 | return
140 | else:
141 | logging.info(f'push of {self.branch_name} branch successful')
142 |
--------------------------------------------------------------------------------
/.github/actions/updater/updater/entry.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from datetime import datetime
3 | from os import path
4 |
5 | from git.objects.commit import Commit
6 | from git.objects.tag import TagObject
7 |
8 | from repo import clone_or_reset_repo
9 |
10 | import yaml
11 |
12 |
13 | class Entry():
14 | def __init__(self, catalog, name):
15 | self.catalog = catalog
16 | self.name = name
17 | self.metadata = None
18 | self.repo = None
19 | self.tag = None
20 | self.date = None
21 |
22 | def get_tag_date(self, tag):
23 | # lightweight tags don't have tagged_date
24 | # use the commit object's date then
25 | date = 0
26 | logging.debug(f'getting date of {tag} for {self.name}')
27 | object = tag.object
28 | if type(object) is Commit:
29 | date = object.committed_date
30 | elif type(object) is TagObject:
31 | date = object.tagged_date
32 | else:
33 | logging.warning(f'skipping {tag} for {self.name} '
34 | f'due to unknow object type {type(object)}')
35 | return date
36 |
37 | def get_metadata(self):
38 | src_dir = self.catalog.get_src_dir()
39 | metadata_path = path.join(src_dir,
40 | self.name,
41 | '_updater',
42 | 'metadata.yaml')
43 | try:
44 | with open(metadata_path) as stream:
45 | try:
46 | metadata = yaml.safe_load(stream)
47 | except yaml.YAMLError as e:
48 | logging.exception(e)
49 | except FileNotFoundError:
50 | logging.warning(f'skipping {self.name} '
51 | 'due to missing metadata')
52 | else:
53 | return metadata
54 | return None
55 |
56 | def check_releases(self):
57 | logging.debug(f'start updating {self.name}')
58 |
59 | self.metadata = self.get_metadata()
60 | if not self.metadata:
61 | return
62 |
63 | self.repo = clone_or_reset_repo(
64 | self.name,
65 | self.metadata.get('url'),
66 | self.metadata.get('ref', 'master'))
67 | entry_tags = sorted(self.repo.tags,
68 | key=lambda x: self.get_tag_date(x))
69 | if not entry_tags:
70 | return
71 |
72 | catalog_tags = self.catalog.repo.tags
73 | self.releases = list(filter(
74 | lambda x: str(x).startswith(self.name),
75 | catalog_tags))
76 |
77 | latest_release = None
78 | self.latest_release_date = 0
79 | if self.releases:
80 | latest_release = sorted(self.releases,
81 | key=lambda x: self.get_tag_date(x))[-1]
82 | self.latest_release_date = self.get_tag_date(latest_release)
83 |
84 | for tag in entry_tags:
85 | if self.get_tag_date(tag) < self.latest_release_date:
86 | # skip tags older than the last release in the catalog
87 | dt = datetime.utcfromtimestamp(self.latest_release_date)
88 | log_date = dt.strftime('%Y-%m-%d %H:%M:%S')
89 | logging.debug(f'skipping {self.name} {tag}, '
90 | f'older than {log_date}')
91 | continue
92 |
93 | self.tag = tag
94 | self.date = self.get_tag_date(self.tag)
95 |
96 | self.catalog.update_entry(self)
97 |
98 | self.repo.close()
99 | logging.debug(f'finished updating {self.name}')
100 |
--------------------------------------------------------------------------------
/.github/actions/updater/updater/main.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from catalog import Catalog
4 |
5 | from entry import Entry
6 |
7 |
8 | if __name__ == '__main__':
9 | logging.basicConfig(level=logging.INFO)
10 |
11 | catalog = Catalog()
12 | for entry_name in catalog.get_entries():
13 | Entry(catalog, entry_name).check_releases()
14 | catalog.repo.close()
15 |
--------------------------------------------------------------------------------
/.github/actions/updater/updater/repo.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from os import path
3 |
4 | from git import Repo
5 | from git.exc import GitCommandError
6 |
7 | REPO_DIR = path.abspath('repos')
8 |
9 |
10 | def clone_or_reset_repo(name, url, ref='master'):
11 | logging.debug(f'start cloning or resetting {url}')
12 | repo_path = path.join(REPO_DIR, name)
13 | repo = Repo.init(repo_path)
14 |
15 | try:
16 | repo.delete_remote('origin')
17 | except GitCommandError:
18 | pass
19 | finally:
20 | repo.create_remote('origin', url)
21 |
22 | repo.git.fetch('--tags', 'origin')
23 | repo.git.checkout('-f', f'origin/{ref}')
24 | repo.git.reset('--hard', f'origin/{ref}')
25 | logging.debug(f'finished cloning or resetting {url}')
26 | return repo
27 |
--------------------------------------------------------------------------------
/.github/actions/updater/updater/settings.py:
--------------------------------------------------------------------------------
1 | from os import getenv
2 |
3 | CATALOG_NAME = getenv('CATALOG_NAME', 'catalog')
4 | CATALOG_REF = getenv('CATALOG_REF', 'master')
5 |
6 | GITHUB_ACTOR = getenv('GITHUB_ACTOR', None)
7 | GITHUB_TOKEN = getenv('INPUT_GITHUB_TOKEN', None)
8 |
9 | CATALOG_URL = getenv('CATALOG_URL', 'github.com/kbst/catalog.git')
10 | if GITHUB_ACTOR and GITHUB_TOKEN:
11 | CATALOG_URL = f'{GITHUB_ACTOR}:{GITHUB_TOKEN}@{CATALOG_URL}'
12 | CATALOG_URL = f'https://{CATALOG_URL}'
13 |
14 | GIT_USER_NAME = getenv('GIT_USER_NAME', 'Catalog Updater')
15 | GIT_USER_EMAIL = getenv('GIT_USER_EMAIL', 'catalog-updater@ghactions')
16 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | run-name: 'Build & test :: ${{ github.ref }}'
3 |
4 | on:
5 | push:
6 | branches:
7 | - "*" # run for branches
8 | tags:
9 | - "!*" # do not run for tags
10 |
11 | env:
12 | TERRAFORM_VERSION: "1.5.7"
13 |
14 | jobs:
15 | #
16 | #
17 | # Build artifacts
18 | build:
19 | runs-on: ubuntu-latest
20 |
21 | outputs:
22 | TF_VAR_names: ${{ steps.build.outputs.TF_VAR_names }}
23 | matrix: ${{ steps.build.outputs.matrix }}
24 |
25 | steps:
26 | - uses: actions/checkout@v4.0.0
27 |
28 | # Run builder
29 | - id: build
30 | name: Run builder
31 | uses: ./.github/actions/builder
32 |
33 | # Upload artifacts
34 | - name: 'Upload artifacts'
35 | uses: actions/upload-artifact@v4.6.0
36 | with:
37 | name: _dist
38 | path: _dist/*.zip
39 |
40 |
41 | #
42 | #
43 | # Run `terraform test`
44 | test-terraform:
45 | runs-on: ubuntu-latest
46 |
47 | steps:
48 | # Checkout
49 | - uses: actions/checkout@v4.0.0
50 |
51 | # Setup Terraform
52 | - name: Setup Terraform
53 | uses: hashicorp/setup-terraform@v2.0.3
54 | with:
55 | terraform_wrapper: false
56 | terraform_version: "${{ env.TERRAFORM_VERSION }}"
57 |
58 | # Run tests
59 | - name: Run tests
60 | run: make test-terraform
61 |
62 |
63 | #
64 | #
65 | # Test deploy to k3d
66 | test-k3d:
67 | runs-on: ubuntu-latest
68 | needs: build
69 |
70 | strategy:
71 | fail-fast: false
72 | matrix: ${{ fromJSON(needs.build.outputs.matrix) }}
73 |
74 | steps:
75 | # Checkout
76 | - uses: actions/checkout@v4.0.0
77 |
78 | # Setup k3d
79 | - name: Setup k3d
80 | uses: rinx/setup-k3d@v0.0.4
81 | with:
82 | skipClusterCreation: true
83 |
84 | - name: Create k3d cluster
85 | run: make k3d
86 |
87 | # Download build artifacts
88 | - name: 'Download build-artifacts'
89 | uses: actions/download-artifact@v4.1.8
90 | with:
91 | name: _dist
92 | path: _dist
93 |
94 | # Deploy to cluster
95 | - name: Run test container
96 | run: make test-k3d test-name=${{ matrix.name }} test-variant=${{ matrix.variant}}
97 |
98 |
99 | #
100 | #
101 | #
102 | publish-gh:
103 | runs-on: ubuntu-latest
104 | concurrency:
105 | group: publish-gh
106 | cancel-in-progress: false
107 | needs: [build, test-k3d, test-terraform]
108 | if: startsWith(github.ref, 'refs/heads/release-')
109 |
110 | env:
111 | GITHUB_TOKEN: ${{ secrets.MODULES_PAT }}
112 | TF_VAR_names: ${{ needs.build.outputs.TF_VAR_names }}
113 |
114 | permissions:
115 | contents: read
116 | id-token: write
117 |
118 | steps:
119 | - uses: actions/checkout@v4.0.0
120 |
121 | - uses: google-github-actions/auth@v1.1.1
122 | with:
123 | workload_identity_provider: projects/168092815911/locations/global/workloadIdentityPools/oidc/providers/github
124 | service_account: kbst-catalog-repos-tf@nice-road-159709.iam.gserviceaccount.com
125 |
126 | # Apply target kubestack-modules repository
127 | - run: terraform init
128 | working-directory: repositories
129 |
130 | - run: terraform apply --auto-approve
131 | working-directory: repositories
132 |
133 | - name: 'Download build-artifacts'
134 | uses: actions/download-artifact@v4.1.8
135 | with:
136 | name: _dist
137 | path: _dist
138 |
139 | # Push artifact content as brach to target repo
140 | - run: |
141 | export BRANCH=$(echo $GITHUB_REF | sed -e "s#^refs/heads/##")
142 | export NAMEVERSION=$(echo $GITHUB_REF | sed -e "s#^refs/heads/release-##")
143 | export NAME=$(echo $NAMEVERSION | sed -r 's#-v[0-9]+.*$##')
144 |
145 | mkdir "terraform-kustomization-${NAME}"
146 | cd "terraform-kustomization-${NAME}"
147 |
148 | git init .
149 | git config user.name "Kubestack Modules"
150 | git config user.email "hello+modules@kubestack.com"
151 |
152 | git branch -m "${BRANCH}"
153 | git remote add target "https://${{ secrets.MODULES_PAT }}@github.com/kubestack-modules/terraform-kustomization-${NAME}.git"
154 |
155 | unzip ../_dist/module-${NAME}-${GITHUB_SHA}.zip
156 |
157 | git add .
158 | git commit -m "Release ${NAMEVERSION}"
159 | git push target "${BRANCH}"
160 |
161 |
162 | #
163 | #
164 | #
165 | publish-gcs:
166 | runs-on: ubuntu-latest
167 | needs: [build, test-k3d, test-terraform]
168 | if: startsWith(github.ref, 'refs/heads/release-')
169 |
170 | permissions:
171 | id-token: write
172 |
173 | steps:
174 | # Download build artifacts
175 | - name: 'Download build-artifacts'
176 | uses: actions/download-artifact@v4.1.8
177 | with:
178 | name: _dist
179 | path: _dist
180 |
181 | # Upload archive
182 | - uses: google-github-actions/auth@v1.1.1
183 | with:
184 | workload_identity_provider: projects/168092815911/locations/global/workloadIdentityPools/oidc/providers/github
185 | service_account: github-actions-catalog-uploade@nice-road-159709.iam.gserviceaccount.com
186 |
187 | - uses: google-github-actions/setup-gcloud@v1.1.1
188 |
189 | - run: gsutil -m cp _dist/*.zip gs://dev.catalog.kubestack.com
190 |
191 |
192 | #
193 | #
194 | # trigger promotion by tagging release
195 | trigger-promote:
196 | runs-on: ubuntu-latest
197 | needs: [publish-gcs, publish-gh]
198 | if: startsWith(github.ref, 'refs/heads/release-')
199 |
200 | permissions:
201 | contents: write # required for createRef
202 | actions: write # required for createWorkflowDispatch
203 |
204 | steps:
205 | - uses: actions/github-script@v6
206 | with:
207 | script: |
208 | const tag = context.ref.replace("refs/heads/release-", "refs/tags/")
209 |
210 | await github.rest.git.createRef({
211 | owner: context.repo.owner,
212 | repo: context.repo.repo,
213 | ref: tag,
214 | sha: context.sha,
215 | });
216 |
217 | await github.rest.actions.createWorkflowDispatch({
218 | owner: context.repo.owner,
219 | repo: context.repo.repo,
220 | workflow_id: "promote.yml",
221 | ref: tag,
222 | });
223 |
--------------------------------------------------------------------------------
/.github/workflows/promote.yml:
--------------------------------------------------------------------------------
1 | name: Promote
2 | run-name: 'Promote :: ${{ github.ref }}'
3 |
4 | on: workflow_dispatch
5 |
6 | jobs:
7 | #
8 | #
9 | # Promote tagged releases
10 | # from `dev.catalog.kubestack.com` to `catalog.kubestack.com`
11 | promote-gcs:
12 | runs-on: ubuntu-latest
13 |
14 | # promote only for tags
15 | if: startsWith(github.ref, 'refs/tags/')
16 |
17 | permissions:
18 | id-token: write
19 |
20 | steps:
21 | # Setup gcloud CLI
22 | - uses: google-github-actions/auth@v1.1.1
23 | with:
24 | workload_identity_provider: projects/168092815911/locations/global/workloadIdentityPools/oidc/providers/github
25 | service_account: github-actions-catalog-uploade@nice-road-159709.iam.gserviceaccount.com
26 |
27 | - uses: google-github-actions/setup-gcloud@v1.1.1
28 |
29 | # Promote archive
30 | - run: |
31 | export TAG=$(echo $GITHUB_REF | sed -e "s#^refs/tags/##")
32 | export NAME=$(echo $TAG | sed -r 's#-v[0-9]+.*$##')
33 | set +e
34 | while true
35 | do
36 | gsutil cp gs://dev.catalog.kubestack.com/module-${NAME}-${GITHUB_SHA}.zip gs://catalog.kubestack.com/module-${TAG}.zip &&\
37 | break
38 | sleep 15
39 | done
40 |
41 | # Check promotion
42 | - name: Check promotion
43 | run: |
44 | export TAG=$(echo $GITHUB_REF | sed -e "s#^refs/tags/##")
45 | wget https://storage.googleapis.com/catalog.kubestack.com/module-${TAG}.zip
46 |
47 | promote-gh:
48 | runs-on: ubuntu-latest
49 |
50 | # promote only for tags
51 | if: startsWith(github.ref, 'refs/tags/')
52 |
53 | steps:
54 | - uses: actions/github-script@v6
55 | with:
56 | github-token: ${{ secrets.MODULES_PAT }}
57 | script: |
58 | const nameVersion = context.ref.replace("refs/tags/", "")
59 | const name = nameVersion.replace(/-v[0-9]+.*$/i, "")
60 | const version = nameVersion.replace(`${name}-`, "")
61 |
62 | const targetOwner = "kubestack-modules"
63 | const targetRepo = `terraform-kustomization-${name}`
64 | const targetRef = `refs/tags/${version}`
65 |
66 | const refResp = await github.rest.git.getRef({
67 | owner: targetOwner,
68 | repo: targetRepo,
69 | ref: context.ref.replace("refs/tags/", "heads/release-"),
70 | });
71 |
72 | await github.rest.git.createRef({
73 | owner: targetOwner,
74 | repo: targetRepo,
75 | ref: targetRef,
76 | sha: refResp.data.object.sha,
77 | });
78 |
--------------------------------------------------------------------------------
/.github/workflows/updater.yml:
--------------------------------------------------------------------------------
1 | name: Update
2 |
3 | on:
4 | schedule:
5 | - cron: "0 6 * * *"
6 | workflow_dispatch:
7 |
8 | jobs:
9 | update:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v1
14 |
15 | #
16 | #
17 | # Run updater
18 | - name: Run updater
19 | uses: ./.github/actions/updater
20 | with:
21 | github_token: "${{ secrets.UPDATER_PTA }}"
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _build/
2 | _dist/
3 | .terraform/
4 |
5 | *.tfstate
6 | *.tfstate.*
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at hello@kubestack.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Please follow common sense when creating issues and [the GitHub flow](https://guides.github.com/introduction/flow/) after forking when creating merge requests.
4 |
5 | ## Issues
6 |
7 | Issues are very valuable to this project.
8 |
9 | - Ideas are a valuable source of contributions others can make
10 | - Problems show where this project is lacking
11 | - With a question, you show where contributors can improve the user experience
12 |
13 | Thank you for creating them.
14 |
15 | ## Merge Requests
16 |
17 | Merge requests are a great way to get your ideas into this repository.
18 |
19 | When deciding if I merge in a merge request I look at the following things:
20 |
21 | ### Does it state intent
22 |
23 | You should be clear about which problem you're trying to solve with your
24 | contribution.
25 |
26 | For example:
27 |
28 | > Add link to code of conduct in README.md
29 |
30 | Doesn't tell me anything about why you're doing that
31 |
32 | > Add link to code of conduct in README.md because users don't always look in the CONTRIBUTING.md
33 |
34 | Tells me the problem that you have found, and the merge request shows me the action you have taken to solve it.
35 |
36 | ### Is it of good quality
37 |
38 | - There are no spelling mistakes
39 | - It reads well
40 | - For English language contributions: Has a good score on [Grammarly](grammarly.com) or [Hemingway Editor](http://www.hemingwayapp.com/)
41 |
42 | ### Does it move this repository closer to my vision for the repository
43 |
44 | The aim of this repository is documented at [README](README.md).
45 |
46 | ### Does it follow the contributor covenant
47 |
48 | This repository has a [code of conduct](./CODE_OF_CONDUCT.md), I will remove things that do not respect it.
49 |
50 | The origin of this document is from [PurpleBooth Templates](https://github.com/PurpleBooth/a-good-readme-template).
51 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | _all: test-terraform dist
2 |
3 | GITHUB_REF ?= $(shell echo "refs/heads/"`git rev-parse --abbrev-ref HEAD`)
4 | GITHUB_SHA ?= $(shell echo `git rev-parse --verify HEAD^{commit}`)
5 |
6 | test-terraform:
7 | cd src/_terraform_module/; terraform test
8 |
9 | dist:
10 | docker build -t catalog:dist-${GITHUB_SHA} .github/actions/builder
11 | docker run --rm -v `pwd`:/workdir:z --workdir=/workdir -e GITHUB_REF=${GITHUB_REF} -e GITHUB_SHA=${GITHUB_SHA} catalog:dist-${GITHUB_SHA}
12 |
13 | k3d:
14 | k3d cluster delete catalog-tests
15 | k3d cluster create catalog-tests -s 1 -a 3 --no-lb --k3s-arg "--disable=traefik@server:*" --k3s-arg "--disable=servicelb@server:*" --k3s-arg="--node-label=ingress-ready=true@agent:*"
16 | kubectl config use-context k3d-catalog-tests
17 | kubectl cluster-info
18 |
19 | get-matrix: dist
20 | docker build -t catalog:get-matrix-${GITHUB_SHA} .github/actions/get-matrix
21 | docker run --network host --rm -v `pwd`/_dist:/_dist:z catalog:get-matrix-${GITHUB_SHA}
22 |
23 | test-k3d: dist
24 | docker build -t catalog:test-k3d-${GITHUB_SHA} test/k3d/
25 | docker run --network host --rm -v `pwd`/_dist:/_dist:z -v ${HOME}/.kube/config:/opt/test/.kubeconfig:z catalog:test-k3d-${GITHUB_SHA} $(test-name) $(test-variant)
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Kubestack Catalog
6 | Manifest Catalog for the Kubestack Gitops Framework
7 |
8 |
9 |
10 | []()
11 | [](https://github.com/kbst/catalog/issues)
12 | [](https://github.com/kbst/catalog/pulls)
13 |
14 |
15 |
16 |
17 |
18 | 
19 | 
20 |
21 |
22 |
23 |
24 |
25 |
26 |
33 |
34 | ## Introduction
35 |
36 | This repository holds the kustomize source manifests and build toolchain for the [Kubestack catalog of Kustomize bases](https://www.kubestack.com/catalog).
37 |
38 | This is maintained as part of the [Terraform GitOps framework Kubestack](https://www.kubestack.com/).
39 |
40 |
41 | ## Getting Started with Kubestack
42 |
43 | For the easiest way to get started, [visit the official Kubestack quickstart](https://www.kubestack.com/infrastructure/documentation/quickstart). This tutorial will help you get started with the Kubestack GitOps framework. It is divided into three steps.
44 |
45 | 1. Develop Locally
46 | * Scaffold your repository and tweak your config in a local development environment that simulates your actual cloud configuration using Kubernetes in Docker (KinD).
47 | 3. Provision Infrastructure
48 | * Set-up cloud prerequisites and bootstrap Kubestack's environment and clusters on your cloud provider for the first time.
49 | 4. Set-up Automation
50 | * Integrate CI/CD to automate changes following Kubestack's GitOps workflow.
51 |
52 |
53 | ## Getting Help
54 |
55 | **Official Documentation**
56 | Refer to the [official documentation](https://www.kubestack.com/framework/documentation) for a deeper dive into how to use and configure Kubetack.
57 |
58 | **Community Help**
59 | If you have any questions while following the tutorial, join the [#kubestack](https://app.slack.com/client/T09NY5SBT/CMBCT7XRQ) channel on the Kubernetes community. To create an account request an [invitation](https://slack.k8s.io/).
60 |
61 | **Professional Services**
62 | For organizations interested in accelerating their GitOps journey, [professional services](https://www.kubestack.com/lp/professional-services) are available.
63 |
64 |
65 | ## Contributing
66 | Contributions to the Kubestack framework are welcome and encouraged. Before contributing, please read the [Contributing](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md) Guidelines.
67 |
68 | One super simple way to contribute to the success of this project is to give it a star.
69 |
70 |
71 |
72 | 
73 |
74 |
75 |
76 |
77 | ## Development Workflow
78 |
79 | 1. Fork this repository
80 | 1. Work in a feature branch
81 | 1. Validate your changes locally
82 | ```
83 | # Build the helper image
84 | # optional `--build-arg KUSTOMIZE_VERSION=3.2.3`
85 | docker build -t python3-kustomize .
86 |
87 | # Run dist.py to generate the archives
88 | docker run \
89 | --rm \
90 | -u `id -u`:`id -g` \
91 | -v `pwd`:/workspace \
92 | -w /workspace \
93 | -e GIT_SHA=`git rev-parse --verify HEAD^{commit}` \
94 | -e GIT_REF=refs/heads/`git rev-parse --abbrev-ref HEAD` \
95 | python3-kustomize \
96 | ./dist.py
97 |
98 | # Run test.py to test your changes
99 | docker run \
100 | --rm \
101 | -u `id -u`:`id -g` \
102 | -v `pwd`:/workspace \
103 | -w /workspace \
104 | python3-kustomize \
105 | ./test.py
106 |
107 | ```
108 | 1. Send a pull-request
109 |
110 |
111 | ## Making a Release
112 |
113 | 1. Create a Git tag in the format `name-version`
114 | * name must be the name of the catalog entry to release, e.g. `memcached`
115 | * version must be in format `major.minor.patch` prefixed with a `v`,
116 | e.g. `v0.0.1`
117 | 2. Push the tag to trigger CI/CD
118 |
119 |
120 | ## Kubestack Repositories
121 | * [kbst/terraform-kubestack](https://github.com/kbst/terraform-kubestack)
122 | * Terraform GitOps Framework - Everything you need to build reliable automation for AKS, EKS and GKE Kubernetes clusters in one free and open-source framework.
123 | * [kbst/kbst](https://github.com/kbst/kbst)
124 | * Kubestack Framework CLI - All-in-one CLI to scaffold your Infrastructure as Code repository and deploy your entire platform stack locally for faster iteration.
125 | * [kbst/terraform-provider-kustomization](https://github.com/kbst/terraform-provider-kustomization)
126 | * Kustomize Terraform Provider - A Kubestack maintained Terraform provider for Kustomize, available in the [Terraform registry](https://registry.terraform.io/providers/kbst/kustomization/latest).
127 | * [kbst/catalog](https://github.com/kbst/catalog) (this repository)
128 | * Catalog of cluster services as Kustomize bases - Continuously tested and updated Kubernetes services, installed and customizable using native Terraform syntax.
129 |
130 |
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbst/catalog/79d2a797940685d7e576a89f50d8ce761ddbc3b6/assets/favicon.png
--------------------------------------------------------------------------------
/repositories/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/integrations/github" {
5 | version = "5.36.0"
6 | constraints = "~> 5.0"
7 | hashes = [
8 | "h1:a1w2jOfagQ7EtArkrvYf0scbI41ySFo9PmBmVmCyDiI=",
9 | "zh:16a8018d4bf8febca9a5482ce66559646f760184e89bb39ed34592451681a252",
10 | "zh:1c2781f9938df9ef571d90281c4319fbc1d961afdce6aec4a8faac12da16871a",
11 | "zh:48b2155411f1e6dd996ab4abf3846decf6d1404d86ceeb5652e4a982195de4b9",
12 | "zh:4f21a97e4d9e5569373ba59a7cf564ab6db9cdea1930f760179ac349f2d03030",
13 | "zh:57d39fb320b3f3ffc55d80ae8dd205a2cfc7d9fafb270a371500370f526e0baa",
14 | "zh:89b444491a25d789288a80a32531991a29565b6873af5f37face588d04fcff35",
15 | "zh:8db5d4bdc47bb0fd71971954bb0c22dcd25c9550b1598f5075fd0a92c040d7ac",
16 | "zh:95913de9a0c348bdc0cc1fa727fa8f4c092a311a56981ab7c48959a82a363a70",
17 | "zh:9e9aeac23cec279cc0eea6e21eeb8977e291ed9cf831a8d09a147eeda4ef22d8",
18 | "zh:bc7a19a4cacb20e26a4021942acefa7b1a05de22250651ef5e3fb36272a5e85b",
19 | "zh:c68d27aedec0e6f6551e4db79cc86b6098c626594272265bb3d84bb0bdf99b47",
20 | "zh:ca37ae109cf7537b1cb188244ee028df3da34db803a10e9d64d44da9d88b02e7",
21 | "zh:db1ac55a2b2d15678845f5a3cde8fae75ef6b67d1830e37488a9e65fbd2caf09",
22 | "zh:f14b1b46320455edaed88b74c7324ecea43b5daf382c4cd891fd88addb8b8940",
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/repositories/README.md.tpl:
--------------------------------------------------------------------------------
1 | # Kubestack ${title(name)} Terraform Module for Kubernetes
2 |
3 | This repository exists to publish the `${name}` module on the Terraform registry.
4 | Module versions built from upstream releases are stored in `release-$version` branches.
5 | The branch will be tagged to publish on the Terraform registry.
6 |
7 | ## Learn more about the ${title(name)} platform service module
8 |
9 | * [Catalog page](https://www.kubestack.com/catalog/${name})
10 | * [Kubestack module types](https://www.kubestack.com/framework/documentation/module-types/)
11 |
12 | ## Contribute to the ${title(name)} module
13 |
14 | All content here is generated from upstream releases.
15 | Any contributions have to happen in the [kbst/catalog](https://github.com/kbst/catalog) repository.
16 |
--------------------------------------------------------------------------------
/repositories/main.tf:
--------------------------------------------------------------------------------
1 | resource "github_repository" "module" {
2 | for_each = var.names
3 |
4 | name = "terraform-kustomization-${each.key}"
5 | description = "${title(each.key)} Terraform Module for Kubernetes by Kubestack"
6 | homepage_url = "https://www.kubestack.com/catalog/${each.key}/"
7 |
8 | visibility = "public"
9 |
10 | auto_init = true
11 |
12 | has_issues = false
13 | has_discussions = false
14 | has_projects = false
15 | has_wiki = false
16 | has_downloads = false
17 |
18 | archive_on_destroy = true
19 |
20 | topics = [
21 | "kubernetes",
22 | "terraform",
23 | "terraform-module",
24 | "kustomize",
25 | "kubestack",
26 | each.key,
27 | ]
28 |
29 | lifecycle {
30 | prevent_destroy = true
31 | }
32 | }
33 |
34 | resource "github_branch" "main" {
35 | for_each = var.names
36 |
37 | repository = github_repository.module[each.key].name
38 | branch = "main"
39 |
40 | lifecycle {
41 | prevent_destroy = true
42 | }
43 | }
44 |
45 | resource "github_branch_default" "default" {
46 | for_each = var.names
47 |
48 | repository = github_repository.module[each.key].name
49 | branch = github_branch.main[each.key].branch
50 |
51 | lifecycle {
52 | prevent_destroy = true
53 | }
54 | }
55 |
56 | resource "github_repository_file" "readme" {
57 | for_each = var.names
58 |
59 | repository = github_repository.module[each.key].name
60 | branch = github_branch.main[each.key].branch
61 |
62 | file = "README.md"
63 | content = templatefile(
64 | "${path.root}/README.md.tpl",
65 | { name : each.key }
66 | )
67 |
68 | commit_message = "Create placeholder README.md for main branch"
69 | commit_author = "Philipp Strube"
70 | commit_email = "pst@kubestack.com"
71 | overwrite_on_create = true
72 |
73 | lifecycle {
74 | prevent_destroy = true
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/repositories/providers.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | github = {
4 | source = "integrations/github"
5 | version = "~> 5.0"
6 | }
7 | }
8 | }
9 |
10 | provider "github" {
11 | owner = var.owner
12 | }
13 |
--------------------------------------------------------------------------------
/repositories/state.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | backend "gcs" {
3 | bucket = "terraform-state-kubestack-catalog-repositories-d18c22a"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/repositories/variables.tf:
--------------------------------------------------------------------------------
1 | variable "names" {
2 | type = set(string)
3 | description = "List of entry names to create repositories for."
4 | }
5 |
6 | variable "owner" {
7 | type = string
8 | description = "The name of the organization owning the repositories."
9 | default = "kubestack-modules"
10 | }
11 |
--------------------------------------------------------------------------------
/src/_terraform_module/configuration.tf:
--------------------------------------------------------------------------------
1 | module "configuration" {
2 | source = "github.com/kbst/terraform-kubestack//common/configuration?ref=v0.18.0-beta.0"
3 | configuration = var.configuration
4 | base_key = var.configuration_base_key
5 | }
6 |
7 | locals {
8 | # current workspace config
9 | cfg = lookup(module.configuration.merged, terraform.workspace)
10 |
11 | variant = local.cfg["variant"] != null ? local.cfg["variant"] : local.default_variant
12 |
13 | additional_resources = local.cfg["additional_resources"] != null ? local.cfg["additional_resources"] : []
14 | }
15 |
--------------------------------------------------------------------------------
/src/_terraform_module/data_source.tf:
--------------------------------------------------------------------------------
1 | data "kustomization_overlay" "current" {
2 | common_annotations = local.cfg["common_annotations"]
3 |
4 | common_labels = local.cfg["common_labels"]
5 |
6 | components = local.cfg["components"]
7 |
8 | dynamic "config_map_generator" {
9 | for_each = local.cfg["config_map_generator"] != null ? local.cfg["config_map_generator"] : []
10 | iterator = i
11 | content {
12 | name = i.value["name"]
13 | namespace = i.value["namespace"]
14 | behavior = i.value["behavior"]
15 | envs = i.value["envs"]
16 | files = i.value["files"]
17 | literals = i.value["literals"]
18 | options {
19 | labels = lookup(i.value, "options") != null ? i.value["options"]["labels"] : null
20 | annotations = lookup(i.value, "options") != null ? i.value["options"]["annotations"] : null
21 | disable_name_suffix_hash = lookup(i.value, "options") != null ? i.value["options"]["disable_name_suffix_hash"] : null
22 | }
23 | }
24 | }
25 |
26 | crds = local.cfg["crds"]
27 |
28 | generators = local.cfg["generators"]
29 |
30 | dynamic "generator_options" {
31 | for_each = local.cfg["generator_options"] != null ? [local.cfg["generator_options"]] : []
32 | iterator = i
33 | content {
34 | labels = i.value["labels"]
35 | annotations = i.value["annotations"]
36 | disable_name_suffix_hash = i.value["disable_name_suffix_hash"]
37 | }
38 | }
39 |
40 | dynamic "images" {
41 | for_each = lookup(local.cfg, "images") != null ? lookup(local.cfg, "images") : []
42 | iterator = i
43 | content {
44 | name = i.value["name"]
45 | new_name = i.value["new_name"]
46 | new_tag = i.value["new_tag"]
47 | digest = i.value["digest"]
48 | }
49 | }
50 |
51 | name_prefix = local.cfg["name_prefix"]
52 |
53 | namespace = local.cfg["namespace"]
54 |
55 | name_suffix = local.cfg["name_suffix"]
56 |
57 | dynamic "patches" {
58 | for_each = local.cfg["patches"] != null ? local.cfg["patches"] : []
59 | iterator = i
60 | content {
61 | path = i.value["path"]
62 | patch = i.value["patch"]
63 |
64 | dynamic "target" {
65 | for_each = i.value["target"] != null ? toset([i.value["target"]]) : toset([])
66 | iterator = j
67 | content {
68 | group = j.value["group"]
69 | version = j.value["version"]
70 | kind = j.value["kind"]
71 | name = j.value["name"]
72 | namespace = j.value["namespace"]
73 | label_selector = j.value["label_selector"]
74 | annotation_selector = j.value["annotation_selector"]
75 | }
76 | }
77 | }
78 | }
79 |
80 | dynamic "replicas" {
81 | for_each = local.cfg["replicas"] != null ? local.cfg["replicas"] : []
82 | iterator = i
83 | content {
84 | name = i.value["name"]
85 | count = i.value["count"]
86 | }
87 | }
88 |
89 | dynamic "secret_generator" {
90 | for_each = local.cfg["secret_generator"] != null ? local.cfg["secret_generator"] : []
91 | iterator = i
92 | content {
93 | name = i.value["name"]
94 | namespace = i.value["namespace"]
95 | behavior = i.value["behavior"]
96 | type = i.value["type"]
97 | envs = i.value["envs"]
98 | files = i.value["files"]
99 | literals = i.value["literals"]
100 | options {
101 | labels = lookup(i.value, "options") != null ? i.value["options"]["labels"] : null
102 | annotations = lookup(i.value, "options") != null ? i.value["options"]["annotations"] : null
103 | disable_name_suffix_hash = lookup(i.value, "options") != null ? i.value["options"]["disable_name_suffix_hash"] : null
104 | }
105 | }
106 | }
107 |
108 | transformers = local.cfg["transformers"]
109 |
110 | dynamic "vars" {
111 | for_each = local.cfg["vars"] != null ? local.cfg["vars"] : []
112 | iterator = i
113 | content {
114 | name = i.value["name"]
115 | obj_ref {
116 | api_version = lookup(i.value, "obj_ref") != null ? i.value["obj_ref"]["api_version"] : null
117 | group = lookup(i.value, "obj_ref") != null ? i.value["obj_ref"]["group"] : null
118 | version = lookup(i.value, "obj_ref") != null ? i.value["obj_ref"]["version"] : null
119 | kind = lookup(i.value, "obj_ref") != null ? i.value["obj_ref"]["kind"] : null
120 | name = lookup(i.value, "obj_ref") != null ? i.value["obj_ref"]["name"] : null
121 | namespace = lookup(i.value, "obj_ref") != null ? i.value["obj_ref"]["namespace"] : null
122 | }
123 | field_ref {
124 | field_path = lookup(i.value, "field_ref") != null ? i.value["field_ref"]["field_path"] : null
125 | }
126 | }
127 | }
128 |
129 | resources = local.cfg["resources"] != null ? local.cfg["resources"] : concat(["${path.module}/${local.variant}/"], local.additional_resources)
130 | }
131 |
--------------------------------------------------------------------------------
/src/_terraform_module/main._tf:
--------------------------------------------------------------------------------
1 | resource "kustomization_resource" "p0" {
2 | for_each = data.kustomization_overlay.current.ids_prio[0]
3 |
4 | manifest = (
5 | contains(var.sensitive_group_kinds, regex("(?P.*/.*)/.*/.*", each.value)["group_kind"])
6 | ? sensitive(data.kustomization_overlay.current.manifests[each.value])
7 | : data.kustomization_overlay.current.manifests[each.value]
8 | )
9 | }
10 |
11 | resource "kustomization_resource" "p1" {
12 | for_each = data.kustomization_overlay.current.ids_prio[1]
13 |
14 | manifest = (
15 | contains(var.sensitive_group_kinds, regex("(?P.*/.*)/.*/.*", each.value)["group_kind"])
16 | ? sensitive(data.kustomization_overlay.current.manifests[each.value])
17 | : data.kustomization_overlay.current.manifests[each.value]
18 | )
19 |
20 | depends_on = [kustomization_resource.p0]
21 | }
22 |
23 | resource "kustomization_resource" "p2" {
24 | for_each = data.kustomization_overlay.current.ids_prio[2]
25 |
26 | manifest = (
27 | contains(var.sensitive_group_kinds, regex("(?P.*/.*)/.*/.*", each.value)["group_kind"])
28 | ? sensitive(data.kustomization_overlay.current.manifests[each.value])
29 | : data.kustomization_overlay.current.manifests[each.value]
30 | )
31 |
32 | depends_on = [kustomization_resource.p1]
33 | }
34 |
--------------------------------------------------------------------------------
/src/_terraform_module/test_default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "test_kustomization"
3 | }
4 |
--------------------------------------------------------------------------------
/src/_terraform_module/test_kustomization/Kustomization:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 | namespace: test
5 |
6 | resources:
7 | - namespace.yaml
8 | - configmap.yaml
9 | - deployment.yaml
10 |
--------------------------------------------------------------------------------
/src/_terraform_module/test_kustomization/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | creationTimestamp: null
5 | name: test
6 | annotations:
7 | test: test
8 | labels:
9 | test: test
10 |
--------------------------------------------------------------------------------
/src/_terraform_module/test_kustomization/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app: test
7 | name: test
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: test
13 | strategy: {}
14 | template:
15 | metadata:
16 | creationTimestamp: null
17 | labels:
18 | app: test
19 | spec:
20 | containers:
21 | - image: busybox
22 | name: busybox
23 | command:
24 | - sleep
25 | - "60"
26 | resources: {}
27 | status: {}
28 |
--------------------------------------------------------------------------------
/src/_terraform_module/test_kustomization/namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: test
--------------------------------------------------------------------------------
/src/_terraform_module/test_outputs.tf:
--------------------------------------------------------------------------------
1 | output "ids" {
2 | value = data.kustomization_overlay.current.ids
3 | }
4 |
5 | output "ids_prio" {
6 | value = data.kustomization_overlay.current.ids_prio
7 | }
8 |
9 | output "manifests" {
10 | value = data.kustomization_overlay.current.manifests
11 | }
12 |
--------------------------------------------------------------------------------
/src/_terraform_module/test_provider.tf:
--------------------------------------------------------------------------------
1 | provider "kustomization" {
2 | kubeconfig_raw = yamlencode({
3 | apiVersion = "v1"
4 | current-context = "test"
5 | clusters = [
6 | {
7 | name = "test"
8 | cluster = {
9 | certificate-authority-data = ""
10 | server = "https://127.0.0.1:8080"
11 | }
12 | }
13 | ]
14 | users = [
15 | {
16 | name = "test"
17 | user = {
18 | token = ""
19 | }
20 | }
21 | ]
22 | contexts = [
23 | {
24 | name = "test"
25 | context = {
26 | cluster = "test"
27 | user = "test"
28 | }
29 | }
30 | ]
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/common_annotations/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | module "mut" {
10 | source = "../.."
11 |
12 | configuration = {
13 | (terraform.workspace) = {
14 | common_annotations = {
15 | "terraform-workspace" = terraform.workspace
16 | }
17 | }
18 | }
19 |
20 | configuration_base_key = terraform.workspace
21 | }
22 |
23 | resource "test_assertions" "common_annotations" {
24 | component = "common_annotations"
25 |
26 | equal "metadata_annotations_is_correct" {
27 | description = "metadata_annotations_is_correct"
28 | got = jsondecode(module.mut.manifests["_/Namespace/_/test"]).metadata.annotations
29 | want = {
30 | "terraform-workspace" = terraform.workspace
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/common_labels/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | module "mut" {
10 | source = "../.."
11 |
12 | configuration = {
13 | (terraform.workspace) = {
14 | common_labels = {
15 | "terraform-workspace" = terraform.workspace
16 | }
17 | }
18 | }
19 |
20 | configuration_base_key = terraform.workspace
21 | }
22 |
23 | resource "test_assertions" "common_labels" {
24 | component = "common_labels"
25 |
26 | equal "metadata_labels_are_correct" {
27 | description = "metadata_labels_are_correct"
28 | got = jsondecode(module.mut.manifests["_/Namespace/_/test"]).metadata.labels
29 | want = {
30 | "terraform-workspace" = terraform.workspace
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/config_map_generator/env:
--------------------------------------------------------------------------------
1 | TEST=value
2 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/config_map_generator/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | locals {
10 | test_key = "test"
11 | test_value = "value"
12 |
13 | test_file = "env"
14 | }
15 |
16 | module "mut" {
17 | source = "../.."
18 |
19 | configuration = {
20 | apps = {
21 | namespace = "test-cmgen"
22 |
23 | config_map_generator = [
24 | {
25 | name = "test"
26 | behavior = "merge"
27 | literals = [
28 | "${local.test_key}=${local.test_value}"
29 | ]
30 | options = {
31 | annotations = {
32 | source = "from_base_merged"
33 | }
34 | }
35 | },
36 | {
37 | name = "test-literal"
38 | behavior = "create"
39 | literals = [
40 | "${local.test_key}=${local.test_value}"
41 | ]
42 | options = {
43 | labels = {
44 | source = "from_literal"
45 | }
46 | }
47 | },
48 | {
49 | name = "test-envs"
50 | envs = [
51 | "${path.module}/${local.test_file}"
52 | ]
53 | options = {
54 | disable_name_suffix_hash = true
55 | }
56 | },
57 | {
58 | name = "test-files"
59 | files = [
60 | "${path.module}/${local.test_file}"
61 | ]
62 | }
63 | ]
64 | }
65 |
66 | (terraform.workspace) = {}
67 | }
68 |
69 | configuration_base_key = "apps"
70 | }
71 |
72 | locals {
73 | manifests = { for k, v in module.mut.manifests : k => jsondecode(v) }
74 | }
75 |
76 | //resource "test_assertions" "debug" {
77 | // component = "config_map_generator"
78 | //
79 | // equal "value_correct_debug" {
80 | // description = "key in configmap data has correct value"
81 | // got = local.manifests
82 | // want = {}
83 | // }
84 | //}
85 |
86 | resource "test_assertions" "from_base_merge" {
87 | component = "config_map_generator"
88 |
89 | check "key_exists_from_base_merge" {
90 | description = "key_exists_from_base_merge"
91 | condition = contains(keys(local.manifests["_/ConfigMap/test-cmgen/test"].data), local.test_key)
92 | }
93 |
94 | equal "value_correct_from_base_merge" {
95 | description = "value_correct_from_base_merge"
96 | got = local.manifests["_/ConfigMap/test-cmgen/test"].data[local.test_key]
97 | want = local.test_value
98 | }
99 |
100 | equal "annotation_correct_from_base_merge" {
101 | description = "annotation_correct_from_base_merge"
102 | got = local.manifests["_/ConfigMap/test-cmgen/test"].metadata.annotations["source"]
103 | want = "from_base_merged"
104 | }
105 | }
106 |
107 | resource "test_assertions" "from_literal" {
108 | component = "config_map_generator"
109 |
110 | check "key_exists_from_literal" {
111 | description = "key_exists_from_literal"
112 | condition = contains(keys(local.manifests["_/ConfigMap/test-cmgen/test-literal-cc854d6db8"].data), local.test_key)
113 | }
114 |
115 | equal "value_correct_from_literal" {
116 | description = "value_correct_from_literal"
117 | got = local.manifests["_/ConfigMap/test-cmgen/test-literal-cc854d6db8"].data[local.test_key]
118 | want = local.test_value
119 | }
120 |
121 | equal "annotation_correct_from_base_merge" {
122 | description = "annotation_correct_from_base_merge"
123 | got = local.manifests["_/ConfigMap/test-cmgen/test-literal-cc854d6db8"].metadata.labels.source
124 | want = "from_literal"
125 | }
126 | }
127 |
128 | resource "test_assertions" "from_envs" {
129 | component = "config_map_generator"
130 |
131 | check "key_exists_from_envs" {
132 | description = "key_exists_from_envs"
133 | condition = contains(keys(local.manifests["_/ConfigMap/test-cmgen/test-envs"].data), upper(local.test_key))
134 | }
135 |
136 | equal "value_correct_from_envs" {
137 | description = "value_correct_from_envs"
138 | got = local.manifests["_/ConfigMap/test-cmgen/test-envs"].data[upper(local.test_key)]
139 | want = local.test_value
140 | }
141 | }
142 |
143 | resource "test_assertions" "from_files" {
144 | component = "config_map_generator"
145 |
146 | check "key_exists_from_files" {
147 | description = "key_exists_from_files"
148 | condition = contains(keys(local.manifests["_/ConfigMap/test-cmgen/test-files-k7fk56g6g8"].data), local.test_file)
149 | }
150 |
151 | equal "value_correct_from_files" {
152 | description = "value_correct_from_files"
153 | got = local.manifests["_/ConfigMap/test-cmgen/test-files-k7fk56g6g8"].data[local.test_file]
154 | want = file("${path.module}/${local.test_file}")
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/generator_options/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | locals {
10 | test_key = "test"
11 | test_value = "value"
12 |
13 | test_file = "env"
14 | }
15 |
16 | module "mut" {
17 | source = "../.."
18 |
19 | configuration = {
20 | apps = {
21 | namespace = "test-genopts"
22 |
23 | generator_options = {
24 | annotations = {
25 | (local.test_key) = local.test_value
26 | }
27 |
28 | labels = {
29 | (local.test_key) = local.test_value
30 | }
31 |
32 | disable_name_suffix_hash = true
33 | }
34 |
35 | config_map_generator = [
36 | {
37 | name = "test-literal"
38 | behavior = "create"
39 | literals = []
40 | },
41 | ]
42 |
43 | secret_generator = [
44 | {
45 | name = "test-literal"
46 | behavior = "create"
47 | literals = []
48 | },
49 | ]
50 | }
51 |
52 | (terraform.workspace) = {}
53 | }
54 |
55 | configuration_base_key = "apps"
56 | }
57 |
58 | locals {
59 | manifests = { for k, v in module.mut.manifests : k => jsondecode(v) }
60 | }
61 |
62 | resource "test_assertions" "configmap" {
63 | component = "generator_options"
64 |
65 | check "cm_has_no_name_suffix" {
66 | description = "cm_has_no_name_suffix"
67 | condition = contains(keys(local.manifests), "_/ConfigMap/test-genopts/test-literal")
68 | }
69 |
70 | equal "cm_annotation_correct" {
71 | description = "cm_annotation_correct"
72 | got = local.manifests["_/ConfigMap/test-genopts/test-literal"].metadata.annotations[local.test_key]
73 | want = local.test_value
74 | }
75 |
76 | equal "cm_labels_correct" {
77 | description = "cm_labels_correct"
78 | got = local.manifests["_/ConfigMap/test-genopts/test-literal"].metadata.labels[local.test_key]
79 | want = local.test_value
80 | }
81 | }
82 |
83 | resource "test_assertions" "secret" {
84 | component = "generator_options"
85 |
86 | check "secret_has_no_name_suffix" {
87 | description = "secret_has_no_name_suffix"
88 | condition = contains(keys(local.manifests), "_/Secret/test-genopts/test-literal")
89 | }
90 |
91 | equal "secret_annotation_correct" {
92 | description = "secret_annotation_correct"
93 | got = local.manifests["_/Secret/test-genopts/test-literal"].metadata.annotations[local.test_key]
94 | want = local.test_value
95 | }
96 |
97 | equal "secret_labels_correct" {
98 | description = "secret_labels_correct"
99 | got = local.manifests["_/Secret/test-genopts/test-literal"].metadata.labels[local.test_key]
100 | want = local.test_value
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/images/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | module "mut" {
10 | source = "../.."
11 |
12 | configuration = {
13 | (terraform.workspace) = {
14 | images = [
15 | {
16 | name = "busybox"
17 | new_name = "new_name"
18 | new_tag = "new_tag"
19 | }
20 | ]
21 | }
22 | }
23 |
24 | configuration_base_key = terraform.workspace
25 | }
26 |
27 | resource "test_assertions" "images" {
28 | component = "images"
29 |
30 | equal "image_is_correct" {
31 | description = "image_is_correct"
32 | got = jsondecode(module.mut.manifests["apps/Deployment/test/test"]).spec.template.spec.containers[0].image
33 | want = "new_name:new_tag"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/inheritance/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | module "mut_upstream" {
10 | source = "../.."
11 |
12 | configuration = {
13 | upstream = {
14 | namespace = "from-upstream"
15 | name_prefix = "pre-"
16 | name_suffix = "-suf"
17 | }
18 |
19 | (terraform.workspace) = {}
20 | }
21 |
22 | configuration_base_key = "upstream"
23 | }
24 |
25 | resource "test_assertions" "from_upstream" {
26 | component = "configuration_inheritance_from_upstream"
27 |
28 | equal "namespace_name_changed" {
29 | description = "namespace_name_changed"
30 | got = jsondecode(module.mut_upstream.manifests["_/Namespace/_/from-upstream"]).metadata.name
31 | want = "from-upstream"
32 | }
33 |
34 | equal "deployment_has_prefix_and_suffix" {
35 | description = "deployment_has_prefix_and_suffix"
36 | got = jsondecode(module.mut_upstream.manifests["apps/Deployment/from-upstream/pre-test-suf"]).metadata.name
37 | want = "pre-test-suf"
38 | }
39 | }
40 |
41 | module "mut_workspace" {
42 | source = "../.."
43 |
44 | configuration = {
45 | upstream = {
46 | namespace = "from-upstream"
47 | }
48 |
49 | (terraform.workspace) = {
50 | namespace = "from-workspace"
51 | }
52 | }
53 |
54 | configuration_base_key = "upstream"
55 | }
56 |
57 | resource "test_assertions" "from_workspace" {
58 | component = "configuration_overwritten_by_workspace"
59 |
60 | equal "configuration_gets_overwritten_by_workspace" {
61 | description = "configuration_gets_overwritten_by_workspace"
62 | got = jsondecode(module.mut_workspace.manifests["_/Namespace/_/from-workspace"]).metadata.name
63 | want = "from-workspace"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/patches/patch_deployment_resources.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: test
5 | spec:
6 | template:
7 | spec:
8 | containers:
9 | - name: busybox
10 | resources:
11 | requests:
12 | cpu: 100m
13 | memory: 100Mi
14 | limits:
15 | cpu: 100m
16 | memory: 100Mi
17 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/patches/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | module "mut" {
10 | source = "../.."
11 |
12 | configuration = {
13 | (terraform.workspace) = {
14 | patches = [
15 | {
16 | path = "${path.module}/patch_deployment_resources.yaml"
17 | },
18 | {
19 | patch = <<-EOF
20 | - op: replace
21 | path: /metadata/name
22 | value: newname
23 | EOF
24 | target = {
25 | group = ""
26 | version = "v1"
27 | kind = "ConfigMap"
28 | name = "test"
29 | namespace = "test"
30 | label_selector = "test"
31 | annotation_selector = "test"
32 | }
33 | }
34 | ]
35 | }
36 | }
37 |
38 | configuration_base_key = terraform.workspace
39 | }
40 |
41 | locals {
42 | manifests = { for k, v in module.mut.manifests : k => jsondecode(v) }
43 | }
44 |
45 | resource "test_assertions" "patches_deployment_resources" {
46 | component = "patches_deployment_resources"
47 |
48 | equal "resources_are_correct" {
49 | description = "resources_are_correct"
50 | got = local.manifests["apps/Deployment/test/test"].spec.template.spec.containers[0].resources
51 | want = {
52 | limits = {
53 | cpu = "100m"
54 | memory = "100Mi"
55 | }
56 | requests = {
57 | cpu = "100m"
58 | memory = "100Mi"
59 | }
60 | }
61 | }
62 | }
63 |
64 | resource "test_assertions" "patches_rename_configmap" {
65 | component = "patches_rename_configmap"
66 |
67 | check "changed_configmap_name_in_manifests" {
68 | description = "changed_configmap_name_in_manifests"
69 | condition = contains(keys(local.manifests), "_/ConfigMap/test/newname")
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/replicas/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | module "mut" {
10 | source = "../.."
11 |
12 | configuration = {
13 | (terraform.workspace) = {
14 | replicas = [
15 | {
16 | name = "test"
17 | count = 3
18 | }
19 | ]
20 | }
21 | }
22 |
23 | configuration_base_key = terraform.workspace
24 | }
25 |
26 | resource "test_assertions" "replicas" {
27 | component = "replicas"
28 |
29 | equal "replicas_is_correct" {
30 | description = "replicas_is_correct"
31 | got = jsondecode(module.mut.manifests["apps/Deployment/test/test"]).spec.replicas
32 | want = 3
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/secret_generator/env:
--------------------------------------------------------------------------------
1 | TEST=value
2 |
--------------------------------------------------------------------------------
/src/_terraform_module/tests/secret_generator/test.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | test = {
4 | source = "terraform.io/builtin/test"
5 | }
6 | }
7 | }
8 |
9 | locals {
10 | test_key = "test"
11 | test_value = "value"
12 |
13 | test_file = "env"
14 | }
15 |
16 | module "mut" {
17 | source = "../.."
18 |
19 | configuration = {
20 | apps = {
21 | namespace = "test-secgen"
22 |
23 | secret_generator = [
24 | {
25 | name = "test-literal"
26 | behavior = "create"
27 | literals = [
28 | "${local.test_key}=${local.test_value}"
29 | ]
30 | options = {
31 | labels = {
32 | source = "from_literal"
33 | }
34 | }
35 | },
36 | {
37 | name = "test-envs"
38 | envs = [
39 | "${path.module}/${local.test_file}"
40 | ]
41 | options = {
42 | disable_name_suffix_hash = true
43 | }
44 | },
45 | {
46 | name = "test-files"
47 | files = [
48 | "${path.module}/${local.test_file}"
49 | ]
50 | }
51 | ]
52 | }
53 |
54 | (terraform.workspace) = {}
55 | }
56 |
57 | configuration_base_key = "apps"
58 | }
59 |
60 | locals {
61 | manifests = { for k, v in module.mut.manifests : k => jsondecode(v) }
62 | }
63 |
64 | //resource "test_assertions" "debug" {
65 | // component = "secret_generator"
66 | //
67 | // equal "value_correct_debug" {
68 | // description = "key in configmap data has correct value"
69 | // got = local.manifests
70 | // want = {}
71 | // }
72 | //}
73 |
74 | resource "test_assertions" "from_literal" {
75 | component = "secret_generator"
76 |
77 | check "key_exists_from_literal" {
78 | description = "key_exists_from_literal"
79 | condition = contains(keys(local.manifests["_/Secret/test-secgen/test-literal-9kf247ck92"].data), local.test_key)
80 | }
81 |
82 | equal "value_correct_from_literal" {
83 | description = "value_correct_from_literal"
84 | got = local.manifests["_/Secret/test-secgen/test-literal-9kf247ck92"].data[local.test_key]
85 | want = base64encode(local.test_value)
86 | }
87 |
88 | equal "annotation_correct_from_base_merge" {
89 | description = "annotation_correct_from_base_merge"
90 | got = local.manifests["_/Secret/test-secgen/test-literal-9kf247ck92"].metadata.labels.source
91 | want = "from_literal"
92 | }
93 | }
94 |
95 | resource "test_assertions" "from_envs" {
96 | component = "secret_generator"
97 |
98 | check "key_exists_from_envs" {
99 | description = "key_exists_from_envs"
100 | condition = contains(keys(local.manifests["_/Secret/test-secgen/test-envs"].data), upper(local.test_key))
101 | }
102 |
103 | equal "value_correct_from_envs" {
104 | description = "value_correct_from_envs"
105 | got = local.manifests["_/Secret/test-secgen/test-envs"].data[upper(local.test_key)]
106 | want = base64encode(local.test_value)
107 | }
108 | }
109 |
110 | resource "test_assertions" "from_files" {
111 | component = "secret_generator"
112 |
113 | check "key_exists_from_files" {
114 | description = "key_exists_from_files"
115 | condition = contains(keys(local.manifests["_/Secret/test-secgen/test-files-49cdkh47f9"].data), local.test_file)
116 | }
117 |
118 | equal "value_correct_from_files" {
119 | description = "value_correct_from_files"
120 | got = local.manifests["_/Secret/test-secgen/test-files-49cdkh47f9"].data[local.test_file]
121 | want = base64encode(file("${path.module}/${local.test_file}"))
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/_terraform_module/variables.tf:
--------------------------------------------------------------------------------
1 | variable "configuration" {
2 | type = map(object({
3 | # Variant is specific to these modules
4 | # it selects which of the bundled Kustomizations
5 | # to include in the resources list.
6 | # Each module has a default_variant
7 | variant = optional(string)
8 |
9 | # if set, will overwrite all of the module's
10 | # upstream resources, only useful in edge cases
11 | # see additional_resources instead
12 | resources = optional(list(string))
13 |
14 | # concat additional resources to the list of
15 | # included upstream resources
16 | additional_resources = optional(list(string))
17 |
18 | # Below are all Kustomization built-in
19 | # attributes that modules pass through to the
20 | # kustomizatoin_overlay data source
21 | common_annotations = optional(map(string))
22 | common_labels = optional(map(string))
23 | components = optional(list(string))
24 | config_map_generator = optional(list(object({
25 | name = optional(string)
26 | namespace = optional(string)
27 | behavior = optional(string)
28 | envs = optional(list(string))
29 | files = optional(list(string))
30 | literals = optional(list(string))
31 | options = optional(object({
32 | labels = optional(map(string))
33 | annotations = optional(map(string))
34 | disable_name_suffix_hash = optional(bool)
35 | }))
36 | })))
37 | crds = optional(list(string))
38 | generators = optional(list(string))
39 | generator_options = optional(object({
40 | labels = optional(map(string))
41 | annotations = optional(map(string))
42 | disable_name_suffix_hash = optional(bool)
43 | }))
44 | images = optional(list(object({
45 | name = optional(string)
46 | new_name = optional(string)
47 | new_tag = optional(string)
48 | digest = optional(string)
49 | })))
50 | name_prefix = optional(string)
51 | namespace = optional(string)
52 | name_suffix = optional(string)
53 | patches = optional(list(object({
54 | path = optional(string)
55 | patch = optional(string)
56 | target = optional(object({
57 | group = optional(string)
58 | version = optional(string)
59 | kind = optional(string)
60 | name = optional(string)
61 | namespace = optional(string)
62 | label_selector = optional(string)
63 | annotation_selector = optional(string)
64 | }))
65 | })))
66 | replicas = optional(list(object({
67 | name = optional(string)
68 | count = optional(number)
69 | })))
70 | secret_generator = optional(list(object({
71 | name = optional(string)
72 | namespace = optional(string)
73 | behavior = optional(string)
74 | type = optional(string)
75 | envs = optional(list(string))
76 | files = optional(list(string))
77 | literals = optional(list(string))
78 | options = optional(object({
79 | labels = optional(map(string))
80 | annotations = optional(map(string))
81 | disable_name_suffix_hash = optional(bool)
82 | }))
83 | })))
84 | transformers = optional(list(string))
85 | vars = optional(list(object({
86 | name = optional(string)
87 | obj_ref = optional(object({
88 | api_version = optional(string)
89 | group = optional(string)
90 | version = optional(string)
91 | kind = optional(string)
92 | name = optional(string)
93 | namespace = optional(string)
94 | }))
95 | field_ref = optional(object({
96 | field_path = optional(string)
97 | }))
98 | })))
99 | }))
100 | description = "Map with per workspace module configuration."
101 | default = { apps = {}, ops = {}, loc = {} }
102 | }
103 |
104 | variable "configuration_base_key" {
105 | type = string
106 | description = "The key in the configuration map all other keys inherit from."
107 | default = "apps"
108 | }
109 |
110 | variable "sensitive_group_kinds" {
111 | type = list(string)
112 | description = "List of GroupKinds to mark sensitive. Defaults to [\"_/Secret\"]"
113 | default = ["_/Secret"]
114 | }
115 |
--------------------------------------------------------------------------------
/src/_terraform_module/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | kustomization = {
4 | source = "kbst/kustomization"
5 | version = ">= 0.9.0"
6 | }
7 | }
8 |
9 | required_version = ">= 1.3.0"
10 | }
11 |
--------------------------------------------------------------------------------
/src/argo-cd/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/argoproj/argo-cd.git
2 | filter_tags: ^v(.+)
3 |
--------------------------------------------------------------------------------
/src/argo-cd/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | # copy install.yaml
9 | cp $source_path/manifests/install.yaml $target_path/normal/install.yaml
10 |
11 | cd $target_path/normal/
12 |
13 | # update version annotation
14 | kustomize edit add annotation -f app.kubernetes.io/version:$version
15 |
16 | cd -
17 |
18 | # copy ha/install.yaml
19 | cp $source_path/manifests/ha/install.yaml $target_path/ha/install.yaml
20 |
21 | cd $target_path/ha/
22 |
23 | # update version annotation
24 | kustomize edit add annotation -f app.kubernetes.io/version:$version
25 |
--------------------------------------------------------------------------------
/src/argo-cd/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/argo-cd/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/argo-cd/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "ha"
3 | }
4 |
--------------------------------------------------------------------------------
/src/argo-cd/ha/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: argocd
4 | commonAnnotations:
5 | app.kubernetes.io/managed-by: kubestack
6 | app.kubernetes.io/version: v2.6.7
7 | catalog.kubestack.com/heritage: kubestack.com/catalog/argo-cd
8 | catalog.kubestack.com/variant: ha
9 | resources:
10 | - namespace.yaml
11 | - install.yaml
12 |
--------------------------------------------------------------------------------
/src/argo-cd/ha/namespace.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: argocd
6 |
--------------------------------------------------------------------------------
/src/argo-cd/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/argo-cd/normal/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: argocd
4 | commonAnnotations:
5 | app.kubernetes.io/managed-by: kubestack
6 | app.kubernetes.io/version: v2.6.7
7 | catalog.kubestack.com/heritage: kubestack.com/catalog/argo-cd
8 | catalog.kubestack.com/variant: normal
9 | resources:
10 | - namespace.yaml
11 | - install.yaml
12 |
--------------------------------------------------------------------------------
/src/argo-cd/normal/namespace.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: argocd
6 |
--------------------------------------------------------------------------------
/src/argo-cd/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/argo-cd/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/cert-manager/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/jetstack/cert-manager.git
2 |
--------------------------------------------------------------------------------
/src/cert-manager/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | curl -Lo $target_path/base/cert-manager.yaml https://github.com/jetstack/cert-manager/releases/download/$version/cert-manager.yaml
9 |
--------------------------------------------------------------------------------
/src/cert-manager/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | app.kubernetes.io/version: v1.3.1
5 | catalog.kubestack.com/heritage: kubestack.com/catalog/cert-manager
6 | catalog.kubestack.com/variant: base
7 | commonLabels:
8 | app.kubernetes.io/managed-by: kubestack
9 | resources:
10 | - cert-manager.yaml
11 |
--------------------------------------------------------------------------------
/src/cert-manager/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/cert-manager/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/cert-manager/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/cert-manager/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/cert-manager/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/cert-manager/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/custom-manifests/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/custom-manifests/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/custom-manifests/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "empty"
3 | }
4 |
--------------------------------------------------------------------------------
/src/custom-manifests/empty/Kustomization:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
--------------------------------------------------------------------------------
/src/custom-manifests/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/custom-manifests/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/custom-manifests/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/flux/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/fluxcd/flux.git
2 | filter_tags: ^v(.+)
3 |
--------------------------------------------------------------------------------
/src/flux/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | rm -rf $target_path/base
9 | mkdir -p $target_path/base
10 | cp $source_path/deploy/* $target_path/base/
11 |
12 | cd $target_path/base/
13 |
14 | # set commonAnnotations
15 | kustomize edit add annotation catalog.kubestack.com/heritage:kubestack.com/catalog/flux,catalog.kubestack.com/variant:base,app.kubernetes.io/version:$version
16 |
17 | # set commonLabels
18 | kustomize edit add label app.kubernetes.io/component:controller,app.kubernetes.io/managed-by:kubestack,app.kubernetes.io/name:flux
19 |
--------------------------------------------------------------------------------
/src/flux/base/flux-account.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # The service account, cluster roles, and cluster role binding are
3 | # only needed for Kubernetes with role-based access control (RBAC).
4 | apiVersion: v1
5 | kind: ServiceAccount
6 | metadata:
7 | labels:
8 | name: flux
9 | name: flux
10 | namespace: flux
11 | ---
12 | apiVersion: rbac.authorization.k8s.io/v1
13 | kind: ClusterRole
14 | metadata:
15 | labels:
16 | name: flux
17 | name: flux
18 | rules:
19 | - apiGroups: ['*']
20 | resources: ['*']
21 | verbs: ['*']
22 | - nonResourceURLs: ['*']
23 | verbs: ['*']
24 | ---
25 | apiVersion: rbac.authorization.k8s.io/v1
26 | kind: ClusterRoleBinding
27 | metadata:
28 | labels:
29 | name: flux
30 | name: flux
31 | roleRef:
32 | apiGroup: rbac.authorization.k8s.io
33 | kind: ClusterRole
34 | name: flux
35 | subjects:
36 | - kind: ServiceAccount
37 | name: flux
38 | namespace: flux
39 |
--------------------------------------------------------------------------------
/src/flux/base/flux-deployment.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: flux
6 | namespace: flux
7 | spec:
8 | replicas: 1
9 | selector:
10 | matchLabels:
11 | name: flux
12 | strategy:
13 | type: Recreate
14 | template:
15 | metadata:
16 | annotations:
17 | prometheus.io/port: "3031" # tell prometheus to scrape /metrics endpoint's port.
18 | labels:
19 | name: flux
20 | spec:
21 | nodeSelector:
22 | beta.kubernetes.io/os: linux
23 | serviceAccountName: flux
24 | volumes:
25 | - name: git-key
26 | secret:
27 | secretName: flux-git-deploy
28 | defaultMode: 0400 # when mounted read-only, we won't be able to chmod
29 |
30 | # This is a tmpfs used for generating SSH keys. In K8s >= 1.10,
31 | # mounted secrets are read-only, so we need a separate volume we
32 | # can write to.
33 | - name: git-keygen
34 | emptyDir:
35 | medium: Memory
36 |
37 | # The following volume is for using a customised known_hosts
38 | # file, which you will need to do if you host your own git
39 | # repo rather than using github or the like. You'll also need to
40 | # mount it into the container, below. See
41 | # https://fluxcd.io/legacy/flux/guides/use-private-git-host/
42 | # - name: ssh-config
43 | # configMap:
44 | # name: flux-ssh-config
45 |
46 | # The following volume is for using a customised .kube/config,
47 | # which you will need to do if you wish to have a different
48 | # default namespace. You will also need to provide the configmap
49 | # with an entry for `config`, and uncomment the volumeMount and
50 | # env entries below.
51 | # - name: kubeconfig
52 | # configMap:
53 | # name: flux-kubeconfig
54 |
55 | # The following volume is used to import GPG keys (for signing
56 | # and verification purposes). You will also need to provide the
57 | # secret with the keys, and uncomment the volumeMount and args
58 | # below.
59 | # - name: gpg-keys
60 | # secret:
61 | # secretName: flux-gpg-keys
62 | # defaultMode: 0400
63 |
64 | containers:
65 | - name: flux
66 | # There are no ":latest" images for flux. Find the most recent
67 | # release or image version at https://hub.docker.com/r/fluxcd/flux/tags
68 | # and replace the tag here.
69 | image: docker.io/fluxcd/flux:1.25.4
70 | imagePullPolicy: IfNotPresent
71 | resources:
72 | requests:
73 | cpu: 50m
74 | memory: 64Mi
75 | ports:
76 | - containerPort: 3030 # informational
77 | livenessProbe:
78 | httpGet:
79 | port: 3030
80 | path: /api/flux/v6/identity.pub
81 | initialDelaySeconds: 5
82 | timeoutSeconds: 5
83 | readinessProbe:
84 | httpGet:
85 | port: 3030
86 | path: /api/flux/v6/identity.pub
87 | initialDelaySeconds: 5
88 | timeoutSeconds: 5
89 | volumeMounts:
90 | - name: git-key
91 | mountPath: /etc/fluxd/ssh # to match location given in image's /etc/ssh/config
92 | readOnly: true # this will be the case perforce in K8s >=1.10
93 | - name: git-keygen
94 | mountPath: /var/fluxd/keygen # to match location given in image's /etc/ssh/config
95 |
96 | # Include this if you need to mount a customised known_hosts
97 | # file; you'll also need the volume declared above.
98 | # - name: ssh-config
99 | # mountPath: /root/.ssh
100 |
101 | # Include this and the volume "kubeconfig" above, and the
102 | # environment entry "KUBECONFIG" below, to override the config
103 | # used by kubectl.
104 | # - name: kubeconfig
105 | # mountPath: /etc/fluxd/kube
106 |
107 | # Include this to point kubectl at a different config; you
108 | # will need to do this if you have mounted an alternate config
109 | # from a configmap, as in commented blocks above.
110 | # env:
111 | # - name: KUBECONFIG
112 | # value: /etc/fluxd/kube/config
113 |
114 | # Include this and the volume "gpg-keys" above, and the
115 | # args below.
116 | # - name: gpg-keys
117 | # mountPath: /root/gpg-import
118 | # readOnly: true
119 |
120 | # Include this if you want to supply HTTP basic auth credentials for git
121 | # via the `GIT_AUTHUSER` and `GIT_AUTHKEY` environment variables using a
122 | # secret.
123 | # envFrom:
124 | # - secretRef:
125 | # name: flux-git-auth
126 |
127 | args:
128 |
129 | # If you deployed memcached in a different namespace to flux,
130 | # or with a different service name, you can supply these
131 | # following two arguments to tell fluxd how to connect to it.
132 | # - --memcached-hostname=memcached.default.svc.cluster.local
133 |
134 | # Use the memcached ClusterIP service name by setting the
135 | # memcached-service to string empty
136 | - --memcached-service=
137 |
138 | # This must be supplied, and be in the tmpfs (emptyDir)
139 | # mounted above, for K8s >= 1.10
140 | - --ssh-keygen-dir=/var/fluxd/keygen
141 |
142 | # Replace the following URL to change the Git repository used by Flux.
143 | # HTTP basic auth credentials can be supplied using environment variables:
144 | # https://$(GIT_AUTHUSER):$(GIT_AUTHKEY)@github.com/user/repository.git
145 | - --git-url=git@github.com:fluxcd/flux-get-started
146 | - --git-branch=master
147 | # Include this if you want to restrict the manifests considered by flux
148 | # to those under the following relative paths in the git repository
149 | # - --git-path=subdir1,subdir2
150 | - --git-label=flux-sync
151 | - --git-user=Flux automation
152 | - --git-email=flux@example.com
153 |
154 | # Include these two to enable git commit signing
155 | # - --git-gpg-key-import=/root/gpg-import
156 | # - --git-signing-key=
157 |
158 | # Include this to enable git signature verification
159 | # - --git-verify-signatures
160 |
161 | # Tell flux it has readonly access to the repo (default `false`)
162 | # - --git-readonly
163 |
164 | # Instruct flux where to put sync bookkeeping (default "git", meaning use a tag in the upstream git repo)
165 | # - --sync-state=git
166 |
167 | # Include these next two to connect to an "upstream" service
168 | # (e.g., Weave Cloud). The token is particular to the service.
169 | # - --connect=wss://cloud.weave.works/api/flux
170 | # - --token=abc123abc123abc123abc123
171 |
172 | # Enable manifest generation (default `false`)
173 | # - --manifest-generation=false
174 |
175 | # Serve /metrics endpoint at different port;
176 | # make sure to set prometheus' annotation to scrape the port value.
177 | - --listen-metrics=:3031
178 |
179 | # Optional DNS settings, configuring the ndots option may resolve
180 | # nslookup issues on some Kubernetes setups.
181 | # dnsPolicy: "None"
182 | # dnsConfig:
183 | # options:
184 | # - name: ndots
185 | # value: "1"
186 |
--------------------------------------------------------------------------------
/src/flux/base/flux-ns.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: flux
6 |
--------------------------------------------------------------------------------
/src/flux/base/flux-secret.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: flux-git-deploy
6 | namespace: flux
7 | type: Opaque
8 |
--------------------------------------------------------------------------------
/src/flux/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - flux-ns.yaml
3 | - memcache-svc.yaml
4 | - memcache-dep.yaml
5 | - flux-account.yaml
6 | - flux-secret.yaml
7 | - flux-deployment.yaml
8 | apiVersion: kustomize.config.k8s.io/v1beta1
9 | kind: Kustomization
10 | commonAnnotations:
11 | app.kubernetes.io/version: v1.25.4
12 | catalog.kubestack.com/heritage: kubestack.com/catalog/flux
13 | catalog.kubestack.com/variant: base
14 | commonLabels:
15 | app.kubernetes.io/component: controller
16 | app.kubernetes.io/managed-by: kubestack
17 | app.kubernetes.io/name: flux
18 |
--------------------------------------------------------------------------------
/src/flux/base/memcache-dep.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # memcached deployment used by Flux to cache
3 | # container image metadata.
4 | apiVersion: apps/v1
5 | kind: Deployment
6 | metadata:
7 | name: memcached
8 | namespace: flux
9 | spec:
10 | replicas: 1
11 | selector:
12 | matchLabels:
13 | name: memcached
14 | template:
15 | metadata:
16 | labels:
17 | name: memcached
18 | spec:
19 | nodeSelector:
20 | beta.kubernetes.io/os: linux
21 | containers:
22 | - name: memcached
23 | image: memcached:1.6.10-alpine
24 | imagePullPolicy: IfNotPresent
25 | args:
26 | - -m 512 # Maximum memory to use, in megabytes
27 | - -I 5m # Maximum size for one item
28 | - -p 11211 # Default port
29 | # - -vv # Uncomment to get logs of each request and response.
30 | ports:
31 | - name: clients
32 | containerPort: 11211
33 | securityContext:
34 | runAsUser: 11211
35 | runAsGroup: 11211
36 | allowPrivilegeEscalation: false
37 |
--------------------------------------------------------------------------------
/src/flux/base/memcache-svc.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: memcached
6 | namespace: flux
7 | spec:
8 | ports:
9 | - name: memcached
10 | port: 11211
11 | selector:
12 | name: memcached
13 |
--------------------------------------------------------------------------------
/src/flux/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/flux/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/flux/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/flux/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/flux/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/flux/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/nginx/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/kubernetes/ingress-nginx.git
2 | ref: main
3 | filter_tags: ^controller-(.*)
4 |
--------------------------------------------------------------------------------
/src/nginx/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 |
7 | cp $source_path/deploy/static/provider/cloud/deploy.yaml $target_path/base/mandatory.yaml
8 |
--------------------------------------------------------------------------------
/src/nginx/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: ingress-nginx
4 | commonAnnotations:
5 | app.kubernetes.io/version: v0.46.0
6 | catalog.kubestack.com/heritage: kubestack.com/catalog/nginx
7 | catalog.kubestack.com/variant: base
8 | commonLabels:
9 | app.kubernetes.io/component: ingress-controller
10 | app.kubernetes.io/managed-by: kubestack
11 | app.kubernetes.io/name: nginx
12 | resources:
13 | - mandatory.yaml
14 | replicas:
15 | - name: ingress-nginx-controller
16 | count: 2
17 |
--------------------------------------------------------------------------------
/src/nginx/base/mandatory.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | labels:
5 | app.kubernetes.io/instance: ingress-nginx
6 | app.kubernetes.io/name: ingress-nginx
7 | name: ingress-nginx
8 | ---
9 | apiVersion: v1
10 | automountServiceAccountToken: true
11 | kind: ServiceAccount
12 | metadata:
13 | labels:
14 | app.kubernetes.io/component: controller
15 | app.kubernetes.io/instance: ingress-nginx
16 | app.kubernetes.io/name: ingress-nginx
17 | app.kubernetes.io/part-of: ingress-nginx
18 | app.kubernetes.io/version: 1.7.0
19 | name: ingress-nginx
20 | namespace: ingress-nginx
21 | ---
22 | apiVersion: v1
23 | kind: ServiceAccount
24 | metadata:
25 | labels:
26 | app.kubernetes.io/component: admission-webhook
27 | app.kubernetes.io/instance: ingress-nginx
28 | app.kubernetes.io/name: ingress-nginx
29 | app.kubernetes.io/part-of: ingress-nginx
30 | app.kubernetes.io/version: 1.7.0
31 | name: ingress-nginx-admission
32 | namespace: ingress-nginx
33 | ---
34 | apiVersion: rbac.authorization.k8s.io/v1
35 | kind: Role
36 | metadata:
37 | labels:
38 | app.kubernetes.io/component: controller
39 | app.kubernetes.io/instance: ingress-nginx
40 | app.kubernetes.io/name: ingress-nginx
41 | app.kubernetes.io/part-of: ingress-nginx
42 | app.kubernetes.io/version: 1.7.0
43 | name: ingress-nginx
44 | namespace: ingress-nginx
45 | rules:
46 | - apiGroups:
47 | - ""
48 | resources:
49 | - namespaces
50 | verbs:
51 | - get
52 | - apiGroups:
53 | - ""
54 | resources:
55 | - configmaps
56 | - pods
57 | - secrets
58 | - endpoints
59 | verbs:
60 | - get
61 | - list
62 | - watch
63 | - apiGroups:
64 | - ""
65 | resources:
66 | - services
67 | verbs:
68 | - get
69 | - list
70 | - watch
71 | - apiGroups:
72 | - networking.k8s.io
73 | resources:
74 | - ingresses
75 | verbs:
76 | - get
77 | - list
78 | - watch
79 | - apiGroups:
80 | - networking.k8s.io
81 | resources:
82 | - ingresses/status
83 | verbs:
84 | - update
85 | - apiGroups:
86 | - networking.k8s.io
87 | resources:
88 | - ingressclasses
89 | verbs:
90 | - get
91 | - list
92 | - watch
93 | - apiGroups:
94 | - coordination.k8s.io
95 | resourceNames:
96 | - ingress-nginx-leader
97 | resources:
98 | - leases
99 | verbs:
100 | - get
101 | - update
102 | - apiGroups:
103 | - coordination.k8s.io
104 | resources:
105 | - leases
106 | verbs:
107 | - create
108 | - apiGroups:
109 | - ""
110 | resources:
111 | - events
112 | verbs:
113 | - create
114 | - patch
115 | - apiGroups:
116 | - discovery.k8s.io
117 | resources:
118 | - endpointslices
119 | verbs:
120 | - list
121 | - watch
122 | - get
123 | ---
124 | apiVersion: rbac.authorization.k8s.io/v1
125 | kind: Role
126 | metadata:
127 | labels:
128 | app.kubernetes.io/component: admission-webhook
129 | app.kubernetes.io/instance: ingress-nginx
130 | app.kubernetes.io/name: ingress-nginx
131 | app.kubernetes.io/part-of: ingress-nginx
132 | app.kubernetes.io/version: 1.7.0
133 | name: ingress-nginx-admission
134 | namespace: ingress-nginx
135 | rules:
136 | - apiGroups:
137 | - ""
138 | resources:
139 | - secrets
140 | verbs:
141 | - get
142 | - create
143 | ---
144 | apiVersion: rbac.authorization.k8s.io/v1
145 | kind: ClusterRole
146 | metadata:
147 | labels:
148 | app.kubernetes.io/instance: ingress-nginx
149 | app.kubernetes.io/name: ingress-nginx
150 | app.kubernetes.io/part-of: ingress-nginx
151 | app.kubernetes.io/version: 1.7.0
152 | name: ingress-nginx
153 | rules:
154 | - apiGroups:
155 | - ""
156 | resources:
157 | - configmaps
158 | - endpoints
159 | - nodes
160 | - pods
161 | - secrets
162 | - namespaces
163 | verbs:
164 | - list
165 | - watch
166 | - apiGroups:
167 | - coordination.k8s.io
168 | resources:
169 | - leases
170 | verbs:
171 | - list
172 | - watch
173 | - apiGroups:
174 | - ""
175 | resources:
176 | - nodes
177 | verbs:
178 | - get
179 | - apiGroups:
180 | - ""
181 | resources:
182 | - services
183 | verbs:
184 | - get
185 | - list
186 | - watch
187 | - apiGroups:
188 | - networking.k8s.io
189 | resources:
190 | - ingresses
191 | verbs:
192 | - get
193 | - list
194 | - watch
195 | - apiGroups:
196 | - ""
197 | resources:
198 | - events
199 | verbs:
200 | - create
201 | - patch
202 | - apiGroups:
203 | - networking.k8s.io
204 | resources:
205 | - ingresses/status
206 | verbs:
207 | - update
208 | - apiGroups:
209 | - networking.k8s.io
210 | resources:
211 | - ingressclasses
212 | verbs:
213 | - get
214 | - list
215 | - watch
216 | - apiGroups:
217 | - discovery.k8s.io
218 | resources:
219 | - endpointslices
220 | verbs:
221 | - list
222 | - watch
223 | - get
224 | ---
225 | apiVersion: rbac.authorization.k8s.io/v1
226 | kind: ClusterRole
227 | metadata:
228 | labels:
229 | app.kubernetes.io/component: admission-webhook
230 | app.kubernetes.io/instance: ingress-nginx
231 | app.kubernetes.io/name: ingress-nginx
232 | app.kubernetes.io/part-of: ingress-nginx
233 | app.kubernetes.io/version: 1.7.0
234 | name: ingress-nginx-admission
235 | rules:
236 | - apiGroups:
237 | - admissionregistration.k8s.io
238 | resources:
239 | - validatingwebhookconfigurations
240 | verbs:
241 | - get
242 | - update
243 | ---
244 | apiVersion: rbac.authorization.k8s.io/v1
245 | kind: RoleBinding
246 | metadata:
247 | labels:
248 | app.kubernetes.io/component: controller
249 | app.kubernetes.io/instance: ingress-nginx
250 | app.kubernetes.io/name: ingress-nginx
251 | app.kubernetes.io/part-of: ingress-nginx
252 | app.kubernetes.io/version: 1.7.0
253 | name: ingress-nginx
254 | namespace: ingress-nginx
255 | roleRef:
256 | apiGroup: rbac.authorization.k8s.io
257 | kind: Role
258 | name: ingress-nginx
259 | subjects:
260 | - kind: ServiceAccount
261 | name: ingress-nginx
262 | namespace: ingress-nginx
263 | ---
264 | apiVersion: rbac.authorization.k8s.io/v1
265 | kind: RoleBinding
266 | metadata:
267 | labels:
268 | app.kubernetes.io/component: admission-webhook
269 | app.kubernetes.io/instance: ingress-nginx
270 | app.kubernetes.io/name: ingress-nginx
271 | app.kubernetes.io/part-of: ingress-nginx
272 | app.kubernetes.io/version: 1.7.0
273 | name: ingress-nginx-admission
274 | namespace: ingress-nginx
275 | roleRef:
276 | apiGroup: rbac.authorization.k8s.io
277 | kind: Role
278 | name: ingress-nginx-admission
279 | subjects:
280 | - kind: ServiceAccount
281 | name: ingress-nginx-admission
282 | namespace: ingress-nginx
283 | ---
284 | apiVersion: rbac.authorization.k8s.io/v1
285 | kind: ClusterRoleBinding
286 | metadata:
287 | labels:
288 | app.kubernetes.io/instance: ingress-nginx
289 | app.kubernetes.io/name: ingress-nginx
290 | app.kubernetes.io/part-of: ingress-nginx
291 | app.kubernetes.io/version: 1.7.0
292 | name: ingress-nginx
293 | roleRef:
294 | apiGroup: rbac.authorization.k8s.io
295 | kind: ClusterRole
296 | name: ingress-nginx
297 | subjects:
298 | - kind: ServiceAccount
299 | name: ingress-nginx
300 | namespace: ingress-nginx
301 | ---
302 | apiVersion: rbac.authorization.k8s.io/v1
303 | kind: ClusterRoleBinding
304 | metadata:
305 | labels:
306 | app.kubernetes.io/component: admission-webhook
307 | app.kubernetes.io/instance: ingress-nginx
308 | app.kubernetes.io/name: ingress-nginx
309 | app.kubernetes.io/part-of: ingress-nginx
310 | app.kubernetes.io/version: 1.7.0
311 | name: ingress-nginx-admission
312 | roleRef:
313 | apiGroup: rbac.authorization.k8s.io
314 | kind: ClusterRole
315 | name: ingress-nginx-admission
316 | subjects:
317 | - kind: ServiceAccount
318 | name: ingress-nginx-admission
319 | namespace: ingress-nginx
320 | ---
321 | apiVersion: v1
322 | data:
323 | allow-snippet-annotations: "true"
324 | kind: ConfigMap
325 | metadata:
326 | labels:
327 | app.kubernetes.io/component: controller
328 | app.kubernetes.io/instance: ingress-nginx
329 | app.kubernetes.io/name: ingress-nginx
330 | app.kubernetes.io/part-of: ingress-nginx
331 | app.kubernetes.io/version: 1.7.0
332 | name: ingress-nginx-controller
333 | namespace: ingress-nginx
334 | ---
335 | apiVersion: v1
336 | kind: Service
337 | metadata:
338 | labels:
339 | app.kubernetes.io/component: controller
340 | app.kubernetes.io/instance: ingress-nginx
341 | app.kubernetes.io/name: ingress-nginx
342 | app.kubernetes.io/part-of: ingress-nginx
343 | app.kubernetes.io/version: 1.7.0
344 | name: ingress-nginx-controller
345 | namespace: ingress-nginx
346 | spec:
347 | externalTrafficPolicy: Local
348 | ipFamilies:
349 | - IPv4
350 | ipFamilyPolicy: SingleStack
351 | ports:
352 | - appProtocol: http
353 | name: http
354 | port: 80
355 | protocol: TCP
356 | targetPort: http
357 | - appProtocol: https
358 | name: https
359 | port: 443
360 | protocol: TCP
361 | targetPort: https
362 | selector:
363 | app.kubernetes.io/component: controller
364 | app.kubernetes.io/instance: ingress-nginx
365 | app.kubernetes.io/name: ingress-nginx
366 | type: LoadBalancer
367 | ---
368 | apiVersion: v1
369 | kind: Service
370 | metadata:
371 | labels:
372 | app.kubernetes.io/component: controller
373 | app.kubernetes.io/instance: ingress-nginx
374 | app.kubernetes.io/name: ingress-nginx
375 | app.kubernetes.io/part-of: ingress-nginx
376 | app.kubernetes.io/version: 1.7.0
377 | name: ingress-nginx-controller-admission
378 | namespace: ingress-nginx
379 | spec:
380 | ports:
381 | - appProtocol: https
382 | name: https-webhook
383 | port: 443
384 | targetPort: webhook
385 | selector:
386 | app.kubernetes.io/component: controller
387 | app.kubernetes.io/instance: ingress-nginx
388 | app.kubernetes.io/name: ingress-nginx
389 | type: ClusterIP
390 | ---
391 | apiVersion: apps/v1
392 | kind: Deployment
393 | metadata:
394 | labels:
395 | app.kubernetes.io/component: controller
396 | app.kubernetes.io/instance: ingress-nginx
397 | app.kubernetes.io/name: ingress-nginx
398 | app.kubernetes.io/part-of: ingress-nginx
399 | app.kubernetes.io/version: 1.7.0
400 | name: ingress-nginx-controller
401 | namespace: ingress-nginx
402 | spec:
403 | minReadySeconds: 0
404 | revisionHistoryLimit: 10
405 | selector:
406 | matchLabels:
407 | app.kubernetes.io/component: controller
408 | app.kubernetes.io/instance: ingress-nginx
409 | app.kubernetes.io/name: ingress-nginx
410 | template:
411 | metadata:
412 | labels:
413 | app.kubernetes.io/component: controller
414 | app.kubernetes.io/instance: ingress-nginx
415 | app.kubernetes.io/name: ingress-nginx
416 | app.kubernetes.io/part-of: ingress-nginx
417 | app.kubernetes.io/version: 1.7.0
418 | spec:
419 | containers:
420 | - args:
421 | - /nginx-ingress-controller
422 | - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
423 | - --election-id=ingress-nginx-leader
424 | - --controller-class=k8s.io/ingress-nginx
425 | - --ingress-class=nginx
426 | - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
427 | - --validating-webhook=:8443
428 | - --validating-webhook-certificate=/usr/local/certificates/cert
429 | - --validating-webhook-key=/usr/local/certificates/key
430 | env:
431 | - name: POD_NAME
432 | valueFrom:
433 | fieldRef:
434 | fieldPath: metadata.name
435 | - name: POD_NAMESPACE
436 | valueFrom:
437 | fieldRef:
438 | fieldPath: metadata.namespace
439 | - name: LD_PRELOAD
440 | value: /usr/local/lib/libmimalloc.so
441 | image: registry.k8s.io/ingress-nginx/controller:v1.7.0@sha256:7612338342a1e7b8090bef78f2a04fffcadd548ccaabe8a47bf7758ff549a5f7
442 | imagePullPolicy: IfNotPresent
443 | lifecycle:
444 | preStop:
445 | exec:
446 | command:
447 | - /wait-shutdown
448 | livenessProbe:
449 | failureThreshold: 5
450 | httpGet:
451 | path: /healthz
452 | port: 10254
453 | scheme: HTTP
454 | initialDelaySeconds: 10
455 | periodSeconds: 10
456 | successThreshold: 1
457 | timeoutSeconds: 1
458 | name: controller
459 | ports:
460 | - containerPort: 80
461 | name: http
462 | protocol: TCP
463 | - containerPort: 443
464 | name: https
465 | protocol: TCP
466 | - containerPort: 8443
467 | name: webhook
468 | protocol: TCP
469 | readinessProbe:
470 | failureThreshold: 3
471 | httpGet:
472 | path: /healthz
473 | port: 10254
474 | scheme: HTTP
475 | initialDelaySeconds: 10
476 | periodSeconds: 10
477 | successThreshold: 1
478 | timeoutSeconds: 1
479 | resources:
480 | requests:
481 | cpu: 100m
482 | memory: 90Mi
483 | securityContext:
484 | allowPrivilegeEscalation: true
485 | capabilities:
486 | add:
487 | - NET_BIND_SERVICE
488 | drop:
489 | - ALL
490 | runAsUser: 101
491 | volumeMounts:
492 | - mountPath: /usr/local/certificates/
493 | name: webhook-cert
494 | readOnly: true
495 | dnsPolicy: ClusterFirst
496 | nodeSelector:
497 | kubernetes.io/os: linux
498 | serviceAccountName: ingress-nginx
499 | terminationGracePeriodSeconds: 300
500 | volumes:
501 | - name: webhook-cert
502 | secret:
503 | secretName: ingress-nginx-admission
504 | ---
505 | apiVersion: batch/v1
506 | kind: Job
507 | metadata:
508 | labels:
509 | app.kubernetes.io/component: admission-webhook
510 | app.kubernetes.io/instance: ingress-nginx
511 | app.kubernetes.io/name: ingress-nginx
512 | app.kubernetes.io/part-of: ingress-nginx
513 | app.kubernetes.io/version: 1.7.0
514 | name: ingress-nginx-admission-create
515 | namespace: ingress-nginx
516 | spec:
517 | template:
518 | metadata:
519 | labels:
520 | app.kubernetes.io/component: admission-webhook
521 | app.kubernetes.io/instance: ingress-nginx
522 | app.kubernetes.io/name: ingress-nginx
523 | app.kubernetes.io/part-of: ingress-nginx
524 | app.kubernetes.io/version: 1.7.0
525 | name: ingress-nginx-admission-create
526 | spec:
527 | containers:
528 | - args:
529 | - create
530 | - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
531 | - --namespace=$(POD_NAMESPACE)
532 | - --secret-name=ingress-nginx-admission
533 | env:
534 | - name: POD_NAMESPACE
535 | valueFrom:
536 | fieldRef:
537 | fieldPath: metadata.namespace
538 | image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230312-helm-chart-4.5.2-28-g66a760794@sha256:01d181618f270f2a96c04006f33b2699ad3ccb02da48d0f89b22abce084b292f
539 | imagePullPolicy: IfNotPresent
540 | name: create
541 | securityContext:
542 | allowPrivilegeEscalation: false
543 | nodeSelector:
544 | kubernetes.io/os: linux
545 | restartPolicy: OnFailure
546 | securityContext:
547 | fsGroup: 2000
548 | runAsNonRoot: true
549 | runAsUser: 2000
550 | serviceAccountName: ingress-nginx-admission
551 | ---
552 | apiVersion: batch/v1
553 | kind: Job
554 | metadata:
555 | labels:
556 | app.kubernetes.io/component: admission-webhook
557 | app.kubernetes.io/instance: ingress-nginx
558 | app.kubernetes.io/name: ingress-nginx
559 | app.kubernetes.io/part-of: ingress-nginx
560 | app.kubernetes.io/version: 1.7.0
561 | name: ingress-nginx-admission-patch
562 | namespace: ingress-nginx
563 | spec:
564 | template:
565 | metadata:
566 | labels:
567 | app.kubernetes.io/component: admission-webhook
568 | app.kubernetes.io/instance: ingress-nginx
569 | app.kubernetes.io/name: ingress-nginx
570 | app.kubernetes.io/part-of: ingress-nginx
571 | app.kubernetes.io/version: 1.7.0
572 | name: ingress-nginx-admission-patch
573 | spec:
574 | containers:
575 | - args:
576 | - patch
577 | - --webhook-name=ingress-nginx-admission
578 | - --namespace=$(POD_NAMESPACE)
579 | - --patch-mutating=false
580 | - --secret-name=ingress-nginx-admission
581 | - --patch-failure-policy=Fail
582 | env:
583 | - name: POD_NAMESPACE
584 | valueFrom:
585 | fieldRef:
586 | fieldPath: metadata.namespace
587 | image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230312-helm-chart-4.5.2-28-g66a760794@sha256:01d181618f270f2a96c04006f33b2699ad3ccb02da48d0f89b22abce084b292f
588 | imagePullPolicy: IfNotPresent
589 | name: patch
590 | securityContext:
591 | allowPrivilegeEscalation: false
592 | nodeSelector:
593 | kubernetes.io/os: linux
594 | restartPolicy: OnFailure
595 | securityContext:
596 | fsGroup: 2000
597 | runAsNonRoot: true
598 | runAsUser: 2000
599 | serviceAccountName: ingress-nginx-admission
600 | ---
601 | apiVersion: networking.k8s.io/v1
602 | kind: IngressClass
603 | metadata:
604 | labels:
605 | app.kubernetes.io/component: controller
606 | app.kubernetes.io/instance: ingress-nginx
607 | app.kubernetes.io/name: ingress-nginx
608 | app.kubernetes.io/part-of: ingress-nginx
609 | app.kubernetes.io/version: 1.7.0
610 | name: nginx
611 | spec:
612 | controller: k8s.io/ingress-nginx
613 | ---
614 | apiVersion: admissionregistration.k8s.io/v1
615 | kind: ValidatingWebhookConfiguration
616 | metadata:
617 | labels:
618 | app.kubernetes.io/component: admission-webhook
619 | app.kubernetes.io/instance: ingress-nginx
620 | app.kubernetes.io/name: ingress-nginx
621 | app.kubernetes.io/part-of: ingress-nginx
622 | app.kubernetes.io/version: 1.7.0
623 | name: ingress-nginx-admission
624 | webhooks:
625 | - admissionReviewVersions:
626 | - v1
627 | clientConfig:
628 | service:
629 | name: ingress-nginx-controller-admission
630 | namespace: ingress-nginx
631 | path: /networking/v1/ingresses
632 | failurePolicy: Fail
633 | matchPolicy: Equivalent
634 | name: validate.nginx.ingress.kubernetes.io
635 | rules:
636 | - apiGroups:
637 | - networking.k8s.io
638 | apiVersions:
639 | - v1
640 | operations:
641 | - CREATE
642 | - UPDATE
643 | resources:
644 | - ingresses
645 | sideEffects: None
646 |
--------------------------------------------------------------------------------
/src/nginx/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/nginx/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/nginx/default-ingress/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | bases:
4 | - ../base/
5 | namespace: ingress-kbst-default
6 | commonAnnotations:
7 | catalog.kubestack.com/heritage: kubestack.com/catalog/nginx
8 | catalog.kubestack.com/variant: default-ingress
9 | app.kubernetes.io/version: v0.46.0
10 | commonLabels:
11 | app.kubernetes.io/component: ingress-controller
12 | app.kubernetes.io/managed-by: kubestack
13 | app.kubernetes.io/name: nginx
14 | kubestack.com/ingress-default: 'true'
15 | patchesJson6902:
16 | - path: patch-namespace.yaml
17 | target:
18 | kind: Namespace
19 | group: ''
20 | name: ingress-nginx
21 | version: v1
22 |
--------------------------------------------------------------------------------
/src/nginx/default-ingress/patch-namespace.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /metadata/name
3 | value: ingress-kbst-default
4 |
--------------------------------------------------------------------------------
/src/nginx/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/nginx/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/nginx/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/nginx/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/opa-gatekeeper/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/open-policy-agent/gatekeeper.git
2 | filter_tags: ^v([0-9.]+)$
3 |
--------------------------------------------------------------------------------
/src/opa-gatekeeper/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | cp $source_path/deploy/gatekeeper.yaml $target_path/base/gatekeeper.yaml
9 |
--------------------------------------------------------------------------------
/src/opa-gatekeeper/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | catalog.kubestack.com/heritage: kubestack.com/catalog/opa-gatekeeper
5 | catalog.kubestack.com/variant: base
6 | app.kubernetes.io/version: v3.4.0
7 | commonLabels:
8 | app.kubernetes.io/component: admission-controller
9 | app.kubernetes.io/managed-by: kubestack
10 | app.kubernetes.io/name: opa-gatekeeper
11 | resources:
12 | - gatekeeper.yaml
13 |
--------------------------------------------------------------------------------
/src/opa-gatekeeper/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/opa-gatekeeper/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/opa-gatekeeper/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/opa-gatekeeper/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/opa-gatekeeper/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/opa-gatekeeper/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/pinniped/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/vmware-tanzu/pinniped.git
2 | ref: main
3 | filter_tags: ^v(.+)
4 |
--------------------------------------------------------------------------------
/src/pinniped/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | # concierge
9 | curl -Lo $target_path/concierge-base/crds.yaml https://get.pinniped.dev/$version/install-pinniped-concierge-crds.yaml
10 | curl -Lo $target_path/concierge-base/resources.yaml https://get.pinniped.dev/$version/install-pinniped-concierge-resources.yaml
11 |
12 | cd $target_path/concierge-base/
13 |
14 | # set commonAnnotations
15 | kustomize edit add annotation -f app.kubernetes.io/version:$version
16 |
17 | cd -
18 |
19 | # supervisor
20 | curl -Lo $target_path/supervisor-base/resources.yaml https://get.pinniped.dev/$version/install-pinniped-supervisor.yaml
21 |
22 | cd $target_path/concierge-base/
23 |
24 | # set commonAnnotations
25 | kustomize edit add annotation -f app.kubernetes.io/version:$version
26 |
--------------------------------------------------------------------------------
/src/pinniped/concierge-base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | app.kubernetes.io/version: v0.23.0
5 | catalog.kubestack.com/heritage: kubestack.com/catalog/pinniped
6 | catalog.kubestack.com/variant: base
7 | resources:
8 | - crds.yaml
9 | - resources.yaml
10 |
--------------------------------------------------------------------------------
/src/pinniped/concierge-base/resources.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: pinniped-concierge-config
5 | namespace: pinniped-concierge
6 | labels:
7 | app: pinniped-concierge
8 | data:
9 | pinniped.yaml: "discovery:\n url: null\napi:\n servingCertificate:\n durationSeconds: 2592000\n renewBeforeSeconds: 2160000\napiGroupSuffix: pinniped.dev\n# aggregatedAPIServerPort may be set here, although other YAML references to the default port (10250) may also need to be updated\n# impersonationProxyServerPort may be set here, although other YAML references to the default port (8444) may also need to be updated\nnames:\n servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate\n credentialIssuer: pinniped-concierge-config\n apiService: pinniped-concierge-api\n impersonationLoadBalancerService: pinniped-concierge-impersonation-proxy-load-balancer\n impersonationClusterIPService: pinniped-concierge-impersonation-proxy-cluster-ip\n impersonationTLSCertificateSecret: pinniped-concierge-impersonation-proxy-tls-serving-certificate\n impersonationCACertificateSecret: pinniped-concierge-impersonation-proxy-ca-certificate\n impersonationSignerSecret: pinniped-concierge-impersonation-proxy-signer-ca-certificate\n agentServiceAccount: pinniped-concierge-kube-cert-agent\nlabels: {\"app\":\"pinniped-concierge\"}\nkubeCertAgent:\n namePrefix: pinniped-concierge-kube-cert-agent-\n \n \n image: projects.registry.vmware.com/pinniped/pinniped-server:v0.23.0@sha256:3549526b0ecc850469a8cfbaf8701876680b522636bd84d573ed80b54552feb2\n \n \n \n\n"
10 | ---
11 | apiVersion: apps/v1
12 | kind: Deployment
13 | metadata:
14 | name: pinniped-concierge
15 | namespace: pinniped-concierge
16 | labels:
17 | app: pinniped-concierge
18 | spec:
19 | replicas: 2
20 | selector:
21 | matchLabels:
22 | app: pinniped-concierge
23 | template:
24 | metadata:
25 | labels:
26 | app: pinniped-concierge
27 | deployment.pinniped.dev: concierge
28 | annotations:
29 | scheduler.alpha.kubernetes.io/critical-pod: ""
30 | spec:
31 | securityContext:
32 | runAsUser: 65532
33 | runAsGroup: 65532
34 | serviceAccountName: pinniped-concierge
35 | containers:
36 | - name: pinniped-concierge
37 | image: projects.registry.vmware.com/pinniped/pinniped-server:v0.23.0@sha256:3549526b0ecc850469a8cfbaf8701876680b522636bd84d573ed80b54552feb2
38 | imagePullPolicy: IfNotPresent
39 | securityContext:
40 | readOnlyRootFilesystem: true
41 | runAsNonRoot: true
42 | allowPrivilegeEscalation: false
43 | capabilities:
44 | drop:
45 | - ALL
46 | seccompProfile:
47 | type: RuntimeDefault
48 | resources:
49 | requests:
50 | cpu: 100m
51 | memory: 128Mi
52 | limits:
53 | cpu: 100m
54 | memory: 128Mi
55 | command:
56 | - pinniped-concierge
57 | - --config=/etc/config/pinniped.yaml
58 | - --downward-api-path=/etc/podinfo
59 | volumeMounts:
60 | - name: tmp
61 | mountPath: /tmp
62 | - name: config-volume
63 | mountPath: /etc/config
64 | readOnly: true
65 | - name: podinfo
66 | mountPath: /etc/podinfo
67 | readOnly: true
68 | - name: impersonation-proxy
69 | mountPath: /var/run/secrets/impersonation-proxy.concierge.pinniped.dev/serviceaccount
70 | readOnly: true
71 | env: []
72 | livenessProbe:
73 | httpGet:
74 | path: /healthz
75 | port: 10250
76 | scheme: HTTPS
77 | initialDelaySeconds: 2
78 | timeoutSeconds: 15
79 | periodSeconds: 10
80 | failureThreshold: 5
81 | readinessProbe:
82 | httpGet:
83 | path: /healthz
84 | port: 10250
85 | scheme: HTTPS
86 | initialDelaySeconds: 2
87 | timeoutSeconds: 3
88 | periodSeconds: 10
89 | failureThreshold: 3
90 | volumes:
91 | - name: tmp
92 | emptyDir:
93 | medium: Memory
94 | sizeLimit: 100Mi
95 | - name: config-volume
96 | configMap:
97 | name: pinniped-concierge-config
98 | - name: impersonation-proxy
99 | secret:
100 | secretName: pinniped-concierge-impersonation-proxy
101 | items:
102 | - key: token
103 | path: token
104 | - name: podinfo
105 | downwardAPI:
106 | items:
107 | - path: labels
108 | fieldRef:
109 | fieldPath: metadata.labels
110 | - path: name
111 | fieldRef:
112 | fieldPath: metadata.name
113 | - path: namespace
114 | fieldRef:
115 | fieldPath: metadata.namespace
116 | tolerations:
117 | - key: CriticalAddonsOnly
118 | operator: Exists
119 | - key: node-role.kubernetes.io/master
120 | effect: NoSchedule
121 | - key: node-role.kubernetes.io/control-plane
122 | effect: NoSchedule
123 | affinity:
124 | podAntiAffinity:
125 | preferredDuringSchedulingIgnoredDuringExecution:
126 | - weight: 50
127 | podAffinityTerm:
128 | labelSelector:
129 | matchLabels:
130 | deployment.pinniped.dev: concierge
131 | topologyKey: kubernetes.io/hostname
132 | ---
133 | apiVersion: v1
134 | kind: Service
135 | metadata:
136 | name: pinniped-concierge-api
137 | namespace: pinniped-concierge
138 | labels:
139 | app: pinniped-concierge
140 | annotations:
141 | kapp.k14s.io/disable-default-label-scoping-rules: ""
142 | spec:
143 | type: ClusterIP
144 | selector:
145 | deployment.pinniped.dev: concierge
146 | ports:
147 | - protocol: TCP
148 | port: 443
149 | targetPort: 10250
150 | ---
151 | apiVersion: v1
152 | kind: Service
153 | metadata:
154 | name: pinniped-concierge-proxy
155 | namespace: pinniped-concierge
156 | labels:
157 | app: pinniped-concierge
158 | annotations:
159 | kapp.k14s.io/disable-default-label-scoping-rules: ""
160 | spec:
161 | type: ClusterIP
162 | selector:
163 | deployment.pinniped.dev: concierge
164 | ports:
165 | - protocol: TCP
166 | port: 443
167 | targetPort: 8444
168 | ---
169 | apiVersion: apiregistration.k8s.io/v1
170 | kind: APIService
171 | metadata:
172 | name: v1alpha1.login.concierge.pinniped.dev
173 | labels:
174 | app: pinniped-concierge
175 | spec:
176 | version: v1alpha1
177 | group: login.concierge.pinniped.dev
178 | groupPriorityMinimum: 9900
179 | versionPriority: 15
180 | service:
181 | name: pinniped-concierge-api
182 | namespace: pinniped-concierge
183 | port: 443
184 | ---
185 | apiVersion: apiregistration.k8s.io/v1
186 | kind: APIService
187 | metadata:
188 | name: v1alpha1.identity.concierge.pinniped.dev
189 | labels:
190 | app: pinniped-concierge
191 | spec:
192 | version: v1alpha1
193 | group: identity.concierge.pinniped.dev
194 | groupPriorityMinimum: 9900
195 | versionPriority: 15
196 | service:
197 | name: pinniped-concierge-api
198 | namespace: pinniped-concierge
199 | port: 443
200 | ---
201 | apiVersion: config.concierge.pinniped.dev/v1alpha1
202 | kind: CredentialIssuer
203 | metadata:
204 | name: pinniped-concierge-config
205 | labels:
206 | app: pinniped-concierge
207 | spec:
208 | impersonationProxy:
209 | mode: auto
210 | service:
211 | type: LoadBalancer
212 | annotations:
213 | service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "4000"
214 | ---
215 | apiVersion: v1
216 | kind: Secret
217 | metadata:
218 | name: pinniped-concierge-impersonation-proxy
219 | namespace: pinniped-concierge
220 | labels:
221 | app: pinniped-concierge
222 | annotations:
223 | kapp.k14s.io/change-rule: upsert after upserting impersonation-proxy.concierge.pinniped.dev/serviceaccount
224 | kubernetes.io/service-account.name: pinniped-concierge-impersonation-proxy
225 | type: kubernetes.io/service-account-token
226 | ---
227 | apiVersion: rbac.authorization.k8s.io/v1
228 | kind: ClusterRole
229 | metadata:
230 | name: pinniped-concierge-aggregated-api-server
231 | labels:
232 | app: pinniped-concierge
233 | rules:
234 | - apiGroups:
235 | - ""
236 | resources:
237 | - namespaces
238 | verbs:
239 | - get
240 | - list
241 | - watch
242 | - apiGroups:
243 | - apiregistration.k8s.io
244 | resources:
245 | - apiservices
246 | verbs:
247 | - get
248 | - list
249 | - patch
250 | - update
251 | - watch
252 | - apiGroups:
253 | - admissionregistration.k8s.io
254 | resources:
255 | - validatingwebhookconfigurations
256 | - mutatingwebhookconfigurations
257 | verbs:
258 | - get
259 | - list
260 | - watch
261 | - apiGroups:
262 | - flowcontrol.apiserver.k8s.io
263 | resources:
264 | - flowschemas
265 | - prioritylevelconfigurations
266 | verbs:
267 | - get
268 | - list
269 | - watch
270 | - apiGroups:
271 | - security.openshift.io
272 | resources:
273 | - securitycontextconstraints
274 | verbs:
275 | - use
276 | resourceNames:
277 | - nonroot
278 | - apiGroups:
279 | - ""
280 | resources:
281 | - nodes
282 | verbs:
283 | - list
284 | - apiGroups:
285 | - config.concierge.pinniped.dev
286 | resources:
287 | - credentialissuers
288 | verbs:
289 | - get
290 | - list
291 | - watch
292 | - create
293 | - apiGroups:
294 | - config.concierge.pinniped.dev
295 | resources:
296 | - credentialissuers/status
297 | verbs:
298 | - get
299 | - patch
300 | - update
301 | - apiGroups:
302 | - authentication.concierge.pinniped.dev
303 | resources:
304 | - jwtauthenticators
305 | - webhookauthenticators
306 | verbs:
307 | - get
308 | - list
309 | - watch
310 | ---
311 | kind: ClusterRoleBinding
312 | apiVersion: rbac.authorization.k8s.io/v1
313 | metadata:
314 | name: pinniped-concierge-aggregated-api-server
315 | labels:
316 | app: pinniped-concierge
317 | subjects:
318 | - kind: ServiceAccount
319 | name: pinniped-concierge
320 | namespace: pinniped-concierge
321 | roleRef:
322 | kind: ClusterRole
323 | name: pinniped-concierge-aggregated-api-server
324 | apiGroup: rbac.authorization.k8s.io
325 | ---
326 | apiVersion: rbac.authorization.k8s.io/v1
327 | kind: ClusterRole
328 | metadata:
329 | name: pinniped-concierge-impersonation-proxy
330 | labels:
331 | app: pinniped-concierge
332 | rules:
333 | - apiGroups:
334 | - ""
335 | resources:
336 | - users
337 | - groups
338 | - serviceaccounts
339 | verbs:
340 | - impersonate
341 | - apiGroups:
342 | - authentication.k8s.io
343 | resources:
344 | - '*'
345 | verbs:
346 | - impersonate
347 | ---
348 | kind: ClusterRoleBinding
349 | apiVersion: rbac.authorization.k8s.io/v1
350 | metadata:
351 | name: pinniped-concierge-impersonation-proxy
352 | labels:
353 | app: pinniped-concierge
354 | subjects:
355 | - kind: ServiceAccount
356 | name: pinniped-concierge-impersonation-proxy
357 | namespace: pinniped-concierge
358 | roleRef:
359 | kind: ClusterRole
360 | name: pinniped-concierge-impersonation-proxy
361 | apiGroup: rbac.authorization.k8s.io
362 | ---
363 | apiVersion: rbac.authorization.k8s.io/v1
364 | kind: Role
365 | metadata:
366 | name: pinniped-concierge-kube-cert-agent
367 | namespace: pinniped-concierge
368 | labels:
369 | app: pinniped-concierge
370 | rules:
371 | - apiGroups:
372 | - policy
373 | resources:
374 | - podsecuritypolicies
375 | verbs:
376 | - use
377 | ---
378 | kind: RoleBinding
379 | apiVersion: rbac.authorization.k8s.io/v1
380 | metadata:
381 | name: pinniped-concierge-kube-cert-agent
382 | namespace: pinniped-concierge
383 | labels:
384 | app: pinniped-concierge
385 | subjects:
386 | - kind: ServiceAccount
387 | name: pinniped-concierge-kube-cert-agent
388 | namespace: pinniped-concierge
389 | roleRef:
390 | kind: Role
391 | name: pinniped-concierge-kube-cert-agent
392 | apiGroup: rbac.authorization.k8s.io
393 | ---
394 | apiVersion: rbac.authorization.k8s.io/v1
395 | kind: Role
396 | metadata:
397 | name: pinniped-concierge-aggregated-api-server
398 | namespace: pinniped-concierge
399 | labels:
400 | app: pinniped-concierge
401 | rules:
402 | - apiGroups:
403 | - ""
404 | resources:
405 | - services
406 | verbs:
407 | - create
408 | - get
409 | - list
410 | - patch
411 | - update
412 | - watch
413 | - delete
414 | - apiGroups:
415 | - ""
416 | resources:
417 | - secrets
418 | verbs:
419 | - create
420 | - get
421 | - list
422 | - patch
423 | - update
424 | - watch
425 | - delete
426 | - apiGroups:
427 | - ""
428 | resources:
429 | - pods
430 | verbs:
431 | - get
432 | - list
433 | - watch
434 | - apiGroups:
435 | - ""
436 | resources:
437 | - pods/exec
438 | verbs:
439 | - create
440 | - apiGroups:
441 | - ""
442 | resources:
443 | - pods
444 | verbs:
445 | - delete
446 | - apiGroups:
447 | - apps
448 | resources:
449 | - deployments
450 | verbs:
451 | - create
452 | - get
453 | - list
454 | - patch
455 | - update
456 | - watch
457 | - delete
458 | - apiGroups:
459 | - apps
460 | resources:
461 | - replicasets
462 | verbs:
463 | - get
464 | - apiGroups:
465 | - ""
466 | resources:
467 | - configmaps
468 | verbs:
469 | - list
470 | - get
471 | - watch
472 | - apiGroups:
473 | - coordination.k8s.io
474 | resources:
475 | - leases
476 | verbs:
477 | - create
478 | - get
479 | - update
480 | ---
481 | kind: RoleBinding
482 | apiVersion: rbac.authorization.k8s.io/v1
483 | metadata:
484 | name: pinniped-concierge-aggregated-api-server
485 | namespace: pinniped-concierge
486 | labels:
487 | app: pinniped-concierge
488 | subjects:
489 | - kind: ServiceAccount
490 | name: pinniped-concierge
491 | namespace: pinniped-concierge
492 | roleRef:
493 | kind: Role
494 | name: pinniped-concierge-aggregated-api-server
495 | apiGroup: rbac.authorization.k8s.io
496 | ---
497 | apiVersion: rbac.authorization.k8s.io/v1
498 | kind: Role
499 | metadata:
500 | name: pinniped-concierge-kube-system-pod-read
501 | namespace: kube-system
502 | labels:
503 | app: pinniped-concierge
504 | rules:
505 | - apiGroups:
506 | - ""
507 | resources:
508 | - pods
509 | verbs:
510 | - get
511 | - list
512 | - watch
513 | ---
514 | kind: RoleBinding
515 | apiVersion: rbac.authorization.k8s.io/v1
516 | metadata:
517 | name: pinniped-concierge-kube-system-pod-read
518 | namespace: kube-system
519 | labels:
520 | app: pinniped-concierge
521 | subjects:
522 | - kind: ServiceAccount
523 | name: pinniped-concierge
524 | namespace: pinniped-concierge
525 | roleRef:
526 | kind: Role
527 | name: pinniped-concierge-kube-system-pod-read
528 | apiGroup: rbac.authorization.k8s.io
529 | ---
530 | apiVersion: rbac.authorization.k8s.io/v1
531 | kind: ClusterRole
532 | metadata:
533 | name: pinniped-concierge-pre-authn-apis
534 | labels:
535 | app: pinniped-concierge
536 | rules:
537 | - apiGroups:
538 | - login.concierge.pinniped.dev
539 | resources:
540 | - tokencredentialrequests
541 | verbs:
542 | - create
543 | - list
544 | - apiGroups:
545 | - identity.concierge.pinniped.dev
546 | resources:
547 | - whoamirequests
548 | verbs:
549 | - create
550 | - list
551 | ---
552 | kind: ClusterRoleBinding
553 | apiVersion: rbac.authorization.k8s.io/v1
554 | metadata:
555 | name: pinniped-concierge-pre-authn-apis
556 | labels:
557 | app: pinniped-concierge
558 | subjects:
559 | - kind: Group
560 | name: system:authenticated
561 | apiGroup: rbac.authorization.k8s.io
562 | - kind: Group
563 | name: system:unauthenticated
564 | apiGroup: rbac.authorization.k8s.io
565 | roleRef:
566 | kind: ClusterRole
567 | name: pinniped-concierge-pre-authn-apis
568 | apiGroup: rbac.authorization.k8s.io
569 | ---
570 | kind: ClusterRoleBinding
571 | apiVersion: rbac.authorization.k8s.io/v1
572 | metadata:
573 | name: pinniped-concierge
574 | labels:
575 | app: pinniped-concierge
576 | subjects:
577 | - kind: ServiceAccount
578 | name: pinniped-concierge
579 | namespace: pinniped-concierge
580 | roleRef:
581 | kind: ClusterRole
582 | name: system:auth-delegator
583 | apiGroup: rbac.authorization.k8s.io
584 | ---
585 | kind: RoleBinding
586 | apiVersion: rbac.authorization.k8s.io/v1
587 | metadata:
588 | name: pinniped-concierge-extension-apiserver-authentication-reader
589 | namespace: kube-system
590 | labels:
591 | app: pinniped-concierge
592 | subjects:
593 | - kind: ServiceAccount
594 | name: pinniped-concierge
595 | namespace: pinniped-concierge
596 | roleRef:
597 | kind: Role
598 | name: extension-apiserver-authentication-reader
599 | apiGroup: rbac.authorization.k8s.io
600 | ---
601 | kind: Role
602 | apiVersion: rbac.authorization.k8s.io/v1
603 | metadata:
604 | name: pinniped-concierge-cluster-info-lister-watcher
605 | namespace: kube-public
606 | labels:
607 | app: pinniped-concierge
608 | rules:
609 | - apiGroups:
610 | - ""
611 | resources:
612 | - configmaps
613 | verbs:
614 | - list
615 | - watch
616 | ---
617 | kind: RoleBinding
618 | apiVersion: rbac.authorization.k8s.io/v1
619 | metadata:
620 | name: pinniped-concierge-cluster-info-lister-watcher
621 | namespace: kube-public
622 | labels:
623 | app: pinniped-concierge
624 | subjects:
625 | - kind: ServiceAccount
626 | name: pinniped-concierge
627 | namespace: pinniped-concierge
628 | roleRef:
629 | kind: Role
630 | name: pinniped-concierge-cluster-info-lister-watcher
631 | apiGroup: rbac.authorization.k8s.io
632 |
--------------------------------------------------------------------------------
/src/pinniped/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/pinniped/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/pinniped/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "concierge-base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/pinniped/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/pinniped/supervisor-base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | catalog.kubestack.com/heritage: kubestack.com/catalog/pinniped
5 | catalog.kubestack.com/variant: base
6 | app.kubernetes.io/version: v0.15.0
7 | resources:
8 | - resources.yaml
9 |
--------------------------------------------------------------------------------
/src/pinniped/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/pinniped/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/postgresql/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/zalando/postgres-operator.git
2 |
--------------------------------------------------------------------------------
/src/postgresql/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | tag=$3
7 |
8 | cp $source_path/manifests/postgres-operator.yaml $target_path/base/postgres-operator.yaml
9 |
10 | cp $source_path/manifests/operator-service-account-rbac.yaml $target_path/clusterwide/rbac.yaml
11 |
12 | # fix upstream by default exposing db externally
13 | # make base not clusterwide
14 | # and make provider indepented
15 | sed -e 's/enable_master_load_balancer: "true"/enable_master_load_balancer: "false"/g' \
16 | -e '/watched_namespace/d' \
17 | -e '/aws_region:/d' \
18 | "${source_path}/manifests/configmap.yaml" \
19 | > "${target_path}/base/configmap.yaml"
20 |
21 | # fix upstream net setting image correctly in provided manifest
22 | cd $target_path/base
23 | kustomize edit set image registry.opensource.zalan.do/acid/smoke-tested-postgres-operator=registry.opensource.zalan.do/acid/postgres-operator:$tag
24 |
--------------------------------------------------------------------------------
/src/postgresql/base/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: postgres-operator
5 | data:
6 | # additional_owner_roles: "cron_admin"
7 | # additional_pod_capabilities: "SYS_NICE"
8 | # additional_secret_mount: "some-secret-name"
9 | # additional_secret_mount_path: "/some/dir"
10 | api_port: "8080"
11 | cluster_domain: cluster.local
12 | cluster_history_entries: "1000"
13 | cluster_labels: application:spilo
14 | cluster_name_label: cluster-name
15 | # connection_pooler_default_cpu_limit: "1"
16 | # connection_pooler_default_cpu_request: "500m"
17 | # connection_pooler_default_memory_limit: 100Mi
18 | # connection_pooler_default_memory_request: 100Mi
19 | connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-26"
20 | # connection_pooler_max_db_connections: 60
21 | # connection_pooler_mode: "transaction"
22 | # connection_pooler_number_of_instances: 2
23 | # connection_pooler_schema: "pooler"
24 | # connection_pooler_user: "pooler"
25 | crd_categories: "all"
26 | # custom_service_annotations: "keyx:valuez,keya:valuea"
27 | # custom_pod_annotations: "keya:valuea,keyb:valueb"
28 | db_hosted_zone: db.example.com
29 | debug_logging: "true"
30 | # default_cpu_limit: "1"
31 | # default_cpu_request: 100m
32 | # default_memory_limit: 500Mi
33 | # default_memory_request: 100Mi
34 | # delete_annotation_date_key: delete-date
35 | # delete_annotation_name_key: delete-clustername
36 | docker_image: ghcr.io/zalando/spilo-15:2.1-p9
37 | # downscaler_annotations: "deployment-time,downscaler/*"
38 | # enable_admin_role_for_users: "true"
39 | # enable_crd_registration: "true"
40 | # enable_cross_namespace_secret: "false"
41 | # enable_database_access: "true"
42 | enable_ebs_gp3_migration: "false"
43 | # enable_ebs_gp3_migration_max_size: "1000"
44 | # enable_init_containers: "true"
45 | # enable_lazy_spilo_upgrade: "false"
46 | enable_master_load_balancer: "false"
47 | enable_master_pooler_load_balancer: "false"
48 | enable_password_rotation: "false"
49 | # enable_patroni_failsafe_mode: "false"
50 | enable_pgversion_env_var: "true"
51 | # enable_pod_antiaffinity: "false"
52 | # enable_pod_disruption_budget: "true"
53 | # enable_postgres_team_crd: "false"
54 | # enable_postgres_team_crd_superusers: "false"
55 | enable_readiness_probe: "false"
56 | enable_replica_load_balancer: "false"
57 | enable_replica_pooler_load_balancer: "false"
58 | # enable_shm_volume: "true"
59 | # enable_sidecars: "true"
60 | enable_spilo_wal_path_compat: "true"
61 | enable_team_id_clustername_prefix: "false"
62 | enable_team_member_deprecation: "false"
63 | # enable_team_superuser: "false"
64 | enable_teams_api: "false"
65 | # etcd_host: ""
66 | external_traffic_policy: "Cluster"
67 | # gcp_credentials: ""
68 | # ignored_annotations: ""
69 | # infrastructure_roles_secret_name: "postgresql-infrastructure-roles"
70 | # infrastructure_roles_secrets: "secretname:monitoring-roles,userkey:user,passwordkey:password,rolekey:inrole"
71 | # ignore_instance_limits_annotation_key: ""
72 | # inherited_annotations: owned-by
73 | # inherited_labels: application,environment
74 | # kube_iam_role: ""
75 | # kubernetes_use_configmaps: "false"
76 | # log_s3_bucket: ""
77 | # logical_backup_azure_storage_account_name: ""
78 | # logical_backup_azure_storage_container: ""
79 | # logical_backup_azure_storage_account_key: ""
80 | # logical_backup_cpu_limit: ""
81 | # logical_backup_cpu_request: ""
82 | logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.9.0"
83 | # logical_backup_google_application_credentials: ""
84 | logical_backup_job_prefix: "logical-backup-"
85 | # logical_backup_memory_limit: ""
86 | # logical_backup_memory_request: ""
87 | logical_backup_provider: "s3"
88 | # logical_backup_s3_access_key_id: ""
89 | logical_backup_s3_bucket: "my-bucket-url"
90 | # logical_backup_s3_region: ""
91 | # logical_backup_s3_endpoint: ""
92 | # logical_backup_s3_secret_access_key: ""
93 | logical_backup_s3_sse: "AES256"
94 | # logical_backup_s3_retention_time: ""
95 | logical_backup_schedule: "30 00 * * *"
96 | major_version_upgrade_mode: "manual"
97 | # major_version_upgrade_team_allow_list: ""
98 | master_dns_name_format: "{cluster}.{namespace}.{hostedzone}"
99 | # master_legacy_dns_name_format: "{cluster}.{team}.{hostedzone}"
100 | # master_pod_move_timeout: 20m
101 | # max_instances: "-1"
102 | # min_instances: "-1"
103 | # max_cpu_request: "1"
104 | # max_memory_request: 4Gi
105 | # min_cpu_limit: 250m
106 | # min_memory_limit: 250Mi
107 | # minimal_major_version: "11"
108 | # node_readiness_label: "status:ready"
109 | # node_readiness_label_merge: "OR"
110 | # oauth_token_secret_name: postgresql-operator
111 | # pam_configuration: |
112 | # https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees
113 | # pam_role_name: zalandos
114 | patroni_api_check_interval: "1s"
115 | patroni_api_check_timeout: "5s"
116 | # password_rotation_interval: "90"
117 | # password_rotation_user_retention: "180"
118 | pdb_name_format: "postgres-{cluster}-pdb"
119 | # pod_antiaffinity_preferred_during_scheduling: "false"
120 | # pod_antiaffinity_topology_key: "kubernetes.io/hostname"
121 | pod_deletion_wait_timeout: 10m
122 | # pod_environment_configmap: "default/my-custom-config"
123 | # pod_environment_secret: "my-custom-secret"
124 | pod_label_wait_timeout: 10m
125 | pod_management_policy: "ordered_ready"
126 | # pod_priority_class_name: "postgres-pod-priority"
127 | pod_role_label: spilo-role
128 | # pod_service_account_definition: ""
129 | pod_service_account_name: "postgres-pod"
130 | # pod_service_account_role_binding_definition: ""
131 | pod_terminate_grace_period: 5m
132 | # postgres_superuser_teams: "postgres_superusers"
133 | # protected_role_names: "admin,cron_admin"
134 | ready_wait_interval: 3s
135 | ready_wait_timeout: 30s
136 | repair_period: 5m
137 | replica_dns_name_format: "{cluster}-repl.{namespace}.{hostedzone}"
138 | # replica_legacy_dns_name_format: "{cluster}-repl.{team}.{hostedzone}"
139 | replication_username: standby
140 | resource_check_interval: 3s
141 | resource_check_timeout: 10m
142 | resync_period: 30m
143 | ring_log_lines: "100"
144 | role_deletion_suffix: "_deleted"
145 | secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}"
146 | share_pgsocket_with_sidecars: "false"
147 | # sidecar_docker_images: ""
148 | # set_memory_request_to_limit: "false"
149 | spilo_allow_privilege_escalation: "true"
150 | # spilo_runasuser: 101
151 | # spilo_runasgroup: 103
152 | # spilo_fsgroup: 103
153 | spilo_privileged: "false"
154 | storage_resize_mode: "pvc"
155 | super_username: postgres
156 | # target_major_version: "15"
157 | # team_admin_role: "admin"
158 | # team_api_role_configuration: "log_statement:all"
159 | # teams_api_url: http://fake-teams-api.default.svc.cluster.local
160 | # toleration: "key:db-only,operator:Exists,effect:NoSchedule"
161 | # wal_az_storage_account: ""
162 | # wal_gs_bucket: ""
163 | # wal_s3_bucket: ""
164 | workers: "8"
165 |
--------------------------------------------------------------------------------
/src/postgresql/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | namespace: default
4 | commonAnnotations:
5 | app.kubernetes.io/version: v1.6.2
6 | catalog.kubestack.com/heritage: kubestack.com/catalog/postgresql
7 | catalog.kubestack.com/variant: base
8 | commonLabels:
9 | app.kubernetes.io/component: operator
10 | app.kubernetes.io/managed-by: kubestack
11 | app.kubernetes.io/name: postgresql
12 | resources:
13 | - postgres-operator.yaml
14 | - configmap.yaml
15 | images:
16 | - name: registry.opensource.zalan.do/acid/smoke-tested-postgres-operator
17 | newName: registry.opensource.zalan.do/acid/postgres-operator
18 | newTag: v1.9.0
19 |
--------------------------------------------------------------------------------
/src/postgresql/base/postgres-operator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: postgres-operator
5 | labels:
6 | application: postgres-operator
7 | spec:
8 | replicas: 1
9 | strategy:
10 | type: "Recreate"
11 | selector:
12 | matchLabels:
13 | name: postgres-operator
14 | template:
15 | metadata:
16 | labels:
17 | name: postgres-operator
18 | spec:
19 | serviceAccountName: postgres-operator
20 | containers:
21 | - name: postgres-operator
22 | image: registry.opensource.zalan.do/acid/postgres-operator:v1.9.0
23 | imagePullPolicy: IfNotPresent
24 | resources:
25 | requests:
26 | cpu: 100m
27 | memory: 250Mi
28 | limits:
29 | cpu: 500m
30 | memory: 500Mi
31 | securityContext:
32 | runAsUser: 1000
33 | runAsNonRoot: true
34 | readOnlyRootFilesystem: true
35 | allowPrivilegeEscalation: false
36 | env:
37 | # provided additional ENV vars can overwrite individual config map entries
38 | - name: CONFIG_MAP_NAME
39 | value: "postgres-operator"
40 | # In order to use the CRD OperatorConfiguration instead, uncomment these lines and comment out the two lines above
41 | # - name: POSTGRES_OPERATOR_CONFIGURATION_OBJECT
42 | # value: postgresql-operator-default-configuration
43 | # Define an ID to isolate controllers from each other
44 | # - name: CONTROLLER_ID
45 | # value: "second-operator"
46 |
--------------------------------------------------------------------------------
/src/postgresql/clusterwide/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | bases:
4 | - ../base/
5 | namespace: operator-postgresql
6 | commonAnnotations:
7 | app.kubernetes.io/version: v1.6.2
8 | catalog.kubestack.com/heritage: kubestack.com/catalog/postgresql
9 | catalog.kubestack.com/variant: clusterwide
10 | commonLabels:
11 | app.kubernetes.io/component: operator
12 | app.kubernetes.io/managed-by: kubestack
13 | app.kubernetes.io/name: postgresql
14 | patchesStrategicMerge:
15 | - patch-deployment-env.yaml
16 | resources:
17 | - namespace.yaml
18 | - rbac.yaml
19 |
--------------------------------------------------------------------------------
/src/postgresql/clusterwide/namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: operator-postgresql
5 |
--------------------------------------------------------------------------------
/src/postgresql/clusterwide/patch-deployment-env.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: postgres-operator
5 | spec:
6 | template:
7 | spec:
8 | containers:
9 | - name: postgres-operator
10 | env:
11 | - name: WATCHED_NAMESPACE
12 | value: '*'
13 |
--------------------------------------------------------------------------------
/src/postgresql/clusterwide/rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: postgres-operator
5 | namespace: default
6 |
7 | ---
8 | apiVersion: rbac.authorization.k8s.io/v1
9 | kind: ClusterRole
10 | metadata:
11 | name: postgres-operator
12 | rules:
13 | # all verbs allowed for custom operator resources
14 | - apiGroups:
15 | - acid.zalan.do
16 | resources:
17 | - postgresqls
18 | - postgresqls/status
19 | - operatorconfigurations
20 | verbs:
21 | - create
22 | - delete
23 | - deletecollection
24 | - get
25 | - list
26 | - patch
27 | - update
28 | - watch
29 | # operator only reads PostgresTeams
30 | - apiGroups:
31 | - acid.zalan.do
32 | resources:
33 | - postgresteams
34 | verbs:
35 | - get
36 | - list
37 | - watch
38 | # all verbs allowed for event streams (Zalando-internal feature)
39 | # - apiGroups:
40 | # - zalando.org
41 | # resources:
42 | # - fabriceventstreams
43 | # verbs:
44 | # - create
45 | # - delete
46 | # - deletecollection
47 | # - get
48 | # - list
49 | # - patch
50 | # - update
51 | # - watch
52 | # to create or get/update CRDs when starting up
53 | - apiGroups:
54 | - apiextensions.k8s.io
55 | resources:
56 | - customresourcedefinitions
57 | verbs:
58 | - create
59 | - get
60 | - patch
61 | - update
62 | # to read configuration from ConfigMaps
63 | - apiGroups:
64 | - ""
65 | resources:
66 | - configmaps
67 | verbs:
68 | - get
69 | # to send events to the CRs
70 | - apiGroups:
71 | - ""
72 | resources:
73 | - events
74 | verbs:
75 | - create
76 | - get
77 | - list
78 | - patch
79 | - update
80 | - watch
81 | # to manage endpoints which are also used by Patroni
82 | - apiGroups:
83 | - ""
84 | resources:
85 | - endpoints
86 | verbs:
87 | - create
88 | - delete
89 | - deletecollection
90 | - get
91 | - list
92 | - patch
93 | - update
94 | - watch
95 | # to CRUD secrets for database access
96 | - apiGroups:
97 | - ""
98 | resources:
99 | - secrets
100 | verbs:
101 | - create
102 | - delete
103 | - get
104 | - update
105 | # to check nodes for node readiness label
106 | - apiGroups:
107 | - ""
108 | resources:
109 | - nodes
110 | verbs:
111 | - get
112 | - list
113 | - watch
114 | # to read or delete existing PVCs. Creation via StatefulSet
115 | - apiGroups:
116 | - ""
117 | resources:
118 | - persistentvolumeclaims
119 | verbs:
120 | - delete
121 | - get
122 | - list
123 | - patch
124 | - update
125 | # to read existing PVs. Creation should be done via dynamic provisioning
126 | - apiGroups:
127 | - ""
128 | resources:
129 | - persistentvolumes
130 | verbs:
131 | - get
132 | - list
133 | - update # only for resizing AWS volumes
134 | # to watch Spilo pods and do rolling updates. Creation via StatefulSet
135 | - apiGroups:
136 | - ""
137 | resources:
138 | - pods
139 | verbs:
140 | - delete
141 | - get
142 | - list
143 | - patch
144 | - update
145 | - watch
146 | # to resize the filesystem in Spilo pods when increasing volume size
147 | - apiGroups:
148 | - ""
149 | resources:
150 | - pods/exec
151 | verbs:
152 | - create
153 | # to CRUD services to point to Postgres cluster instances
154 | - apiGroups:
155 | - ""
156 | resources:
157 | - services
158 | verbs:
159 | - create
160 | - delete
161 | - get
162 | - patch
163 | - update
164 | # to CRUD the StatefulSet which controls the Postgres cluster instances
165 | - apiGroups:
166 | - apps
167 | resources:
168 | - statefulsets
169 | - deployments
170 | verbs:
171 | - create
172 | - delete
173 | - get
174 | - list
175 | - patch
176 | # to CRUD cron jobs for logical backups
177 | - apiGroups:
178 | - batch
179 | resources:
180 | - cronjobs
181 | verbs:
182 | - create
183 | - delete
184 | - get
185 | - list
186 | - patch
187 | - update
188 | # to get namespaces operator resources can run in
189 | - apiGroups:
190 | - ""
191 | resources:
192 | - namespaces
193 | verbs:
194 | - get
195 | # to define PDBs. Update happens via delete/create
196 | - apiGroups:
197 | - policy
198 | resources:
199 | - poddisruptionbudgets
200 | verbs:
201 | - create
202 | - delete
203 | - get
204 | # to create ServiceAccounts in each namespace the operator watches
205 | - apiGroups:
206 | - ""
207 | resources:
208 | - serviceaccounts
209 | verbs:
210 | - get
211 | - create
212 | # to create role bindings to the postgres-pod service account
213 | - apiGroups:
214 | - rbac.authorization.k8s.io
215 | resources:
216 | - rolebindings
217 | verbs:
218 | - get
219 | - create
220 | # to grant privilege to run privileged pods (not needed by default)
221 | #- apiGroups:
222 | # - extensions
223 | # resources:
224 | # - podsecuritypolicies
225 | # resourceNames:
226 | # - privileged
227 | # verbs:
228 | # - use
229 |
230 | ---
231 | apiVersion: rbac.authorization.k8s.io/v1
232 | kind: ClusterRoleBinding
233 | metadata:
234 | name: postgres-operator
235 | roleRef:
236 | apiGroup: rbac.authorization.k8s.io
237 | kind: ClusterRole
238 | name: postgres-operator
239 | subjects:
240 | - kind: ServiceAccount
241 | name: postgres-operator
242 | namespace: default
243 |
244 | ---
245 | apiVersion: rbac.authorization.k8s.io/v1
246 | kind: ClusterRole
247 | metadata:
248 | name: postgres-pod
249 | rules:
250 | # Patroni needs to watch and manage endpoints
251 | - apiGroups:
252 | - ""
253 | resources:
254 | - endpoints
255 | verbs:
256 | - create
257 | - delete
258 | - deletecollection
259 | - get
260 | - list
261 | - patch
262 | - update
263 | - watch
264 | # Patroni needs to watch pods
265 | - apiGroups:
266 | - ""
267 | resources:
268 | - pods
269 | verbs:
270 | - get
271 | - list
272 | - patch
273 | - update
274 | - watch
275 | # to let Patroni create a headless service
276 | - apiGroups:
277 | - ""
278 | resources:
279 | - services
280 | verbs:
281 | - create
282 | # to grant privilege to run privileged pods (not needed by default)
283 | #- apiGroups:
284 | # - extensions
285 | # resources:
286 | # - podsecuritypolicies
287 | # resourceNames:
288 | # - privileged
289 | # verbs:
290 | # - use
291 |
--------------------------------------------------------------------------------
/src/postgresql/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/postgresql/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/postgresql/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "clusterwide"
3 | }
4 |
--------------------------------------------------------------------------------
/src/postgresql/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/postgresql/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/postgresql/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/prometheus/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/coreos/prometheus-operator.git
2 | ref: main
3 | filter_tags: ^v(.+)
4 |
--------------------------------------------------------------------------------
/src/prometheus/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | cp $source_path/bundle.yaml $target_path/base/bundle.yaml
9 |
--------------------------------------------------------------------------------
/src/prometheus/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | catalog.kubestack.com/heritage: kubestack.com/catalog/prometheus
5 | catalog.kubestack.com/variant: base
6 | app.kubernetes.io/version: v0.47.1
7 | resources:
8 | - bundle.yaml
9 |
--------------------------------------------------------------------------------
/src/prometheus/clusterwide/instance-cluster-role.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: prometheus-instance
5 | rules:
6 | - apiGroups: [""]
7 | resources:
8 | - nodes
9 | - services
10 | - endpoints
11 | - pods
12 | verbs: ["get", "list", "watch"]
13 | - apiGroups: [""]
14 | resources:
15 | - configmaps
16 | verbs: ["get"]
17 |
--------------------------------------------------------------------------------
/src/prometheus/clusterwide/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | bases:
4 | - ../base/
5 | namespace: operator-prometheus
6 | commonAnnotations:
7 | catalog.kubestack.com/heritage: kubestack.com/catalog/prometheus
8 | catalog.kubestack.com/variant: clusterwide
9 | app.kubernetes.io/version: v0.47.1
10 | resources:
11 | - namespace.yaml
12 | - instance-cluster-role.yaml
13 |
--------------------------------------------------------------------------------
/src/prometheus/clusterwide/namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: operator-prometheus
5 |
--------------------------------------------------------------------------------
/src/prometheus/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/prometheus/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/prometheus/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "clusterwide"
3 | }
4 |
--------------------------------------------------------------------------------
/src/prometheus/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/prometheus/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/prometheus/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/sealed-secrets/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/bitnami-labs/sealed-secrets.git
2 | ref: main
3 | filter_tags: ^v([0-9.]+)$
4 |
--------------------------------------------------------------------------------
/src/sealed-secrets/_updater/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | source_path=$1
5 | target_path=$2
6 | version=$3
7 |
8 | curl -Lo $target_path/base/controller.yaml https://github.com/bitnami-labs/sealed-secrets/releases/download/$version/controller.yaml
9 |
--------------------------------------------------------------------------------
/src/sealed-secrets/base/controller.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: sealedsecrets.bitnami.com
6 | spec:
7 | group: bitnami.com
8 | names:
9 | kind: SealedSecret
10 | listKind: SealedSecretList
11 | plural: sealedsecrets
12 | singular: sealedsecret
13 | scope: Namespaced
14 | versions:
15 | - name: v1alpha1
16 | schema:
17 | openAPIV3Schema:
18 | description: SealedSecret is the K8s representation of a "sealed Secret" -
19 | a regular k8s Secret that has been sealed (encrypted) using the controller's
20 | key.
21 | properties:
22 | apiVersion:
23 | description: 'APIVersion defines the versioned schema of this representation
24 | of an object. Servers should convert recognized schemas to the latest
25 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
26 | type: string
27 | kind:
28 | description: 'Kind is a string value representing the REST resource this
29 | object represents. Servers may infer this from the endpoint the client
30 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
31 | type: string
32 | metadata:
33 | type: object
34 | spec:
35 | description: SealedSecretSpec is the specification of a SealedSecret
36 | properties:
37 | data:
38 | description: Data is deprecated and will be removed eventually. Use
39 | per-value EncryptedData instead.
40 | format: byte
41 | type: string
42 | encryptedData:
43 | additionalProperties:
44 | type: string
45 | type: object
46 | x-kubernetes-preserve-unknown-fields: true
47 | template:
48 | description: Template defines the structure of the Secret that will
49 | be created from this sealed secret.
50 | properties:
51 | data:
52 | additionalProperties:
53 | type: string
54 | description: Keys that should be templated using decrypted data
55 | nullable: true
56 | type: object
57 | metadata:
58 | description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
59 | nullable: true
60 | type: object
61 | x-kubernetes-preserve-unknown-fields: true
62 | type:
63 | description: Used to facilitate programmatic handling of secret
64 | data.
65 | type: string
66 | type: object
67 | required:
68 | - encryptedData
69 | type: object
70 | status:
71 | description: SealedSecretStatus is the most recently observed status of
72 | the SealedSecret.
73 | properties:
74 | conditions:
75 | description: Represents the latest available observations of a sealed
76 | secret's current state.
77 | items:
78 | description: SealedSecretCondition describes the state of a sealed
79 | secret at a certain point.
80 | properties:
81 | lastTransitionTime:
82 | description: Last time the condition transitioned from one status
83 | to another.
84 | format: date-time
85 | type: string
86 | lastUpdateTime:
87 | description: The last time this condition was updated.
88 | format: date-time
89 | type: string
90 | message:
91 | description: A human readable message indicating details about
92 | the transition.
93 | type: string
94 | reason:
95 | description: The reason for the condition's last transition.
96 | type: string
97 | status:
98 | description: 'Status of the condition for a sealed secret. Valid
99 | values for "Synced": "True", "False", or "Unknown".'
100 | type: string
101 | type:
102 | description: 'Type of condition for a sealed secret. Valid value:
103 | "Synced"'
104 | type: string
105 | required:
106 | - status
107 | - type
108 | type: object
109 | type: array
110 | observedGeneration:
111 | description: ObservedGeneration reflects the generation most recently
112 | observed by the sealed-secrets controller.
113 | format: int64
114 | type: integer
115 | type: object
116 | required:
117 | - spec
118 | type: object
119 | served: true
120 | storage: true
121 | subresources:
122 | status: {}
123 | ---
124 | apiVersion: v1
125 | kind: Service
126 | metadata:
127 | annotations: {}
128 | labels:
129 | name: sealed-secrets-controller
130 | name: sealed-secrets-controller
131 | namespace: kube-system
132 | spec:
133 | ports:
134 | - port: 8080
135 | targetPort: 8080
136 | selector:
137 | name: sealed-secrets-controller
138 | type: ClusterIP
139 | ---
140 | apiVersion: rbac.authorization.k8s.io/v1
141 | kind: RoleBinding
142 | metadata:
143 | annotations: {}
144 | labels:
145 | name: sealed-secrets-service-proxier
146 | name: sealed-secrets-service-proxier
147 | namespace: kube-system
148 | roleRef:
149 | apiGroup: rbac.authorization.k8s.io
150 | kind: Role
151 | name: sealed-secrets-service-proxier
152 | subjects:
153 | - apiGroup: rbac.authorization.k8s.io
154 | kind: Group
155 | name: system:authenticated
156 | ---
157 | apiVersion: rbac.authorization.k8s.io/v1
158 | kind: Role
159 | metadata:
160 | annotations: {}
161 | labels:
162 | name: sealed-secrets-service-proxier
163 | name: sealed-secrets-service-proxier
164 | namespace: kube-system
165 | rules:
166 | - apiGroups:
167 | - ""
168 | resourceNames:
169 | - sealed-secrets-controller
170 | resources:
171 | - services
172 | verbs:
173 | - get
174 | - apiGroups:
175 | - ""
176 | resourceNames:
177 | - 'http:sealed-secrets-controller:'
178 | - http:sealed-secrets-controller:http
179 | - sealed-secrets-controller
180 | resources:
181 | - services/proxy
182 | verbs:
183 | - create
184 | - get
185 | ---
186 | apiVersion: rbac.authorization.k8s.io/v1
187 | kind: Role
188 | metadata:
189 | annotations: {}
190 | labels:
191 | name: sealed-secrets-key-admin
192 | name: sealed-secrets-key-admin
193 | namespace: kube-system
194 | rules:
195 | - apiGroups:
196 | - ""
197 | resources:
198 | - secrets
199 | verbs:
200 | - create
201 | - list
202 | ---
203 | apiVersion: v1
204 | kind: ServiceAccount
205 | metadata:
206 | annotations: {}
207 | labels:
208 | name: sealed-secrets-controller
209 | name: sealed-secrets-controller
210 | namespace: kube-system
211 | ---
212 | apiVersion: apps/v1
213 | kind: Deployment
214 | metadata:
215 | annotations: {}
216 | labels:
217 | name: sealed-secrets-controller
218 | name: sealed-secrets-controller
219 | namespace: kube-system
220 | spec:
221 | minReadySeconds: 30
222 | replicas: 1
223 | revisionHistoryLimit: 10
224 | selector:
225 | matchLabels:
226 | name: sealed-secrets-controller
227 | strategy:
228 | rollingUpdate:
229 | maxSurge: 25%
230 | maxUnavailable: 25%
231 | type: RollingUpdate
232 | template:
233 | metadata:
234 | annotations: {}
235 | labels:
236 | name: sealed-secrets-controller
237 | spec:
238 | containers:
239 | - args: []
240 | command:
241 | - controller
242 | env: []
243 | image: docker.io/bitnami/sealed-secrets-controller:v0.20.2
244 | imagePullPolicy: IfNotPresent
245 | livenessProbe:
246 | httpGet:
247 | path: /healthz
248 | port: http
249 | name: sealed-secrets-controller
250 | ports:
251 | - containerPort: 8080
252 | name: http
253 | readinessProbe:
254 | httpGet:
255 | path: /healthz
256 | port: http
257 | securityContext:
258 | readOnlyRootFilesystem: true
259 | runAsNonRoot: true
260 | runAsUser: 1001
261 | stdin: false
262 | tty: false
263 | volumeMounts:
264 | - mountPath: /tmp
265 | name: tmp
266 | imagePullSecrets: []
267 | initContainers: []
268 | securityContext:
269 | fsGroup: 65534
270 | serviceAccountName: sealed-secrets-controller
271 | terminationGracePeriodSeconds: 30
272 | volumes:
273 | - emptyDir: {}
274 | name: tmp
275 | ---
276 | apiVersion: rbac.authorization.k8s.io/v1
277 | kind: RoleBinding
278 | metadata:
279 | annotations: {}
280 | labels:
281 | name: sealed-secrets-controller
282 | name: sealed-secrets-controller
283 | namespace: kube-system
284 | roleRef:
285 | apiGroup: rbac.authorization.k8s.io
286 | kind: Role
287 | name: sealed-secrets-key-admin
288 | subjects:
289 | - kind: ServiceAccount
290 | name: sealed-secrets-controller
291 | namespace: kube-system
292 | ---
293 | apiVersion: rbac.authorization.k8s.io/v1
294 | kind: ClusterRoleBinding
295 | metadata:
296 | annotations: {}
297 | labels:
298 | name: sealed-secrets-controller
299 | name: sealed-secrets-controller
300 | roleRef:
301 | apiGroup: rbac.authorization.k8s.io
302 | kind: ClusterRole
303 | name: secrets-unsealer
304 | subjects:
305 | - kind: ServiceAccount
306 | name: sealed-secrets-controller
307 | namespace: kube-system
308 | ---
309 | apiVersion: rbac.authorization.k8s.io/v1
310 | kind: ClusterRole
311 | metadata:
312 | annotations: {}
313 | labels:
314 | name: secrets-unsealer
315 | name: secrets-unsealer
316 | rules:
317 | - apiGroups:
318 | - bitnami.com
319 | resources:
320 | - sealedsecrets
321 | verbs:
322 | - get
323 | - list
324 | - watch
325 | - apiGroups:
326 | - bitnami.com
327 | resources:
328 | - sealedsecrets/status
329 | verbs:
330 | - update
331 | - apiGroups:
332 | - ""
333 | resources:
334 | - secrets
335 | verbs:
336 | - get
337 | - list
338 | - create
339 | - update
340 | - delete
341 | - watch
342 | - apiGroups:
343 | - ""
344 | resources:
345 | - events
346 | verbs:
347 | - create
348 | - patch
349 | - apiGroups:
350 | - ""
351 | resources:
352 | - namespaces
353 | verbs:
354 | - get
355 |
--------------------------------------------------------------------------------
/src/sealed-secrets/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | app.kubernetes.io/version: v0.15.0
5 | catalog.kubestack.com/heritage: kubestack.com/catalog/sealed-secrets
6 | catalog.kubestack.com/variant: base
7 | commonLabels:
8 | app.kubernetes.io/component: controller
9 | app.kubernetes.io/managed-by: kubestack
10 | app.kubernetes.io/name: sealed-secrets
11 | resources:
12 | - controller.yaml
13 |
--------------------------------------------------------------------------------
/src/sealed-secrets/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/sealed-secrets/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/sealed-secrets/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/sealed-secrets/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/sealed-secrets/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/sealed-secrets/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/tektoncd/_updater/metadata.yaml:
--------------------------------------------------------------------------------
1 | url: https://github.com/tektoncd/pipeline.git
2 | ref: main
3 |
--------------------------------------------------------------------------------
/src/tektoncd/_updater/run.sh:
--------------------------------------------------------------------------------
1 | # https://storage.googleapis.com/tekton-releases/previous/v0.4.0/release.yaml
2 |
3 | #!/bin/sh
4 |
5 | set -e
6 | source_path=$1
7 | target_path=$2
8 | version=$3
9 |
10 | curl -Lo $target_path/base/release.yaml https://github.com/tektoncd/pipeline/releases/download/$version/release.yaml
11 |
--------------------------------------------------------------------------------
/src/tektoncd/base/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | commonAnnotations:
4 | app.kubernetes.io/version: v0.23.0
5 | catalog.kubestack.com/heritage: kubestack.com/catalog/tektoncd
6 | catalog.kubestack.com/variant: base
7 | commonLabels:
8 | app.kubernetes.io/component: controller
9 | app.kubernetes.io/managed-by: kubestack
10 | app.kubernetes.io/name: tektoncd
11 | resources:
12 | - release.yaml
13 |
--------------------------------------------------------------------------------
/src/tektoncd/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/tektoncd/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/tektoncd/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/tektoncd/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/tektoncd/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/tektoncd/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/src/test/base/Kustomization:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 | namespace: test
5 |
6 | resources:
7 | - namespace.yaml
8 | - configmap.yaml
9 | - deployment.yaml
10 |
11 | secretGenerator:
12 | - name: test
13 | literals:
14 | - "TEST=TEST"
15 |
--------------------------------------------------------------------------------
/src/test/base/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | creationTimestamp: null
5 | name: test
6 |
--------------------------------------------------------------------------------
/src/test/base/deployment.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | creationTimestamp: null
5 | labels:
6 | app: test
7 | name: test
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: test
13 | strategy: {}
14 | template:
15 | metadata:
16 | creationTimestamp: null
17 | labels:
18 | app: test
19 | spec:
20 | containers:
21 | - image: busybox
22 | name: busybox
23 | command:
24 | - sleep
25 | - "60"
26 | resources: {}
27 | status: {}
28 |
--------------------------------------------------------------------------------
/src/test/base/namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: test
--------------------------------------------------------------------------------
/src/test/configuration.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/configuration.tf
--------------------------------------------------------------------------------
/src/test/data_source.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/data_source.tf
--------------------------------------------------------------------------------
/src/test/default_variant.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | default_variant = "base"
3 | }
4 |
--------------------------------------------------------------------------------
/src/test/main.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/main._tf
--------------------------------------------------------------------------------
/src/test/overlay/Kustomization:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 |
4 | namespace: test-overlay
5 |
6 | resources:
7 | - ../base
8 |
9 | patches:
10 | - path: patch-namespace.yaml
11 | target:
12 | kind: Namespace
13 | name: test
14 | version: v1
15 |
--------------------------------------------------------------------------------
/src/test/overlay/patch-namespace.yaml:
--------------------------------------------------------------------------------
1 | - op: replace
2 | path: /metadata/name
3 | value: test-overlay
4 |
--------------------------------------------------------------------------------
/src/test/variables.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/variables.tf
--------------------------------------------------------------------------------
/src/test/versions.tf:
--------------------------------------------------------------------------------
1 | ../_terraform_module/versions.tf
--------------------------------------------------------------------------------
/test/k3d/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM kubestack/framework:v0.19.1-beta.0-kind
2 |
3 | COPY Pipfile Pipfile.lock /opt/
4 | WORKDIR /opt
5 |
6 | RUN pip install --no-cache-dir pipenv &&\
7 | PIPENV_VENV_IN_PROJECT=true pipenv install
8 |
9 | COPY main.tf.tpl main.py /opt/test/
10 |
11 | ENV PATH=/opt/.venv/bin:$PATH \
12 | KUBECONFIG=/opt/test/.kubeconfig \
13 | KUBECONFIG_PATH=/opt/test/.kubeconfig
14 |
15 | WORKDIR /opt/test
16 | ENTRYPOINT ["python", "main.py"]
17 |
--------------------------------------------------------------------------------
/test/k3d/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | verify_ssl = true
5 |
6 | [dev-packages]
7 |
8 | [packages]
9 | kubernetes = "*"
10 | jinja2 = "*"
11 |
12 | [requires]
13 | python_version = "3"
14 |
--------------------------------------------------------------------------------
/test/k3d/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import logging
4 | import sys
5 | import time
6 |
7 | from os.path import isdir, join
8 | from subprocess import Popen
9 | from tempfile import TemporaryDirectory
10 | from shutil import unpack_archive
11 |
12 | from kubernetes import client, config
13 | from jinja2 import Environment, FileSystemLoader
14 |
15 | DISTDIR = "/_dist"
16 | TIMEOUT = 600 # 10 minutes in seconds
17 |
18 |
19 | def run_cmd(name, path, cmd, timeout):
20 | p = Popen(cmd, cwd=path)
21 | p.wait(timeout)
22 | assert p.returncode == 0
23 |
24 |
25 | def wait_retries(name, timeout):
26 | config.load_kube_config()
27 |
28 | v1 = client.CoreV1Api()
29 |
30 | count = 0
31 | start = time.time()
32 | failed_pods = []
33 |
34 | while True:
35 | # we give up
36 | if (time.time() - start) >= timeout:
37 | break
38 |
39 | failed_pods = []
40 |
41 | ret = v1.list_pod_for_all_namespaces(watch=False)
42 |
43 | for p in ret.items:
44 | metann = f"{p.metadata.namespace}/{p.metadata.name}"
45 |
46 | # continue if there are no conditions yet
47 | if not p.status.conditions:
48 | continue
49 |
50 | is_ready = False
51 | for c in p.status.conditions:
52 | if c.type != "Ready":
53 | continue
54 |
55 | if c.status == "True" or (c.status == "False" and c.reason == "PodCompleted"):
56 | is_ready = True
57 |
58 | if not is_ready:
59 | failed_pods.append(metann)
60 |
61 | # we're done here
62 | if len(failed_pods) == 0:
63 | break
64 |
65 | # we're not done
66 | # sleep a little, then try again
67 | count += 1
68 | time.sleep(min(count * 2, 30))
69 |
70 | # output debug info
71 | if len(failed_pods) > 0:
72 | ret = v1.list_pod_for_all_namespaces(watch=False)
73 | for p in ret.items:
74 | metann = f"{p.metadata.namespace}/{p.metadata.name}"
75 | podstatus = f"{p.status.phase:<11} {metann}"
76 | logging.error(podstatus)
77 |
78 | logging.error(f"timed out waiting for: {failed_pods}")
79 |
80 | assert len(failed_pods) == 0
81 |
82 |
83 | def run_steps(name, path):
84 | steps = {
85 | "init": {"type": "run_cmd",
86 | "path": path,
87 | "cmd": ["terraform", "init"]},
88 | "apply": {"type": "run_cmd",
89 | "path": path,
90 | "cmd": ["terraform",
91 | "apply",
92 | "--auto-approve"]},
93 | "wait": {"type": "wait_retries"},
94 | "destroy": {"type": "run_cmd",
95 | "path": path,
96 | "cmd": ["terraform",
97 | "destroy",
98 | "--auto-approve"]}
99 | }
100 |
101 | for step in steps.values():
102 | if step["type"] == "run_cmd":
103 | run_cmd(name, step["path"], step["cmd"], TIMEOUT)
104 | if step["type"] == "wait_retries":
105 | wait_retries(name, TIMEOUT)
106 |
107 |
108 | if __name__ == '__main__':
109 | if len(sys.argv) < 3:
110 | logging.fatal(f"missing 2 args: name and variant")
111 | sys.exit(1)
112 |
113 | name = sys.argv[1]
114 | variant = sys.argv[2]
115 |
116 | with TemporaryDirectory() as root:
117 | mut = join(root, "mut")
118 | archive = join(DISTDIR, name)
119 | unpack_archive(archive, mut, "zip")
120 |
121 | variant_path = join(mut, variant)
122 | if not isdir(variant_path):
123 | logging.fatal(f"path not found: {variant_path}")
124 | sys.exit(1)
125 |
126 | # write main.tf into root_module
127 | jinja = Environment(loader=FileSystemLoader("."))
128 | template = jinja.get_template('main.tf.tpl')
129 | data = template.render(
130 | {'entry_module': mut, 'variant': variant})
131 |
132 | with open(f'{root}/main.tf', 'w') as f:
133 | f.write(data)
134 | # always include newline at end of file
135 | f.write('\n')
136 |
137 | run_steps(f"{name} - {variant}", root)
138 |
--------------------------------------------------------------------------------
/test/k3d/main.tf.tpl:
--------------------------------------------------------------------------------
1 | module "test" {
2 | source = "{{entry_module}}"
3 |
4 | configuration = {
5 | apps = {
6 | variant = "{{variant}}"
7 | }
8 |
9 | ops = {}
10 |
11 | default = {}
12 | }
13 | }
14 |
--------------------------------------------------------------------------------