nyl 0.0.0__tar.gz → 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. nyl-0.0.2/PKG-INFO +155 -0
  2. nyl-0.0.2/README.md +136 -0
  3. nyl-0.0.2/pyproject.toml +52 -0
  4. nyl-0.0.2/src/nyl/appmanager/__init__.py +3 -0
  5. nyl-0.0.2/src/nyl/appmanager/appmanager.py +150 -0
  6. nyl-0.0.2/src/nyl/appmanager/crd.py +107 -0
  7. nyl-0.0.2/src/nyl/commands/__init__.py +19 -0
  8. nyl-0.0.2/src/nyl/commands/profile.py +30 -0
  9. nyl-0.0.2/src/nyl/commands/secrets.py +31 -0
  10. nyl-0.0.2/src/nyl/commands/template.py +274 -0
  11. nyl-0.0.2/src/nyl/commands/tun.py +122 -0
  12. nyl-0.0.2/src/nyl/packages/__init__.py +3 -0
  13. nyl-0.0.2/src/nyl/packages/metadata.py +7 -0
  14. nyl-0.0.2/src/nyl/packages/reference.py +91 -0
  15. nyl-0.0.2/src/nyl/packages/reference_test.py +12 -0
  16. nyl-0.0.2/src/nyl/packages/templating.py +52 -0
  17. nyl-0.0.2/src/nyl/profiles/__init__.py +124 -0
  18. nyl-0.0.2/src/nyl/profiles/config.py +160 -0
  19. nyl-0.0.2/src/nyl/profiles/kubeconfig.py +138 -0
  20. nyl-0.0.2/src/nyl/profiles/tunnel.py +247 -0
  21. nyl-0.0.2/src/nyl/resources/__init__.py +62 -0
  22. nyl-0.0.2/src/nyl/resources/helmchart.py +61 -0
  23. nyl-0.0.2/src/nyl/resources/package.py +17 -0
  24. nyl-0.0.2/src/nyl/resources/statefulsecret.py +13 -0
  25. nyl-0.0.2/src/nyl/secrets/__init__.py +1 -0
  26. nyl-0.0.2/src/nyl/secrets/config.py +80 -0
  27. nyl-0.0.2/src/nyl/secrets/sops.py +81 -0
  28. nyl-0.0.2/src/nyl/secrets/sops_test.py +69 -0
  29. nyl-0.0.2/src/nyl/tools/kubectl.py +130 -0
  30. nyl-0.0.2/src/nyl/tools/kvstore.py +132 -0
  31. nyl-0.0.2/src/nyl/tools/typer.py +8 -0
  32. nyl-0.0.0/PKG-INFO +0 -17
  33. nyl-0.0.0/README.md +0 -8
  34. nyl-0.0.0/pyproject.toml +0 -22
  35. {nyl-0.0.0 → nyl-0.0.2}/src/nyl/__init__.py +0 -0
  36. {nyl-0.0.0 → nyl-0.0.2}/tests/__init__.py +0 -0
