diff --git a/konfig/LICENSE b/konfig/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/konfig/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/konfig/README-zh.md b/konfig/README-zh.md new file mode 100644 index 00000000..55b7e399 --- /dev/null +++ b/konfig/README-zh.md @@ -0,0 +1,56 @@ +# Konfig + +[英语](README.md) | [中文](README-zh.md) + +Konfig 是 KCL 配置中基础设施配置的存储库。Konfig 提供给用户开箱即用、高度抽象的配置界面,模型库最初朴素的出发点就是改善 YAML 用户的效率和体验,我们希望通过将代码更繁杂的模型抽象封装到统一的模型中,从而简化用户侧配置代码的编写。当然您也可以使用 kpm 工具将 Konfig 代码作为依赖集成到您的配置代码中。 + +更多细节可参考:[《模型概览》](https://kcl-lang.io/docs/user_docs/guides/working-with-konfig/overview) + +## 目录结构概览 + +配置大库整体结构如下: + +```bash +. +├── LICENSE +├── Makefile +├── README-zh.md +├── README.md +├── examples # konfig examples +├── kcl.mod # konfig package metadata file +├── kcl.mod.lock # konfig package metadata lock file +└── models + ├── commons # Common models + ├── kube # Cloud-native resource core models + │ ├── backend # Back-end models + │ ├── frontend # Front-end models + │ │ ├── common # Common front-end models + │ │ ├── configmap # ConfigMap + │ │ ├── container # Container + │ │ ├── ingress # Ingress + │ │ ├── resource # Resource + │ │ ├── secret # Secret + │ │ ├── service # Service + │ │ ├── sidecar # Sidecar + │ │ ├── strategy # strategy + │ │ ├── volume # Volume + │ │ └── server.k # The `Server` model + │ ├── metadata # Kubernetes metadata + │ ├── mixins # Mixin + │ ├── render # Front-to-back-end renderers. + │ ├── templates # Data template + │ └── utils + └── metadata # Common metadata +``` + +## 前置条件 + +安装 [kpm](https://kcl-lang.io/docs/user_docs/guides/package-management/installation) + +## 快速开始 + +参考[这里](https://kcl-lang.io/docs/user_docs/guides/working-with-konfig/guide) + +## License + +Apache License Version 2.0 diff --git a/konfig/README.md b/konfig/README.md new file mode 100644 index 00000000..85d7f086 --- /dev/null +++ b/konfig/README.md @@ -0,0 +1,55 @@ +# Konfig + +Konfig is the repository of the infra configuration in KCL. + +Konfig provides users with an out-of-the-box, highly abstract configuration interface. The original starting point of the model library is to improve the efficiency and experience of YAML users. We hope to simplify the writing of user-side configuration code by abstracting and encapsulating the model with more complex code into a unified model. + +For more details, please refer to: [Model Overview](https://kcl-lang.io/docs/user_docs/guides/working-with-konfig/overview) + +## Directory Structure + +The overall structure of the configuration library is as follows: + +```bash +. +├── LICENSE +├── README-zh.md +├── README.md +├── examples # konfig examples +├── kcl.mod # konfig package metadata file +├── kcl.mod.lock # konfig package metadata lock file +└── models + ├── commons # Common models + ├── kube # Cloud-native resource core models + │ ├── backend # Back-end models + │ ├── frontend # Front-end models + │ │ ├── common # Common front-end models + │ │ ├── configmap # ConfigMap + │ │ ├── container # Container + │ │ ├── ingress # Ingress + │ │ ├── resource # Resource + │ │ ├── secret # Secret + │ │ ├── service # Service + │ │ ├── sidecar # Sidecar + │ │ ├── strategy # strategy + │ │ ├── volume # Volume + │ │ └── server.k # The `Server` model + │ ├── metadata # Kubernetes metadata + │ ├── mixins # Mixin + │ ├── render # Front-to-back-end renderers. + │ ├── templates # Data template + │ └── utils + └── metadata # Common metadata +``` + +## Prerequisites + +Install [kpm](https://kcl-lang.io/docs/user_docs/guides/package-management/installation) + +## Quick Start + +See [here](https://kcl-lang.io/docs/user_docs/guides/working-with-konfig/guide) + +## License + +Apache License Version 2.0 diff --git a/konfig/docs/konfig.md b/konfig/docs/konfig.md new file mode 100644 index 00000000..f68980c5 --- /dev/null +++ b/konfig/docs/konfig.md @@ -0,0 +1,1315 @@ +# konfig + +## Index + +- models + - commons + - [Provider](#provider) + - [RESOURCE](#resource) + - [ResourceBuilder](#resourcebuilder) + - kube + - backend + - [JobBackend](#jobbackend) + - [ServerBackend](#serverbackend) + - frontend + - [Job](#job) + - [Server](#server) + - common + - [Metadata](#metadata) + - configmap + - [ConfigMap](#configmap) + - container + - [Main](#main) + - env + - [Env](#env) + - [EnvFromSource](#envfromsource) + - [EnvValueFrom](#envvaluefrom) + - [ObjectFieldSelector](#objectfieldselector) + - [ObjectKeySelector](#objectkeyselector) + - [ResourceFieldSelector](#resourcefieldselector) + - lifecycle + - [Lifecycle](#lifecycle) + - port + - [ContainerPort](#containerport) + - probe + - [Exec](#exec) + - [Http](#http) + - [Probe](#probe) + - [Tcp](#tcp) + - ingress + - [Ingress](#ingress) + - rbac + - [ClusterRole](#clusterrole) + - [ClusterRoleBinding](#clusterrolebinding) + - [Role](#role) + - [RoleBinding](#rolebinding) + - resource + - [Resource](#resource) + - [ResourceRequirements](#resourcerequirements) + - secret + - [Secret](#secret) + - service + - [Service](#service) + - serviceaccount + - [ServiceAccount](#serviceaccount) + - sidecar + - [Sidecar](#sidecar) + - [SimpleSidecar](#simplesidecar) + - storage + - [DBAttr](#dbattr) + - [DataBase](#database) + - [ObjectStorage](#objectstorage) + - [StorageAttr](#storageattr) + - strategy + - [SchedulingStrategy](#schedulingstrategy) + - volume + - [CSI](#csi) + - [ConfigMap](#configmap) + - [DownwardAPI](#downwardapi) + - [EmptyDir](#emptydir) + - [FlexVolume](#flexvolume) + - [HostPath](#hostpath) + - [Mount](#mount) + - [Secret](#secret) + - [Volume](#volume) + - mixins + - [ConfigMapMixin](#configmapmixin) + - [IngressMixin](#ingressmixin) + - [MetadataMixin](#metadatamixin) + - [NamespaceMixin](#namespacemixin) + - [SecretMixin](#secretmixin) + - [ServiceAccountMixin](#serviceaccountmixin) + - [ServiceMixin](#servicemixin) + - protocol + - [ServerProtocol](#serverprotocol) + - resource + - [ResourceMapping](#resourcemapping) + - utils + - [ApplicationBuilder](#applicationbuilder) + - [Str2ResourceRequirements](#str2resourcerequirements) + +## Schemas + +### Provider + +Provider + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**host** `required`|str||| +|**name** `required`|str||| +|**namespace** `required`|str||| +|**version** `required`|str||| +### RESOURCE + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**attributes**|any||| +|**dependsOn**|[str]||| +|**extensions**|{str:}||| +|**id**|str||| +|**type** `required`|str||| +### ResourceBuilder + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**name** `required`|str||| +|**provider** `required`|[Provider](#provider)||| +|**providerAttr** `required`|any||| +|**providerDependsOn**|[str]||| +|**providerMeta**|{str:}||| +|**result** `required`|any||_resource| +|**type** `required`|str||| +### JobBackend + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**app** `required`|[ApplicationBuilder](#applicationbuilder)||utils.ApplicationBuilder {}| +|**config** `required`|[Job](#job)||inputConfig| +|**initContainers**|[{str:}]||| +|**jobAttrs** `required`|{str:}||{ + metadata = utils.MetadataBuilder(config) | {name = jobName} + spec = { + activeDeadlineSeconds = config.activeDeadlineSeconds + backoffLimit = config.backoffLimit + completionMode = config.completionMode + completions = config.completions + manualSelector = config.manualSelector + parallelism = config.parallelism + suspend = config.suspend + ttlSecondsAfterFinished = config.ttlSecondsAfterFinished + selector: {matchLabels = app.selector | config.selector} + template = { + metadata = { + labels = app.labels + **config.podMetadata + } + spec = { + containers = [ + mainContainer + *sidecarContainers + ] + initContainers = initContainers + restartPolicy = config.restartPolicy + if config.volumes: + volumes = [(lambda volume { + volumeType = typeof(volume.volumeSource) + assert volumeType in VOLUME_SOURCE_TYPE_MAPPING, "Invalid frontend volume type, please check VOLUME_SOURCE_TYPE_MAPPING" + kubeVolumeType = VOLUME_SOURCE_TYPE_MAPPING[volumeType] + { + name = volume.name + if typeof(volume.volumeSource) == "EmptyDir" and volume.volumeSource.medium == "": + "${kubeVolumeType}" = {} + else: + "${kubeVolumeType}" = volume.volumeSource + } + + })(volume) for volume in config.volumes if volume.volumeSource] + + if config.serviceAccount: + serviceAccountName = config.serviceAccount.name + + } + } + } +}| +|**jobName** `required`|str||"{}-{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower()| +|**kubernetes** `required`|[ResourceMapping](#resourcemapping)||{"${typeof(_jobInstance)}" = [_jobInstance]}| +|**mainContainer** `required`|{str:}||| +|**mainContainerDict** `required`|{str:}||| +|**sidecarContainers**|[{str:}]||| +### ServerBackend + +ServerBackend converts the user-written front-end model `Server` into a collection of k8s resources and places the resource collection into the `k8s` attribute. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**_applicationLabel** `required`|{str:str}||{"app.k8s.io/component": workloadName}| +|**_workloadInstance**| | ||| +|**app** `required`|[ApplicationBuilder](#applicationbuilder)||utils.ApplicationBuilder {}| +|**config** `required`|[Server](#server)||inputConfig| +|**initContainers**|[{str:}]||| +|**kubernetes** `required`|[ResourceMapping](#resourcemapping)||{ + if _workloadInstance: + "${typeof(_workloadInstance)}" = [_workloadInstance] + + if _headlessServiceInstance: + "${typeof(_headlessServiceInstance)}" = [_headlessServiceInstance] + +}| +|**mainContainer** `required`|{str:}||| +|**provider**|[]||| +|**sidecarContainers**|[{str:}]||| +|**workloadAttributes** `required`|{str:}||{ + metadata = utils.MetadataBuilder(config) | {name = workloadName} + spec = { + replicas = config.replicas + if config.useBuiltInSelector: + selector: {matchLabels: app.selector | config.selector | _applicationLabel} + else: + selector: {matchLabels: config.selector} + template = { + metadata = { + if config.useBuiltInLabels: + labels = app.labels | _applicationLabel + + **config.podMetadata + } + spec = { + containers = [mainContainer] + (sidecarContainers or []) + initContainers = initContainers + if config.volumes: + volumes = [(lambda volume { + """Convert frontend volume to k8s Volume.""" + volumeType = typeof(volume.volumeSource) + assert volumeType in VOLUME_SOURCE_TYPE_MAPPING, "Invalid frontend volume type, please check VOLUME_SOURCE_TYPE_MAPPING" + kubeVolumeType = VOLUME_SOURCE_TYPE_MAPPING[volumeType] + { + name = volume.name + if typeof(volume.volumeSource) == "EmptyDir" and volume.volumeSource.medium == "": + "${kubeVolumeType}" = {} + else: + "${kubeVolumeType}" = volume.volumeSource + } + + })(volume) for volume in config.volumes if volume.volumeSource] + + if config.serviceAccount: + serviceAccountName = config.serviceAccount.name + + } + } + } +}| +|**workloadName** `required`|str||config.name or "{}{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower()| +### Job + +Job is the common user interface for one-time jobs, which is defined by Kubernetes Job. Job supports reliable parallel execution of Pods. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**activeDeadlineSeconds**|int|Specifies the duration in seconds relative to the startTime that the job may be active
before the system tries to terminate it; value must be positive integer|| +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**backoffLimit**|int|Specifies the number of retries before marking this job failed. Defaults to 6|6| +|**completionMode**|"NonIndexed" | "Indexed"|CompletionMode specifies how Pod completions are tracked. It can be `NonIndexed` (default) or `Indexed`.|"NonIndexed"| +|**completions**|int|Specifies the desired number of successfully finished pods the job should be run with.
More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/|| +|**configMaps**|[[ConfigMap](#configmap)]|ConfigMaps is a list of ConfigMap which holds configuration data for server to consume.|| +|**image** `required`|str|Container image name. More info: https://kubernetes.io/docs/concepts/containers/images|option("image")| +|**initContainers**|[[Sidecar](#sidecar)]|InitContainers describes the list of sidecar container configuration that is expected to be run on the host.|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to organize and categorize (scope and select) objects.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**mainContainer** `required`|[Main](#main)|MainContainer describes the main container configuration that is expected to be run on the host.|| +|**manualSelector**|bool|manualSelector controls generation of pod labels and pod selectors.
More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector|| +|**needNamespace**|bool|NeedNamespace mark server is namespace scoped or not.|True| +|**parallelism**|int|Specifies the maximum desired number of pods the job should run at any given time.
More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/|| +|**podMetadata**|any|PodMetadata is metadata that all persisted resources must have, which includes all objects users must create.|| +|**restartPolicy**|"Never" | "OnFailure"|Restart policy for all containers within the pod. One of Always, OnFailure, Never.
Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy|"Never"| +|**schedulingStrategy**|[SchedulingStrategy](#schedulingstrategy)|SchedulingStrategy represents scheduling strategy.|strategy.SchedulingStrategy {}| +|**selector**|{str:str}|A label query over pods that should match the pod count.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors|| +|**serviceAccount**|[ServiceAccount](#serviceaccount)|ServiceAccount is used to run this pod.|| +|**sidecarContainers**|[[Sidecar](#sidecar)]|SidecarContainers describes the list of sidecar container configuration that is expected to be run on the host.|| +|**suspend**|bool|Suspend specifies whether the Job controller should create Pods or not.|| +|**ttlSecondsAfterFinished**|int|ttlSecondsAfterFinished limits the lifetime of a Job that has finished execution (either Complete or Failed).|| +|**volumes**|[[Volume](#volume)]|Volumes represents a named volume and corresponding mounts in containers.|| +#### Examples + +``` +import models.kube.frontend + +jobConfiguration: frontend.Job { + # main container + mainContainer = container.Main { + name = "pi" + command = ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + } + image = "perl" +} +``` + +### Server + +Server is abstaction of Deployment and StatefulSet. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**configMaps**|[[ConfigMap](#configmap)]|ConfigMaps is a list of ConfigMap which holds configuration data for server to consume.|| +|**database**|[DataBase](#database)||| +|**enableMonitoring**|bool|EnableMonitoring mark server is enable monitor or not.|False| +|**image** `required`|str|Container image name.
More info: https://kubernetes.io/docs/concepts/containers/images|option("image")| +|**ingresses**|[[Ingress](#ingress)]|Ingresses is a list of Ingress which is collection of rules that allow inbound connections to reach the endpoints defined by a backend.|| +|**initContainers**|[[Sidecar](#sidecar)]|InitContainers describes the list of sidecar container configuration that is expected to be run on the host.|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to organize and categorize (scope and select) objects.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**mainContainer** `required`|[Main](#main)|MainContainer describes the main container configuration that is expected to be run on the host.|| +|**name**|str|The name of the workload and service.
If not defined, a generated name ("{__META_APP_NAME}-{__META_ENV_TYPE_NAME}") will be used.
The value of __META_APP_NAME will be extracted from the value of the "name" defined in project.yaml,
and the value of __META_ENV_TYPE_NAME will be extracted from the value of the "name" defined in stack.yaml.|| +|**needNamespace**|bool|NeedNamespace mark server is namespace scoped or not.|True| +|**podMetadata**|any|PodMetadata is metadata that all persisted resources must have, which includes all objects users must create.|| +|**renderType**|"Server" | "KubeVelaApplication"|Application render type, default to 'Server'|"Server"| +|**replicas** `required`|int|Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.|option("replicas") or 1| +|**schedulingStrategy** `required`|[SchedulingStrategy](#schedulingstrategy)|SchedulingStrategy represents scheduling strategy.|strategy.SchedulingStrategy {}| +|**secrets**|[[Secret](#secret)]|Secrets is a list of Secret which hold secret data of a certain type.|| +|**selector**|{str:str}|Label selector for pods. Existing ReplicaSets/ whose pods are selected by this will be the ones affected by this deployment.|| +|**serviceAccount**|[ServiceAccount](#serviceaccount)|ServiceAccount is used to run this pod.|| +|**services**|[[Service](#service)]|Services is a list of Service which partition a single Kubernetes cluster into multiple virtual clusters.|| +|**sidecarContainers**|[[Sidecar](#sidecar)]|SidecarContainers describes the list of sidecar container configuration that is expected to be run on the host.|| +|**storage**|[ObjectStorage](#objectstorage)||| +|**useBuiltInLabels**|bool|UseBuiltInLabels indicates use built-in labels or not.|True| +|**useBuiltInSelector**|bool|UseBuiltInSelector indicates use built-in selector or not.|True| +|**volumes**|[[Volume](#volume)]|Volumes represents a named volume and corresponding mounts in containers.|| +|**workloadType** `required`|"Deployment" | "StatefulSet"|Application workload type, default to 'Deployment'|"Deployment"| +#### Examples + +``` +import models.kube.frontend +import models.kube.frontend.container +import models.kube.templates.resource as res_tpl + +appConfiguration: frontend.Server { + mainContainer = container.Main { + name = "php-redis" + env = [ + { + name = "GET_HOSTS_FROM" + value = "dns" + } + ] + ports = [{containerPort = 80}] + } + selector = { + tier = "frontend" + } + podMetadata.labels: { + tier = "frontend" + } + schedulingStrategy.resource = res_tpl.tiny +} +``` + +### Metadata + +Metadata is the base schema of all models, which contains data that helps uniquely identify the object. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +### ConfigMap + +ConfigMap holds configuration data for pods to consume. More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/config-map-v1/#ConfigMap + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**binaryData**|{str:str}|BinaryData contains the binary data.|| +|**data**|{str:str}|Data contains the configuration data.|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +#### Examples + +``` +configmap = ConfigMap { + name = "my-configmap" + namespace = "my-configmap-namespace" + data = { + foo = "bar" + bar = "foo" + } +} +``` + +### Main + +Main describes the main container configuration that is expected to be run on the host. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**args**|[str]|A Container-level attribute.
The startup arguments of main process. The image's cmd is used if this is not provided.|| +|**command**|[str]|A Container-level attribute.
The startup command of main process. The image's entrypoint is used if this is not provided.|| +|**env**|[[Env](#env)]|A Container-level attribute.
List of environment variables in the container.|| +|**envFrom**|[[EnvFromSource](#envfromsource)]|A Container-level attribute.
List of sources to populate environment variables in the container.|| +|**lifecycle**|[Lifecycle](#lifecycle)|Actions that the management system should take in response to container lifecycle events. Cannot be updated.|| +|**livenessProbe**|[Probe](#probe)|A Container-level attribute.
The probe to check whether container is live or not.|| +|**name** `required`|str|A Container-level attribute.
The container name. Each container in a pod must have a unique name.|"main"| +|**ports**|[[ContainerPort](#containerport)]|A Container-level attribute.
List of network ports in the container.|| +|**readinessProbe**|[Probe](#probe)|A Container-level attribute.
The probe to check whether container is ready or not.
The default value can be referred to presupposed template: base/pkg/kusion_models/templates/sofa_probe.k|| +|**securityContext**|{str:}|SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/|| +|**startupProbe**|[Probe](#probe)|A Container-level attribute.
The probe to indicates that the Pod has successfully initialized.|| +|**useBuiltInEnv**|bool|useBuiltInEnv indicates use built-in envs or not.|False| +|**workingDir**|str|Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.|| +#### Examples + +``` +import models.kube.frontend.container +import models.kube.frontend.container.probe as p + +main = container.Main { + name = "test" + livenessProbe = p.Probe { + handler = p.Http { + path = "/healthz" + } + initialDelaySeconds = 10 + } +} +``` + +### Env + +Env represents an environment variable present in a Container. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**name** `required`|str|A Container-level attribute.
The env name. This must be a C_IDENTIFIER.|| +|**value**|str|A Container-level attribute.
The simple literal value.|| +|**valueFrom**|[EnvValueFrom](#envvaluefrom)|A Container-level attribute.
The ref source of this env.|| +### EnvFromSource + +EnvFromSource represents the source of a set of ConfigMaps or Secrets. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**configMapRef**|str|A Container-level attribute.
The ConfigMap name to select from.|| +|**secretRef**|str|A Container-level attribute.
The Secret name to select from.|| +### EnvValueFrom + +EnvValueFrom represents the source of the value of an Env. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**configMapKeyRef**|[ObjectKeySelector](#objectkeyselector)|A Container-level attribute.
Selects a key of a ConfigMap.|| +|**fieldRef**|[ObjectFieldSelector](#objectfieldselector)|A Container-level attribute.
Selects a key of a field.|| +|**resourceFieldRef**|[ResourceFieldSelector](#resourcefieldselector)|A Container-level attribute.
Selects a resource of the container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.|| +|**secretKeyRef**|[ObjectKeySelector](#objectkeyselector)|A Container-level attribute.
Selects a key of a secret.|| +### ObjectFieldSelector + +ObjectFieldSelector contains enough information to let you select field of an object. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**apiVersion**|str|A Container-level attribute.
Version of the schema the FieldPath is written in terms of, defaults to "v1".|"v1"| +|**fieldPath** `required`|str|A Container-level attribute.
Path of the field to select of an object.|| +### ObjectKeySelector + +ObjectKeySelector contains enough information to let you locate the referenced object. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**key** `required`|str|A Container-level attribute.
The key of the object to select from.|| +|**name** `required`|str|A Container-level attribute.
The name of object, typically a ConfigMap or Secret name.|| +### ResourceFieldSelector + +ResourceFieldSelector represents container resources (cpu, memory) and their output format. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**containerName**|str|A Container-level attribute.|| +|**divisor**|int | units.NumberMultiplier|A Container-level attribute.
Specifies the output format of the exposed resources, defaults to 1|1| +|**resource** `required`|str|A Container-level attribute.
Resource to select.|| +### Lifecycle + +Lifecycle describes actions that the management system should take in response to container lifecycle events. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**postStart**|[Exec](#exec) | [Http](#http)|A Container-level attribute.
The PostStart action is called immediately after a container is created.|| +|**preStop**|[Exec](#exec) | [Http](#http)|A Container-level attribute.
The PreStop action is called immediately before a container is terminated.|| +#### Examples + +``` +import models.kube.frontend.container.lifecycle as lc +import models.kube.frontend.container.probe as p + +p = lc.Lifecycle { + preStop = p.Exec { + command = [ + "timeout" + "--signal=9" + "1800s" + "sh" + "-c" + "bash -x /tmp/image-builder/boot/boot.sh" + ] + } +} +``` + +### ContainerPort + +ContainerPort represents a network port in a single container. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**containerPort** `required`|int|A Container-level attribute.
The number of port to expose on the container's IP address.|| +|**name**|str|If specified, this must be an IANA_SVC_NAME and unique within the pod.
Each named port in a pod must have a unique name.
Name for the port that can be referred to by services.|| +|**protocol** `required`|"TCP" | "UDP" | "SCTP"|A Container-level attribute.
The protocol for port. Must be UDP, TCP or SCTP. Default is TCP.|"TCP"| +#### Examples + +``` +p = ContainerPort { + name = "test" + protocol = "TCP" + containerPort = 8080 +} +``` + +### Exec + +Exec describes a "run in container" action. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**command** `required`|[str]|A Container-level attribute.
The command line to execute inside the container.|| +### Http + +Http describes an action based on HTTP Get requests. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**path** `required`|str|A Container-level attribute.
The Path to access on the HTTP server. e.g /healthz|| +|**port** `required`|int|A Container-level attribute.
The Number of the port to access on the container.|| +|**scheme** `required`|"HTTP" | "HTTPS"|A Container-level attribute.
Scheme to use for connecting to the host, defaults to HTTP.|"HTTP"| +### Probe + +Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**failureThreshold**|int|A Container-level attribute.
Minimum consecutive failures for the probe to be considered failed after having succeeded.|| +|**handler** `required`|[Exec](#exec) | [Http](#http) | [Tcp](#tcp)|A Container-level attribute.
The action taken to determine the health of a container.|| +|**initialDelaySeconds**|int|A Container-level attribute.
The length of time before health checking is activated. In seconds.|| +|**periodSeconds**|int|A Container-level attribute.
How often (in seconds) to perform the probe.|10| +|**successThreshold**|int|A Container-level attribute.
Minimum consecutive successes for the probe to be considered successful after having failed.|| +|**timeoutSeconds**|int|A Container-level attribute.
The length of time before health checking times out. In seconds.|| +#### Examples + +``` +import models.kube.frontend.container.probe as p + +probe = p.Probe { + handler = p.Http { + path = "/healthz" + } + initialDelaySeconds = 10 +} +``` + +### Tcp + +Tcp describes an action based on opening a socket. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**tcpSocket** `required`|int|A Container-level attribute.
The TCP socket port to connect to.|| +### Ingress + +Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**rules**|[]|A list of host rules used to configure the Ingress. If unspecified, or no rule matches, all traffic is sent to the default backend.|| +|**tls**|[]|TLS configuration. Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI.|| +#### Examples + +``` +ingress.Ingress { + name = "example-ingress" + rules = [ + { + host = "your-domain.com" + http.paths = [ + { + path = "/apple" + pathType = "Prefix" + backend.service: { + name = "app-service" + port.number = 5678 + } + } + ] + } + ] + tls = [ + { + hosts = ["your-domain.com"] + secretName = "example-ingress-tls" + } + ] +} +``` + +### ClusterRole + +rules: [PolicyRule], default is Undefined, optional Rules holds all the PolicyRules for this ClusterRole aggregationRule: AggregationRule, default is Undefined, optional AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**aggregationRule**|any||| +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**kubernetes** `required`|any||rbacv1.ClusterRole { + metadata = metadata + rules = rules + aggregationRule = aggregationRule +}| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**metadata**|{str:}||{ + name: name?.lower() + annotations: annotations + namespace: namespace + labels: labels +}| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**rules**|[]||| +### ClusterRoleBinding + +subjects: [Subject], default is Undefined, optional Subjects holds references to the objects the role applies to. roleRef: ClusterRole, default is Undefined, required RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**kubernetes** `required`|any||rbacv1.ClusterRoleBinding { + metadata = metadata + subjects = subjects + roleRef = roleRef +}| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**metadata**|{str:}||{ + name: name?.lower() + annotations: annotations + namespace: namespace + labels: labels +}| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**roleRef** `required`|any||| +|**subjects**|[]||| +### Role + +rules: [PolicyRule], default is Undefined, optional Rules holds all the PolicyRules for this ClusterRole + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**kubernetes** `required`|any||rbacv1.Role { + metadata = metadata + rules = rules +}| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**metadata**|{str:}||{ + name: name?.lower() + annotations: annotations + namespace: namespace + labels: labels +}| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**rules**|[]||| +### RoleBinding + +subjects: [Subject], default is Undefined, optional Subjects holds references to the objects the role applies to. roleRef: RoleRef, default is Undefined, required RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**kubernetes** `required`|any||rbacv1.RoleBinding { + metadata = metadata + subjects = subjects + roleRef = roleRef +}| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**metadata**|{str:}||{ + name: name?.lower() + annotations: annotations + namespace: namespace + labels: labels +}| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**roleRef** `required`|any||| +|**subjects**|[]||| +### Resource + +Resource describes the compute resource requirements. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**cpu**|int | units.NumberMultiplier|A Container-level attribute.
CPU, in cores, default 1 core. (500m = .5 cores)|1| +|**disk**|units.NumberMultiplier|A Container-level attribute.
Local disk storage, in bytes, default 10Gi. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)|10Gi| +|**memory**|units.NumberMultiplier|A Container-level attribute.
Memory, in bytes, default 1024Mi. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)|1024Mi| +#### Examples + +``` +import models.kube.frontend.resource as res + +res = res.Resource { + cpu = 2 + memory = 2048Mi + disk = 20Gi +} +``` + +### ResourceRequirements + +ResourceRequirements describes the compute resource requirements.. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**limits** `required`|[Resource](#resource)|A Container-level attribute.
Limits describes the maximum amount of compute resources allowed.
More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/|| +|**requests** `required`|[Resource](#resource)|A Container-level attribute.
Requests describes the minimum amount of compute resources required.
If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value.
More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/|| +#### Examples + +``` +import models.kube.frontend.resource as res + +res = res.ResourceRequirements { + limits = { + cpu = 1 + memory = 1Gi + disk = 20Gi + } + requests = { + cpu = 500m + memory = 512Mi + disk = 10Gi + } +} +``` + +### Secret + +Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**data**|{str:str}|Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'.
More info: https://kubernetes.io/docs/concepts/configuration/secret/#restriction-names-data|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**stringData**|{str:str}|stringData allows specifying non-binary secret data in string form.
More info: https://kubernetes.io/docs/concepts/configuration/secret/#restriction-names-data|| +|**type**|str|Used to facilitate programmatic handling of secret data.
More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types|| +#### Examples + +``` +secret = Secret { + name = "my-secret" + namespace = "my-secret-namespace" + data = { + foo = bar + bar = foo + } + $type = "kubernetes.io/service-account-token" +} +``` + +### Service + +Service are Kubernetes objects which partition a single Kubernetes cluster into multiple virtual clusters. More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#Service + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**clusterIP**|str|clusterIP is the IP address of the service and is usually assigned randomly by the master.
More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies|| +|**externalIPs**|[str]|externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service.|| +|**externalName**|str|externalName is the external reference that discovery mechanisms will return as an alias for this service (e.g. a DNS CNAME record).|| +|**externalTrafficPolicy**|str|externalTrafficPolicy denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints.|| +|**healthCheckNodePort**|int|healthCheckNodePort specifies the healthcheck nodePort for the service.|| +|**ipFamilyPolicy**|str|ipFamilyPolicy represents the dual-stack-ness requested or required by this Service, and is gated by the "IPv6DualStack" feature gate.|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**loadBalancerIP**|str|Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field.|| +|**loadBalancerSourceRanges**|[str]|If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs.
This field will be ignored if the cloud-provider does not support the feature.
More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/|| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**ports**|[]|The list of ports that are exposed by this service.
More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies|| +|**publishNotReadyAddresses**|bool|publishNotReadyAddresses indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready.|| +|**selector**|{str:str}|Route service traffic to pods with label keys and values matching this selector.
More info: https://kubernetes.io/docs/concepts/services-networking/service/|| +|**sessionAffinity**|str|Supports "ClientIP" and "None". Used to maintain session affinity.
More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies|| +|**sessionAffinityConfig**|{str:}|sessionAffinityConfig contains the configurations of session affinity.|| +|**type**|str|determines how the Service is exposed.
More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types|| +#### Examples + +``` +service = Service { + name = "my-service-name" + namespace = "my-service-name" + labels.env = "dev" + ports = [ + { + name = "grpc-xds" + port = 15010 + } + { + name = "https-xds" + port = 15011 + } + ] +} +``` + +### ServiceAccount + +A service account provides an identity for processes that run in a Pod. ServiceAccount binds together: - a name, understood by users, and perhaps by peripheral systems, for an identity - a principal that can be authenticated and authorized - a set of secrets More info: https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/service-account-v1/#ServiceAccount + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**annotations**|{str:str}|Annotations is an unstructured key value map stored with a
resource that may be set by external tools to store and retrieve
arbitrary metadata. They are not queryable and should be preserved
when modifying objects.
More info: http://kubernetes.io/docs/user-guide/annotations|| +|**imagePullSecrets**|[{str:str}]|ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount.
More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod|| +|**labels**|{str:str}|Labels is a map of string keys and values that can be used to
organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels|| +|**name**|str|The name of the resource.
Name must be unique within a namespace. It's required when creating
resources, although some resources may allow a client to request the
generation of an appropriate name automatically.
Name is primarily intended for creation idempotence and configuration
definition. Cannot be updated. More info:
http://kubernetes.io/docs/user-guide/identifiers#names|| +|**namespace**|str|Namespaces are intended for use in environments with many users spread
across multiple teams, or projects.
For clusters with a few to tens of users, you should not need to create
or think about namespaces at all. Start using namespaces when you need the features they provide.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/|| +|**secrets**|[{str:str}]|Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount.
More info: https://kubernetes.io/docs/concepts/configuration/secret|| +#### Examples + +``` +my_service_account = ServiceAccount { + name: "my-service-account" + namespace = "my-service-account-namespace" + labels: { + tier: "monitoring" + } + imagePullSecrets: [ + { + name: "my-secret" + } + ] + secrets: [ + { + name: "my-secret" + } + ] +} +``` + +### Sidecar + +Sidecar describes the sidecar container configuration that is expected to be run on the host. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**args**|[str]|A Container-level attribute.
The startup arguments of main process. The image's cmd is used if this is not provided.|| +|**command**|[str]|A Container-level attribute.
The startup command of main process. The image's entrypoint is used if this is not provided.|| +|**env**|[[Env](#env)]|A Container-level attribute.
List of environment variables in the container.|| +|**envFrom**|[[EnvFromSource](#envfromsource)]|A Container-level attribute.
List of sources to populate environment variables in the container.|| +|**image** `required`|str|A Container-level attribute.
Container image name. More info: https://kubernetes.io/docs/concepts/containers/images|| +|**lifecycle**|[Lifecycle](#lifecycle)|Actions that the management system should take in response to container lifecycle events.
Cannot be updated.|| +|**livenessProbe**|[Probe](#probe)|A Container-level attribute.
The probe to check whether container is live or not.|| +|**name** `required`|str|A Container-level attribute.
The container name. Each container in a pod must have a unique name.|| +|**ports**|[[ContainerPort](#containerport)]|List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default "0.0.0.0" address inside a container will be accessible from the network. Cannot be updated.|| +|**readinessProbe**|[Probe](#probe)|A Container-level attribute.
The probe to check whether container is ready or not.|| +|**resource** `required`|str | [Resource](#resource)|A Pod-level attribute.
Sidecar container resource.|| +|**securityContext**|{str:}|SecurityContext defines the security options the container should be run with.
If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.
More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/|| +|**startupProbe**|[Probe](#probe)|A Container-level attribute.
The probe to indicates that the Pod has successfully initialized.|| +|**workingDir**|str|Container's working directory. If not specified, the container runtime's default will be used,
which might be configured in the container image. Cannot be updated.|| +#### Examples + +``` +import models.kube.frontend.sidecar as s +import models.kube.frontend.container.probe as p + +sidecar = s.Sidecar { + name = "test" + livenessProbe = p.Probe { + handler = p.Http { + httpPath = "/healthz" + } + initialDelaySeconds = 10 + } +} +``` + +### SimpleSidecar + +Simple sidecar describes the sidecar container configuration that is expected to be run on the host. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**extInfo**|{str:}|The extended information.|| +|**name** `required`|str|The sidecar name. e.g. 'odp','kmi','antmonitor'.|| +|**version** `required`|str|The sidecar version. e.g. 'v1.2.3'.|| +#### Examples + +``` +import models.kube.frontend.sidecar as s + +sidecar = s.SimpleSidecar { + name = "test" + version = "v1.2.3" +} +``` + +### DBAttr + +DBAttr is the Attributes of cloud database. Attributes ---------- databaseEngine: "MySQL" \| "SQLServer" \| "PostgreSQL" \| "MariaDB", cloud database engine type, default is "MySQL". databaseEngineVersion: str, cloud database engine version, default is Undefined. cloudChargeType: "Prepaid" \| "Postpaid" \| "Serverless", cloud database charge type, default is "Postpaid". databaseAccountName: str, initialized account name of cloud database, default is Undefined. databaseAccountPassWord: str, intitialized account password of cloud database, default is Undefined. internetAccess: bool, decide whether the cloud database needs internet access. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**allocatedStorage**|int||10| +|**databaseAccountName** `required`|str||| +|**databaseAccountPassword** `required`|str||| +|**databaseEngine** `required`|"MySQL" | "SQLServer" | "PostgreSQL" | "MariaDB"||"MySQL"| +|**databaseEngineVersion** `required`|str||| +|**extraMap**|{str:str}||| +|**instanceType** `required`|str||| +|**internetAccess** `required`|bool||| +### DataBase + +DataBase is the schema of cloud database. Attributes ---------- dataBaseType: Literal Type, cloud database type name, default is "aliyun_rds". dataBaseAttr: DBAttr, cloud database attribute, default is Undefined. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**dataBaseAttr** `required`|[DBAttr](#dbattr)||| +|**dataBaseType** `required`|"aliyun_rds" | "aws_rds"||| +### ObjectStorage + +ObjectStorage is the schema of clouds object storage. Attributes ---------- objectStorageType: str, cloud object storage name, default is Undefined. objectStorageAttr: str, cloud object storage attribute, default is Undefined. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**objectStorageAttr** `required`|[StorageAttr](#storageattr)||| +|**objectStorageType** `required`|str||| +### StorageAttr + +StorageAttr is the Attributes of storage. Attributes ---------- bucket: str, The name of the bucket, default is Undefined. acl: str, The canned ACL to apply, default is Undefined. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**acl** `required`|str||| +|**bucket** `required`|str||| +### SchedulingStrategy + +SchedulingStrategy represents scheduling strategy. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**resource**|str | [Resource](#resource) | [ResourceRequirements](#resourcerequirements)|A Pod-level attribute.
Main container resource.|| +### CSI + +CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**driver** `required`|str|A Pod-level attribute.
Driver is the name of the driver to use for this volume.|| +|**fsType**|str|A Pod-level attribute.
Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs".
The default filesystem depends on FlexVolume script.|| +|**readOnly**|bool|A Pod-level attribute.
Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.|| +|**volumeAttributes**|{str:str}|A Pod-level attribute.
Extra command options if any.|| +### ConfigMap + +ConfigMap represents a secret that should populate this volume. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**defaultMode**|int|A Pod-level attribute.
Mode bits used to set permissions on created files by default.|| +|**items**|[{str:str}]|A Pod-level attribute.
Key-value pairs projected into the volume.|| +|**name** `required`|str|A Pod-level attribute.
Name of the configMap in the pod's namespace to use.|| +### DownwardAPI + +DownwardAPI represents a secret that should populate this volume. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**defaultMode**|int|A Pod-level attribute.
Mode bits used to set permissions on created files by default.|| +|**items**|[{str:}]|A Pod-level attribute.
Items is a list of downward API volume file|| +### EmptyDir + +EmptyDir represents a temporary directory that shares a pod's lifetime. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**medium** `required`|"" | "Memory"|A Pod-level attribute.
What type of storage medium should back this directory.|""| +|**sizeLimit**|str|A Pod-level attribute.
Total amount of local storage required for this EmptyDir volume.|| +### FlexVolume + +FlexVolume represents a secret that should populate this volume. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**driver** `required`|str|A Pod-level attribute.
Driver is the name of the driver to use for this volume.|| +|**fsType**|str|A Pod-level attribute.
Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs".
The default filesystem depends on FlexVolume script.|| +|**options**|{str:str}|A Pod-level attribute.
Extra command options if any.|| +|**readOnly**|bool|A Pod-level attribute.
Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.|| +### HostPath + +HostPath represents a secret that should populate this volume. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**path** `required`|str|A Pod-level attribute.
Path of the directory on the host. If the path is a symlink, it will follow the link to the real path.
More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath|| +|**type**|str|A Pod-level attribute.
Type for HostPath Volume Defaults to ""
More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath|| +### Mount + +Mount represents a mounting of a Volume within a container. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**container** `required`|str|A Pod-level attribute.
Name of container to mount, * represents all containers.|"*"| +|**path** `required`|str|A Container-level attribute.
Path within the container at which the volume should be mounted.|| +|**readOnly**|bool|A Container-level attribute.
Mounted read-only if true, read-write otherwise.|False| +|**subPath**|str|A Container-level attribute.
Path within the volume from which the container's volume should be mounted.|| +### Secret + +Secret represents a secret that should populate this volume. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**defaultMode**|int|A Pod-level attribute.
Mode bits used to set permissions on created files by default.|| +|**items**|[{str:str}]|A Pod-level attribute.
Key-value pairs projected into the volume.|| +|**secretName** `required`|str|A Pod-level attribute.
Name of the secret in the pod's namespace to use.|| +### Volume + +Volume represents a named volume and corresponding mounts in containers. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**mounts**|[[Mount](#mount)]|Volumes to mount into the container's filesystem.|| +|**name** `required`|str|Volume's name. Must be a DNS_LABEL and unique within the pod.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names|| +|**volumeSource** `required`|[EmptyDir](#emptydir) | [Secret](#secret) | [ConfigMap](#configmap) | [FlexVolume](#flexvolume) | [HostPath](#hostpath) | [DownwardAPI](#downwardapi) | [CSI](#csi)|VolumeSource represents the location and type of the mounted volume.|| +#### Examples + +``` +volume = v.Volume { + name = "kubeconfig" + volumeSource = v.Secret { + secretName = "kubeconfig" + defaultMode = 420 + } + mounts = [ + v.Mount { + path = "/etc/kubernetes/kubeconfig" + readOnly = true + } + ] +} +``` + +### ConfigMapMixin + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +### IngressMixin + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +### MetadataMixin + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**metadata**|{str:}||{ + name: name?.lower() + annotations: annotations + namespace: namespace + labels: labels +}| +### NamespaceMixin + +NamespaceMixin encapsulate the logic of automatically creating a namespace resource. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +#### Examples + +``` +app = { + needNamespace = True +} +``` + +### SecretMixin + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +### ServiceAccountMixin + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +### ServiceMixin + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +### ServerProtocol + +ServerProtocol provides constraints on mixins required by the server backend. + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**config** `required`|[Server](#server)||| +|**kubernetes** `required`|[ResourceMapping](#resourcemapping)||| +|**mainContainer** `required`|{str:}||| +|**workloadAttributes** `required`|{str:}||| +### ResourceMapping + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +### ApplicationBuilder + +ApplicationBuilder contains the workload labels, selector and environments about the application Reference from: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**envs** `required`|[{str:}]||[ + { + name: "APP_NAME" + value: metadata.__META_APP_NAME + } + { + name: "ENVIRONMENT" + value: metadata.__META_ENV_TYPE_NAME + } + { + name: "INSTANCE" + value: "{}-{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower() + } + { + name: "CLUSTER" + value: metadata.__META_CLUSTER_NAME + } +]| +|**labels** `required`|{str:str}||{ + "app.kubernetes.io/name": metadata.__META_APP_NAME + "app.kubernetes.io/env": metadata.__META_ENV_TYPE_NAME + "app.kubernetes.io/instance": "{}-{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower() + "cluster.x-k8s.io/cluster-name": metadata.__META_CLUSTER_NAME +}| +|**selector** `required`|{str:str}||labels| +### Str2ResourceRequirements + +#### Attributes + +| name | type | description | default value | +| --- | --- | --- | --- | +|**resource** `required`|[{str:}]||[{ + cpu = { + requests = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[0])?.strip() + limits = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[-1])?.strip() + } +} if "cpu" in item else ({ + memory = { + requests = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[0])?.strip() + limits = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[-1])?.strip() + } +} if "memory" in item else ({ + disk = { + requests = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[0])?.strip() + limits = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[-1])?.strip() + } +} if "disk" in item else Undefined)) for item in schedulingResourceItems]| +|**resourceRequirementsUnit**|[ResourceRequirements](#resourcerequirements)||resourcePara as res.ResourceRequirements if typeof(resourcePara) == "ResourceRequirements" else None| +|**resourceStr**|str||resourcePara as str if typeof(resourcePara) == "str" else None| +|**resourceUnit**|[Resource](#resource)||resourcePara as res.Resource if typeof(resourcePara) == "Resource" else None| +|**result** `required`|{str:}||{ + requests = { + cpu = [r?.cpu?.requests for r in resource if r?.cpu?.requests]?[-1] or Undefined + memory = [r?.memory?.requests for r in resource if r?.memory?.requests]?[-1] or Undefined + "ephemeral-storage" = [r?.disk?.requests for r in resource if r?.disk?.requests]?[-1] or Undefined + } + limits = { + cpu = [r?.cpu?.limits for r in resource if r?.cpu?.limits]?[-1] or Undefined + memory = [r?.memory?.limits for r in resource if r?.memory?.limits]?[-1] or Undefined + "ephemeral-storage" = [r?.disk?.limits for r in resource if r?.disk?.limits]?[-1] or Undefined + } +} if resourceStr else { + requests = { + cpu = str(resourceRequirementsUnit.requests.cpu) + memory = str(resourceRequirementsUnit.requests.memory) + "ephemeral-storage" = str(resourceRequirementsUnit.requests.disk) if resourceRequirementsUnit.requests.disk else Undefined + } + limits = { + cpu = str(resourceRequirementsUnit.limits.cpu) + memory = str(resourceRequirementsUnit.limits.memory) + "ephemeral-storage" = str(resourceRequirementsUnit.limits.disk) if resourceRequirementsUnit.limits.disk else Undefined + } +} if resourceRequirementsUnit else { + requests = { + cpu = str(resourceUnit.cpu) + memory = str(resourceUnit.memory) + "ephemeral-storage" = str(resourceUnit.disk) if resourceUnit.disk else Undefined + } + limits = { + cpu = str(resourceUnit.cpu) + memory = str(resourceUnit.memory) + "ephemeral-storage" = str(resourceUnit.disk) if resourceUnit.disk else Undefined + } +}| +|**schedulingResourceItems** `required`|[str]||resourceStr?.split(",") or []| + diff --git a/konfig/kcl.mod b/konfig/kcl.mod new file mode 100644 index 00000000..5c4a05cd --- /dev/null +++ b/konfig/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "konfig" +version = "0.4.0" +description = "Konfig provides users with an out-of-the-box, highly abstract configuration interface. The original starting point of the model library is to improve the efficiency and experience of YAML users. We hope to simplify the writing of user-side configuration code by abstracting and encapsulating the model with more complex code into a unified model." + +[dependencies] +k8s = "1.28" diff --git a/konfig/kcl.mod.lock b/konfig/kcl.mod.lock new file mode 100644 index 00000000..8c61a23b --- /dev/null +++ b/konfig/kcl.mod.lock @@ -0,0 +1,9 @@ +[dependencies] + [dependencies.k8s] + name = "k8s" + full_name = "k8s_1.28" + version = "1.28" + sum = "aTxPUVZyr9MdiB3YdiY/8pCh9sC55yURnZdGlJsKG6Q=" + reg = "ghcr.io" + repo = "kcl-lang/k8s" + oci_tag = "1.28" diff --git a/konfig/models/commons/resource.k b/konfig/models/commons/resource.k new file mode 100644 index 00000000..9d7afb6f --- /dev/null +++ b/konfig/models/commons/resource.k @@ -0,0 +1,19 @@ + +schema RESOURCE: + id?: str + """ id is the unique key of this resource in the whole State. + """ + $type: str + """type is the type of provider resource. + """ + attributes?: any + """attributes represents all specified attributes of this resource + """ + + extensions?: {str:} + """extensions specifies arbitrary metadata of this resource + """ + + dependsOn?: [str] + """dependsOn contains all resources this resource depends on + """ diff --git a/konfig/models/commons/resource_builder.k b/konfig/models/commons/resource_builder.k new file mode 100644 index 00000000..2a31dea6 --- /dev/null +++ b/konfig/models/commons/resource_builder.k @@ -0,0 +1,54 @@ +schema ResourceBuilder: + $type: str + """type is the type of provider resource + """ + + name: str + """name is the name resource. + """ + + provider: Provider + """provider information. + """ + + providerAttr: any + + providerMeta?: {str:} + """providerMeta is the config of provider. + """ + + providerDependsOn?: [str] + + _resource = RESOURCE { + id = provider.namespace + ":" + provider.name + ":" + type + ":" + name + type: "Terraform" + attributes: providerAttr + extensions: { + provider: provider.host + "/" + provider.namespace + "/" + provider.name + "/" + provider.version + resourceType: type + providerMeta: providerMeta + } + dependsOn: providerDependsOn + } + + result: any = _resource + +schema Provider: + """Provider + """ + + host: str + """host is host of provider registry + """ + + namespace: str + """namespace is namespace of provider + """ + + name: str + """name is name of provider + """ + + version: str + """version is verison of provider + """ diff --git a/konfig/models/kube/backend/job_backend.k b/konfig/models/kube/backend/job_backend.k new file mode 100644 index 00000000..5f78fef5 --- /dev/null +++ b/konfig/models/kube/backend/job_backend.k @@ -0,0 +1,104 @@ +import k8s.api.batch.v1 as batchv1 +import models.kube.frontend +import models.kube.mixins +import models.kube.utils +import models.kube.metadata +import models.kube.resource + +schema JobBackend[inputConfig: frontend.Job]: + # mixins + mixin [ + # Resource builder mixin + mixins.NamespaceMixin, + mixins.ConfigMapMixin, + mixins.ServiceAccountMixin + ] + + config: frontend.Job = inputConfig + + # variables + jobName: str = "{}-{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower() + app: utils.ApplicationBuilder = utils.ApplicationBuilder {} + mainContainerDict: {str:} + mainContainer: {str:} + sidecarContainers?: [{str:}] + initContainers?: [{str:}] + + # rendering logic + if config.mainContainer: + assert config.image, "config.image must be specified and can't be empty or None or Undefined" + # construct input for converter + mainContainerDict = { + **config.mainContainer + if config.mainContainer.useBuiltInEnv: + env += app.envs + name = config.mainContainer.name or "main" + image = config.image + resource = config?.schedulingStrategy?.resource + } + mainContainer = utils.VolumePatch(config.volumes, [utils.ContainerFrontend2Kube(mainContainerDict)])?[0] + + if config.sidecarContainers: + sidecarContainers = utils.VolumePatch(config.volumes, [utils.ContainerFrontend2Kube(_s) for _s in config.sidecarContainers]) + + if config.initContainers: + initContainers = utils.VolumePatch(config.volumes, [utils.ContainerFrontend2Kube(_s) for _s in config.initContainers]) + + # construct job attributes + jobAttrs: {str:} = { + metadata = utils.MetadataBuilder(config) | { + name = jobName + } + spec = { + activeDeadlineSeconds = config.activeDeadlineSeconds + backoffLimit = config.backoffLimit + completionMode = config.completionMode + completions = config.completions + manualSelector = config.manualSelector + parallelism = config.parallelism + suspend = config.suspend + ttlSecondsAfterFinished = config.ttlSecondsAfterFinished + selector.matchLabels = app.selector | config.selector + + template = { + metadata = { + labels = app.labels + **config.podMetadata + } + spec = { + containers = [ + mainContainer + *sidecarContainers + ] + initContainers = initContainers + restartPolicy = config.restartPolicy + # volume + if config.volumes: volumes = [ + (lambda volume { + volumeType = typeof(volume.volumeSource) + assert volumeType in VOLUME_SOURCE_TYPE_MAPPING, "Invalid frontend volume type, please check VOLUME_SOURCE_TYPE_MAPPING" + kubeVolumeType = VOLUME_SOURCE_TYPE_MAPPING[volumeType] + { + name = volume.name + if typeof(volume.volumeSource) == "EmptyDir" and volume.volumeSource.medium == "": + "${kubeVolumeType}" = {} + else: + "${kubeVolumeType}" = volume.volumeSource + } + })(volume) for volume in config.volumes if volume.volumeSource + ] + # service account + if config.serviceAccount: + serviceAccountName = config.serviceAccount.name + } + } + } + } + + # generate job instance + _jobInstance = batchv1.Job {**jobAttrs} + + # put job instance to backend result + kubernetes: resource.ResourceMapping = { + "${typeof(_jobInstance)}" = [_jobInstance] + } diff --git a/konfig/models/kube/backend/server_backend.k b/konfig/models/kube/backend/server_backend.k new file mode 100644 index 00000000..697dd64b --- /dev/null +++ b/konfig/models/kube/backend/server_backend.k @@ -0,0 +1,142 @@ +import k8s.api.apps.v1 as appsv1 +import k8s.api.core.v1 as corev1 +import models.kube.frontend.server +import models.kube.mixins +import models.kube.metadata +import models.kube.utils +import models.kube.resource + +# Frontend volume to k8s volume mapping. +VOLUME_SOURCE_TYPE_MAPPING = { + EmptyDir = "emptyDir" + Secret = "secret" + ConfigMap = "configMap" + DownwardAPI = "downwardAPI" + CSI = "csi" + HostPath = "hostPath" +} + +schema ServerBackend[inputConfig: server.Server]: + """ServerBackend converts the user-written front-end model `Server` into a + collection of k8s resources and places the resource collection into + the `k8s` attribute. + """ + mixin [ + # Resource builder mixin + mixins.NamespaceMixin, + mixins.ConfigMapMixin, + mixins.SecretMixin, + mixins.ServiceMixin, + mixins.IngressMixin, + mixins.ServiceAccountMixin, + ] + + # Store the input config parameter, ensure it can be seen in protocol and mixin. + config: server.Server = inputConfig + # Workload name. + workloadName: str = config.name or "{}{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower() + # App variable contains labels, selector and environments. + app: utils.ApplicationBuilder = utils.ApplicationBuilder {} + # Main containers and sidecar contrainers. + mainContainer: {str:} + sidecarContainers?: [{str:}] + initContainers?: [{str:}] + provider?: [any] + + if config.mainContainer: + assert config.image, "config.image must be specified and can't be empty or None or Undefined" + # Construct input of converter using the volumes. + mainContainer = utils.VolumePatch(config.volumes, [utils.ContainerFrontend2Kube({ + **config.mainContainer + if config.mainContainer.useBuiltInEnv: + env += app.envs + name = config.mainContainer.name or "main" + image = config.image + resource = config?.schedulingStrategy?.resource + })])?[0] + + if config.sidecarContainers: + sidecarContainers = utils.VolumePatch(config.volumes, [utils.ContainerFrontend2Kube(_s) for _s in config.sidecarContainers]) + + if config.initContainers: + initContainers = utils.VolumePatch(config.volumes, [utils.ContainerFrontend2Kube(_s) for _s in config.initContainers]) + + if config.storage: + provider = [*provider, *StorageBackend(config).provider] + + if config.database: + provider = [*provider, *DatabaseBackend(config).provider] + + _applicationLabel: {str: str} = { + "app.k8s.io/component": workloadName + } + # Construct workload attributes. + workloadAttributes: {str:} = { + metadata = utils.MetadataBuilder(config) | { + name = workloadName + } + spec = { + replicas = config.replicas + if config.useBuiltInSelector: + selector.matchLabels: app.selector | config.selector | _applicationLabel + else: + selector.matchLabels: config.selector + template = { + metadata = { + if config.useBuiltInLabels: + labels = app.labels | _applicationLabel + **config.podMetadata + } + spec = { + containers = [mainContainer] + (sidecarContainers or []) + initContainers = initContainers + if config.volumes: volumes = [ + (lambda volume { + """Convert frontend volume to k8s Volume.""" + volumeType = typeof(volume.volumeSource) + assert volumeType in VOLUME_SOURCE_TYPE_MAPPING, "Invalid frontend volume type, please check VOLUME_SOURCE_TYPE_MAPPING" + kubeVolumeType = VOLUME_SOURCE_TYPE_MAPPING[volumeType] + { + name = volume.name + if typeof(volume.volumeSource) == "EmptyDir" and volume.volumeSource.medium == "": + "${kubeVolumeType}" = {} + else: + "${kubeVolumeType}" = volume.volumeSource + } + })(volume) for volume in config.volumes if volume.volumeSource + ] + if config.serviceAccount: + serviceAccountName = config.serviceAccount.name + } + } + } + } + + _workloadInstance?: appsv1.Deployment | appsv1.StatefulSet + + # Generate workload instance. + if config.workloadType == "Deployment": + _workloadInstance = appsv1.Deployment {**workloadAttributes} + elif config.workloadType == "StatefulSet": + # Generate default headless service of StatefulSet. + _headlessServiceInstance = corev1.Service { + metadata = workloadAttributes.metadata + spec = { + clusterIP = "None" + selector = workloadAttributes.spec.selector.matchLabels + } + } + _workloadInstance = appsv1.StatefulSet { + **workloadAttributes + spec.serviceName = _headlessServiceInstance.metadata.name + } + else: + assert False, "Invalid workload name {}".format(config.workloadType) + + # Put workload instance to backend result. + kubernetes: resource.ResourceMapping = { + if _workloadInstance: + "${typeof(_workloadInstance)}" = [_workloadInstance] + if _headlessServiceInstance: + "${typeof(_headlessServiceInstance)}" = [_headlessServiceInstance] + } diff --git a/konfig/models/kube/frontend/common/metadata.k b/konfig/models/kube/frontend/common/metadata.k new file mode 100644 index 00000000..011925a3 --- /dev/null +++ b/konfig/models/kube/frontend/common/metadata.k @@ -0,0 +1,36 @@ +schema Metadata: + """Metadata is the base schema of all models, which contains data + that helps uniquely identify the object. + + Attributes + ---------- + name: str, default is Undefined, optional. + The name of the resource. + Name must be unique within a namespace. It's required when creating + resources, although some resources may allow a client to request the + generation of an appropriate name automatically. + Name is primarily intended for creation idempotence and configuration + definition. Cannot be updated. More info: + http://kubernetes.io/docs/user-guide/identifiers#names + labels: {str:str}, default is Undefined, optional. + Labels is a map of string keys and values that can be used to + organize and categorize (scope and select) objects. + May match selectors of replication controllers and services. + More info: http://kubernetes.io/docs/user-guide/labels + annotations: {str:str}, default is Undefined, optional. + Annotations is an unstructured key value map stored with a + resource that may be set by external tools to store and retrieve + arbitrary metadata. They are not queryable and should be preserved + when modifying objects. + More info: http://kubernetes.io/docs/user-guide/annotations + namespace: str, default is Undefined, optional. + Namespaces are intended for use in environments with many users spread + across multiple teams, or projects. + For clusters with a few to tens of users, you should not need to create + or think about namespaces at all. Start using namespaces when you need the features they provide. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + """ + name?: str + labels?: {str:str} + annotations?: {str:str} + namespace?: str diff --git a/konfig/models/kube/frontend/configmap/configmap.k b/konfig/models/kube/frontend/configmap/configmap.k new file mode 100644 index 00000000..1485c1fe --- /dev/null +++ b/konfig/models/kube/frontend/configmap/configmap.k @@ -0,0 +1,26 @@ +import models.kube.frontend.common + +schema ConfigMap(common.Metadata): + """ConfigMap holds configuration data for pods to consume. + More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/config-map-v1/#ConfigMap + + Attributes + ---------- + data: {str:str}, default is Undefined, optional. + Data contains the configuration data. + binaryData: {str:str}, default is Undefined, optional + BinaryData contains the binary data. + + Examples + -------- + configmap = ConfigMap { + name = "my-configmap" + namespace = "my-configmap-namespace" + data = { + foo = "bar" + bar = "foo" + } + } + """ + data?: {str:str} + binaryData?: {str:str} diff --git a/konfig/models/kube/frontend/container/container.k b/konfig/models/kube/frontend/container/container.k new file mode 100644 index 00000000..8240627d --- /dev/null +++ b/konfig/models/kube/frontend/container/container.k @@ -0,0 +1,81 @@ +import models.kube.frontend.container.probe as p +import models.kube.frontend.container.env as e +import models.kube.frontend.container.port as cp +import models.kube.frontend.container.lifecycle as lc + +schema Main: + """ Main describes the main container configuration that is expected to be run on the host. + + Attributes + ---------- + name: str, default is "main", required. + A Container-level attribute. + The container name. Each container in a pod must have a unique name. + command: [str], default is Undefined, optional. + A Container-level attribute. + The startup command of main process. The image's entrypoint is used if this is not provided. + useBuiltInEnv: bool, default is False, optional. + useBuiltInEnv indicates use built-in envs or not. + args: [str], default is Undefined, optional. + A Container-level attribute. + The startup arguments of main process. The image's cmd is used if this is not provided. + env: [e.Env], default is Undefined, optional. + A Container-level attribute. + List of environment variables in the container. + envFrom: [e.EnvFromSource], default is Undefined, optional. + A Container-level attribute. + List of sources to populate environment variables in the container. + ports: [cp.ContainerPort], default is Undefined, optional. + A Container-level attribute. + List of network ports in the container. + livenessProbe: p.Probe, default is Undefined, optional. + A Container-level attribute. + The probe to check whether container is live or not. + readinessProbe: p.Probe, default is Undefined, optional. + A Container-level attribute. + The probe to check whether container is ready or not. + The default value can be referred to presupposed template: base/pkg/kusion_models/templates/sofa_probe.k + startupProbe: p.Probe, default is Undefined, optional. + A Container-level attribute. + The probe to indicates that the Pod has successfully initialized. + lifecycle: lc.Lifecycle, default is Undefined, optional + Actions that the management system should take in response to container lifecycle events. Cannot be updated. + securityContext: {str:any}, default is Undefined, optional + SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + workingDir: str, default is Undefined, optional + Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. + + Examples + -------- + import models.kube.frontend.container + import models.kube.frontend.container.probe as p + + main = container.Main { + name = "test" + livenessProbe = p.Probe { + handler = p.Http { + path = "/healthz" + } + initialDelaySeconds = 10 + } + } + """ + + name: str = "main" + command?: [str] + args?: [str] + useBuiltInEnv?: bool = False + env?: [e.Env] + envFrom?: [e.EnvFromSource] + ports?: [cp.ContainerPort] + + livenessProbe?: p.Probe + readinessProbe?: p.Probe + startupProbe?: p.Probe + + lifecycle?: lc.Lifecycle + workingDir?: str + securityContext?: {str:} + + check: + livenessProbe.successThreshold == 1 if livenessProbe, "success threshold must be 1 for liveness probe" diff --git a/konfig/models/kube/frontend/container/env/env.k b/konfig/models/kube/frontend/container/env/env.k new file mode 100644 index 00000000..a859e95e --- /dev/null +++ b/konfig/models/kube/frontend/container/env/env.k @@ -0,0 +1,129 @@ +import regex +import units + +schema Env: + """ Env represents an environment variable present in a Container. + + Attributes + ---------- + name: str, default is Undefined, required. + A Container-level attribute. + The env name. This must be a C_IDENTIFIER. + value: str, default is Undefined, optional. + A Container-level attribute. + The simple literal value. + valueFrom: EnvValueFrom, default is Undefined, optional. + A Container-level attribute. + The ref source of this env. + """ + + name: str + value?: str + valueFrom?: EnvValueFrom + + check: + len(name) <= 63, "a valid env name must be no more than 63 characters" + regex.match(name, r"[A-Za-z_][A-Za-z0-9_]*"), "a valid env name must start with alphabetic character or '_', followed by a string of alphanumeric characters or '_'" + not valueFrom if value, "valueFrom may not be specified when `value` is not empty" + +schema EnvValueFrom: + """ EnvValueFrom represents the source of the value of an Env. + + Attributes + ---------- + fieldRef: ObjectFieldSelector, default is Undefined, optional. + A Container-level attribute. + Selects a key of a field. + configMapKeyRef: ObjectKeySelector, default is Undefined, optional. + A Container-level attribute. + Selects a key of a ConfigMap. + secretKeyRef: ObjectKeySelector, default is Undefined, optional. + A Container-level attribute. + Selects a key of a secret. + resourceFieldRef: ResourceFieldSelector, default is Undefined, optional. + A Container-level attribute. + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + """ + + fieldRef?: ObjectFieldSelector + configMapKeyRef?: ObjectKeySelector + secretKeyRef?: ObjectKeySelector + resourceFieldRef?: ResourceFieldSelector + + check: + (fieldRef and not configMapKeyRef and not secretKeyRef and not resourceFieldRef) or \ + (not fieldRef and configMapKeyRef and not secretKeyRef and not resourceFieldRef) or \ + (not fieldRef and not configMapKeyRef and secretKeyRef and not resourceFieldRef) or \ + (not fieldRef and not configMapKeyRef and not secretKeyRef and resourceFieldRef), "must specify one of: `fieldRef`, `configMapKeyRef`, `secretKeyRef` or `resourceFieldRef`" + +schema ObjectKeySelector: + """ ObjectKeySelector contains enough information to let you locate the referenced object. + + Attributes + ---------- + name: str, default is Undefined, required. + A Container-level attribute. + The name of object, typically a ConfigMap or Secret name. + key: str, default is Undefined, required. + A Container-level attribute. + The key of the object to select from. + """ + + name: str + key: str + +schema ObjectFieldSelector: + """ ObjectFieldSelector contains enough information to let you select field of an object. + + Attributes + ---------- + apiVersion: str, default is v1, optional. + A Container-level attribute. + Version of the schema the FieldPath is written in terms of, defaults to "v1". + fieldPath: str, default is Undefined, required. + A Container-level attribute. + Path of the field to select of an object. + """ + + apiVersion?: str = "v1" + fieldPath: str + +type Unit = units.NumberMultiplier +schema ResourceFieldSelector: + """ ResourceFieldSelector represents container resources (cpu, memory) and their output format. + + Attributes + ---------- + containerName: str, default is Undefined, required for volumes, optional for env vars. + A Container-level attribute. + resource: str, default is Undefined, required. + A Container-level attribute. + Resource to select. + divisor: int | Unit, default is 1, optional. + A Container-level attribute. + Specifies the output format of the exposed resources, defaults to 1 + """ + containerName?: str + resource: str + divisor?: int | Unit = 1 + +schema EnvFromSource: + """ EnvFromSource represents the source of a set of ConfigMaps or Secrets. + + Attributes + ---------- + configMapRef: str, default is Undefined, optional. + A Container-level attribute. + The ConfigMap name to select from. + secretRef: str, default is Undefined, optional. + A Container-level attribute. + The Secret name to select from. + """ + + configMapRef?: str + secretRef?: str + + check: + not configMapRef or not secretRef, "can not set configMapRef and secretRef in env at the same time" + configMapRef or secretRef, "must specify one of: `configMapRef` or `secretRef`" diff --git a/konfig/models/kube/frontend/container/lifecycle/lifecycle.k b/konfig/models/kube/frontend/container/lifecycle/lifecycle.k new file mode 100644 index 00000000..af27657a --- /dev/null +++ b/konfig/models/kube/frontend/container/lifecycle/lifecycle.k @@ -0,0 +1,36 @@ +import models.kube.frontend.container.probe as p + +schema Lifecycle: + """ Lifecycle describes actions that the management system should take in response + to container lifecycle events. + + Attributes + ---------- + preStop: p.Exec|p.Http, default is Undefined, optional. + A Container-level attribute. + The PreStop action is called immediately before a container is terminated. + postStart: p.Exec|p.Http, default is Undefined, optional. + A Container-level attribute. + The PostStart action is called immediately after a container is created. + + Examples + -------- + import models.kube.frontend.container.lifecycle as lc + import models.kube.frontend.container.probe as p + + p = lc.Lifecycle { + preStop = p.Exec { + command = [ + "timeout" + "--signal=9" + "1800s" + "sh" + "-c" + "bash -x /tmp/image-builder/boot/boot.sh" + ] + } + } + """ + + preStop?: p.Exec | p.Http + postStart?: p.Exec | p.Http diff --git a/konfig/models/kube/frontend/container/port/container_port.k b/konfig/models/kube/frontend/container/port/container_port.k new file mode 100644 index 00000000..09862421 --- /dev/null +++ b/konfig/models/kube/frontend/container/port/container_port.k @@ -0,0 +1,31 @@ +schema ContainerPort: + """ ContainerPort represents a network port in a single container. + + Attributes + ---------- + name: str, default is Undefined, optional. + If specified, this must be an IANA_SVC_NAME and unique within the pod. + Each named port in a pod must have a unique name. + Name for the port that can be referred to by services. + protocol: "TCP" | "UDP" | "SCTP", default is "TCP", required. + A Container-level attribute. + The protocol for port. Must be UDP, TCP or SCTP. Default is TCP. + containerPort: int, default is Undefined, required. + A Container-level attribute. + The number of port to expose on the container's IP address. + + Examples + -------- + p = ContainerPort { + name = "test" + protocol = "TCP" + containerPort = 8080 + } + """ + + name?: str + protocol: "TCP" | "UDP" | "SCTP" = "TCP" + containerPort: int + + check: + 1 <= containerPort <= 65535, "containerPort must be between 1 and 65535, inclusive" diff --git a/konfig/models/kube/frontend/container/probe/probe.k b/konfig/models/kube/frontend/container/probe/probe.k new file mode 100644 index 00000000..dbbf6eda --- /dev/null +++ b/konfig/models/kube/frontend/container/probe/probe.k @@ -0,0 +1,104 @@ +schema Probe: + """ Probe describes a health check to be performed against a container + to determine whether it is alive or ready to receive traffic. + + Attributes + ---------- + handler: Exec|Http|Tcp, default is Undefined, required. + A Container-level attribute. + The action taken to determine the health of a container. + initialDelaySeconds: int, default is Undefined, optional. + A Container-level attribute. + The length of time before health checking is activated. In seconds. + timeoutSeconds: int, default is Undefined, optional. + A Container-level attribute. + The length of time before health checking times out. In seconds. + periodSeconds: int, default is 10, optional. + A Container-level attribute. + How often (in seconds) to perform the probe. + successThreshold: int, default is Undefined, optional. + A Container-level attribute. + Minimum consecutive successes for the probe to be considered successful after having failed. + failureThreshold: int, default is Undefined, optional. + A Container-level attribute. + Minimum consecutive failures for the probe to be considered failed after having succeeded. + + Examples + -------- + import models.kube.frontend.container.probe as p + + probe = p.Probe { + handler = p.Http { + path = "/healthz" + } + initialDelaySeconds = 10 + } + """ + + handler: Exec | Http | Tcp + + initialDelaySeconds?: int + timeoutSeconds?: int + periodSeconds?: int = 10 + successThreshold?: int + failureThreshold?: int + + check: + initialDelaySeconds >= 0 if initialDelaySeconds, "initialDelaySeconds must be greater than or equal to 0" + timeoutSeconds >= 0 if timeoutSeconds, "timeoutSeconds must be greater than or equal to 0" + periodSeconds >= 0 if periodSeconds, "periodSeconds must be greater than or equal to 0" + successThreshold >= 0 if successThreshold, "successThreshold must be greater than or equal to 0" + failureThreshold >= 0 if failureThreshold, "failureThreshold must be greater than or equal to 0" + +schema Exec: + """ Exec describes a "run in container" action. + + Attributes + ---------- + command: [str], default is Undefined, required. + A Container-level attribute. + The command line to execute inside the container. + """ + + command: [str] + + check: + len(command) > 0, "command must be specified" + +schema Http: + """ Http describes an action based on HTTP Get requests. + + Attributes + ---------- + path: str, default is Undefined, required. + A Container-level attribute. + The Path to access on the HTTP server. e.g /healthz + port: int, default is Undefined, required. + A Container-level attribute. + The Number of the port to access on the container. + scheme: "HTTP" | "HTTPS", default is "HTTP", required. + A Container-level attribute. + Scheme to use for connecting to the host, defaults to HTTP. + """ + + path: str + port: int + scheme: "HTTP" | "HTTPS" = "HTTP" + + check: + 1 <= port <= 65535, "http port must be between 1 and 65535, inclusive" + +schema Tcp: + """ Tcp describes an action based on opening a socket. + + Attributes + ---------- + tcpSocket: int, default is Undefined, required. + A Container-level attribute. + The TCP socket port to connect to. + """ + + tcpSocket: int + + check: + tcpSocket >= 1 and tcpSocket <= 65535, "tcpSocket must be between 1 and 65535, inclusive" diff --git a/konfig/models/kube/frontend/ingress/ingress.k b/konfig/models/kube/frontend/ingress/ingress.k new file mode 100644 index 00000000..638cf0e6 --- /dev/null +++ b/konfig/models/kube/frontend/ingress/ingress.k @@ -0,0 +1,43 @@ +import models.kube.frontend.common +import k8s.api.networking.v1 as networkingv1 + +schema Ingress(common.Metadata): + """Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. + An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc. + + Attributes + ---------- + rules: [networkingv1.IngressRule], default is Undefined, optional + A list of host rules used to configure the Ingress. If unspecified, or no rule matches, all traffic is sent to the default backend. + tls: [networkingv1.IngressTLS], default is Undefined, optional + TLS configuration. Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI. + + Examples + -------- + ingress.Ingress { + name = "example-ingress" + rules = [ + { + host = "your-domain.com" + http.paths = [ + { + path = "/apple" + pathType = "Prefix" + backend.service: { + name = "app-service" + port.number = 5678 + } + } + ] + } + ] + tls = [ + { + hosts = ["your-domain.com"] + secretName = "example-ingress-tls" + } + ] + } + """ + rules?: [networkingv1.IngressRule] + tls?: [networkingv1.IngressTLS] diff --git a/konfig/models/kube/frontend/job.k b/konfig/models/kube/frontend/job.k new file mode 100644 index 00000000..4d45c1c0 --- /dev/null +++ b/konfig/models/kube/frontend/job.k @@ -0,0 +1,114 @@ +import k8s.apimachinery.pkg.apis.meta.v1 as metav1 +import models.kube.frontend.configmap +import models.kube.frontend.container +import models.kube.frontend.serviceaccount as sa +import models.kube.frontend.sidecar as s +import models.kube.frontend.strategy +import models.kube.frontend.volume + +schema Job: + """ + Job is the common user interface for one-time jobs, which is defined by Kubernetes Job. + Job supports reliable parallel execution of Pods. + + Attributes + ---------- + activeDeadlineSeconds: int, default is Undefined, optional. + Specifies the duration in seconds relative to the startTime that the job may be active + before the system tries to terminate it; value must be positive integer + backoffLimit: int, default is 6, optional. + Specifies the number of retries before marking this job failed. Defaults to 6 + completionMode: "NonIndexed" | "Indexed", default is NonIndexed, optional + CompletionMode specifies how Pod completions are tracked. It can be `NonIndexed` (default) or `Indexed`. + completions: int, default is Undefined, optional. + Specifies the desired number of successfully finished pods the job should be run with. + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + manualSelector: bool, default is Undefined, optional. + manualSelector controls generation of pod labels and pod selectors. + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector + parallelism: int, default is Undefined, optional. + Specifies the maximum desired number of pods the job should run at any given time. + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + suspend: bool, default is Undefined, optional + Suspend specifies whether the Job controller should create Pods or not. + ttlSecondsAfterFinished: int, default is Undefined, optional. + ttlSecondsAfterFinished limits the lifetime of a Job that has finished execution (either Complete or Failed). + selector: {str:str}, default is Undefined, optional. + A label query over pods that should match the pod count. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + podMetadata: metav1.ObjectMeta, default is Undefined, optional. + PodMetadata is metadata that all persisted resources must have, which includes all objects users must create. + labels: {str:str}, default is Undefined, optional. + Labels is a map of string keys and values that can be used to organize and categorize (scope and select) objects. + More info: http://kubernetes.io/docs/user-guide/labels + annotations: {str:str}, default is Undefined, optional. + Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. + More info: http://kubernetes.io/docs/user-guide/annotations + restartPolicy: "Never" | "OnFailure", default is Never, optional. + Restart policy for all containers within the pod. One of Always, OnFailure, Never. + Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy + mainContainer: container.Main, default is Undefined, required. + MainContainer describes the main container configuration that is expected to be run on the host. + image: str, default is Undefined, required. + Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + schedulingStrategy: strategy.SchedulingStrategy, default is Undefined, optional. + SchedulingStrategy represents scheduling strategy. + sidecarContainers: [s.Sidecar], default is Undefined, optional. + SidecarContainers describes the list of sidecar container configuration that is expected to be run on the host. + initContainers: [s.Sidecar], default is Undefined, optional. + InitContainers describes the list of sidecar container configuration that is expected to be run on the host. + needNamespace: bool, default is True, optional. + NeedNamespace mark server is namespace scoped or not. + volumes: [volume.Volume], default is Undefined, optional. + Volumes represents a named volume and corresponding mounts in containers. + configMaps: [configmap.ConfigMap], default is Undefined, optional. + ConfigMaps is a list of ConfigMap which holds configuration data for server to consume. + serviceAccount: sa.ServiceAccount, default is Undefined, optional. + ServiceAccount is used to run this pod. + + Examples + -------- + import models.kube.frontend + + jobConfiguration: frontend.Job { + # main container + mainContainer = container.Main { + name = "pi" + command = ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + } + image = "perl" + } + """ + + # subset of batchv1.JobSpec + activeDeadlineSeconds?: int + backoffLimit?: int = 6 + completionMode?: "NonIndexed" | "Indexed" = "NonIndexed" + completions?: int + manualSelector?: bool + parallelism?: int + suspend?: bool + ttlSecondsAfterFinished?: int + selector?: {str:str} + + # subset of corev1.PodTemplateSpec + podMetadata?: metav1.ObjectMeta + labels?: {str:str} + annotations?: {str:str} + restartPolicy?: "Never" | "OnFailure" = "Never" + + # main container configuration + mainContainer: container.Main + image: str = option("image") + schedulingStrategy?: strategy.SchedulingStrategy = strategy.SchedulingStrategy {} + + # sidecar container configurations + sidecarContainers?: [s.Sidecar] + # init container configurations + initContainers?: [s.Sidecar] + + # other + needNamespace?: bool = True + volumes?: [volume.Volume] + configMaps?: [configmap.ConfigMap] + serviceAccount?: sa.ServiceAccount diff --git a/konfig/models/kube/frontend/rbac/cluster_role.k b/konfig/models/kube/frontend/rbac/cluster_role.k new file mode 100644 index 00000000..cbecfa17 --- /dev/null +++ b/konfig/models/kube/frontend/rbac/cluster_role.k @@ -0,0 +1,28 @@ +import k8s.api.rbac.v1 as rbacv1 +import models.kube.frontend.common +import models.kube.mixins + +schema ClusterRole(common.Metadata): + """ + rules: [PolicyRule], default is Undefined, optional + Rules holds all the PolicyRules for this ClusterRole + aggregationRule: AggregationRule, default is Undefined, optional + AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller. + """ + mixin [ + mixins.MetadataMixin + ] + + namespace = Undefined + + rules?: [rbacv1.PolicyRule] + + aggregationRule?: rbacv1.AggregationRule + + kubernetes: rbacv1.ClusterRole = rbacv1.ClusterRole { + metadata = metadata + rules = rules + aggregationRule = aggregationRule + } + + assert not namespace, "namespace is not allowed in ClusterRole" diff --git a/konfig/models/kube/frontend/rbac/cluster_role_binding.k b/konfig/models/kube/frontend/rbac/cluster_role_binding.k new file mode 100644 index 00000000..db39e6f9 --- /dev/null +++ b/konfig/models/kube/frontend/rbac/cluster_role_binding.k @@ -0,0 +1,28 @@ +import k8s.api.rbac.v1 as rbacv1 +import models.kube.frontend.common +import models.kube.mixins + +schema ClusterRoleBinding(common.Metadata): + """ + subjects: [Subject], default is Undefined, optional + Subjects holds references to the objects the role applies to. + roleRef: ClusterRole, default is Undefined, required + RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. + """ + mixin [ + mixins.MetadataMixin + ] + + namespace = Undefined + + subjects?: [rbacv1.Subject] + + roleRef: rbacv1.RoleRef + + kubernetes: rbacv1.ClusterRoleBinding = rbacv1.ClusterRoleBinding { + metadata = metadata + subjects = subjects + roleRef = roleRef + } + + assert not namespace, "namespace is not allowed in ClusterRoleBinding" \ No newline at end of file diff --git a/konfig/models/kube/frontend/rbac/role.k b/konfig/models/kube/frontend/rbac/role.k new file mode 100644 index 00000000..31eca9ef --- /dev/null +++ b/konfig/models/kube/frontend/rbac/role.k @@ -0,0 +1,19 @@ +import k8s.api.rbac.v1 as rbacv1 +import models.kube.frontend.common +import models.kube.mixins + +schema Role(common.Metadata): + """ + rules: [PolicyRule], default is Undefined, optional + Rules holds all the PolicyRules for this ClusterRole + """ + mixin [ + mixins.MetadataMixin + ] + + rules?: [rbacv1.PolicyRule] + + kubernetes: rbacv1.Role = rbacv1.Role { + metadata = metadata + rules = rules + } diff --git a/konfig/models/kube/frontend/rbac/role_binding.k b/konfig/models/kube/frontend/rbac/role_binding.k new file mode 100644 index 00000000..f3fb1ad3 --- /dev/null +++ b/konfig/models/kube/frontend/rbac/role_binding.k @@ -0,0 +1,24 @@ +import k8s.api.rbac.v1 as rbacv1 +import models.kube.frontend.common +import models.kube.mixins + +schema RoleBinding(common.Metadata): + """ + subjects: [Subject], default is Undefined, optional + Subjects holds references to the objects the role applies to. + roleRef: RoleRef, default is Undefined, required + RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. + """ + mixin [ + mixins.MetadataMixin + ] + + subjects?: [rbacv1.Subject] + + roleRef: rbacv1.RoleRef + + kubernetes: rbacv1.RoleBinding = rbacv1.RoleBinding { + metadata = metadata + subjects = subjects + roleRef = roleRef + } diff --git a/konfig/models/kube/frontend/resource/resource.k b/konfig/models/kube/frontend/resource/resource.k new file mode 100644 index 00000000..9d6f85d8 --- /dev/null +++ b/konfig/models/kube/frontend/resource/resource.k @@ -0,0 +1,33 @@ +import units + +type Unit = units.NumberMultiplier + +schema Resource: + """ Resource describes the compute resource requirements. + + Attributes + ---------- + cpu: int | Unit, default is 1, optional. + A Container-level attribute. + CPU, in cores, default 1 core. (500m = .5 cores) + memory: Unit, default is 1024Mi, optional. + A Container-level attribute. + Memory, in bytes, default 1024Mi. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + disk: Unit, default is 10Gi, optional. + A Container-level attribute. + Local disk storage, in bytes, default 10Gi. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024) + + Examples + -------- + import models.kube.frontend.resource as res + + res = res.Resource { + cpu = 2 + memory = 2048Mi + disk = 20Gi + } + """ + + cpu?: int | Unit = 1 + memory?: Unit = 1024Mi + disk?: Unit = 10Gi diff --git a/konfig/models/kube/frontend/resource/resource_requirements.k b/konfig/models/kube/frontend/resource/resource_requirements.k new file mode 100644 index 00000000..3404478c --- /dev/null +++ b/konfig/models/kube/frontend/resource/resource_requirements.k @@ -0,0 +1,35 @@ +schema ResourceRequirements: + """ ResourceRequirements describes the compute resource requirements.. + + Attributes + ---------- + limits: Resource, default is Undefined, required. + A Container-level attribute. + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + requests: Resource, default is Undefined, required. + A Container-level attribute. + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + + Examples + -------- + import models.kube.frontend.resource as res + + res = res.ResourceRequirements { + limits = { + cpu = 1 + memory = 1Gi + disk = 20Gi + } + requests = { + cpu = 500m + memory = 512Mi + disk = 10Gi + } + } + """ + + limits: Resource + requests: Resource diff --git a/konfig/models/kube/frontend/secret/secret.k b/konfig/models/kube/frontend/secret/secret.k new file mode 100644 index 00000000..8b873581 --- /dev/null +++ b/konfig/models/kube/frontend/secret/secret.k @@ -0,0 +1,34 @@ +import models.kube.frontend.common + +schema Secret(common.Metadata): + """Secret holds secret data of a certain type. + The total bytes of the values in the Data field + must be less than MaxSecretSize bytes. + + Attributes + ---------- + data: {str:str}, default is Undefined, optional + Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. + More info: https://kubernetes.io/docs/concepts/configuration/secret/#restriction-names-data + stringData: {str:str}, default is Undefined, optional + stringData allows specifying non-binary secret data in string form. + More info: https://kubernetes.io/docs/concepts/configuration/secret/#restriction-names-data + type: str, default is Undefined, optional + Used to facilitate programmatic handling of secret data. + More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types + + Examples + -------- + secret = Secret { + name = "my-secret" + namespace = "my-secret-namespace" + data = { + foo = bar + bar = foo + } + $type = "kubernetes.io/service-account-token" + } + """ + data?: {str:str} + stringData?: {str:str} + type?: str diff --git a/konfig/models/kube/frontend/server.k b/konfig/models/kube/frontend/server.k new file mode 100644 index 00000000..42a31135 --- /dev/null +++ b/konfig/models/kube/frontend/server.k @@ -0,0 +1,143 @@ +import k8s.apimachinery.pkg.apis.meta.v1 as metav1 +import models.kube.frontend.configmap +import models.kube.frontend.secret +import models.kube.frontend.service +import models.kube.frontend.serviceaccount as sa +import models.kube.frontend.ingress +import models.kube.frontend.container +import models.kube.frontend.volume +import models.kube.frontend.sidecar as s +import models.kube.frontend.strategy +import models.kube.frontend.storage + +schema Server: + """Server is abstaction of Deployment and StatefulSet. + + Attributes + ---------- + name: str, default is Undefined, optional. + The name of the workload and service. + If not defined, a generated name ("{__META_APP_NAME}-{__META_ENV_TYPE_NAME}") will be used. + The value of __META_APP_NAME will be extracted from the value of the "name" defined in project.yaml, + and the value of __META_ENV_TYPE_NAME will be extracted from the value of the "name" defined in stack.yaml. + workloadType: "Deployment" | "StatefulSet", default is "Deployment", required. + Application workload type, default to 'Deployment' + renderType: "Server" | "KubeVelaApplication", default is "Server", optional. + Application render type, default to 'Server' + replicas: int, default is 1, required. + Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1. + image: str, default is Undefined, required. + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + schedulingStrategy: strategy.SchedulingStrategy, default is Undefined, required. + SchedulingStrategy represents scheduling strategy. + mainContainer: container.Main, default is Undefined, required. + MainContainer describes the main container configuration that is expected to be run on the host. + sidecarContainers: [s.Sidecar], default is Undefined, optional. + SidecarContainers describes the list of sidecar container configuration that is expected to be run on the host. + initContainers: [s.Sidecar], default is Undefined, optional. + InitContainers describes the list of sidecar container configuration that is expected to be run on the host. + useBuiltInLabels: bool, default is False, optional. + UseBuiltInLabels indicates use built-in labels or not. + labels: {str:str}, default is Undefined, optional. + Labels is a map of string keys and values that can be used to organize and categorize (scope and select) objects. + More info: http://kubernetes.io/docs/user-guide/labels + annotations: {str:str}, default is Undefined, optional + Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. + More info: http://kubernetes.io/docs/user-guide/annotations + useBuiltInSelector: bool, default is False, optional. + UseBuiltInSelector indicates use built-in selector or not. + selector: {str:str}, default is Undefined, optional. + Label selector for pods. Existing ReplicaSets/ whose pods are selected by this will be the ones affected by this deployment. + podMetadata: metav1.ObjectMeta, default is Undefined, optional. + PodMetadata is metadata that all persisted resources must have, which includes all objects users must create. + volumes: [volume.Volume], default is Undefined, optional. + Volumes represents a named volume and corresponding mounts in containers. + needNamespace: bool, default is True, optional. + NeedNamespace mark server is namespace scoped or not. + enableMonitoring: bool, default is False, optional. + EnableMonitoring mark server is enable monitor or not. + configMaps: [configmap.ConfigMap], default is Undefined, optional. + ConfigMaps is a list of ConfigMap which holds configuration data for server to consume. + secrets: [secret.Secret], default is Undefined, optional. + Secrets is a list of Secret which hold secret data of a certain type. + services: [service.Service], default is Undefined, optional. + Services is a list of Service which partition a single Kubernetes cluster into multiple virtual clusters. + ingresses: [ingress.Ingress], default is Undefined, optional. + Ingresses is a list of Ingress which is collection of rules that allow inbound connections to reach the endpoints defined by a backend. + serviceAccount: sa.ServiceAccount, default is Undefined, optional. + ServiceAccount is used to run this pod. + + Examples + -------- + import models.kube.frontend + import models.kube.frontend.container + import models.kube.templates.resource as res_tpl + + appConfiguration: frontend.Server { + mainContainer = container.Main { + name = "php-redis" + env = [ + { + name = "GET_HOSTS_FROM" + value = "dns" + } + ] + ports = [{containerPort = 80}] + } + selector = { + tier = "frontend" + } + podMetadata.labels: { + tier = "frontend" + } + schedulingStrategy.resource = res_tpl.tiny + } + """ + + # workload name + name?: str + + # Application workload type, default to 'Deployment' + workloadType: "Deployment" | "StatefulSet" = "Deployment" + + # Application render type, default to 'Server' + renderType?: "Server" | "KubeVelaApplication" = "Server" + + # Application replicas + replicas: int = option("replicas") or 1 + + # Main container image + image: str = option("image") + # Main container resource + schedulingStrategy: strategy.SchedulingStrategy = strategy.SchedulingStrategy {} + + # Main container configuration + mainContainer: container.Main + # Sidecar container configurations + sidecarContainers?: [s.Sidecar] + # Init container configurations + initContainers?: [s.Sidecar] + + # Workload configuration + useBuiltInLabels?: bool = True + labels?: {str:str} + annotations?: {str:str} + useBuiltInSelector?: bool = True + selector?: {str:str} + podMetadata?: metav1.ObjectMeta + volumes?: [volume.Volume] + + # Other configurations + needNamespace?: bool = True + enableMonitoring?: bool = False + + configMaps?: [configmap.ConfigMap] + secrets?: [secret.Secret] + services?: [service.Service] + ingresses?: [ingress.Ingress] + serviceAccount?: sa.ServiceAccount + + # app cloud resource + storage?: storage.ObjectStorage + database?: storage.DataBase diff --git a/konfig/models/kube/frontend/service/service.k b/konfig/models/kube/frontend/service/service.k new file mode 100644 index 00000000..44f40360 --- /dev/null +++ b/konfig/models/kube/frontend/service/service.k @@ -0,0 +1,80 @@ +import models.kube.frontend.common +import k8s.api.core.v1 as corev1 + +schema Service(common.Metadata): + """Service are Kubernetes objects which partition a single Kubernetes cluster into multiple virtual clusters. + More info: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#Service + + Attributes + ---------- + ports: [{str:}], default is Undefined, optional. + The list of ports that are exposed by this service. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + selector: {str:str}, default is Undefined, optional. + Route service traffic to pods with label keys and values matching this selector. + More info: https://kubernetes.io/docs/concepts/services-networking/service/ + type: str, default is "ClusterIP", optional. + determines how the Service is exposed. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + clusterIP: str, default is None, optional. + clusterIP is the IP address of the service and is usually assigned randomly by the master. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + externalIPs: [str], default is Undefined, optional + externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. + externalName: str, default is Undefined, optional + externalName is the external reference that discovery mechanisms will return as an alias for this service (e.g. a DNS CNAME record). + externalTrafficPolicy: str, default is Undefined, optional + externalTrafficPolicy denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. + healthCheckNodePort: int, default is Undefined, optional + healthCheckNodePort specifies the healthcheck nodePort for the service. + ipFamilyPolicy: str, default is Undefined, optional + ipFamilyPolicy represents the dual-stack-ness requested or required by this Service, and is gated by the "IPv6DualStack" feature gate. + loadBalancerIP: str, default is Undefined, optional + Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. + loadBalancerSourceRanges: [str], default is Undefined, optional + If specified and supported by the platform, this will restrict traffic through the cloud-provider load-balancer will be restricted to the specified client IPs. + This field will be ignored if the cloud-provider does not support the feature. + More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/ + ports: [corev1.ServicePort], default is Undefined, optional + The list of ports that are exposed by this service. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + publishNotReadyAddresses: bool, default is Undefined, optional + publishNotReadyAddresses indicates that any agent which deals with endpoints for this Service should disregard any indications of ready/not-ready. + sessionAffinity: str, default is Undefined, optional + Supports "ClientIP" and "None". Used to maintain session affinity. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + sessionAffinityConfig: {str:}, default is Undefined, optional + sessionAffinityConfig contains the configurations of session affinity. + + Examples + -------- + service = Service { + name = "my-service-name" + namespace = "my-service-name" + labels.env = "dev" + ports = [ + { + name = "grpc-xds" + port = 15010 + } + { + name = "https-xds" + port = 15011 + } + ] + } + """ + selector?: {str:str} + ports?: [corev1.ServicePort] + clusterIP?: str + type?: str + externalIPs?: [str] + externalName?: str + externalTrafficPolicy?: str + healthCheckNodePort?: int + ipFamilyPolicy?: str + loadBalancerIP?: str + loadBalancerSourceRanges?: [str] + publishNotReadyAddresses?: bool + sessionAffinity?: str + sessionAffinityConfig?: {str:} diff --git a/konfig/models/kube/frontend/serviceaccount/service_account.k b/konfig/models/kube/frontend/serviceaccount/service_account.k new file mode 100644 index 00000000..00aff4e6 --- /dev/null +++ b/konfig/models/kube/frontend/serviceaccount/service_account.k @@ -0,0 +1,45 @@ +import models.kube.frontend.common + +schema ServiceAccount(common.Metadata): + """A service account provides an identity for processes that run in a Pod. + ServiceAccount binds together: + - a name, understood by users, and perhaps by peripheral systems, for an identity + - a principal that can be authenticated and authorized + - a set of secrets + More info: https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/service-account-v1/#ServiceAccount + + Attributes + ---------- + imagePullSecrets: [{str:str}], default is Undefined, optional. + ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. + More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod + secrets: [{str:str}], default is Undefined, optional. + Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. + More info: https://kubernetes.io/docs/concepts/configuration/secret + + Examples + -------- + my_service_account = ServiceAccount { + name: "my-service-account" + namespace = "my-service-account-namespace" + labels: { + tier: "monitoring" + } + imagePullSecrets: [ + { + name: "my-secret" + } + ] + secrets: [ + { + name: "my-secret" + } + ] + } + """ + + imagePullSecrets?: [{str:str}] + secrets?: [{str:str}] + + check: + name, "name must be specified and can't be empty or None or Undefined" diff --git a/konfig/models/kube/frontend/sidecar/sidecar.k b/konfig/models/kube/frontend/sidecar/sidecar.k new file mode 100644 index 00000000..76b9a1ae --- /dev/null +++ b/konfig/models/kube/frontend/sidecar/sidecar.k @@ -0,0 +1,89 @@ +import models.kube.frontend.container.probe as p +import models.kube.frontend.container.env as e +import models.kube.frontend.container.port as cp +import models.kube.frontend.container.lifecycle as lc +import models.kube.frontend.resource as res + +schema Sidecar: + """ Sidecar describes the sidecar container configuration that is expected to be run on the host. + + Attributes + ---------- + name: str, default is Undefined, required. + A Container-level attribute. + The container name. Each container in a pod must have a unique name. + command: [str], default is Undefined, optional. + A Container-level attribute. + The startup command of main process. The image's entrypoint is used if this is not provided. + args: [str], default is Undefined, optional. + A Container-level attribute. + The startup arguments of main process. The image's cmd is used if this is not provided. + env: [e.Env], default is Undefined, optional. + A Container-level attribute. + List of environment variables in the container. + envFrom: [e.EnvFromSource], default is Undefined, optional + A Container-level attribute. + List of sources to populate environment variables in the container. + image: str, default is Undefined, required + A Container-level attribute. + Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + livenessProbe: p.Probe, default is Undefined, optional. + A Container-level attribute. + The probe to check whether container is live or not. + readinessProbe: p.Probe, default is Undefined, optional. + A Container-level attribute. + The probe to check whether container is ready or not. + startupProbe: p.Probe, default is Undefined, optional. + A Container-level attribute. + The probe to indicates that the Pod has successfully initialized. + resource: str | res.Resource, default is "1 0: + ClusterRoleBinding += [r.kubernetes for r in rbac.ClusterRoleBinding.instances()] + if len(rbac.ClusterRole.instances()) > 0: + ClusterRole += [r.kubernetes for r in rbac.ClusterRole.instances()] + if len(rbac.RoleBinding.instances()) > 0: + RoleBinding += [r.kubernetes for r in rbac.RoleBinding.instances()] + if len(rbac.Role.instances()) > 0: + Role += [r.kubernetes for r in rbac.Role.instances()] +} + +# k8s +__k8s__: resource.ResourceMapping = { + Service += corev1.Service.instances() + ServiceAccount += corev1.ServiceAccount.instances() +} + +# merge resource map +__array_of_resource_map___: [resource.ResourceMapping] = [ + _inst?.kubernetes for _inst in __renderBackendInstances__ if _inst?.kubernetes +] | [__rbac_map__] | [__k8s__] + +__resource_map_original___: {str: []} = { + _kind += [r for key, r in _res] \ + for _index, _resource_map in __array_of_resource_map___ \ + for _kind, _res in _resource_map if _kind not in ["__settings__"] +} + +# remove duplicates +__resource_map___: {str: []} = {kind = remove_duplicated_iter(res_list, checkIdentical) for kind, res_list in __resource_map_original___} + +# kubernetes id: apiVersion:Kind:Namespace:Name +getId = lambda _resource { + _resource.apiVersion + ":" + _resource.kind + ":" + (_resource.metadata.namespace + ":" if _resource.metadata.namespace else "") + _resource.metadata.name +} + +_output = { + _kind: [_resource for _resource in _res] \ + for _kind, _res in __resource_map___ +} +manifestsResourceMap(_output) diff --git a/konfig/models/kube/resource/resource.k b/konfig/models/kube/resource/resource.k new file mode 100644 index 00000000..899c902d --- /dev/null +++ b/konfig/models/kube/resource/resource.k @@ -0,0 +1,3 @@ +schema ResourceMapping: + [str]: any + diff --git a/konfig/models/kube/resource/resourceorder.k b/konfig/models/kube/resource/resourceorder.k new file mode 100644 index 00000000..957945da --- /dev/null +++ b/konfig/models/kube/resource/resourceorder.k @@ -0,0 +1,39 @@ +kubernetesOrders: [str] = [ + "ClusterRole", + "ClusterRoleList", + "ClusterRoleBinding", + "ClusterRoleBindingList", + "CustomResourceDefinition", + "Namespace", + "NetworkPolicy", + "ResourceQuota", + "LimitRange", + "PodSecurityPolicy", + "PodDisruptionBudget", + "ServiceAccount", + "Secret", + "SecretList", + "ConfigMap", + "CustomResource", + "StorageClass", + "PersistentVolume", + "PersistentVolumeClaim", + "Role", + "RoleList", + "RoleBinding", + "RoleBindingList", + "Service", + "DaemonSet", + "Pod", + "ReplicationController", + "ReplicaSet", + "Deployment", + "HorizontalPodAutoscaler", + "StatefulSet", + "Job", + "CronJob", + "Ingress", + "APIService", + "ValidatingWebhookConfiguration" +] + diff --git a/konfig/models/kube/templates/resource.k b/konfig/models/kube/templates/resource.k new file mode 100644 index 00000000..62463cd4 --- /dev/null +++ b/konfig/models/kube/templates/resource.k @@ -0,0 +1,49 @@ +import models.kube.frontend.resource as res + +tiny = res.Resource { + cpu = 100m + memory = 100Mi + disk = 1Gi +} + +small = res.Resource { + cpu = 1 + memory = 2Gi + disk = 20Gi +} + +medium = res.Resource { + cpu = 2 + memory = 4Gi + disk = 35Gi +} + +medium100G = res.Resource { + cpu = 2 + memory = 4Gi + disk = 100Gi +} + +large = res.Resource { + cpu = 4 + memory = 8Gi + disk = 70Gi +} + +large100G = res.Resource { + cpu = 4 + memory = 8Gi + disk = 100Gi +} + +large2X32G40G = res.Resource { + cpu = 8 + memory = 32Gi + disk = 40Gi +} + +large4X = res.Resource { + cpu = 16 + memory = 32Gi + disk = 20Gi +} diff --git a/konfig/models/kube/utils/application_builder.k b/konfig/models/kube/utils/application_builder.k new file mode 100644 index 00000000..e74d8382 --- /dev/null +++ b/konfig/models/kube/utils/application_builder.k @@ -0,0 +1,34 @@ +import models.kube.metadata + +schema ApplicationBuilder: + """ApplicationBuilder contains the workload labels, selector and environments about the application + + Reference from: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ + """ + labels: {str:str} = { + "app.kubernetes.io/name": metadata.__META_APP_NAME + "app.kubernetes.io/env": metadata.__META_ENV_TYPE_NAME + "app.kubernetes.io/instance": "{}-{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower() + "cluster.x-k8s.io/cluster-name": metadata.__META_CLUSTER_NAME + } + + selector: {str:str} = labels + + envs: [{str:}] = [ + { + name: "APP_NAME" + value: metadata.__META_APP_NAME + } + { + name: "ENVIRONMENT" + value: metadata.__META_ENV_TYPE_NAME + } + { + name: "INSTANCE" + value: "{}-{}".format(metadata.__META_APP_NAME, metadata.__META_ENV_TYPE_NAME).lower() + } + { + name: "CLUSTER" + value: metadata.__META_CLUSTER_NAME + } + ] diff --git a/konfig/models/kube/utils/container_frontend2kube.k b/konfig/models/kube/utils/container_frontend2kube.k new file mode 100644 index 00000000..01eb86e0 --- /dev/null +++ b/konfig/models/kube/utils/container_frontend2kube.k @@ -0,0 +1,147 @@ +import k8s.api.core.v1 as kubev1 + +ContainerFrontend2Kube = lambda c -> {str:} { + # Kube variable + _kubeResource = Undefined + _kubeEnvList = Undefined + _kubeEnvFromList = Undefined + _kubePortList = Undefined + _kubeReadinessProbe = Undefined + _kubeLivenessProbe = Undefined + _kubeStartupProbe = Undefined + _kubeLifecycle = Undefined + + # Convert frontend resource to kube resource + if c?.resource: + _kubeResource = Str2ResourceRequirements(c.resource).result + + # Convert frontend env to kube env + if c?.env: + _kubeEnvList = [ + { + name: e.name + value: e.value + valueFrom: { + fieldRef: e.valueFrom.fieldRef + configMapKeyRef: { + name: e.valueFrom.configMapKeyRef.name + key: e.valueFrom.configMapKeyRef.key + } if e.valueFrom.configMapKeyRef else Undefined + secretKeyRef: { + name: e.valueFrom.secretKeyRef.name + key: e.valueFrom.secretKeyRef.key + } if e.valueFrom.secretKeyRef else Undefined + resourceFieldRef: { + containerName: e.valueFrom.resourceFieldRef.containerName + resource: e.valueFrom.resourceFieldRef.resource + if e.valueFrom.resourceFieldRef.divisor: + divisor: str(e.valueFrom.resourceFieldRef.divisor) + } if e.valueFrom.resourceFieldRef else Undefined + } if e.valueFrom else Undefined + } for e in c.env + ] + + # Convert frontend envFrom to kube envFrom + if c?.envFrom: + _kubeEnvFromList = [ + { + configMapRef: { + name: ef.configMapRef + } if ef.configMapRef else Undefined + secretRef: { + name: ef.secretRef + } if ef.secretRef else Undefined + } for ef in c.envFrom + ] + + # Convert kube ports to kube ports + if c?.ports: + _kubePortList = [ + { + name: port.name + containerPort: port.containerPort + protocol: port.protocol + } for port in c.ports + ] + + # Convert frontend probe to kube probe + if c?.readinessProbe or c?.livenessProbe or c?.startupProbe: + _iacProbes = [ + c?.readinessProbe + c?.livenessProbe + c?.startupProbe + ] + _kubeProbes = [kubev1.Probe { + exec: kubev1.ExecAction { + command: _iacProbe.handler.command + } if typeof(_iacProbe.handler) == "Exec" else Undefined + httpGet: kubev1.HTTPGetAction { + path: _iacProbe.handler.path + port: _iacProbe.handler.port + scheme: _iacProbe.handler.scheme + } if typeof(_iacProbe.handler) == "Http" else Undefined + tcpSocket: kubev1.TCPSocketAction { + port: _iacProbe.handler.tcpSocket + } if typeof(_iacProbe.handler) == "Tcp" else Undefined + failureThreshold: _iacProbe.failureThreshold + initialDelaySeconds: _iacProbe.initialDelaySeconds + periodSeconds: _iacProbe.periodSeconds + successThreshold: _iacProbe.successThreshold + timeoutSeconds: _iacProbe.timeoutSeconds + } if _iacProbe else Undefined for _iacProbe in _iacProbes] + _kubeReadinessProbe = _kubeProbes[0] + _kubeLivenessProbe = _kubeProbes[1] + _kubeStartupProbe = _kubeProbes[2] + + # Convert frontend lifecycle to kube lifecycle + if c?.lifecycle: + _kubeLifecycle = { + preStop: { + exec: kubev1.ExecAction { + command: c.lifecycle.preStop.command + } if typeof(c.lifecycle.preStop) == "Exec" else Undefined + httpGet: kubev1.HTTPGetAction { + path: c.lifecycle.preStop.path + port: c.lifecycle.preStop.port + scheme: c.lifecycle.preStop.scheme + } if typeof(c.lifecycle.preStop) == "Http" else Undefined + tcpSocket: kubev1.TCPSocketAction { + port: c.lifecycle.preStop.tcpSocket + } if typeof(c.lifecycle.preStop) == "Tcp" else Undefined + } if c.lifecycle.preStop else Undefined + postStart: { + exec: kubev1.ExecAction { + command: c.lifecycle.postStart.command + } if typeof(c.lifecycle.preStop) == "Exec" else Undefined + httpGet: kubev1.HTTPGetAction { + path: c.lifecycle.postStart.path + port: c.lifecycle.postStart.port + scheme: c.lifecycle.postStart.scheme + } if typeof(c.lifecycle.preStop) == "Http" else Undefined + tcpSocket: kubev1.TCPSocketAction { + port: c.lifecycle.postStart.tcpSocket + } if typeof(c.lifecycle.preStop) == "Tcp" else Undefined + } if c.lifecycle.postStart else Undefined + } + + # Construct result + { + name: c?.name + image: c?.image + imagePullPolicy: c?.imagePullPolicy if "imagePullPolicy" in c else Undefined + resources: _kubeResource + env: _kubeEnvList + envFrom: _kubeEnvFromList + command: c?.command + args: c?.args + ports: _kubePortList + securityContext: c?.securityContext + readinessProbe: _kubeReadinessProbe + livenessProbe: _kubeLivenessProbe + startupProbe: _kubeStartupProbe + lifecycle: _kubeLifecycle + workingDir: c?.workingDir + terminationMessagePath: c?.terminationMessagePath if "terminationMessagePath" in c else Undefined + terminationMessagePolicy: c?.terminationMessagePolicy if "terminationMessagePolicy" in c else Undefined + } +} diff --git a/konfig/models/kube/utils/metadata_builder.k b/konfig/models/kube/utils/metadata_builder.k new file mode 100644 index 00000000..47020541 --- /dev/null +++ b/konfig/models/kube/utils/metadata_builder.k @@ -0,0 +1,10 @@ +import models.kube.metadata + +MetadataBuilder = lambda config -> {str:} { + { + name: metadata.__META_APP_NAME + namespace: metadata.__META_APP_NAME + labels: config?.labels + annotations: config?.annotations + } +} diff --git a/konfig/models/kube/utils/str2resource_requirements.k b/konfig/models/kube/utils/str2resource_requirements.k new file mode 100644 index 00000000..8e11e122 --- /dev/null +++ b/konfig/models/kube/utils/str2resource_requirements.k @@ -0,0 +1,69 @@ +import models.kube.frontend.resource as res + +import regex + +schema Str2ResourceRequirements[resourcePara: str | res.Resource | res.ResourceRequirements]: + resourceStr?: str = resourcePara as str if typeof(resourcePara) == "str" else None + resourceUnit?: res.Resource = resourcePara as res.Resource if typeof(resourcePara) == "Resource" else None + resourceRequirementsUnit?: res.ResourceRequirements = resourcePara as res.ResourceRequirements if typeof(resourcePara) == "ResourceRequirements" else None + schedulingResourceItems: [str] = resourceStr?.split(",") or [] + + resource: [{str:}] = [{ + cpu = { + requests = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[0])?.strip() + limits = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[-1])?.strip() + } + } if "cpu" in item else ({ + memory = { + requests = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[0])?.strip() + limits = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[-1])?.strip() + } + } if "memory" in item else ({ + disk = { + requests = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[0])?.strip() + limits = (item.split("=")?[1] if len(item.split("=")) > 1 else item.split("<")?[-1])?.strip() + } + } if "disk" in item else Undefined)) for item in schedulingResourceItems] + + result: {str:} = { + requests = { + cpu = [r?.cpu?.requests for r in resource if r?.cpu?.requests]?[-1] or Undefined + memory = [r?.memory?.requests for r in resource if r?.memory?.requests]?[-1] or Undefined + "ephemeral-storage" = [r?.disk?.requests for r in resource if r?.disk?.requests]?[-1] or Undefined + } + limits = { + cpu = [r?.cpu?.limits for r in resource if r?.cpu?.limits]?[-1] or Undefined + memory = [r?.memory?.limits for r in resource if r?.memory?.limits]?[-1] or Undefined + "ephemeral-storage" = [r?.disk?.limits for r in resource if r?.disk?.limits]?[-1] or Undefined + } + } if resourceStr else { + requests = { + cpu = str(resourceRequirementsUnit.requests.cpu) + memory = str(resourceRequirementsUnit.requests.memory) + "ephemeral-storage" = str(resourceRequirementsUnit.requests.disk) if resourceRequirementsUnit.requests.disk else Undefined + } + limits = { + cpu = str(resourceRequirementsUnit.limits.cpu) + memory = str(resourceRequirementsUnit.limits.memory) + "ephemeral-storage" = str(resourceRequirementsUnit.limits.disk) if resourceRequirementsUnit.limits.disk else Undefined + } + } if resourceRequirementsUnit else { + requests = { + cpu = str(resourceUnit.cpu) + memory = str(resourceUnit.memory) + "ephemeral-storage" = str(resourceUnit.disk) if resourceUnit.disk else Undefined + } + limits = { + cpu = str(resourceUnit.cpu) + memory = str(resourceUnit.memory) + "ephemeral-storage" = str(resourceUnit.disk) if resourceUnit.disk else Undefined + } + } + + check: + regex.match(result?.requests?.cpu, r"^([+-]?[0-9.]+)([m]*[-+]?[0-9]*)$") if result?.requests?.cpu, "cpu must match specific regular expression" + regex.match(result?.requests?.memory, r"^([0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$") if result?.requests?.memory, "memory must match specific regular expression" + regex.match(result?.requests?["ephemeral-storage"], r"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$") if result?.requests?["ephemeral-storage"], "disk must match specific regular expression" + regex.match(result?.limits?.cpu, r"^([+-]?[0-9.]+)([m]*[-+]?[0-9]*)$") if result?.limits?.cpu, "cpu must match specific regular expression" + regex.match(result?.limits?.memory, r"^([0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$") if result?.limits?.memory, "memory must match specific regular expression" + regex.match(result?.limits?["ephemeral-storage"], r"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$") if result?.limits?["ephemeral-storage"], "disk must match specific regular expression" diff --git a/konfig/models/kube/utils/str2resource_requirements_test.k b/konfig/models/kube/utils/str2resource_requirements_test.k new file mode 100644 index 00000000..d4de3c2c --- /dev/null +++ b/konfig/models/kube/utils/str2resource_requirements_test.k @@ -0,0 +1,20 @@ +schema Str2ResourceRequirementsCase[case]: + value = case.value + expected = case.expected + result = Str2ResourceRequirements(value).result + assert result == expected, "test failed expected ${expected} got ${result}" + +schema TestStr2ResourceRequirements: + cases = [ + { + value = "cpu=100m,memory=100Mi,disk=1Gi" + expected = {'requests': {'cpu': '100m', 'memory': '100Mi', 'ephemeral-storage': '1Gi'}, 'limits': {'cpu': '100m', 'memory': '100Mi', 'ephemeral-storage': '1Gi'}} + } + { + value = "cpu=1,memory=2Gi,disk=20Gi" + expected = {'requests': {'cpu': '1', 'memory': '2Gi', 'ephemeral-storage': '20Gi'}, 'limits': {'cpu': '1', 'memory': '2Gi', 'ephemeral-storage': '20Gi'}} + } + ] + [ + Str2ResourceRequirementsCase(case) for case in cases + ] diff --git a/konfig/models/kube/utils/volume_patch.k b/konfig/models/kube/utils/volume_patch.k new file mode 100644 index 00000000..5e008387 --- /dev/null +++ b/konfig/models/kube/utils/volume_patch.k @@ -0,0 +1,17 @@ +import models.kube.frontend.volume + +VolumePatch = lambda volumes: [volume.Volume], containers: [{str:}] -> [{str:}] { + """VolumePatch patches volumes into _containers and returns the patched _container""" + [ + _container | { + volumeMounts = sum([[ + { + name: volume.name + mountPath: mount.path + subPath: mount.subPath + readOnly: mount.readOnly or Undefined + } for mount in volume.mounts if mount.container == _container.name or mount.container == "*" + ] for volume in volumes] if volumes else [], []) + } for _container in containers + ] if containers else Undefined +}