diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/image.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/image.cue index a324851c..ec500aa1 100644 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/image.cue +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/image.cue @@ -3,7 +3,10 @@ package v1alpha1 -import "strings" +import ( + "encoding/base64" + "strings" +) // Image defines the schema for OCI image reference used in Kubernetes PodSpec container image. #Image: { @@ -22,14 +25,14 @@ import "strings" // Spec: https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests. digest!: string - // Reference is the image address computed from repository, tag and digest - // in the format [REPOSITORY]:[TAG]@[DIGEST]. - reference: string - // PullPolicy defines the pull policy for the image. // By default, it is set to IfNotPresent. pullPolicy: *"IfNotPresent" | "Always" | "Never" + // Reference is the image address computed from repository, tag and digest + // in the format [REPOSITORY]:[TAG]@[DIGEST]. + reference: string + if digest != "" && tag != "" { reference: "\(repository):\(tag)@\(digest)" } @@ -46,3 +49,53 @@ import "strings" reference: "\(repository):latest" } } + +// ImagePullSecret is a generator for Kubernetes Secrets of type kubernetes.io/dockerconfigjson. +// Spec: https://kubernetes.io/docs/concepts/configuration/secret/#docker-config-secrets. +#ImagePullSecret: { + // Metadata is the Kubernetes object's metadata generated by Timoni. + meta=metadata: #Metadata + + // Registry is the hostname of the container registry in the format [HOST[:PORT_NUMBER]]. + registry!: string + + // Username is the username used to authenticate to the container registry. + username!: string + + // Password is the password used to authenticate to the container registry. + password!: string + + // Optional suffix used to generate the Secret name. + suffix: *"" | string + + let auth = base64.Encode(null, username+":"+password) + + // The object is a read-only struct that contains the generated + // Kubernetes Secret of type kubernetes.io/dockerconfigjson. + object: { + apiVersion: "v1" + kind: "Secret" + type: "kubernetes.io/dockerconfigjson" + metadata: { + name: meta.name + suffix + namespace: meta.namespace + labels: meta.labels + if meta.annotations != _|_ { + annotations: meta.annotations + } + } + stringData: { + ".dockerconfigjson": #""" + { + "auths": { + "\#(registry)": { + "username": "\#(username)", + "password": "\#(password)", + "auth": "\#(auth)" + } + } + } + """# + } + } +} diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/instance.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/instance.cue new file mode 100644 index 00000000..ad96b062 --- /dev/null +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/instance.cue @@ -0,0 +1,27 @@ +// Copyright 2023 Stefan Prodan +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import "strings" + +// InstanceName defines the schema for the name of a Timoni instance. +// The instance name is used as a Kubernetes label value and must be 63 characters or less. +#InstanceName: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MinRunes(1) & strings.MaxRunes(63) + +// InstanceNamespace defines the schema for the namespace of a Timoni instance. +// The instance namespace is used as a Kubernetes label value and must be 63 characters or less. +#InstanceNamespace: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MinRunes(1) & strings.MaxRunes(63) + +// InstanceOwnerReference defines the schema for Kubernetes labels used to denote ownership. +#InstanceOwnerReference: { + #Name: "instance.timoni.sh/name" + #Namespace: "instance.timoni.sh/namespace" +} + +// InstanceModule defines the schema for the Module of a Timoni instance. +#InstanceModule: { + url: string & =~"^((oci|file)://.*)$" + version: *"latest" | string + digest?: string +} diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/metadata.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/metadata.cue index 3ab30d60..58d029c4 100644 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/metadata.cue +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/metadata.cue @@ -6,10 +6,10 @@ package v1alpha1 import "strings" // Annotations defines the schema for Kubernetes object metadata annotations. -#Annotations: {[string & =~"^(([A-Za-z0-9][-A-Za-z0-9_./]*)?[A-Za-z0-9])?$" & strings.MaxRunes(63)]: string} +#Annotations: {[string & strings.MaxRunes(253)]: string} // Labels defines the schema for Kubernetes object metadata labels. -#Labels: {[string & =~"^(([A-Za-z0-9][-A-Za-z0-9_./]*)?[A-Za-z0-9])?$" & strings.MaxRunes(63)]: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MaxRunes(63)} +#Labels: {[string & strings.MaxRunes(253)]: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MaxRunes(63)} #StdLabelName: "app.kubernetes.io/name" #StdLabelVersion: "app.kubernetes.io/version" @@ -26,11 +26,11 @@ import "strings" // Name must be unique within a namespace. Is required when creating resources. // Name is primarily intended for creation idempotence and configuration definition. // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - name!: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MaxRunes(63) + name!: #InstanceName // Namespace defines the space within which each name must be unique. // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces - namespace!: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MaxRunes(63) + namespace!: #InstanceNamespace // Annotations is an unstructured key value map stored with a resource that may be // set to store and retrieve arbitrary metadata. diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/object.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/object.cue index 734ed397..1dcdb699 100644 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/object.cue +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/object.cue @@ -13,7 +13,7 @@ import "strings" // Namespace of the referent. namespace?: string & strings.MaxRunes(256) - // API version of the referent. + // API version of the referent. apiVersion?: string & strings.MaxRunes(256) // Kind of the referent. diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/resources.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/requirements.cue similarity index 85% rename from blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/resources.cue rename to blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/requirements.cue index d70b9737..d3b5573a 100644 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/resources.cue +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/requirements.cue @@ -14,13 +14,13 @@ import ( // MemoryQuantity is a string that is validated as a quantity of memory, such as 128Mi or 2Gi. #MemoryQuantity: string & =~"^[1-9]\\d*(Mi|Gi)$" -// ResourceRequirement describes the CPU and Memory resource requirements. +// ResourceRequirement defines the schema for the CPU and Memory resource requirements. #ResourceRequirement: { cpu?: #CPUQuantity memory?: #MemoryQuantity } -// ResourceRequirements describes the compute resource requirements. +// ResourceRequirements defines the schema for the compute resource requirements of a container. // More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/. #ResourceRequirements: { // Limits describes the maximum amount of compute resources allowed. diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/secrets.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/secrets.cue deleted file mode 100644 index 99587e9e..00000000 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/secrets.cue +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2023 Stefan Prodan -// SPDX-License-Identifier: Apache-2.0 - -package v1alpha1 - -import ( - "encoding/base64" -) - -// CertSecret is a generator for Kubernetes Secrets of type kubernetes.io/tls. -// Spec: https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets. -#CertSecret: { - // Metadata is the Kubernetes object's metadata generated by Timoni. - meta=metadata: #Metadata - - // Cert is the TLS certificate in PEM format. - cert!: string - - // Key is the TLS private key in PEM format. - key!: string - - // CA is the TLS certificate authority in PEM format. - ca?: string - - // The secret is a read-only field that contains the generated - // Kubernetes Secret of type kubernetes.io/tls. - secret: { - apiVersion: "v1" - kind: "Secret" - type: "kubernetes.io/tls" - metadata: meta - stringData: { - "tls.crt": cert - "tls.key": key - if ca != _|_ { - "ca.crt": ca - } - } - } -} - -// ImagePullSecret is a generator for Kubernetes Secrets of type kubernetes.io/dockerconfigjson. -// Spec: https://kubernetes.io/docs/concepts/configuration/secret/#docker-config-secrets. -#ImagePullSecret: { - // Metadata is the Kubernetes object's metadata generated by Timoni. - meta=metadata: #Metadata - - // Registry is the hostname of the container registry in the format [HOST[:PORT_NUMBER]]. - registry!: string - - // Username is the username used to authenticate to the container registry. - username!: string - - // Password is the password used to authenticate to the container registry. - password!: string - - let auth = base64.Encode(null, username+":"+password) - - // The secret is a read-only field that contains the generated - // Kubernetes Secret of type kubernetes.io/dockerconfigjson. - secret: { - apiVersion: "v1" - kind: "Secret" - type: "kubernetes.io/dockerconfigjson" - metadata: meta - stringData: { - ".dockerconfigjson": #""" - { - "auths": { - "\#(registry)": { - "username": "\#(username)", - "password": "\#(password)", - "auth": "\#(auth)" - } - } - } - """# - } - } -} diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/selector.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/selector.cue index 9c3a0f69..ed141f44 100644 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/selector.cue +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/selector.cue @@ -3,14 +3,12 @@ package v1alpha1 -import "strings" - // Selector defines the schema for Kubernetes Pod label selector used in Deployments, Services, Jobs, etc. #Selector: { // Name must be unique within a namespace. Is required when creating resources. // Name is primarily intended for creation idempotence and configuration definition. // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - #Name!: string & =~"^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$" & strings.MinRunes(1) & strings.MaxRunes(63) + #Name!: #InstanceName // Map of string keys and values that can be used to organize and categorize (scope and select) objects. // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/semver.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/semver.cue new file mode 100644 index 00000000..ecd1e397 --- /dev/null +++ b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/semver.cue @@ -0,0 +1,29 @@ +// Copyright 2023 Stefan Prodan +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + "strconv" + "strings" +) + +// SemVer validates the input version string and extracts the major and minor version numbers. +// When Minimum is set, the major and minor parts must be greater or equal to the minimum +// or a validation error is returned. +#SemVer: { + // Input version string in strict semver format. + #Version!: string & =~"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$" + + // Minimum is the minimum allowed MAJOR.MINOR version. + #Minimum: *"0.0.0" | string & =~"^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$" + + let minMajor = strconv.Atoi(strings.Split(#Minimum, ".")[0]) + let minMinor = strconv.Atoi(strings.Split(#Minimum, ".")[1]) + + major: int & >=minMajor + major: strconv.Atoi(strings.Split(#Version, ".")[0]) + + minor: int & >=minMinor + minor: strconv.Atoi(strings.Split(#Version, ".")[1]) +} diff --git a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/version.cue b/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/version.cue deleted file mode 100644 index 33f30000..00000000 --- a/blueprints/minimal/cue.mod/pkg/timoni.sh/core/v1alpha1/version.cue +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2023 Stefan Prodan -// SPDX-License-Identifier: Apache-2.0 - -package v1alpha1 - -import ( - "strconv" - "strings" -) - -// KubernetesVersion allows enforcing a minimum Kubernetes version. -#KubernetesVersion: { - // Version is the Kubernetes version in semver format, as reported by the cluster. - #Version!: string - - // Minimum is the minimum allowed Kubernetes version in semver format. - #Minimum!: string & =~ "^1\\.\\d+(\\.\\d+)?$" - - minimumMinor: strconv.Atoi(strings.Split(#Minimum, ".")[1]) - - minorVersion: int & >=minimumMinor - minorVersion: strconv.Atoi(strings.Split(#Version, ".")[1]) -} diff --git a/blueprints/minimal/templates/config.cue b/blueprints/minimal/templates/config.cue index 56e1d515..76d94973 100644 --- a/blueprints/minimal/templates/config.cue +++ b/blueprints/minimal/templates/config.cue @@ -12,7 +12,7 @@ import ( kubeVersion!: string // Using the kubeVersion you can enforce a minimum Kubernetes minor version. // By default, the minimum Kubernetes version is set to 1.20. - clusterVersion: timoniv1.#KubernetesVersion & {#Version: kubeVersion, #Minimum: "1.20"} + clusterVersion: timoniv1.#SemVer & {#Version: kubeVersion, #Minimum: "1.20.0"} // The moduleVersion is set from the user-supplied module version. // This field is used for the `app.kubernetes.io/version` label.