diff --git a/apis/v1alpha1/topologyspec.go b/apis/v1alpha1/topologyspec.go index 60cb78fa..8f185c8d 100644 --- a/apis/v1alpha1/topologyspec.go +++ b/apis/v1alpha1/topologyspec.go @@ -116,6 +116,10 @@ type Deployment struct { // mapping applied. // +optional Resources map[string]k8scorev1.ResourceRequirements `json:"resources"` + // Scheduling holds information about how the launcher pod(s) should be configured with respect + // to "scheduling" things (affinity/node selector/tolerations). + // +optional + Scheduling Scheduling `json:"scheduling"` // PrivilegedLauncher, when true, sets the launcher containers to privileged. By default, we do // our best to *not* need this/set this, and instead set only the capabilities we need, however // its possible that some containers launched by the launcher may need/want more capabilities, @@ -164,6 +168,18 @@ type Deployment struct { LauncherLogLevel string `json:"launcherLogLevel,omitempty"` } +// Scheduling holds information about how the launcher pod(s) should be configured with respect +// to "scheduling" things (affinity/node selector/tolerations). +type Scheduling struct { + // NodeSelector sets the node selector that will be configured on all launcher pods for this + // Topology. + // +optional + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // Tolerations is a list of Tolerations that will be set on the launcher pod spec. + // +optional + Tolerations []k8scorev1.Toleration `json:"tolerations"` +} + // ImagePull holds configurations relevant to how clabernetes launcher pods handle pulling // images. type ImagePull struct { diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index c2bc26b0..6d509bb9 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -240,6 +240,7 @@ func (in *Deployment) DeepCopyInto(out *Deployment) { (*out)[key] = *val.DeepCopy() } } + in.Scheduling.DeepCopyInto(&out.Scheduling) if in.PrivilegedLauncher != nil { in, out := &in.PrivilegedLauncher, &out.PrivilegedLauncher *out = new(bool) @@ -567,6 +568,36 @@ func (in *ReconcileHashes) DeepCopy() *ReconcileHashes { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Scheduling) DeepCopyInto(out *Scheduling) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scheduling. +func (in *Scheduling) DeepCopy() *Scheduling { + if in == nil { + return nil + } + out := new(Scheduling) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Topology) DeepCopyInto(out *Topology) { *out = *in diff --git a/assets/crd/clabernetes.containerlab.dev_configs.yaml b/assets/crd/clabernetes.containerlab.dev_configs.yaml index 440ca324..18fee0c2 100644 --- a/assets/crd/clabernetes.containerlab.dev_configs.yaml +++ b/assets/crd/clabernetes.containerlab.dev_configs.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: configs.clabernetes.containerlab.dev spec: group: clabernetes.containerlab.dev @@ -17,20 +17,26 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Config is an object that holds global clabernetes config information. - Note that this CR is expected to effectively be a global singleton -- that - is, there should be only *one* of these, and it *must* be named `clabernetes` - -- CRD metadata spec will enforce this (via x-validation rules). + description: |- + Config is an object that holds global clabernetes config information. Note that this CR is + expected to effectively be a global singleton -- that is, there should be only *one* of these, + and it *must* be named `clabernetes` -- CRD metadata spec will enforce this (via x-validation + rules). properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -42,8 +48,9 @@ spec: settings. properties: containerlabDebug: - description: ContainerlabDebug sets the `--debug` flag when invoking - containerlab in the launcher pods. This is disabled by default. + description: |- + ContainerlabDebug sets the `--debug` flag when invoking containerlab in the launcher pods. + This is disabled by default. type: boolean launcherImage: default: ghcr.io/srl-labs/clabernetes/clabernetes-launcher:latest @@ -52,18 +59,19 @@ spec: type: string launcherImagePullPolicy: default: IfNotPresent - description: LauncherImagePullPolicy sets the default launcher - image pull policy to use when spawning launcher deployments. + description: |- + LauncherImagePullPolicy sets the default launcher image pull policy to use when spawning + launcher deployments. enum: - IfNotPresent - Always - Never type: string launcherLogLevel: - description: 'LauncherLogLevel sets the launcher clabernetes worker - log level -- this overrides whatever is set on the controllers - env vars for this topology. Note: omitempty because empty str - does not satisfy enum of course.' + description: |- + LauncherLogLevel sets the launcher clabernetes worker log level -- this overrides whatever + is set on the controllers env vars for this topology. Note: omitempty because empty str does + not satisfy enum of course. enum: - disabled - critical @@ -72,12 +80,11 @@ spec: - debug type: string privilegedLauncher: - description: PrivilegedLauncher, when true, sets the launcher - containers to privileged. By default, we do our best to *not* - need this/set this, and instead set only the capabilities we - need, however its possible that some containers launched by - the launcher may need/want more capabilities, so this flag exists - for users to bypass the default settings and enable fully privileged + description: |- + PrivilegedLauncher, when true, sets the launcher containers to privileged. By default, we do + our best to *not* need this/set this, and instead set only the capabilities we need, however + its possible that some containers launched by the launcher may need/want more capabilities, + so this flag exists for users to bypass the default settings and enable fully privileged launcher pods. type: boolean resourcesByContainerlabKind: @@ -87,18 +94,23 @@ spec: requirements. properties: claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. \n This field - is immutable. It can only be set for containers." + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: Name must match the name of one entry - in pod.spec.resourceClaims of the Pod where this - field is used. It makes that resource available + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available inside a container. type: string required: @@ -115,8 +127,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -125,46 +138,53 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: '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. - Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + 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. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object - description: 'ResourcesByContainerlabKind is a mapping of container - lab kind -> type -> default resource settings. Note that a key - value of "default" in the inner map will apply the given resources - for any pod of that containerlab *kind*. For example: { "srl": - { "default": DEFAULT RESOURCES FOR KIND "srl", "ixr10": RESOURCES - FOR KIND "srl", TYPE "ixr10" } Given resources as above, a containerlab - node of kind "srl" and "type" ixr10" would get the specific - resources as allocated in the ixr10 key, whereas a containerlab - kind of "srl" and "type" unset or "ixr6" would get the "default" - resource settings. To apply global default resources, regardless - of containerlab kind/type, use the `resourcesDefault` field.' + description: |- + ResourcesByContainerlabKind is a mapping of container lab kind -> type -> default resource + settings. Note that a key value of "default" in the inner map will apply the given resources + for any pod of that containerlab *kind*. For example: + { + "srl": { + "default": DEFAULT RESOURCES FOR KIND "srl", + "ixr10": RESOURCES FOR KIND "srl", TYPE "ixr10" + } + Given resources as above, a containerlab node of kind "srl" and "type" ixr10" would get the + specific resources as allocated in the ixr10 key, whereas a containerlab kind of "srl" and + "type" unset or "ixr6" would get the "default" resource settings. To apply global default + resources, regardless of containerlab kind/type, use the `resourcesDefault` field. type: object resourcesDefault: - description: ResourcesDefault is the default set of resources - for clabernetes launcher pods. This is used only as a last option - if a Topology does not have resources, and there are no resources - for the given containerlab kind/type + description: |- + ResourcesDefault is the default set of resources for clabernetes launcher pods. This is used + only as a last option if a Topology does not have resources, and there are no resources for + the given containerlab kind/type properties: claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. type: string required: - name @@ -180,8 +200,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -190,11 +211,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: '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. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + 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. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object required: @@ -202,47 +223,44 @@ spec: - launcherImagePullPolicy type: object imagePull: - description: ImagePull holds configurations relevant to how clabernetes - launcher pods handle pulling images. + description: |- + ImagePull holds configurations relevant to how clabernetes launcher pods handle pulling + images. properties: criKindOverride: - description: CRIKindOverride allows for overriding the auto discovered - cri flavor of the cluster -- this may be useful if we fail to - parse the cri kind for some reason, or in mixed cri flavor clusters - -- however in the latter case, make sure that if you are using - image pull through that clabernetes workloads are only run on - the nodes of the cri kind specified here! + description: |- + CRIKindOverride allows for overriding the auto discovered cri flavor of the cluster -- this + may be useful if we fail to parse the cri kind for some reason, or in mixed cri flavor + clusters -- however in the latter case, make sure that if you are using image pull through + that clabernetes workloads are only run on the nodes of the cri kind specified here! enum: - containerd type: string criSockOverride: - description: CRISockOverride allows for overriding the path of - the CRI sock that is mounted in the launcher pods (if/when image - pull through mode is auto or always). This can be useful if, - for example, the CRI sock is in a "non-standard" location like - K3s which puts the containerd sock at `/run/k3s/containerd/containerd.sock` - rather than the "normal" (whatever that means) location of `/run/containerd/containerd.sock`. - The value must end with "containerd.sock" for now, in the future - maybe crio support will be added. + description: |- + CRISockOverride allows for overriding the path of the CRI sock that is mounted in the + launcher pods (if/when image pull through mode is auto or always). This can be useful if, + for example, the CRI sock is in a "non-standard" location like K3s which puts the containerd + sock at `/run/k3s/containerd/containerd.sock` rather than the "normal" (whatever that means) + location of `/run/containerd/containerd.sock`. The value must end with "containerd.sock" for + now, in the future maybe crio support will be added. pattern: (.*containerd\.sock) type: string dockerDaemonConfig: - description: DockerDaemonConfig allows for setting a default docker - daemon config for launcher pods with the specified secret. The - secret *must be present in the namespace of any given topology* - -- so if you are configuring this at the "global config" level, - ensure that you are deploying topologies into a specific namespace, - or have ensured there is a secret of the given name in every - namespace you wish to deploy a topology to. When set, insecure - registries config option is ignored as it is assumed you are - handling that in the given docker config. Note that the secret - *must* contain a key "daemon.json" -- as this secret will be - mounted to /etc/docker and docker will be expecting the config - at /etc/docker/daemon.json. + description: |- + DockerDaemonConfig allows for setting a default docker daemon config for launcher pods + with the specified secret. The secret *must be present in the namespace of any given + topology* -- so if you are configuring this at the "global config" level, ensure that you are + deploying topologies into a specific namespace, or have ensured there is a secret of the + given name in every namespace you wish to deploy a topology to. When set, insecure registries + config option is ignored as it is assumed you are handling that in the given docker config. + Note that the secret *must* contain a key "daemon.json" -- as this secret will be mounted to + /etc/docker and docker will be expecting the config at /etc/docker/daemon.json. type: string pullThroughOverride: - description: PullThroughOverride allows for overriding the image - pull through mode for this particular topology. + description: |- + PullThroughOverride allows for overriding the image pull through mode for this + particular topology. enum: - auto - always @@ -254,23 +272,24 @@ spec: suffix used when resolving services. type: string metadata: - description: Metadata holds "global" metadata -- that is, metadata - that is applied to all objects created by the clabernetes controller. + description: |- + Metadata holds "global" metadata -- that is, metadata that is applied to all objects created + by the clabernetes controller. properties: annotations: additionalProperties: type: string - description: Annotations holds key/value pairs that should be - set as annotations on clabernetes created resources. Note that - (currently?) there is no input validation here, but this data - must be valid kubernetes annotation data. + description: |- + Annotations holds key/value pairs that should be set as annotations on clabernetes created + resources. Note that (currently?) there is no input validation here, but this data must be + valid kubernetes annotation data. type: object labels: additionalProperties: type: string - description: Labels holds key/value pairs that should be set as - labels on clabernetes created resources. Note that (currently?) - there is no input validation here, but this data must be valid + description: |- + Labels holds key/value pairs that should be set as labels on clabernetes created resources. + Note that (currently?) there is no input validation here, but this data must be valid kubernetes label data. type: object type: object diff --git a/assets/crd/clabernetes.containerlab.dev_imagerequests.yaml b/assets/crd/clabernetes.containerlab.dev_imagerequests.yaml index 0fbe0fdd..1d39930d 100644 --- a/assets/crd/clabernetes.containerlab.dev_imagerequests.yaml +++ b/assets/crd/clabernetes.containerlab.dev_imagerequests.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: imagerequests.clabernetes.containerlab.dev spec: group: clabernetes.containerlab.dev @@ -17,19 +17,25 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: ImageRequest is an object that represents a request (from a launcher - pod) to pull an image on a given kubernetes node such that the image can - be "pulled through" into the launcher docker daemon. + description: |- + ImageRequest is an object that represents a request (from a launcher pod) to pull an image on a + given kubernetes node such that the image can be "pulled through" into the launcher docker + daemon. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -37,12 +43,14 @@ spec: description: ImageRequestSpec is the spec for a Config resource. properties: kubernetesNode: - description: KubernetesNode is the node where the launcher pod is - running and where the image should be pulled too. + description: |- + KubernetesNode is the node where the launcher pod is running and where the image should be + pulled too. type: string requestedImage: - description: RequestedImage is the image that the launcher pod wants - the controller to get pulled onto the specified node. + description: |- + RequestedImage is the image that the launcher pod wants the controller to get pulled onto + the specified node. type: string requestedImagePullSecrets: description: RequestedImagePullSecrets is a list of configured pull @@ -56,9 +64,9 @@ spec: image. type: string topologyNodeName: - description: TopologyNodeName is the name of the node in the topology - (i.e. the router name in a containerlab topology) that the image - is being requested for. + description: |- + TopologyNodeName is the name of the node in the topology (i.e. the router name in a + containerlab topology) that the image is being requested for. type: string required: - kubernetesNode @@ -70,15 +78,15 @@ spec: description: ImageRequestStatus is the status for a ImageRequest resource. properties: accepted: - description: Accepted indicates that the ImageRequest controller has - seen this image request and is going to process it. This can be - useful to let the requesting pod know that "yep, this is in the + description: |- + Accepted indicates that the ImageRequest controller has seen this image request and is going + to process it. This can be useful to let the requesting pod know that "yep, this is in the works, and i can go watch the cri images on this node now". type: boolean complete: - description: Complete indicates that the ImageRequest controller has - seen that the puller pod has done its job and that the image has - been pulled onto the requested node. + description: |- + Complete indicates that the ImageRequest controller has seen that the puller pod has done its + job and that the image has been pulled onto the requested node. type: boolean required: - accepted diff --git a/assets/crd/clabernetes.containerlab.dev_topologies.yaml b/assets/crd/clabernetes.containerlab.dev_topologies.yaml index 8cf79db2..26cb2867 100644 --- a/assets/crd/clabernetes.containerlab.dev_topologies.yaml +++ b/assets/crd/clabernetes.containerlab.dev_topologies.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: topologies.clabernetes.containerlab.dev spec: group: clabernetes.containerlab.dev @@ -21,19 +21,24 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: 'Topology is an object that holds information about a clabernetes - Topology -- that is, a valid topology file (ex: containerlab topology), - and any associated configurations.' + description: |- + Topology is an object that holds information about a clabernetes Topology -- that is, a valid + topology file (ex: containerlab topology), and any associated configurations. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -41,11 +46,11 @@ spec: description: TopologySpec is the spec for a Topology resource. properties: definition: - description: Definition defines the actual set of nodes (network ones, - not k8s ones!) that this Topology CR represents. Historically, and - probably most often, this means Topology holds a "normal" containerlab - topology file that will be "clabernetsified", however this could - also be a "kne" config, or perhaps others in the future. + description: |- + Definition defines the actual set of nodes (network ones, not k8s ones!) that this Topology + CR represents. Historically, and probably most often, this means Topology holds a "normal" + containerlab topology file that will be "clabernetsified", however this could also be a "kne" + config, or perhaps others in the future. properties: containerlab: description: Containerlab holds a valid containerlab topology. @@ -55,30 +60,31 @@ spec: type: string type: object deployment: - description: Deployment holds configurations relevant to how clabernetes - configures deployments that make up a given topology. + description: |- + Deployment holds configurations relevant to how clabernetes configures deployments that make + up a given topology. properties: containerlabDebug: - description: ContainerlabDebug sets the `--debug` flag when invoking - containerlab in the launcher pods. This is disabled by default. - If this value is unset, the global config value (default of + description: |- + ContainerlabDebug sets the `--debug` flag when invoking containerlab in the launcher pods. + This is disabled by default. If this value is unset, the global config value (default of "false") will be used. type: boolean filesFromConfigMap: additionalProperties: items: - description: FileFromConfigMap represents a file that you - would like to mount (from a configmap) in the launcher pod - for a given node. + description: |- + FileFromConfigMap represents a file that you would like to mount (from a configmap) in the + launcher pod for a given node. properties: configMapName: description: ConfigMapName is the name of the configmap to mount. type: string configMapPath: - description: ConfigMapPath is the path/key in the configmap - to mount, if not specified the configmap will be mounted - without a sub-path. + description: |- + ConfigMapPath is the path/key in the configmap to mount, if not specified the configmap will + be mounted without a sub-path. type: string filePath: description: FilePath is the path to mount the file. @@ -88,62 +94,60 @@ spec: - filePath type: object type: array - description: FilesFromConfigMap is a slice of FileFromConfigMap - that define the configmap/path and node and path on a launcher - node that the file should be mounted to. If the path is not - provided the configmap is mounted in its entirety (like normal - k8s things), so you *probably* want to specify the sub path - unless you are sure what you're doing! + description: |- + FilesFromConfigMap is a slice of FileFromConfigMap that define the configmap/path and node + and path on a launcher node that the file should be mounted to. If the path is not provided + the configmap is mounted in its entirety (like normal k8s things), so you *probably* want + to specify the sub path unless you are sure what you're doing! type: object filesFromURL: additionalProperties: items: - description: FileFromURL represents a file that you would - like to mount from a URL in the launcher pod for a given - node. + description: |- + FileFromURL represents a file that you would like to mount from a URL in the launcher pod for + a given node. properties: filePath: description: FilePath is the path to mount the file. type: string url: - description: URL is the url to fetch and mount at the - provided FilePath. This URL must be a url that can be - simply downloaded and dumped to disk -- meaning a normal - file server type endpoint or if using GitHub or similar - a "raw" path. + description: |- + URL is the url to fetch and mount at the provided FilePath. This URL must be a url that can + be simply downloaded and dumped to disk -- meaning a normal file server type endpoint or if + using GitHub or similar a "raw" path. type: string required: - filePath - url type: object type: array - description: FilesFromURL is a mapping of FileFromURL that define - a URL at which to fetch a file, and path on a launcher node - that the file should be downloaded to. This is useful for configs - that are larger than the ConfigMap (etcd) 1Mb size limit. + description: |- + FilesFromURL is a mapping of FileFromURL that define a URL at which to fetch a file, and path + on a launcher node that the file should be downloaded to. This is useful for configs that are + larger than the ConfigMap (etcd) 1Mb size limit. type: object launcherImage: - description: LauncherImage sets the default launcher image to - use when spawning launcher deployments for this Topology. This - is optional, the launcher image will default to whatever is - set in the global config CR. + description: |- + LauncherImage sets the default launcher image to use when spawning launcher deployments for + this Topology. This is optional, the launcher image will default to whatever is set in the + global config CR. type: string launcherImagePullPolicy: - description: 'LauncherImagePullPolicy sets the default launcher - image pull policy to use when spawning launcher deployments - for this Topology. This is also optional and defaults to whatever - is set in the global config CR (typically "IfNotPresent"). Note: - omitempty because empty str does not satisfy enum of course.' + description: |- + LauncherImagePullPolicy sets the default launcher image pull policy to use when spawning + launcher deployments for this Topology. This is also optional and defaults to whatever is set + in the global config CR (typically "IfNotPresent"). Note: omitempty because empty str does + not satisfy enum of course. enum: - IfNotPresent - Always - Never type: string launcherLogLevel: - description: 'LauncherLogLevel sets the launcher clabernetes worker - log level -- this overrides whatever is set on the controllers - env vars for this topology. Note: omitempty because empty str - does not satisfy enum of course.' + description: |- + LauncherLogLevel sets the launcher clabernetes worker log level -- this overrides whatever + is set on the controllers env vars for this topology. Note: omitempty because empty str does + not satisfy enum of course. enum: - disabled - critical @@ -152,41 +156,40 @@ spec: - debug type: string persistence: - description: Persistence holds configurations relating to persisting - each nodes working containerlab directory. + description: |- + Persistence holds configurations relating to persisting each nodes working containerlab + directory. properties: claimSize: - description: ClaimSize is the size of the PVC for this topology - -- if not provided this defaults to 5Gi. If provided, the - string value must be a valid kubernetes storage requests - style string. Note the claim size *cannot be made smaller* - once created, but it *can* be expanded. If you need to make - the claim smaller you must delete the topology (or the node - from the topology) and re-add it. + description: |- + ClaimSize is the size of the PVC for this topology -- if not provided this defaults to 5Gi. + If provided, the string value must be a valid kubernetes storage requests style string. Note + the claim size *cannot be made smaller* once created, but it *can* be expanded. If you need + to make the claim smaller you must delete the topology (or the node from the topology) and + re-add it. type: string enabled: - description: Enabled indicates if persistence of hte containerlab - lab/working directory will be placed in a mounted PVC. + description: |- + Enabled indicates if persistence of hte containerlab lab/working directory will be placed in + a mounted PVC. type: boolean storageClassName: - description: StorageClassName is the storage class to set - in the PVC -- if not provided this will be left empty which - will end up using your default storage class. Note that - currently we assume you have (as default) or provide a dynamically - provisionable storage class, hence no selector. + description: |- + StorageClassName is the storage class to set in the PVC -- if not provided this will be left + empty which will end up using your default storage class. Note that currently we assume you + have (as default) or provide a dynamically provisionable storage class, hence no selector. type: string required: - enabled type: object privilegedLauncher: - description: PrivilegedLauncher, when true, sets the launcher - containers to privileged. By default, we do our best to *not* - need this/set this, and instead set only the capabilities we - need, however its possible that some containers launched by - the launcher may need/want more capabilities, so this flag exists - for users to bypass the default settings and enable fully privileged - launcher pods. If this value is unset, the global config value - (default of "false") will be used. + description: |- + PrivilegedLauncher, when true, sets the launcher containers to privileged. By default, we do + our best to *not* need this/set this, and instead set only the capabilities we need, however + its possible that some containers launched by the launcher may need/want more capabilities, + so this flag exists for users to bypass the default settings and enable fully privileged + launcher pods. If this value is unset, the global config value (default of "false") will be + used. type: boolean resources: additionalProperties: @@ -194,18 +197,23 @@ spec: requirements. properties: claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only - be set for containers." + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: Name must match the name of one entry - in pod.spec.resourceClaims of the Pod where this - field is used. It makes that resource available + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available inside a container. type: string required: @@ -222,8 +230,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -232,21 +241,73 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: '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. Requests - cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + 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. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object - description: Resources is a mapping of nodeName (or "default") - to kubernetes resource requirements -- any value set here overrides - the "global" config resource definitions. If a key "default" - is set, those resource values will be preferred over *all global - settings* for this topology -- meaning, the "global" resource - settings will never be looked up for this topology, and any - kind/type that is *not* in this resources map will have the - "default" resources from this mapping applied. + description: |- + Resources is a mapping of nodeName (or "default") to kubernetes resource requirements -- any + value set here overrides the "global" config resource definitions. If a key "default" is set, + those resource values will be preferred over *all global settings* for this topology -- + meaning, the "global" resource settings will never be looked up for this topology, and any + kind/type that is *not* in this resources map will have the "default" resources from this + mapping applied. + type: object + scheduling: + description: |- + Scheduling holds information about how the launcher pod(s) should be configured with respect + to "scheduling" things (affinity/node selector/tolerations). + properties: + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector sets the node selector that will be configured on all launcher pods for this + Topology. + type: object + tolerations: + description: Tolerations is a list of Tolerations that will + be set on the launcher pod spec. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array type: object type: object expose: @@ -254,79 +315,87 @@ spec: exposes a topology. properties: disableAutoExpose: - description: "DisableAutoExpose disables the automagic exposing - of ports for a given topology. When this setting is disabled - clabernetes will not auto add ports so if you want to expose - (via a load balancer service) you will need to have ports outlined - in your containerlab config (or equivalent for kne). When this - is `false` (default), clabernetes will add and expose the following - list of ports to whatever ports you have already defined: \n - 21 - tcp - ftp 22 - tcp - ssh 23 - tcp - telnet 80 - \ - tcp - http 161 - udp - snmp 443 - tcp - https 830 - \ - tcp - netconf (over ssh) 5000 - tcp - telnet for vrnetlab - qemu host 5900 - tcp - vnc 6030 - tcp - gnmi (arista default) - 9339 - tcp - gnmi/gnoi 9340 - tcp - gribi 9559 - tcp - p4rt - 57400 - tcp - gnmi (nokia srl/sros default) \n This setting - is *ignored completely* if `DisableExpose` is true!" + description: |- + DisableAutoExpose disables the automagic exposing of ports for a given topology. When this + setting is disabled clabernetes will not auto add ports so if you want to expose (via a + load balancer service) you will need to have ports outlined in your containerlab config + (or equivalent for kne). When this is `false` (default), clabernetes will add and expose the + following list of ports to whatever ports you have already defined: + + + 21 - tcp - ftp + 22 - tcp - ssh + 23 - tcp - telnet + 80 - tcp - http + 161 - udp - snmp + 443 - tcp - https + 830 - tcp - netconf (over ssh) + 5000 - tcp - telnet for vrnetlab qemu host + 5900 - tcp - vnc + 6030 - tcp - gnmi (arista default) + 9339 - tcp - gnmi/gnoi + 9340 - tcp - gribi + 9559 - tcp - p4rt + 57400 - tcp - gnmi (nokia srl/sros default) + + + This setting is *ignored completely* if `DisableExpose` is true! type: boolean disableExpose: - description: DisableExpose indicates if exposing nodes via LoadBalancer - service should be disabled, by default any mapped ports in a - containerlab topology will be exposed. + description: |- + DisableExpose indicates if exposing nodes via LoadBalancer service should be disabled, by + default any mapped ports in a containerlab topology will be exposed. type: boolean disableNodeAliasService: - description: DisableNodeAliasService indicates if headless services - for each node in a containerlab topology should *not* be created. - By default, clabernetes creates these headless services for - each node so that "normal" docker and containerlab service discovery - works -- this means you can simply resolve "my-neat-node" from - within the namespace of a topology like you would in docker - locally. You may wish to disable this feature though if you - have no need of it and just don't want the extra services around. - Additionally, you may want to disable this feature if you are - running multiple labs in the same namespace (which is not generally - recommended by the way!) as you may end up in a situation where - a name (i.e. "leaf1") is duplicated in more than one topology - -- this will cause some problems for clabernetes! + description: |- + DisableNodeAliasService indicates if headless services for each node in a containerlab + topology should *not* be created. By default, clabernetes creates these headless services for + each node so that "normal" docker and containerlab service discovery works -- this means you + can simply resolve "my-neat-node" from within the namespace of a topology like you would in + docker locally. You may wish to disable this feature though if you have no need of it and + just don't want the extra services around. Additionally, you may want to disable this feature + if you are running multiple labs in the same namespace (which is not generally recommended by + the way!) as you may end up in a situation where a name (i.e. "leaf1") is duplicated in more + than one topology -- this will cause some problems for clabernetes! type: boolean type: object imagePull: - description: ImagePull holds configurations relevant to how clabernetes - launcher pods handle pulling images. + description: |- + ImagePull holds configurations relevant to how clabernetes launcher pods handle pulling + images. properties: dockerDaemonConfig: - description: DockerDaemonConfig allows for setting the docker - daemon config for all launchers in this topology. The secret - *must be present in the namespace of this topology*. The secret - *must* contain a key "daemon.json" -- as this secret will be - mounted to /etc/docker and docker will be expecting the config - at /etc/docker/daemon.json. + description: |- + DockerDaemonConfig allows for setting the docker daemon config for all launchers in this + topology. The secret *must be present in the namespace of this topology*. The secret *must* + contain a key "daemon.json" -- as this secret will be mounted to /etc/docker and docker will + be expecting the config at /etc/docker/daemon.json. type: string insecureRegistries: - description: InsecureRegistries is a slice of strings of insecure - registries to configure in the launcher pods. + description: |- + InsecureRegistries is a slice of strings of insecure registries to configure in the launcher + pods. items: type: string type: array pullSecrets: - description: PullSecrets allows for providing secret(s) to use - when pulling the image. This is only applicable *if* ImagePullThrough - mode is auto or always. The secret is used by the launcher pod - to pull the image via the cluster CRI. The secret is *not* mounted - to the pod, but instead is used in conjunction with a job that - spawns a pod using the specified secret. The job will kill the - pod as soon as the image has been pulled -- we do this because - we don't care if the pod runs, we only care that the image gets - pulled on a specific node. Note that just like "normal" pull - secrets, the secret needs to be in the namespace that the topology + description: |- + PullSecrets allows for providing secret(s) to use when pulling the image. This is only + applicable *if* ImagePullThrough mode is auto or always. The secret is used by the launcher + pod to pull the image via the cluster CRI. The secret is *not* mounted to the pod, but + instead is used in conjunction with a job that spawns a pod using the specified secret. The + job will kill the pod as soon as the image has been pulled -- we do this because we don't + care if the pod runs, we only care that the image gets pulled on a specific node. Note that + just like "normal" pull secrets, the secret needs to be in the namespace that the topology is in. items: type: string type: array x-kubernetes-list-type: set pullThroughOverride: - description: PullThroughOverride allows for overriding the image - pull through mode for this particular topology. + description: |- + PullThroughOverride allows for overriding the image pull through mode for this + particular topology. enum: - auto - always @@ -343,19 +412,20 @@ spec: configs: additionalProperties: type: string - description: Configs is a map of node name -> containerlab config - -- in other words, this is the original Topology.Spec.Definition - converted to containerlab "sub-topologies" The actual "sub-topologies"/"sub-configs" - are stored as a string -- this is the actual containerlab topology - that gets mounted in the launcher pod. + description: |- + Configs is a map of node name -> containerlab config -- in other words, this is the original + Topology.Spec.Definition converted to containerlab "sub-topologies" The actual + "sub-topologies"/"sub-configs" are stored as a string -- this is the actual containerlab + topology that gets mounted in the launcher pod. type: object exposedPorts: additionalProperties: description: ExposedPorts holds information about exposed ports. properties: loadBalancerAddress: - description: LoadBalancerAddress holds the address assigned - to the load balancer exposing ports for a given node. + description: |- + LoadBalancerAddress holds the address assigned to the load balancer exposing ports for a + given node. type: string tcpPorts: description: TCPPorts is a list of TCP ports exposed on the @@ -376,8 +446,9 @@ spec: - tcpPorts - udpPorts type: object - description: ExposedPorts holds a map of (containerlab not k8s!) nodes - and their exposed ports (via load balancer). + description: |- + ExposedPorts holds a map of (containerlab not k8s!) nodes and their exposed ports + (via load balancer). type: object kind: description: Kind is the topology kind this CR represents -- for example @@ -391,37 +462,35 @@ spec: run. properties: config: - description: Config is the last stored hash of the rendered config(s) - -- that is, the map of "sub topologies" representing the overall - Topology.Spec.Definition. + description: |- + Config is the last stored hash of the rendered config(s) -- that is, the map of "sub + topologies" representing the overall Topology.Spec.Definition. type: string exposedPorts: - description: ExposedPorts is the last stored hash of the exposed - ports mapping for this Topology. Note that while we obviously - care about the exposed ports on a *per node basis*, we don't - need to track that here -- this is here strictly to track differences - in the load balancer service -- the actual sub-topologies (or - sub-configs) effectively track the expose port status per node. + description: |- + ExposedPorts is the last stored hash of the exposed ports mapping for this Topology. Note + that while we obviously care about the exposed ports on a *per node basis*, we don't need to + track that here -- this is here strictly to track differences in the load balancer service -- + the actual sub-topologies (or sub-configs) effectively track the expose port status per node. type: string filesFromURL: additionalProperties: type: string - description: FilesFromURL is the hash of the last stored mapping - of files from URL (to node mapping). Note that this is tracked - on a *per node basis* because the URL of a file could be updated - without any change to the actual config/topology (or sub-config/sub-topology); - as such we need to explicitly track this per node to know when - a node needs to be restarted such that the new URL is "picked - up" by the node/launcher. + description: |- + FilesFromURL is the hash of the last stored mapping of files from URL (to node mapping). Note + that this is tracked on a *per node basis* because the URL of a file could be updated without + any change to the actual config/topology (or sub-config/sub-topology); as such we need to + explicitly track this per node to know when a node needs to be restarted such that the new + URL is "picked up" by the node/launcher. type: object imagePullSecrets: description: ImagePullSecrets is the hash of hte last stored image pull secrets for this Topology. type: string tunnels: - description: Tunnels is the last stored hash of the tunnels that - provided connectivity between the launcher nodes. As this can - change due to the dns suffix changing and not just the config + description: |- + Tunnels is the last stored hash of the tunnels that provided connectivity between the + launcher nodes. As this can change due to the dns suffix changing and not just the config changing we need to independently track this state. type: string required: diff --git a/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml b/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml index 440ca324..18fee0c2 100644 --- a/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml +++ b/charts/clabernetes/crds/clabernetes.containerlab.dev_configs.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: configs.clabernetes.containerlab.dev spec: group: clabernetes.containerlab.dev @@ -17,20 +17,26 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: Config is an object that holds global clabernetes config information. - Note that this CR is expected to effectively be a global singleton -- that - is, there should be only *one* of these, and it *must* be named `clabernetes` - -- CRD metadata spec will enforce this (via x-validation rules). + description: |- + Config is an object that holds global clabernetes config information. Note that this CR is + expected to effectively be a global singleton -- that is, there should be only *one* of these, + and it *must* be named `clabernetes` -- CRD metadata spec will enforce this (via x-validation + rules). properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -42,8 +48,9 @@ spec: settings. properties: containerlabDebug: - description: ContainerlabDebug sets the `--debug` flag when invoking - containerlab in the launcher pods. This is disabled by default. + description: |- + ContainerlabDebug sets the `--debug` flag when invoking containerlab in the launcher pods. + This is disabled by default. type: boolean launcherImage: default: ghcr.io/srl-labs/clabernetes/clabernetes-launcher:latest @@ -52,18 +59,19 @@ spec: type: string launcherImagePullPolicy: default: IfNotPresent - description: LauncherImagePullPolicy sets the default launcher - image pull policy to use when spawning launcher deployments. + description: |- + LauncherImagePullPolicy sets the default launcher image pull policy to use when spawning + launcher deployments. enum: - IfNotPresent - Always - Never type: string launcherLogLevel: - description: 'LauncherLogLevel sets the launcher clabernetes worker - log level -- this overrides whatever is set on the controllers - env vars for this topology. Note: omitempty because empty str - does not satisfy enum of course.' + description: |- + LauncherLogLevel sets the launcher clabernetes worker log level -- this overrides whatever + is set on the controllers env vars for this topology. Note: omitempty because empty str does + not satisfy enum of course. enum: - disabled - critical @@ -72,12 +80,11 @@ spec: - debug type: string privilegedLauncher: - description: PrivilegedLauncher, when true, sets the launcher - containers to privileged. By default, we do our best to *not* - need this/set this, and instead set only the capabilities we - need, however its possible that some containers launched by - the launcher may need/want more capabilities, so this flag exists - for users to bypass the default settings and enable fully privileged + description: |- + PrivilegedLauncher, when true, sets the launcher containers to privileged. By default, we do + our best to *not* need this/set this, and instead set only the capabilities we need, however + its possible that some containers launched by the launcher may need/want more capabilities, + so this flag exists for users to bypass the default settings and enable fully privileged launcher pods. type: boolean resourcesByContainerlabKind: @@ -87,18 +94,23 @@ spec: requirements. properties: claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. \n This field - is immutable. It can only be set for containers." + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: Name must match the name of one entry - in pod.spec.resourceClaims of the Pod where this - field is used. It makes that resource available + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available inside a container. type: string required: @@ -115,8 +127,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -125,46 +138,53 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: '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. - Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + 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. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object type: object - description: 'ResourcesByContainerlabKind is a mapping of container - lab kind -> type -> default resource settings. Note that a key - value of "default" in the inner map will apply the given resources - for any pod of that containerlab *kind*. For example: { "srl": - { "default": DEFAULT RESOURCES FOR KIND "srl", "ixr10": RESOURCES - FOR KIND "srl", TYPE "ixr10" } Given resources as above, a containerlab - node of kind "srl" and "type" ixr10" would get the specific - resources as allocated in the ixr10 key, whereas a containerlab - kind of "srl" and "type" unset or "ixr6" would get the "default" - resource settings. To apply global default resources, regardless - of containerlab kind/type, use the `resourcesDefault` field.' + description: |- + ResourcesByContainerlabKind is a mapping of container lab kind -> type -> default resource + settings. Note that a key value of "default" in the inner map will apply the given resources + for any pod of that containerlab *kind*. For example: + { + "srl": { + "default": DEFAULT RESOURCES FOR KIND "srl", + "ixr10": RESOURCES FOR KIND "srl", TYPE "ixr10" + } + Given resources as above, a containerlab node of kind "srl" and "type" ixr10" would get the + specific resources as allocated in the ixr10 key, whereas a containerlab kind of "srl" and + "type" unset or "ixr6" would get the "default" resource settings. To apply global default + resources, regardless of containerlab kind/type, use the `resourcesDefault` field. type: object resourcesDefault: - description: ResourcesDefault is the default set of resources - for clabernetes launcher pods. This is used only as a last option - if a Topology does not have resources, and there are no resources - for the given containerlab kind/type + description: |- + ResourcesDefault is the default set of resources for clabernetes launcher pods. This is used + only as a last option if a Topology does not have resources, and there are no resources for + the given containerlab kind/type properties: claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. type: string required: - name @@ -180,8 +200,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -190,11 +211,11 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: '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. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + 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. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object required: @@ -202,47 +223,44 @@ spec: - launcherImagePullPolicy type: object imagePull: - description: ImagePull holds configurations relevant to how clabernetes - launcher pods handle pulling images. + description: |- + ImagePull holds configurations relevant to how clabernetes launcher pods handle pulling + images. properties: criKindOverride: - description: CRIKindOverride allows for overriding the auto discovered - cri flavor of the cluster -- this may be useful if we fail to - parse the cri kind for some reason, or in mixed cri flavor clusters - -- however in the latter case, make sure that if you are using - image pull through that clabernetes workloads are only run on - the nodes of the cri kind specified here! + description: |- + CRIKindOverride allows for overriding the auto discovered cri flavor of the cluster -- this + may be useful if we fail to parse the cri kind for some reason, or in mixed cri flavor + clusters -- however in the latter case, make sure that if you are using image pull through + that clabernetes workloads are only run on the nodes of the cri kind specified here! enum: - containerd type: string criSockOverride: - description: CRISockOverride allows for overriding the path of - the CRI sock that is mounted in the launcher pods (if/when image - pull through mode is auto or always). This can be useful if, - for example, the CRI sock is in a "non-standard" location like - K3s which puts the containerd sock at `/run/k3s/containerd/containerd.sock` - rather than the "normal" (whatever that means) location of `/run/containerd/containerd.sock`. - The value must end with "containerd.sock" for now, in the future - maybe crio support will be added. + description: |- + CRISockOverride allows for overriding the path of the CRI sock that is mounted in the + launcher pods (if/when image pull through mode is auto or always). This can be useful if, + for example, the CRI sock is in a "non-standard" location like K3s which puts the containerd + sock at `/run/k3s/containerd/containerd.sock` rather than the "normal" (whatever that means) + location of `/run/containerd/containerd.sock`. The value must end with "containerd.sock" for + now, in the future maybe crio support will be added. pattern: (.*containerd\.sock) type: string dockerDaemonConfig: - description: DockerDaemonConfig allows for setting a default docker - daemon config for launcher pods with the specified secret. The - secret *must be present in the namespace of any given topology* - -- so if you are configuring this at the "global config" level, - ensure that you are deploying topologies into a specific namespace, - or have ensured there is a secret of the given name in every - namespace you wish to deploy a topology to. When set, insecure - registries config option is ignored as it is assumed you are - handling that in the given docker config. Note that the secret - *must* contain a key "daemon.json" -- as this secret will be - mounted to /etc/docker and docker will be expecting the config - at /etc/docker/daemon.json. + description: |- + DockerDaemonConfig allows for setting a default docker daemon config for launcher pods + with the specified secret. The secret *must be present in the namespace of any given + topology* -- so if you are configuring this at the "global config" level, ensure that you are + deploying topologies into a specific namespace, or have ensured there is a secret of the + given name in every namespace you wish to deploy a topology to. When set, insecure registries + config option is ignored as it is assumed you are handling that in the given docker config. + Note that the secret *must* contain a key "daemon.json" -- as this secret will be mounted to + /etc/docker and docker will be expecting the config at /etc/docker/daemon.json. type: string pullThroughOverride: - description: PullThroughOverride allows for overriding the image - pull through mode for this particular topology. + description: |- + PullThroughOverride allows for overriding the image pull through mode for this + particular topology. enum: - auto - always @@ -254,23 +272,24 @@ spec: suffix used when resolving services. type: string metadata: - description: Metadata holds "global" metadata -- that is, metadata - that is applied to all objects created by the clabernetes controller. + description: |- + Metadata holds "global" metadata -- that is, metadata that is applied to all objects created + by the clabernetes controller. properties: annotations: additionalProperties: type: string - description: Annotations holds key/value pairs that should be - set as annotations on clabernetes created resources. Note that - (currently?) there is no input validation here, but this data - must be valid kubernetes annotation data. + description: |- + Annotations holds key/value pairs that should be set as annotations on clabernetes created + resources. Note that (currently?) there is no input validation here, but this data must be + valid kubernetes annotation data. type: object labels: additionalProperties: type: string - description: Labels holds key/value pairs that should be set as - labels on clabernetes created resources. Note that (currently?) - there is no input validation here, but this data must be valid + description: |- + Labels holds key/value pairs that should be set as labels on clabernetes created resources. + Note that (currently?) there is no input validation here, but this data must be valid kubernetes label data. type: object type: object diff --git a/charts/clabernetes/crds/clabernetes.containerlab.dev_imagerequests.yaml b/charts/clabernetes/crds/clabernetes.containerlab.dev_imagerequests.yaml index 0fbe0fdd..1d39930d 100644 --- a/charts/clabernetes/crds/clabernetes.containerlab.dev_imagerequests.yaml +++ b/charts/clabernetes/crds/clabernetes.containerlab.dev_imagerequests.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: imagerequests.clabernetes.containerlab.dev spec: group: clabernetes.containerlab.dev @@ -17,19 +17,25 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: - description: ImageRequest is an object that represents a request (from a launcher - pod) to pull an image on a given kubernetes node such that the image can - be "pulled through" into the launcher docker daemon. + description: |- + ImageRequest is an object that represents a request (from a launcher pod) to pull an image on a + given kubernetes node such that the image can be "pulled through" into the launcher docker + daemon. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -37,12 +43,14 @@ spec: description: ImageRequestSpec is the spec for a Config resource. properties: kubernetesNode: - description: KubernetesNode is the node where the launcher pod is - running and where the image should be pulled too. + description: |- + KubernetesNode is the node where the launcher pod is running and where the image should be + pulled too. type: string requestedImage: - description: RequestedImage is the image that the launcher pod wants - the controller to get pulled onto the specified node. + description: |- + RequestedImage is the image that the launcher pod wants the controller to get pulled onto + the specified node. type: string requestedImagePullSecrets: description: RequestedImagePullSecrets is a list of configured pull @@ -56,9 +64,9 @@ spec: image. type: string topologyNodeName: - description: TopologyNodeName is the name of the node in the topology - (i.e. the router name in a containerlab topology) that the image - is being requested for. + description: |- + TopologyNodeName is the name of the node in the topology (i.e. the router name in a + containerlab topology) that the image is being requested for. type: string required: - kubernetesNode @@ -70,15 +78,15 @@ spec: description: ImageRequestStatus is the status for a ImageRequest resource. properties: accepted: - description: Accepted indicates that the ImageRequest controller has - seen this image request and is going to process it. This can be - useful to let the requesting pod know that "yep, this is in the + description: |- + Accepted indicates that the ImageRequest controller has seen this image request and is going + to process it. This can be useful to let the requesting pod know that "yep, this is in the works, and i can go watch the cri images on this node now". type: boolean complete: - description: Complete indicates that the ImageRequest controller has - seen that the puller pod has done its job and that the image has - been pulled onto the requested node. + description: |- + Complete indicates that the ImageRequest controller has seen that the puller pod has done its + job and that the image has been pulled onto the requested node. type: boolean required: - accepted diff --git a/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml b/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml index 8cf79db2..26cb2867 100644 --- a/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml +++ b/charts/clabernetes/crds/clabernetes.containerlab.dev_topologies.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 + controller-gen.kubebuilder.io/version: v0.14.0 name: topologies.clabernetes.containerlab.dev spec: group: clabernetes.containerlab.dev @@ -21,19 +21,24 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: 'Topology is an object that holds information about a clabernetes - Topology -- that is, a valid topology file (ex: containerlab topology), - and any associated configurations.' + description: |- + Topology is an object that holds information about a clabernetes Topology -- that is, a valid + topology file (ex: containerlab topology), and any associated configurations. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -41,11 +46,11 @@ spec: description: TopologySpec is the spec for a Topology resource. properties: definition: - description: Definition defines the actual set of nodes (network ones, - not k8s ones!) that this Topology CR represents. Historically, and - probably most often, this means Topology holds a "normal" containerlab - topology file that will be "clabernetsified", however this could - also be a "kne" config, or perhaps others in the future. + description: |- + Definition defines the actual set of nodes (network ones, not k8s ones!) that this Topology + CR represents. Historically, and probably most often, this means Topology holds a "normal" + containerlab topology file that will be "clabernetsified", however this could also be a "kne" + config, or perhaps others in the future. properties: containerlab: description: Containerlab holds a valid containerlab topology. @@ -55,30 +60,31 @@ spec: type: string type: object deployment: - description: Deployment holds configurations relevant to how clabernetes - configures deployments that make up a given topology. + description: |- + Deployment holds configurations relevant to how clabernetes configures deployments that make + up a given topology. properties: containerlabDebug: - description: ContainerlabDebug sets the `--debug` flag when invoking - containerlab in the launcher pods. This is disabled by default. - If this value is unset, the global config value (default of + description: |- + ContainerlabDebug sets the `--debug` flag when invoking containerlab in the launcher pods. + This is disabled by default. If this value is unset, the global config value (default of "false") will be used. type: boolean filesFromConfigMap: additionalProperties: items: - description: FileFromConfigMap represents a file that you - would like to mount (from a configmap) in the launcher pod - for a given node. + description: |- + FileFromConfigMap represents a file that you would like to mount (from a configmap) in the + launcher pod for a given node. properties: configMapName: description: ConfigMapName is the name of the configmap to mount. type: string configMapPath: - description: ConfigMapPath is the path/key in the configmap - to mount, if not specified the configmap will be mounted - without a sub-path. + description: |- + ConfigMapPath is the path/key in the configmap to mount, if not specified the configmap will + be mounted without a sub-path. type: string filePath: description: FilePath is the path to mount the file. @@ -88,62 +94,60 @@ spec: - filePath type: object type: array - description: FilesFromConfigMap is a slice of FileFromConfigMap - that define the configmap/path and node and path on a launcher - node that the file should be mounted to. If the path is not - provided the configmap is mounted in its entirety (like normal - k8s things), so you *probably* want to specify the sub path - unless you are sure what you're doing! + description: |- + FilesFromConfigMap is a slice of FileFromConfigMap that define the configmap/path and node + and path on a launcher node that the file should be mounted to. If the path is not provided + the configmap is mounted in its entirety (like normal k8s things), so you *probably* want + to specify the sub path unless you are sure what you're doing! type: object filesFromURL: additionalProperties: items: - description: FileFromURL represents a file that you would - like to mount from a URL in the launcher pod for a given - node. + description: |- + FileFromURL represents a file that you would like to mount from a URL in the launcher pod for + a given node. properties: filePath: description: FilePath is the path to mount the file. type: string url: - description: URL is the url to fetch and mount at the - provided FilePath. This URL must be a url that can be - simply downloaded and dumped to disk -- meaning a normal - file server type endpoint or if using GitHub or similar - a "raw" path. + description: |- + URL is the url to fetch and mount at the provided FilePath. This URL must be a url that can + be simply downloaded and dumped to disk -- meaning a normal file server type endpoint or if + using GitHub or similar a "raw" path. type: string required: - filePath - url type: object type: array - description: FilesFromURL is a mapping of FileFromURL that define - a URL at which to fetch a file, and path on a launcher node - that the file should be downloaded to. This is useful for configs - that are larger than the ConfigMap (etcd) 1Mb size limit. + description: |- + FilesFromURL is a mapping of FileFromURL that define a URL at which to fetch a file, and path + on a launcher node that the file should be downloaded to. This is useful for configs that are + larger than the ConfigMap (etcd) 1Mb size limit. type: object launcherImage: - description: LauncherImage sets the default launcher image to - use when spawning launcher deployments for this Topology. This - is optional, the launcher image will default to whatever is - set in the global config CR. + description: |- + LauncherImage sets the default launcher image to use when spawning launcher deployments for + this Topology. This is optional, the launcher image will default to whatever is set in the + global config CR. type: string launcherImagePullPolicy: - description: 'LauncherImagePullPolicy sets the default launcher - image pull policy to use when spawning launcher deployments - for this Topology. This is also optional and defaults to whatever - is set in the global config CR (typically "IfNotPresent"). Note: - omitempty because empty str does not satisfy enum of course.' + description: |- + LauncherImagePullPolicy sets the default launcher image pull policy to use when spawning + launcher deployments for this Topology. This is also optional and defaults to whatever is set + in the global config CR (typically "IfNotPresent"). Note: omitempty because empty str does + not satisfy enum of course. enum: - IfNotPresent - Always - Never type: string launcherLogLevel: - description: 'LauncherLogLevel sets the launcher clabernetes worker - log level -- this overrides whatever is set on the controllers - env vars for this topology. Note: omitempty because empty str - does not satisfy enum of course.' + description: |- + LauncherLogLevel sets the launcher clabernetes worker log level -- this overrides whatever + is set on the controllers env vars for this topology. Note: omitempty because empty str does + not satisfy enum of course. enum: - disabled - critical @@ -152,41 +156,40 @@ spec: - debug type: string persistence: - description: Persistence holds configurations relating to persisting - each nodes working containerlab directory. + description: |- + Persistence holds configurations relating to persisting each nodes working containerlab + directory. properties: claimSize: - description: ClaimSize is the size of the PVC for this topology - -- if not provided this defaults to 5Gi. If provided, the - string value must be a valid kubernetes storage requests - style string. Note the claim size *cannot be made smaller* - once created, but it *can* be expanded. If you need to make - the claim smaller you must delete the topology (or the node - from the topology) and re-add it. + description: |- + ClaimSize is the size of the PVC for this topology -- if not provided this defaults to 5Gi. + If provided, the string value must be a valid kubernetes storage requests style string. Note + the claim size *cannot be made smaller* once created, but it *can* be expanded. If you need + to make the claim smaller you must delete the topology (or the node from the topology) and + re-add it. type: string enabled: - description: Enabled indicates if persistence of hte containerlab - lab/working directory will be placed in a mounted PVC. + description: |- + Enabled indicates if persistence of hte containerlab lab/working directory will be placed in + a mounted PVC. type: boolean storageClassName: - description: StorageClassName is the storage class to set - in the PVC -- if not provided this will be left empty which - will end up using your default storage class. Note that - currently we assume you have (as default) or provide a dynamically - provisionable storage class, hence no selector. + description: |- + StorageClassName is the storage class to set in the PVC -- if not provided this will be left + empty which will end up using your default storage class. Note that currently we assume you + have (as default) or provide a dynamically provisionable storage class, hence no selector. type: string required: - enabled type: object privilegedLauncher: - description: PrivilegedLauncher, when true, sets the launcher - containers to privileged. By default, we do our best to *not* - need this/set this, and instead set only the capabilities we - need, however its possible that some containers launched by - the launcher may need/want more capabilities, so this flag exists - for users to bypass the default settings and enable fully privileged - launcher pods. If this value is unset, the global config value - (default of "false") will be used. + description: |- + PrivilegedLauncher, when true, sets the launcher containers to privileged. By default, we do + our best to *not* need this/set this, and instead set only the capabilities we need, however + its possible that some containers launched by the launcher may need/want more capabilities, + so this flag exists for users to bypass the default settings and enable fully privileged + launcher pods. If this value is unset, the global config value (default of "false") will be + used. type: boolean resources: additionalProperties: @@ -194,18 +197,23 @@ spec: requirements. properties: claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only - be set for containers." + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: Name must match the name of one entry - in pod.spec.resourceClaims of the Pod where this - field is used. It makes that resource available + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available inside a container. type: string required: @@ -222,8 +230,9 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -232,21 +241,73 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: '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. Requests - cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + description: |- + 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. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object - description: Resources is a mapping of nodeName (or "default") - to kubernetes resource requirements -- any value set here overrides - the "global" config resource definitions. If a key "default" - is set, those resource values will be preferred over *all global - settings* for this topology -- meaning, the "global" resource - settings will never be looked up for this topology, and any - kind/type that is *not* in this resources map will have the - "default" resources from this mapping applied. + description: |- + Resources is a mapping of nodeName (or "default") to kubernetes resource requirements -- any + value set here overrides the "global" config resource definitions. If a key "default" is set, + those resource values will be preferred over *all global settings* for this topology -- + meaning, the "global" resource settings will never be looked up for this topology, and any + kind/type that is *not* in this resources map will have the "default" resources from this + mapping applied. + type: object + scheduling: + description: |- + Scheduling holds information about how the launcher pod(s) should be configured with respect + to "scheduling" things (affinity/node selector/tolerations). + properties: + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector sets the node selector that will be configured on all launcher pods for this + Topology. + type: object + tolerations: + description: Tolerations is a list of Tolerations that will + be set on the launcher pod spec. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array type: object type: object expose: @@ -254,79 +315,87 @@ spec: exposes a topology. properties: disableAutoExpose: - description: "DisableAutoExpose disables the automagic exposing - of ports for a given topology. When this setting is disabled - clabernetes will not auto add ports so if you want to expose - (via a load balancer service) you will need to have ports outlined - in your containerlab config (or equivalent for kne). When this - is `false` (default), clabernetes will add and expose the following - list of ports to whatever ports you have already defined: \n - 21 - tcp - ftp 22 - tcp - ssh 23 - tcp - telnet 80 - \ - tcp - http 161 - udp - snmp 443 - tcp - https 830 - \ - tcp - netconf (over ssh) 5000 - tcp - telnet for vrnetlab - qemu host 5900 - tcp - vnc 6030 - tcp - gnmi (arista default) - 9339 - tcp - gnmi/gnoi 9340 - tcp - gribi 9559 - tcp - p4rt - 57400 - tcp - gnmi (nokia srl/sros default) \n This setting - is *ignored completely* if `DisableExpose` is true!" + description: |- + DisableAutoExpose disables the automagic exposing of ports for a given topology. When this + setting is disabled clabernetes will not auto add ports so if you want to expose (via a + load balancer service) you will need to have ports outlined in your containerlab config + (or equivalent for kne). When this is `false` (default), clabernetes will add and expose the + following list of ports to whatever ports you have already defined: + + + 21 - tcp - ftp + 22 - tcp - ssh + 23 - tcp - telnet + 80 - tcp - http + 161 - udp - snmp + 443 - tcp - https + 830 - tcp - netconf (over ssh) + 5000 - tcp - telnet for vrnetlab qemu host + 5900 - tcp - vnc + 6030 - tcp - gnmi (arista default) + 9339 - tcp - gnmi/gnoi + 9340 - tcp - gribi + 9559 - tcp - p4rt + 57400 - tcp - gnmi (nokia srl/sros default) + + + This setting is *ignored completely* if `DisableExpose` is true! type: boolean disableExpose: - description: DisableExpose indicates if exposing nodes via LoadBalancer - service should be disabled, by default any mapped ports in a - containerlab topology will be exposed. + description: |- + DisableExpose indicates if exposing nodes via LoadBalancer service should be disabled, by + default any mapped ports in a containerlab topology will be exposed. type: boolean disableNodeAliasService: - description: DisableNodeAliasService indicates if headless services - for each node in a containerlab topology should *not* be created. - By default, clabernetes creates these headless services for - each node so that "normal" docker and containerlab service discovery - works -- this means you can simply resolve "my-neat-node" from - within the namespace of a topology like you would in docker - locally. You may wish to disable this feature though if you - have no need of it and just don't want the extra services around. - Additionally, you may want to disable this feature if you are - running multiple labs in the same namespace (which is not generally - recommended by the way!) as you may end up in a situation where - a name (i.e. "leaf1") is duplicated in more than one topology - -- this will cause some problems for clabernetes! + description: |- + DisableNodeAliasService indicates if headless services for each node in a containerlab + topology should *not* be created. By default, clabernetes creates these headless services for + each node so that "normal" docker and containerlab service discovery works -- this means you + can simply resolve "my-neat-node" from within the namespace of a topology like you would in + docker locally. You may wish to disable this feature though if you have no need of it and + just don't want the extra services around. Additionally, you may want to disable this feature + if you are running multiple labs in the same namespace (which is not generally recommended by + the way!) as you may end up in a situation where a name (i.e. "leaf1") is duplicated in more + than one topology -- this will cause some problems for clabernetes! type: boolean type: object imagePull: - description: ImagePull holds configurations relevant to how clabernetes - launcher pods handle pulling images. + description: |- + ImagePull holds configurations relevant to how clabernetes launcher pods handle pulling + images. properties: dockerDaemonConfig: - description: DockerDaemonConfig allows for setting the docker - daemon config for all launchers in this topology. The secret - *must be present in the namespace of this topology*. The secret - *must* contain a key "daemon.json" -- as this secret will be - mounted to /etc/docker and docker will be expecting the config - at /etc/docker/daemon.json. + description: |- + DockerDaemonConfig allows for setting the docker daemon config for all launchers in this + topology. The secret *must be present in the namespace of this topology*. The secret *must* + contain a key "daemon.json" -- as this secret will be mounted to /etc/docker and docker will + be expecting the config at /etc/docker/daemon.json. type: string insecureRegistries: - description: InsecureRegistries is a slice of strings of insecure - registries to configure in the launcher pods. + description: |- + InsecureRegistries is a slice of strings of insecure registries to configure in the launcher + pods. items: type: string type: array pullSecrets: - description: PullSecrets allows for providing secret(s) to use - when pulling the image. This is only applicable *if* ImagePullThrough - mode is auto or always. The secret is used by the launcher pod - to pull the image via the cluster CRI. The secret is *not* mounted - to the pod, but instead is used in conjunction with a job that - spawns a pod using the specified secret. The job will kill the - pod as soon as the image has been pulled -- we do this because - we don't care if the pod runs, we only care that the image gets - pulled on a specific node. Note that just like "normal" pull - secrets, the secret needs to be in the namespace that the topology + description: |- + PullSecrets allows for providing secret(s) to use when pulling the image. This is only + applicable *if* ImagePullThrough mode is auto or always. The secret is used by the launcher + pod to pull the image via the cluster CRI. The secret is *not* mounted to the pod, but + instead is used in conjunction with a job that spawns a pod using the specified secret. The + job will kill the pod as soon as the image has been pulled -- we do this because we don't + care if the pod runs, we only care that the image gets pulled on a specific node. Note that + just like "normal" pull secrets, the secret needs to be in the namespace that the topology is in. items: type: string type: array x-kubernetes-list-type: set pullThroughOverride: - description: PullThroughOverride allows for overriding the image - pull through mode for this particular topology. + description: |- + PullThroughOverride allows for overriding the image pull through mode for this + particular topology. enum: - auto - always @@ -343,19 +412,20 @@ spec: configs: additionalProperties: type: string - description: Configs is a map of node name -> containerlab config - -- in other words, this is the original Topology.Spec.Definition - converted to containerlab "sub-topologies" The actual "sub-topologies"/"sub-configs" - are stored as a string -- this is the actual containerlab topology - that gets mounted in the launcher pod. + description: |- + Configs is a map of node name -> containerlab config -- in other words, this is the original + Topology.Spec.Definition converted to containerlab "sub-topologies" The actual + "sub-topologies"/"sub-configs" are stored as a string -- this is the actual containerlab + topology that gets mounted in the launcher pod. type: object exposedPorts: additionalProperties: description: ExposedPorts holds information about exposed ports. properties: loadBalancerAddress: - description: LoadBalancerAddress holds the address assigned - to the load balancer exposing ports for a given node. + description: |- + LoadBalancerAddress holds the address assigned to the load balancer exposing ports for a + given node. type: string tcpPorts: description: TCPPorts is a list of TCP ports exposed on the @@ -376,8 +446,9 @@ spec: - tcpPorts - udpPorts type: object - description: ExposedPorts holds a map of (containerlab not k8s!) nodes - and their exposed ports (via load balancer). + description: |- + ExposedPorts holds a map of (containerlab not k8s!) nodes and their exposed ports + (via load balancer). type: object kind: description: Kind is the topology kind this CR represents -- for example @@ -391,37 +462,35 @@ spec: run. properties: config: - description: Config is the last stored hash of the rendered config(s) - -- that is, the map of "sub topologies" representing the overall - Topology.Spec.Definition. + description: |- + Config is the last stored hash of the rendered config(s) -- that is, the map of "sub + topologies" representing the overall Topology.Spec.Definition. type: string exposedPorts: - description: ExposedPorts is the last stored hash of the exposed - ports mapping for this Topology. Note that while we obviously - care about the exposed ports on a *per node basis*, we don't - need to track that here -- this is here strictly to track differences - in the load balancer service -- the actual sub-topologies (or - sub-configs) effectively track the expose port status per node. + description: |- + ExposedPorts is the last stored hash of the exposed ports mapping for this Topology. Note + that while we obviously care about the exposed ports on a *per node basis*, we don't need to + track that here -- this is here strictly to track differences in the load balancer service -- + the actual sub-topologies (or sub-configs) effectively track the expose port status per node. type: string filesFromURL: additionalProperties: type: string - description: FilesFromURL is the hash of the last stored mapping - of files from URL (to node mapping). Note that this is tracked - on a *per node basis* because the URL of a file could be updated - without any change to the actual config/topology (or sub-config/sub-topology); - as such we need to explicitly track this per node to know when - a node needs to be restarted such that the new URL is "picked - up" by the node/launcher. + description: |- + FilesFromURL is the hash of the last stored mapping of files from URL (to node mapping). Note + that this is tracked on a *per node basis* because the URL of a file could be updated without + any change to the actual config/topology (or sub-config/sub-topology); as such we need to + explicitly track this per node to know when a node needs to be restarted such that the new + URL is "picked up" by the node/launcher. type: object imagePullSecrets: description: ImagePullSecrets is the hash of hte last stored image pull secrets for this Topology. type: string tunnels: - description: Tunnels is the last stored hash of the tunnels that - provided connectivity between the launcher nodes. As this can - change due to the dns suffix changing and not just the config + description: |- + Tunnels is the last stored hash of the tunnels that provided connectivity between the + launcher nodes. As this can change due to the dns suffix changing and not just the config changing we need to independently track this state. type: string required: diff --git a/clabverter/test-fixtures/golden/srl02.yaml b/clabverter/test-fixtures/golden/srl02.yaml index ba3eabb5..cc6500ae 100755 --- a/clabverter/test-fixtures/golden/srl02.yaml +++ b/clabverter/test-fixtures/golden/srl02.yaml @@ -55,6 +55,8 @@ spec: enabled: false privilegedLauncher: null resources: null + scheduling: + tolerations: null expose: disableAutoExpose: false disableExpose: false diff --git a/controllers/topology/configmap.go b/controllers/topology/configmap.go index 467d56ec..dc8138b1 100644 --- a/controllers/topology/configmap.go +++ b/controllers/topology/configmap.go @@ -127,14 +127,14 @@ func (r *ConfigMapReconciler) Conforms( return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingConfigMap.ObjectMeta.Annotations, renderedConfigMap.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingConfigMap.ObjectMeta.Labels, renderedConfigMap.ObjectMeta.Labels, ) { diff --git a/controllers/topology/deployment.go b/controllers/topology/deployment.go index 33ddf6fb..ae33ecbc 100644 --- a/controllers/topology/deployment.go +++ b/controllers/topology/deployment.go @@ -162,6 +162,17 @@ func (r *DeploymentReconciler) renderDeploymentBase( } } +func (r *DeploymentReconciler) renderDeploymentScheduling( + deployment *k8sappsv1.Deployment, + owningTopology *clabernetesapisv1alpha1.Topology, +) { + nodeSelector := owningTopology.Spec.Deployment.Scheduling.NodeSelector + tolerations := owningTopology.Spec.Deployment.Scheduling.Tolerations + + deployment.Spec.Template.Spec.NodeSelector = nodeSelector + deployment.Spec.Template.Spec.Tolerations = tolerations +} + func (r *DeploymentReconciler) renderDeploymentVolumes( deployment *k8sappsv1.Deployment, nodeName, @@ -778,6 +789,11 @@ func (r *DeploymentReconciler) Render( nodeName, ) + r.renderDeploymentScheduling( + deployment, + owningTopology, + ) + volumeMountsFromCommonSpec := r.renderDeploymentVolumes( deployment, nodeName, @@ -851,7 +867,7 @@ func (r *DeploymentReconciler) RenderAll( } // Conforms checks if the existingDeployment conforms with the renderedDeployment. -func (r *DeploymentReconciler) Conforms( +func (r *DeploymentReconciler) Conforms( //nolint: gocyclo existingDeployment, renderedDeployment *k8sappsv1.Deployment, expectedOwnerUID apimachinerytypes.UID, @@ -869,6 +885,20 @@ func (r *DeploymentReconciler) Conforms( return false } + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( + existingDeployment.Spec.Template.Spec.NodeSelector, + renderedDeployment.Spec.Template.Spec.NodeSelector, + ) { + return false + } + + if !reflect.DeepEqual( + existingDeployment.Spec.Template.Spec.Tolerations, + renderedDeployment.Spec.Template.Spec.Tolerations, + ) { + return false + } + if !reflect.DeepEqual( existingDeployment.Spec.Template.Spec.Volumes, renderedDeployment.Spec.Template.Spec.Volumes, @@ -897,28 +927,28 @@ func (r *DeploymentReconciler) Conforms( return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingDeployment.ObjectMeta.Annotations, renderedDeployment.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingDeployment.ObjectMeta.Labels, renderedDeployment.ObjectMeta.Labels, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingDeployment.Spec.Template.ObjectMeta.Annotations, renderedDeployment.Spec.Template.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingDeployment.Spec.Template.ObjectMeta.Labels, renderedDeployment.Spec.Template.ObjectMeta.Labels, ) { diff --git a/controllers/topology/deployment_test.go b/controllers/topology/deployment_test.go index f8a4766e..0d1953a4 100644 --- a/controllers/topology/deployment_test.go +++ b/controllers/topology/deployment_test.go @@ -493,6 +493,61 @@ func TestRenderDeployment(t *testing.T) { }, nodeName: "srl1", }, + { + name: "scheduling", + owningTopology: &clabernetesapisv1alpha1.Topology{ + ObjectMeta: metav1.ObjectMeta{ + Name: "render-deployment-test", + Namespace: "clabernetes", + }, + Spec: clabernetesapisv1alpha1.TopologySpec{ + Deployment: clabernetesapisv1alpha1.Deployment{ + Scheduling: clabernetesapisv1alpha1.Scheduling{ + NodeSelector: map[string]string{ + "somelabel": "somevalue", + }, + Tolerations: []k8scorev1.Toleration{ + { + Key: "sometaintkey", + Operator: "Equal", + Value: "sometaintvalue", + Effect: "NoSchedule", + }, + }, + }, + }, + Definition: clabernetesapisv1alpha1.Definition{ + Containerlab: `--- + name: test + topology: + nodes: + srl1: + kind: srl + image: ghcr.io/nokia/srlinux + `, + }, + }, + }, + clabernetesConfigs: map[string]*clabernetesutilcontainerlab.Config{ + "srl1": { + Name: "srl1", + Prefix: clabernetesutil.ToPointer(""), + Topology: &clabernetesutilcontainerlab.Topology{ + Defaults: &clabernetesutilcontainerlab.NodeDefinition{}, + Kinds: nil, + Nodes: map[string]*clabernetesutilcontainerlab.NodeDefinition{ + "srl1": { + Kind: "srl", + Image: "ghcr.io/nokia/srlinux", + }, + }, + Links: nil, + }, + Debug: false, + }, + }, + nodeName: "srl1", + }, } for _, testCase := range cases { @@ -1074,6 +1129,146 @@ func TestDeploymentConforms(t *testing.T) { ownerUID: apimachinerytypes.UID("clabernetes-testing"), conforms: false, }, + + // scheduling things + { + name: "mismatched-node-selector-simple", + existing: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + NodeSelector: map[string]string{ + "somenodekey": "somenodevalue", + }, + }, + }, + }, + }, + rendered: &k8sappsv1.Deployment{}, + ownerUID: apimachinerytypes.UID("clabernetes-testing"), + conforms: false, + }, + { + name: "mismatched-node-selector", + existing: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + NodeSelector: map[string]string{ + "somenodekey": "somenodevalue", + }, + }, + }, + }, + }, + rendered: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + NodeSelector: map[string]string{ + "somenodekey": "somenodevalue", + "anotherkey": "anothervalue", + }, + }, + }, + }, + }, + ownerUID: apimachinerytypes.UID("clabernetes-testing"), + conforms: false, + }, + { + name: "node-selector-ignore-extras", + existing: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + NodeSelector: map[string]string{ + "somenodekey": "somenodevalue", + "anotherkey": "anothervalue", + }, + }, + }, + }, + }, + rendered: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + NodeSelector: map[string]string{ + "somenodekey": "somenodevalue", + }, + }, + }, + }, + }, + ownerUID: apimachinerytypes.UID("clabernetes-testing"), + conforms: false, + }, + { + name: "mismatched-tolerations-simple", + existing: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + Tolerations: []k8scorev1.Toleration{ + { + Key: "sometoleration", + Operator: "Equal", + Value: "something", + Effect: "NoSchedule", + }, + }, + }, + }, + }, + }, + rendered: &k8sappsv1.Deployment{}, + ownerUID: apimachinerytypes.UID("clabernetes-testing"), + conforms: false, + }, + { + name: "mismatched-tolerations", + existing: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + Tolerations: []k8scorev1.Toleration{ + { + Key: "sometoleration", + Operator: "Equal", + Value: "something", + Effect: "NoSchedule", + }, + }, + }, + }, + }, + }, + rendered: &k8sappsv1.Deployment{ + Spec: k8sappsv1.DeploymentSpec{ + Template: k8scorev1.PodTemplateSpec{ + Spec: k8scorev1.PodSpec{ + Tolerations: []k8scorev1.Toleration{ + { + Key: "sometoleration", + Operator: "Equal", + Value: "something", + Effect: "NoSchedule", + }, + { + Key: "extratoleration", + Operator: "Equal", + Value: "foobar", + Effect: "NoSchedule", + }, + }, + }, + }, + }, + }, + ownerUID: apimachinerytypes.UID("clabernetes-testing"), + conforms: false, + }, } for _, testCase := range cases { diff --git a/controllers/topology/persistentvolumeclaim.go b/controllers/topology/persistentvolumeclaim.go index a780c2de..c665dd7c 100644 --- a/controllers/topology/persistentvolumeclaim.go +++ b/controllers/topology/persistentvolumeclaim.go @@ -244,14 +244,14 @@ func (r *PersistentVolumeClaimReconciler) Conforms( ) } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingPVC.ObjectMeta.Annotations, renderedPVC.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingPVC.ObjectMeta.Labels, renderedPVC.ObjectMeta.Labels, ) { diff --git a/controllers/topology/rolebinding.go b/controllers/topology/rolebinding.go index b02ca5c4..1a8c1cff 100644 --- a/controllers/topology/rolebinding.go +++ b/controllers/topology/rolebinding.go @@ -225,14 +225,14 @@ func (r *RoleBindingReconciler) Conforms( return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingRoleBinding.ObjectMeta.Annotations, renderedRoleBinding.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingRoleBinding.ObjectMeta.Labels, renderedRoleBinding.ObjectMeta.Labels, ) { diff --git a/controllers/topology/service.go b/controllers/topology/service.go index a815569c..80af24e3 100644 --- a/controllers/topology/service.go +++ b/controllers/topology/service.go @@ -55,14 +55,14 @@ func ServiceConforms( } } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingService.ObjectMeta.Annotations, renderedService.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingService.ObjectMeta.Labels, renderedService.ObjectMeta.Labels, ) { diff --git a/controllers/topology/serviceaccount.go b/controllers/topology/serviceaccount.go index 03bbe9d4..6ed3385a 100644 --- a/controllers/topology/serviceaccount.go +++ b/controllers/topology/serviceaccount.go @@ -205,14 +205,14 @@ func (r *ServiceAccountReconciler) Conforms( renderedServiceAccount *k8scorev1.ServiceAccount, expectedOwnerUID apimachinerytypes.UID, ) bool { - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingServiceAccount.ObjectMeta.Annotations, renderedServiceAccount.ObjectMeta.Annotations, ) { return false } - if !clabernetesutilkubernetes.AnnotationsOrLabelsConform( + if !clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( existingServiceAccount.ObjectMeta.Labels, renderedServiceAccount.ObjectMeta.Labels, ) { diff --git a/controllers/topology/test-fixtures/golden/deployment/render-deployment/scheduling.json b/controllers/topology/test-fixtures/golden/deployment/render-deployment/scheduling.json new file mode 100755 index 00000000..3904b638 --- /dev/null +++ b/controllers/topology/test-fixtures/golden/deployment/render-deployment/scheduling.json @@ -0,0 +1,251 @@ +{ + "metadata": { + "name": "render-deployment-test-srl1", + "namespace": "clabernetes", + "creationTimestamp": null, + "labels": { + "app.kubernetes.io/name": "render-deployment-test-srl1", + "clabernetes/app": "clabernetes", + "clabernetes/name": "render-deployment-test-srl1", + "clabernetes/topologyNode": "srl1", + "clabernetes/topologyOwner": "render-deployment-test" + }, + "annotations": { + "container.apparmor.security.beta.kubernetes.io/srl1": "unconfined" + } + }, + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { + "app.kubernetes.io/name": "render-deployment-test-srl1", + "clabernetes/app": "clabernetes", + "clabernetes/name": "render-deployment-test-srl1", + "clabernetes/topologyNode": "srl1", + "clabernetes/topologyOwner": "render-deployment-test" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app.kubernetes.io/name": "render-deployment-test-srl1", + "clabernetes/app": "clabernetes", + "clabernetes/name": "render-deployment-test-srl1", + "clabernetes/topologyNode": "srl1", + "clabernetes/topologyOwner": "render-deployment-test" + }, + "annotations": { + "container.apparmor.security.beta.kubernetes.io/srl1": "unconfined" + } + }, + "spec": { + "volumes": [ + { + "name": "render-deployment-test-config", + "configMap": { + "name": "render-deployment-test", + "defaultMode": 493 + } + }, + { + "name": "dev-kvm", + "hostPath": { + "path": "/dev/kvm", + "type": "" + } + }, + { + "name": "dev-fuse", + "hostPath": { + "path": "/dev/fuse", + "type": "" + } + }, + { + "name": "dev-net-tun", + "hostPath": { + "path": "/dev/net/tun", + "type": "" + } + } + ], + "containers": [ + { + "name": "srl1", + "image": "ghcr.io/srl-labs/clabernetes/clabernetes-launcher:latest", + "command": [ + "/clabernetes/manager", + "launch" + ], + "workingDir": "/clabernetes", + "ports": [ + { + "name": "vxlan", + "containerPort": 14789, + "protocol": "UDP" + } + ], + "env": [ + { + "name": "NODE_NAME", + "valueFrom": { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "spec.nodeName" + } + } + }, + { + "name": "POD_NAME", + "valueFrom": { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.name" + } + } + }, + { + "name": "POD_NAMESPACE", + "valueFrom": { + "fieldRef": { + "apiVersion": "v1", + "fieldPath": "metadata.namespace" + } + } + }, + { + "name": "APP_NAME", + "value": "clabernetes" + }, + { + "name": "MANAGER_NAMESPACE", + "value": "clabernetes" + }, + { + "name": "LAUNCHER_CRI_KIND" + }, + { + "name": "LAUNCHER_IMAGE_PULL_THROUGH_MODE", + "value": "auto" + }, + { + "name": "LAUNCHER_LOGGER_LEVEL", + "value": "info" + }, + { + "name": "LAUNCHER_TOPOLOGY_NAME", + "value": "render-deployment-test" + }, + { + "name": "LAUNCHER_NODE_NAME", + "value": "srl1" + }, + { + "name": "LAUNCHER_NODE_IMAGE", + "value": "ghcr.io/nokia/srlinux" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "render-deployment-test-config", + "readOnly": true, + "mountPath": "/clabernetes/topo.clab.yaml", + "subPath": "srl1" + }, + { + "name": "render-deployment-test-config", + "readOnly": true, + "mountPath": "/clabernetes/tunnels.yaml", + "subPath": "srl1-tunnels" + }, + { + "name": "render-deployment-test-config", + "readOnly": true, + "mountPath": "/clabernetes/files-from-url.yaml", + "subPath": "srl1-files-from-url" + }, + { + "name": "render-deployment-test-config", + "readOnly": true, + "mountPath": "/clabernetes/configured-pull-secrets.yaml", + "subPath": "configured-pull-secrets" + }, + { + "name": "dev-kvm", + "readOnly": true, + "mountPath": "/dev/kvm" + }, + { + "name": "dev-fuse", + "readOnly": true, + "mountPath": "/dev/fuse" + }, + { + "name": "dev-net-tun", + "readOnly": true, + "mountPath": "/dev/net/tun" + } + ], + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": { + "add": [ + "CHOWN", + "DAC_OVERRIDE", + "FSETID", + "FOWNER", + "MKNOD", + "NET_RAW", + "SETGID", + "SETUID", + "SETFCAP", + "SETPCAP", + "NET_BIND_SERVICE", + "SYS_CHROOT", + "KILL", + "AUDIT_WRITE", + "NET_ADMIN", + "SYS_ADMIN", + "SYS_RESOURCE", + "LINUX_IMMUTABLE", + "SYS_BOOT", + "SYS_TIME", + "SYS_MODULE", + "SYS_RAWIO", + "SYS_PTRACE", + "SYS_NICE", + "IPC_LOCK" + ] + }, + "privileged": false, + "runAsUser": 0 + } + } + ], + "restartPolicy": "Always", + "nodeSelector": { + "somelabel": "somevalue" + }, + "serviceAccountName": "clabernetes-launcher-service-account", + "hostname": "srl1", + "tolerations": [ + { + "key": "sometaintkey", + "operator": "Equal", + "value": "sometaintvalue", + "effect": "NoSchedule" + } + ] + } + }, + "strategy": { + "type": "Recreate" + }, + "revisionHistoryLimit": 0 + }, + "status": {} +} \ No newline at end of file diff --git a/e2e/clabverter/test-fixtures/golden/10-topology.clabverter-basic.yaml b/e2e/clabverter/test-fixtures/golden/10-topology.clabverter-basic.yaml index 619c9a7b..98d70763 100755 --- a/e2e/clabverter/test-fixtures/golden/10-topology.clabverter-basic.yaml +++ b/e2e/clabverter/test-fixtures/golden/10-topology.clabverter-basic.yaml @@ -24,6 +24,7 @@ spec: deployment: persistence: enabled: false + scheduling: {} expose: disableAutoExpose: false disableExpose: false diff --git a/e2e/topology/basic/test-fixtures/golden/10-topology.topology-basic.yaml b/e2e/topology/basic/test-fixtures/golden/10-topology.topology-basic.yaml index 0094ea3f..86427013 100755 --- a/e2e/topology/basic/test-fixtures/golden/10-topology.topology-basic.yaml +++ b/e2e/topology/basic/test-fixtures/golden/10-topology.topology-basic.yaml @@ -17,6 +17,7 @@ spec: deployment: persistence: enabled: false + scheduling: {} expose: disableAutoExpose: false disableExpose: false diff --git a/generated/openapi/openapi_generated.go b/generated/openapi/openapi_generated.go index b9a7581f..8a937c79 100644 --- a/generated/openapi/openapi_generated.go +++ b/generated/openapi/openapi_generated.go @@ -93,6 +93,9 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/srl-labs/clabernetes/apis/v1alpha1.ReconcileHashes": schema_srl_labs_clabernetes_apis_v1alpha1_ReconcileHashes( ref, ), + "github.com/srl-labs/clabernetes/apis/v1alpha1.Scheduling": schema_srl_labs_clabernetes_apis_v1alpha1_Scheduling( + ref, + ), "github.com/srl-labs/clabernetes/apis/v1alpha1.Topology": schema_srl_labs_clabernetes_apis_v1alpha1_Topology( ref, ), @@ -511,6 +514,15 @@ func schema_srl_labs_clabernetes_apis_v1alpha1_Deployment( }, }, }, + "scheduling": { + SchemaProps: spec.SchemaProps{ + Description: "Scheduling holds information about how the launcher pod(s) should be configured with respect to \"scheduling\" things (affinity/node selector/tolerations).", + Default: map[string]interface{}{}, + Ref: ref( + "github.com/srl-labs/clabernetes/apis/v1alpha1.Scheduling", + ), + }, + }, "privilegedLauncher": { SchemaProps: spec.SchemaProps{ Description: "PrivilegedLauncher, when true, sets the launcher containers to privileged. By default, we do our best to *not* need this/set this, and instead set only the capabilities we need, however its possible that some containers launched by the launcher may need/want more capabilities, so this flag exists for users to bypass the default settings and enable fully privileged launcher pods. If this value is unset, the global config value (default of \"false\") will be used.", @@ -607,7 +619,7 @@ func schema_srl_labs_clabernetes_apis_v1alpha1_Deployment( }, }, Dependencies: []string{ - "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromConfigMap", "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromURL", "github.com/srl-labs/clabernetes/apis/v1alpha1.Persistence", "k8s.io/api/core/v1.ResourceRequirements"}, + "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromConfigMap", "github.com/srl-labs/clabernetes/apis/v1alpha1.FileFromURL", "github.com/srl-labs/clabernetes/apis/v1alpha1.Persistence", "github.com/srl-labs/clabernetes/apis/v1alpha1.Scheduling", "k8s.io/api/core/v1.ResourceRequirements"}, } } @@ -1201,6 +1213,53 @@ func schema_srl_labs_clabernetes_apis_v1alpha1_ReconcileHashes( } } +func schema_srl_labs_clabernetes_apis_v1alpha1_Scheduling( + ref common.ReferenceCallback, +) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Scheduling holds information about how the launcher pod(s) should be configured with respect to \"scheduling\" things (affinity/node selector/tolerations).", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "nodeSelector": { + SchemaProps: spec.SchemaProps{ + Description: "NodeSelector sets the node selector that will be configured on all launcher pods for this Topology.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "tolerations": { + SchemaProps: spec.SchemaProps{ + Description: "Tolerations is a list of Tolerations that will be set on the launcher pod spec.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.Toleration"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.Toleration"}, + } +} + func schema_srl_labs_clabernetes_apis_v1alpha1_Topology( ref common.ReferenceCallback, ) common.OpenAPIDefinition { diff --git a/util/kubernetes/meta.go b/util/kubernetes/meta.go index 1eba55b7..fa0e9861 100644 --- a/util/kubernetes/meta.go +++ b/util/kubernetes/meta.go @@ -1,8 +1,12 @@ package kubernetes -// AnnotationsOrLabelsConform returns false if the existing labels/annotations (or really just map) -// does *not* have all the keys/values from the expected/rendered labels/annotations. -func AnnotationsOrLabelsConform(existing, expected map[string]string) bool { +// ExistingMapStringStringContainsAllExpectedKeyValues returns false if the existing map of strings +// does *not* have all the keys/values from the expected/rendered labels/annotations. Basically -- +// if the existing map has what we expect and anything else return true. If the existing map does +// not contain all the things we expected, return false. +func ExistingMapStringStringContainsAllExpectedKeyValues( + existing, expected map[string]string, +) bool { if len(existing) == 0 && len(expected) > 0 { // obviously our annotations don't exist, so we need to enforce that return false diff --git a/util/kubernetes/meta_test.go b/util/kubernetes/meta_test.go index cf1d6e32..a9703c56 100644 --- a/util/kubernetes/meta_test.go +++ b/util/kubernetes/meta_test.go @@ -70,7 +70,7 @@ func TestContainersEqualAnnotationsOrLabelsConform(t *testing.T) { func(t *testing.T) { t.Logf("%s: starting", testCase.name) - actual := clabernetesutilkubernetes.AnnotationsOrLabelsConform( + actual := clabernetesutilkubernetes.ExistingMapStringStringContainsAllExpectedKeyValues( testCase.a, testCase.b, )