nyl-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.1
2
+ Name: nyl
3
+ Version: 0.0.2
4
+ Summary: Default template for PDM package
5
+ Author-Email: Niklas Rosenstein <rosensteinniklas@gmail.com>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: databind>=4.5.2
9
+ Requires-Dist: pyyaml>=6.0.1
10
+ Requires-Dist: jinja2>=3.1.4
11
+ Requires-Dist: loguru>=0.7.2
12
+ Requires-Dist: kubernetes>=30.1.0
13
+ Requires-Dist: typer>=0.12.3
14
+ Requires-Dist: filelock>=3.15.4
15
+ Requires-Dist: stablehash>=0.2.0
16
+ Requires-Dist: nr-stream>=1.1.5
17
+ Requires-Dist: requests>=2.32.3
18
+ Description-Content-Type: text/markdown
19
+
20
+ # nyl
21
+
22
+ Nyl is a versatile Kubernetes resource management tool that fulfills various functions to enable reusable
23
+ deployment configurations.
24
+
25
+ __Features__
26
+
27
+ * Generate Kubernetes manifests from a simple YAML configuration with templating support.
28
+ * Inject secrets into Kubernetes manifests as time of generation.
29
+ * Bootstrap a cluster and transfer control to ArgoCD or use it to manage a cluster from CI/CD or locally.
30
+ * Connect to a Kubernetes cluster via an SSH tunnel.
31
+
32
+ __Roadmap__
33
+
34
+ * Integrate as an ArgoCD ConfigManagementPlugin.
35
+ * Diffing
36
+ * How to work around fields owned by a different field manager (e.g. MetalLB CRD `conversion..caBundle`) or `Job` resources?
37
+
38
+ ## Concepts
39
+
40
+ ### Packages
41
+
42
+ A package is similar to a Helm chart in that it is a source for Kubernetes resources that can make use of
43
+ templating to conditionally render resources and inject values into them. Resources generated by packages
44
+ may make use of Nyl-specific resource kinds that are only available time of resource generation (see the
45
+ [Templating > Resource Kinds](#resource-kinds) section below).
46
+
47
+ Nyl packages can be checked into a source repository in a DRY form, but can be compiled to a bundle (e.g.
48
+ including other referenced packages or Helm charts) for deployment when needed (e.g. for shipping to an
49
+ air-gapped environment).
50
+
51
+ Packages may have a `nyl-package.yaml` file that defines a schema for the package parameters and additional
52
+ metadata. A package without this file may still accept and use parameters in its templates.
53
+
54
+ ### Applications
55
+
56
+ An application is an instance of one package that is deployed to a Kubernetes cluster and are in turn defined
57
+ also in a Nyl package. Packages instantiated as applications may not produce other applications. Applications
58
+ are usually accompanied by a `nyl-deployment.yaml` file that defines the top-level templating context for the
59
+ package(s), such as the secret store.
60
+
61
+ When deploying a package as an application, the package must not generated resources other than applications,
62
+ as all deployed resources must be owned by an application.
63
+
64
+ ### Deployment
65
+
66
+ A deployment is where things get together: This is the place where you define the applications that should be
67
+ deployed to a Kubernetes cluster, which cluster they are being deployed to, as well as sourcing secrets from
68
+ a secret store. The configuration for a deployment is defined in a `nyl-deployment.yaml` file.
69
+
70
+ ```yaml
71
+ apiVersion: nyl/v1
72
+ kind: Deployment
73
+ spec:
74
+ secretStores:
75
+ default:
76
+ type: Sops
77
+ path: secrets.yaml
78
+ ```
79
+
80
+ __Spec__
81
+
82
+ * `secrets` (array): The secret stores to make available in the templating context of the deployment. Any secrets
83
+ need to be injected from these stores into the application values at templating time.
84
+
85
+ ## Templating
86
+
87
+ [Jinja2]: https://jinja.palletsprojects.com/en/3.0.x/
88
+
89
+ Nyl uses [Jinja2] as a templating engine, and as such is slightly different from Helm.
90
+
91
+ ### Injecting secrets
92
+
93
+ Secrets are only available at the deployment level and need to be propagated further down.
94
+
95
+ ```yaml
96
+ apiVersion: nyl/v1
97
+ kind: Application
98
+ metadata:
99
+ name: my-app
100
+ spec:
101
+ package: ./path/to/package
102
+ values:
103
+ theSecret: {{ Secrets.default.get("my-secret") }}
104
+ ```
105
+
106
+ ### Resource kinds
107
+
108
+ At templating time, Nyl supports special resource kinds that will be expanded to more Kubernetes resources.
109
+
110
+ #### `templating.nyl/v1/HelmChart`
111
+
112
+ This resource can be used to instantiate Helm charts as part of a package.
113
+
114
+ ```yaml
115
+ apiVersion: templating.nyl/v1
116
+ kind: HelmChart
117
+ spec:
118
+ repository: https://kubernetes.github.io/ingress-nginx
119
+ chart: ingress-nginx
120
+ version: 4.10.1
121
+ releaseName: ingress-nginx
122
+ releaseNamespace: ingress-nginx
123
+ values: {}
124
+ ```
125
+
126
+ __Spec__
127
+
128
+ * `repository` (string): The Helm repository URL, OCI registry URL (sans the chart name), a local path or a
129
+ Git repository clone URL.
130
+ * `chart` (string): The name of the chart in the repository, the chart name to append to the OCI registry URL,
131
+ the name of the chart in the local path or the path to the chart in the Git repository.
132
+ * `version` (string): The version of the chart to use. Only relevant for Helm/OCI repositories.
133
+ * `releaseName` (string): The name of the Helm release.
134
+ * `releaseNamespace` (string): The namespace to install the Helm release into. If any resources generated by the
135
+ chart have no `metadata.namespace` field, it will be set to this value.
136
+ * `values` (object): The values to pass to the Helm chart.
137
+
138
+ #### `templating.nyl/v1/Package`
139
+
140
+ Use this resource to instantiate another package.
141
+
142
+ ```yaml
143
+ apiVersion: templating.nyl/v1
144
+ kind: Package
145
+ spec:
146
+ package: ./path/to/package
147
+ values: {}
148
+ ```
149
+
150
+ __Spec__
151
+
152
+ * `package` (string): The path to the package to instantiate. Must be prefixed with `./` to be resolved relative
153
+ to the package that references it. Otherwise, it will be resolved in a search path that is defined in the
154
+ `nyl-deployment.yaml` file.
155
+ * `values` (object): The values to pass to the package.
nyl-0.0.2/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # nyl
2
+
3
+ Nyl is a versatile Kubernetes resource management tool that fulfills various functions to enable reusable
4
+ deployment configurations.
5
+
6
+ __Features__
7
+
8
+ * Generate Kubernetes manifests from a simple YAML configuration with templating support.
9
+ * Inject secrets into Kubernetes manifests as time of generation.
10
+ * Bootstrap a cluster and transfer control to ArgoCD or use it to manage a cluster from CI/CD or locally.
11
+ * Connect to a Kubernetes cluster via an SSH tunnel.
12
+
13
+ __Roadmap__
14
+
15
+ * Integrate as an ArgoCD ConfigManagementPlugin.
16
+ * Diffing
17
+ * How to work around fields owned by a different field manager (e.g. MetalLB CRD `conversion..caBundle`) or `Job` resources?
18
+
19
+ ## Concepts
20
+
21
+ ### Packages
22
+
23
+ A package is similar to a Helm chart in that it is a source for Kubernetes resources that can make use of
24
+ templating to conditionally render resources and inject values into them. Resources generated by packages
25
+ may make use of Nyl-specific resource kinds that are only available time of resource generation (see the
26
+ [Templating > Resource Kinds](#resource-kinds) section below).
27
+
28
+ Nyl packages can be checked into a source repository in a DRY form, but can be compiled to a bundle (e.g.
29
+ including other referenced packages or Helm charts) for deployment when needed (e.g. for shipping to an
30
+ air-gapped environment).
31
+
32
+ Packages may have a `nyl-package.yaml` file that defines a schema for the package parameters and additional
33
+ metadata. A package without this file may still accept and use parameters in its templates.
34
+
35
+ ### Applications
36
+
37
+ An application is an instance of one package that is deployed to a Kubernetes cluster and are in turn defined
38
+ also in a Nyl package. Packages instantiated as applications may not produce other applications. Applications
39
+ are usually accompanied by a `nyl-deployment.yaml` file that defines the top-level templating context for the
40
+ package(s), such as the secret store.
41
+
42
+ When deploying a package as an application, the package must not generated resources other than applications,
43
+ as all deployed resources must be owned by an application.
44
+
45
+ ### Deployment
46
+
47
+ A deployment is where things get together: This is the place where you define the applications that should be
48
+ deployed to a Kubernetes cluster, which cluster they are being deployed to, as well as sourcing secrets from
49
+ a secret store. The configuration for a deployment is defined in a `nyl-deployment.yaml` file.
50
+
51
+ ```yaml
52
+ apiVersion: nyl/v1
53
+ kind: Deployment
54
+ spec:
55
+ secretStores:
56
+ default:
57
+ type: Sops
58
+ path: secrets.yaml
59
+ ```
60
+
61
+ __Spec__
62
+
63
+ * `secrets` (array): The secret stores to make available in the templating context of the deployment. Any secrets
64
+ need to be injected from these stores into the application values at templating time.
65
+
66
+ ## Templating
67
+
68
+ [Jinja2]: https://jinja.palletsprojects.com/en/3.0.x/
69
+
70
+ Nyl uses [Jinja2] as a templating engine, and as such is slightly different from Helm.
71
+
72
+ ### Injecting secrets
73
+
74
+ Secrets are only available at the deployment level and need to be propagated further down.
75
+
76
+ ```yaml
77
+ apiVersion: nyl/v1
78
+ kind: Application
79
+ metadata:
80
+ name: my-app
81
+ spec:
82
+ package: ./path/to/package
83
+ values:
84
+ theSecret: {{ Secrets.default.get("my-secret") }}
85
+ ```
86
+
87
+ ### Resource kinds
88
+
89
+ At templating time, Nyl supports special resource kinds that will be expanded to more Kubernetes resources.
90
+
91
+ #### `templating.nyl/v1/HelmChart`
92
+
93
+ This resource can be used to instantiate Helm charts as part of a package.
94
+
95
+ ```yaml
96
+ apiVersion: templating.nyl/v1
97
+ kind: HelmChart
98
+ spec:
99
+ repository: https://kubernetes.github.io/ingress-nginx
100
+ chart: ingress-nginx
101
+ version: 4.10.1
102
+ releaseName: ingress-nginx
103
+ releaseNamespace: ingress-nginx
104
+ values: {}
105
+ ```
106
+
107
+ __Spec__
108
+
109
+ * `repository` (string): The Helm repository URL, OCI registry URL (sans the chart name), a local path or a
110
+ Git repository clone URL.
111
+ * `chart` (string): The name of the chart in the repository, the chart name to append to the OCI registry URL,
112
+ the name of the chart in the local path or the path to the chart in the Git repository.
113
+ * `version` (string): The version of the chart to use. Only relevant for Helm/OCI repositories.
114
+ * `releaseName` (string): The name of the Helm release.
115
+ * `releaseNamespace` (string): The namespace to install the Helm release into. If any resources generated by the
116
+ chart have no `metadata.namespace` field, it will be set to this value.
117
+ * `values` (object): The values to pass to the Helm chart.
118
+
119
+ #### `templating.nyl/v1/Package`
120
+
121
+ Use this resource to instantiate another package.
122
+
123
+ ```yaml
124
+ apiVersion: templating.nyl/v1
125
+ kind: Package
126
+ spec:
127
+ package: ./path/to/package
128
+ values: {}
129
+ ```
130
+
131
+ __Spec__
132
+
133
+ * `package` (string): The path to the package to instantiate. Must be prefixed with `./` to be resolved relative
134
+ to the package that references it. Otherwise, it will be resolved in a search path that is defined in the
135
+ `nyl-deployment.yaml` file.
136
+ * `values` (object): The values to pass to the package.
@@ -0,0 +1,52 @@
1
+ [project]
2
+ name = "nyl"
3
+ version = "0.0.2"
4
+ description = "Default template for PDM package"
5
+ authors = [
6
+ { name = "Niklas Rosenstein", email = "rosensteinniklas@gmail.com" },
7
+ ]
8
+ dependencies = [
9
+ "databind>=4.5.2",
10
+ "pyyaml>=6.0.1",
11
+ "jinja2>=3.1.4",
12
+ "loguru>=0.7.2",
13
+ "kubernetes>=30.1.0",
14
+ "typer>=0.12.3",
15
+ "filelock>=3.15.4",
16
+ "stablehash>=0.2.0",
17
+ "nr-stream>=1.1.5",
18
+ "requests>=2.32.3",
19
+ ]
20
+ requires-python = ">=3.10"
21
+ readme = "README.md"
22
+
23
+ [project.license]
24
+ text = "MIT"
25
+
26
+ [project.scripts]
27
+ nyl = "nyl.commands:app"
28
+
29
+ [build-system]
30
+ requires = [
31
+ "pdm-backend",
32
+ ]
33
+ build-backend = "pdm.backend"
34
+
35
+ [tool.pdm]
36
+ distribution = true
37
+
38
+ [tool.pdm.dev-dependencies]
39
+ dev = [
40
+ "ruff>=0.4.8",
41
+ "mypy>=1.10.0",
42
+ "types-pyyaml>=6.0.12.20240311",
43
+ "mkdocs>=1.6.0",
44
+ "mkdocs-material>=9.5.28",
45
+ "mkdocstrings[python]>=0.25.1",
46
+ "pytest>=8.2.2",
47
+ "kubernetes-stubs>=22.6.0.post1",
48
+ "types-requests>=2.32.0.20240712",
49
+ ]
50
+
51
+ [tool.ruff]
52
+ line-length = 120
@@ -0,0 +1,3 @@
1
+ from .appmanager import Application, ApplicationManager
2
+
3
+ __all__ = ["Application", "ApplicationManager"]
@@ -0,0 +1,150 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+ from kubernetes.client import CustomObjectsApi
4
+ from kubernetes.client.api_client import ApiClient
5
+ from . import crd
6
+ from nyl.tools.kubectl import Kubectl
7
+
8
+
9
+ @dataclass
10
+ class Application:
11
+ """
12
+ Represents an application deployed in the system.
13
+ """
14
+
15
+ name: str
16
+ contains_group_kinds: list[str]
17
+
18
+
19
+ class ApplicationManager:
20
+ """
21
+ Manage applications deployed in the system.
22
+ """
23
+
24
+ def __init__(self, client: ApiClient, kubectl: Kubectl) -> None:
25
+ """
26
+ Args:
27
+ client: Kubernetes API client.
28
+ kubectl: A corresponding `kubectl` client to interact with the cluster. We re-use kubectl's applset
29
+ implementation to create and manage applications in the system.
30
+ """
31
+
32
+ self._client = client
33
+ self._kubectl = kubectl
34
+ self._kubectl_version_cached: str | None = None
35
+
36
+ @property
37
+ def _kubectl_version(self) -> str:
38
+ """
39
+ Get the version of the kubectl client.
40
+ """
41
+
42
+ if self._kubectl_version_cached is None:
43
+ self._kubectl_version_cached = self._kubectl.version()["gitVersion"]
44
+ return self._kubectl_version_cached
45
+
46
+ def _get_applyset_ref(self, name: str) -> str:
47
+ """
48
+ Get the reference to the ApplySet resource for the application.
49
+ """
50
+
51
+ return f"application.{crd.GROUP}/{name}"
52
+
53
+ def list_applications(self) -> Application:
54
+ """
55
+ List applications deployed in the system.
56
+ """
57
+
58
+ api = CustomObjectsApi(self._client)
59
+ objects = api.list_cluster_custom_object( # noqa
60
+ group=crd.GROUP,
61
+ version=crd.VERSION,
62
+ plural=crd.PLURAL,
63
+ )
64
+
65
+ # TODO
66
+ return # type: ignore[return-value]
67
+
68
+ def get_application(self, name: str) -> Application:
69
+ """
70
+ Get an application deployed in the system.
71
+ """
72
+
73
+ api = CustomObjectsApi(self._client)
74
+ obj = api.get_cluster_custom_object(group=crd.GROUP, version=crd.VERSION, plural=crd.PLURAL, name=name)
75
+ print(obj)
76
+ # TODO
77
+ return # type: ignore[return-value]
78
+
79
+ def delete_application(self, name: str, cascade: bool = True) -> None:
80
+ """
81
+ Delete an application from the system.
82
+
83
+ Args:
84
+ name: The name of the application to delete.
85
+ cascade: If True, delete all resources associated with the application.
86
+ """
87
+
88
+ if cascade:
89
+ self._kubectl.apply(
90
+ manifests=[],
91
+ force_conflicts=True,
92
+ server_side=True,
93
+ applyset=self._get_applyset_ref(name),
94
+ )
95
+
96
+ api = CustomObjectsApi(self._client)
97
+ api.delete_cluster_custom_object(group=crd.GROUP, version=crd.VERSION, plural=crd.PLURAL, name=name)
98
+
99
+ # def upsert_application(self, app: Application) -> None:
100
+ # """
101
+ # Create or update an application in the system.
102
+ # """
103
+
104
+ # api = CustomObjectsApi(self._client)
105
+ # api.create_cluster_custom_object(
106
+ # group=crd.GROUP,
107
+ # version=crd.VERSION,
108
+ # plural=crd.PLURAL,
109
+ # body=crd.generate_application_resource(
110
+ # app.name,
111
+ # contains_resources=app.contains_group_kinds,
112
+ # kubectl_version=self._kubectl_version,
113
+ # ),
114
+ # )
115
+
116
+ def update_application(self, name: str, manifests: list[dict[str, Any]]) -> None:
117
+ """
118
+ Update an application in the system or create it.
119
+
120
+ Args:
121
+ name: The name of the application to update.
122
+ manifests: The updated manifests of the application.
123
+ """
124
+
125
+ resource_kinds = {crd.get_canonical_resource_kind_name(m["apiVersion"], m["kind"]) for m in manifests}
126
+
127
+ # Ensure that the application object exists.
128
+ # TODO Check if it exists instead of always calling the create endpoint?
129
+ # TODO Do we maybe need to update the resource kinds only after the apply?
130
+ # Somehow kubectl must understand the previous resource kinds that were involved in the
131
+ # application prior to the update.
132
+
133
+ api = CustomObjectsApi(self._client)
134
+ api.create_cluster_custom_object(
135
+ group=crd.GROUP,
136
+ version=crd.VERSION,
137
+ plural=crd.PLURAL,
138
+ body=crd.generate_application_resource(
139
+ name,
140
+ contains_resources=resource_kinds,
141
+ kubectl_version=self._kubectl_version,
142
+ ),
143
+ )
144
+
145
+ self._kubectl.apply(
146
+ manifests=manifests,
147
+ force_conflicts=True,
148
+ server_side=True,
149
+ applyset=self._get_applyset_ref(name),
150
+ )
@@ -0,0 +1,107 @@
1
+ """
2
+ This module implements a Kubernetes CRD that represents Nyl's own understanding of an application, which also
3
+ acts as a Kubernetes ApplySet. To read more about ApplySets, check out
4
+
5
+ https://kubernetes.io/blog/2023/05/09/introducing-kubectl-applyset-pruning/.
6
+ """
7
+
8
+ import base64
9
+ import hashlib
10
+ from typing import Any, Collection
11
+
12
+
13
+ GROUP = "nyl.io"
14
+ KIND = "Application"
15
+ PLURAL = "applications"
16
+ VERSION = "v1"
17
+
18
+ # note: the only purpose of this CRD is to create resources that act as a parent for ApplySets.
19
+ # check out this GitHub issue, and specifically this comment for more information:
20
+ # https://github.com/kubernetes/enhancements/issues/3659#issuecomment-1753091733
21
+ APPLICATION_CRD = {
22
+ "apiVersion": "apiextensions.k8s.io/v1",
23
+ "kind": "CustomResourceDefinition",
24
+ "metadata": {
25
+ "name": f"{PLURAL}.{GROUP}",
26
+ "labels": {
27
+ "applyset.kubernetes.io/is-parent-type": "true",
28
+ },
29
+ },
30
+ "spec": {
31
+ "group": GROUP,
32
+ "names": {
33
+ "kind": KIND,
34
+ "plural": PLURAL,
35
+ },
36
+ "scope": "Cluster",
37
+ "versions": [
38
+ {
39
+ "name": VERSION,
40
+ "served": True,
41
+ "storage": True,
42
+ "schema": {
43
+ "openAPIV3Schema": {
44
+ "type": "object",
45
+ }
46
+ },
47
+ }
48
+ ],
49
+ },
50
+ }
51
+
52
+
53
+ def calculate_applyset_id(*, name: str, namespace: str = "", group: str) -> str:
54
+ """
55
+ Calculate the ID of a Kubernetes ApplySet with the specified name.
56
+ """
57
+
58
+ # reference: https://kubernetes.io/docs/reference/labels-annotations-taints/#applyset-kubernetes-io-id
59
+ hash = hashlib.sha256(f"{name}.{namespace}.ApplySet.{group}".encode()).digest()
60
+ uid = base64.b64encode(hash).decode().rstrip("=").replace("/", "_").replace("+", "-")
61
+ return f"applyset-{uid}-v1"
62
+
63
+
64
+ def get_canonical_resource_kind_name(api_version: str, kind: str) -> str:
65
+ """
66
+ Given the apiVersion and kind of a Kubernetes resource, return the canonical name of the resource. This name can
67
+ be used to identify the resource in an ApplySet's `applyset.kubernetes.io/contains-group-kinds` annotation.
68
+
69
+ Args:
70
+ api_version: The apiVersion of the resource.
71
+ kind: The kind of the resource.
72
+ """
73
+
74
+ return (f"{kind}." + (api_version.split("/")[0] if "/" in api_version else "")).rstrip(".")
75
+
76
+
77
+ def generate_application_resource(
78
+ name: str,
79
+ contains_resources: Collection[str],
80
+ kubectl_version: str,
81
+ ) -> dict[str, Any]:
82
+ """
83
+ Generate a Kubernetes resource that represents an application in Nyl's system.
84
+
85
+ Args:
86
+ name: The name of the application.
87
+ contains_resources: A list of Kubernetes resources names that are contained in this application. This is a
88
+ required information for Kubernetes ApplySets. You can use `get_canonical_resource_kind_name` to get the
89
+ names of the resource kinds.
90
+ kubectl_version: The version of kubectl that was used to create this resource. This is a required information
91
+ for the `applyset.kubernetes.io/tooling` annotation in the resource if `kubectl` is used to apply it.
92
+ """
93
+
94
+ return {
95
+ "apiVersion": f"{GROUP}/{VERSION}",
96
+ "kind": KIND,
97
+ "metadata": {
98
+ "name": name,
99
+ "annotations": {
100
+ "applyset.kubernetes.io/tooling": f"kubectl/{kubectl_version}",
101
+ "applyset.kubernetes.io/contains-group-kinds": ",".join(sorted(contains_resources)),
102
+ },
103
+ "labels": {
104
+ "applyset.kubernetes.io/id": calculate_applyset_id(name=name, group=GROUP),
105
+ },
106
+ },
107
+ }
@@ -0,0 +1,19 @@
1
+ """
2
+ Nyl is a flexible configuration management tool for Kubernetes resources that can be used to generate and deploy
3
+ applications directly or integrate as an ArgoCD ConfigManagementPlugin.
4
+ """
5
+
6
+ from nyl.tools.typer import new_typer
7
+
8
+
9
+ app = new_typer(help=__doc__)
10
+
11
+
12
+ from . import profile # noqa: E402
13
+ from . import secrets # noqa: E402
14
+ from . import template # noqa: F401,E402
15
+ from . import tun # noqa: E402
16
+
17
+ app.add_typer(profile.app)
18
+ app.add_typer(secrets.app)
19
+ app.add_typer(tun.app)
@@ -0,0 +1,30 @@
1
+ """
2
+ Interact with your Nyl profile configuration.
3
+ """
4
+
5
+ import shlex
6
+
7
+ from typer import Argument
8
+ from nyl.profiles import ProfileManager
9
+ from nyl.tools.typer import new_typer
10
+
11
+
12
+ app = new_typer(name="profile", help=__doc__)
13
+
14
+
15
+ @app.command()
16
+ def activate(profile_name: str = Argument("default", envvar="NYL_PROFILE")) -> None:
17
+ """
18
+ Activate a Nyl profile.
19
+
20
+ Evaluate the stdout of this command to export the KUBECONFIG into your environment.
21
+ """
22
+
23
+ with ProfileManager.load() as manager:
24
+ profile = manager.activate_profile(profile_name)
25
+
26
+ # For standard tooling, like kubectl.
27
+ print(f"export KUBECONFIG={shlex.quote(str(profile.kubeconfig.absolute()))}")
28
+
29
+ # Used by Terraform providers.
30
+ print(f"export KUBE_CONFIG_PATH={shlex.quote(str(profile.kubeconfig.absolute()))}")
@@ -0,0 +1,31 @@
1
+ """
2
+ Interact with the secrets providers configured in `nyl-secrets.yaml`.
3
+ """
4
+
5
+ import json
6
+ from nyl.secrets.config import SecretsConfig
7
+ from nyl.tools.typer import new_typer
8
+
9
+
10
+ app = new_typer(name="secrets", help=__doc__)
11
+
12
+
13
+ @app.command()
14
+ def list() -> None:
15
+ """
16
+ List the keys for all secrets in the provider.
17
+ """
18
+
19
+ secrets = SecretsConfig.load(SecretsConfig.find_config_file())
20
+ for key in secrets.provider.keys():
21
+ print(key)
22
+
23
+
24
+ @app.command()
25
+ def get(key: str, pretty: bool = False) -> None:
26
+ """
27
+ Get the value of a secret as JSON.
28
+ """
29
+
30
+ secrets = SecretsConfig.load(SecretsConfig.find_config_file())
31
+ print(json.dumps(secrets.provider.get(key), indent=4 if pretty else None))