From 9a0db98c89019eb5d43746ad3bc0460f487ce99d Mon Sep 17 00:00:00 2001 From: Fred Rolland Date: Mon, 24 Jul 2023 14:13:16 +0300 Subject: [PATCH] NVIPAMPool CRD - Add CRD definition - Add Make targets - Add CR examples based on ConfigMap example Signed-off-by: Fred Rolland --- Makefile | 15 +- api/v1alpha1/groupversion_info.go | 33 ++++ api/v1alpha1/ippool_type.go | 72 ++++++++ api/v1alpha1/zz_generated.deepcopy.go | 137 +++++++++++++++ boilerplate.go.txt | 12 ++ deploy/crds/nv-ipam.nvidia.com_ippools.yaml | 175 ++++++++++++++++++++ examples/ippool-1.yaml | 16 ++ examples/ippool-2.yaml | 16 ++ 8 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 api/v1alpha1/groupversion_info.go create mode 100644 api/v1alpha1/ippool_type.go create mode 100644 api/v1alpha1/zz_generated.deepcopy.go create mode 100644 boilerplate.go.txt create mode 100644 deploy/crds/nv-ipam.nvidia.com_ippools.yaml create mode 100644 examples/ippool-1.yaml create mode 100644 examples/ippool-2.yaml diff --git a/Makefile b/Makefile index e2b9e1d..f755d6b 100644 --- a/Makefile +++ b/Makefile @@ -143,6 +143,7 @@ PROTOC ?= $(LOCALBIN)/protoc/bin/protoc PROTOC_GEN_GO ?= $(LOCALBIN)/protoc-gen-go PROTOC_GEN_GO_GRPC ?= $(LOCALBIN)/protoc-gen-go-grpc BUF ?= $(LOCALBIN)/buf +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ## Tool Versions GOLANGCILINT_VERSION ?= v1.52.2 @@ -152,7 +153,7 @@ PROTOC_VER ?= 23.4 PROTOC_GEN_GO_VER ?= 1.31.0 PROTOC_GEN_GO_GRPC_VER ?= 1.3.0 BUF_VERSION ?= 1.23.1 - +CONTROLLER_GEN_VERSION ?= v0.13.0 .PHONY: envtest envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. @@ -251,3 +252,15 @@ grpc-format: buf ## Format GRPC files @echo "format protobuf files"; cd $(PROTO_DIR) && \ $(BUF) format -w --exit-code +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary +$(CONTROLLER_GEN): | $(LOCALBIN) + GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_GEN_VERSION) + +.PHONY: generate +generate: controller-gen + $(CONTROLLER_GEN) object:headerFile="./boilerplate.go.txt" paths="./api/..." + +.PHONY: manifests +manifests: controller-gen + $(CONTROLLER_GEN) crd paths="./api/..." output:dir="./deploy/crds" diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000..2852a03 --- /dev/null +++ b/api/v1alpha1/groupversion_info.go @@ -0,0 +1,33 @@ +/* + Copyright 2023, NVIDIA CORPORATION & AFFILIATES + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// +kubebuilder:object:generate=true +// +groupName=nv-ipam.nvidia.com + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "nv-ipam.nvidia.com", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1alpha1/ippool_type.go b/api/v1alpha1/ippool_type.go new file mode 100644 index 0000000..834921a --- /dev/null +++ b/api/v1alpha1/ippool_type.go @@ -0,0 +1,72 @@ +/* + Copyright 2023, NVIDIA CORPORATION & AFFILIATES + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Subnet",type="string",JSONPath=`.spec.subnet` +// +kubebuilder:printcolumn:name="Gateway",type="string",JSONPath=`.spec.gateway` +// +kubebuilder:printcolumn:name="Block Size",type="integer",JSONPath=`.spec.perNodeBlockSize` + +// IPPool contains configuration for IPAM controller +type IPPool struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec IPPoolSpec `json:"spec"` + Status IPPoolStatus `json:"status,omitempty"` +} + +// IPPoolSpec contains configuration for IP pool +type IPPoolSpec struct { + // subnet of the pool + Subnet string `json:"subnet"` + // amount of IPs to allocate for each node, + // must be less than amount of available IPs in the subnet + PerNodeBlockSize int `json:"perNodeBlockSize"` + // gateway for the pool + Gateway string `json:"gateway"` + // selector for nodes, if empty match all nodes + NodeSelector *corev1.NodeSelector `json:"nodeSelector,omitempty"` +} + +// IPPoolStatus contains the IP ranges allocated to nodes +type IPPoolStatus struct { + // IP allocations for Nodes + Allocations []Allocation `json:"allocations"` +} + +// Allocation contains IP Allocation for a specific Node +type Allocation struct { + NodeName string `json:"nodeName"` + StartIP string `json:"startIP"` + EndIP string `json:"endIP"` +} + +// +kubebuilder:object:root=true + +// IPPoolList contains a list of IPPool +type IPPoolList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IPPool `json:"items"` +} + +func init() { + SchemeBuilder.Register(&IPPool{}, &IPPoolList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..f74af3e --- /dev/null +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,137 @@ +//go:build !ignore_autogenerated + +/* + Copyright 2023, NVIDIA CORPORATION & AFFILIATES + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Allocation) DeepCopyInto(out *Allocation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Allocation. +func (in *Allocation) DeepCopy() *Allocation { + if in == nil { + return nil + } + out := new(Allocation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPool) DeepCopyInto(out *IPPool) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. +func (in *IPPool) DeepCopy() *IPPool { + if in == nil { + return nil + } + out := new(IPPool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPPool) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IPPool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. +func (in *IPPoolList) DeepCopy() *IPPoolList { + if in == nil { + return nil + } + out := new(IPPoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPPoolList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolSpec) DeepCopyInto(out *IPPoolSpec) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = new(v1.NodeSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolSpec. +func (in *IPPoolSpec) DeepCopy() *IPPoolSpec { + if in == nil { + return nil + } + out := new(IPPoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPPoolStatus) DeepCopyInto(out *IPPoolStatus) { + *out = *in + if in.Allocations != nil { + in, out := &in.Allocations, &out.Allocations + *out = make([]Allocation, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolStatus. +func (in *IPPoolStatus) DeepCopy() *IPPoolStatus { + if in == nil { + return nil + } + out := new(IPPoolStatus) + in.DeepCopyInto(out) + return out +} diff --git a/boilerplate.go.txt b/boilerplate.go.txt new file mode 100644 index 0000000..44d6a40 --- /dev/null +++ b/boilerplate.go.txt @@ -0,0 +1,12 @@ +/* + Copyright 2023, NVIDIA CORPORATION & AFFILIATES + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ diff --git a/deploy/crds/nv-ipam.nvidia.com_ippools.yaml b/deploy/crds/nv-ipam.nvidia.com_ippools.yaml new file mode 100644 index 0000000..0190190 --- /dev/null +++ b/deploy/crds/nv-ipam.nvidia.com_ippools.yaml @@ -0,0 +1,175 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: ippools.nv-ipam.nvidia.com +spec: + group: nv-ipam.nvidia.com + names: + kind: IPPool + listKind: IPPoolList + plural: ippools + singular: ippool + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.subnet + name: Subnet + type: string + - jsonPath: .spec.gateway + name: Gateway + type: string + - jsonPath: .spec.perNodeBlockSize + name: Block Size + type: integer + name: v1alpha1 + schema: + openAPIV3Schema: + description: IPPool contains configuration for IPAM controller + 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' + 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' + type: string + metadata: + type: object + spec: + description: IPPoolSpec contains configuration for IP pool + properties: + gateway: + description: gateway for the pool + type: string + nodeSelector: + description: selector for nodes, if empty match all nodes + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms + are ORed. + items: + description: A null or empty node selector term matches no objects. + The requirements of them are ANDed. The TopologySelectorTerm + type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's + labels. + items: + description: A node selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: Represents a key's relationship to a + set of values. Valid operators are In, NotIn, Exists, + DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator + is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. If the operator is Gt or Lt, + the values array must have a single element, which + will be interpreted as an integer. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements by node's + fields. + items: + description: A node selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: Represents a key's relationship to a + set of values. Valid operators are In, NotIn, Exists, + DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator + is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. If the operator is Gt or Lt, + the values array must have a single element, which + will be interpreted as an integer. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + perNodeBlockSize: + description: amount of IPs to allocate for each node, must be less + than amount of available IPs in the subnet + type: integer + subnet: + description: subnet of the pool + type: string + required: + - gateway + - perNodeBlockSize + - subnet + type: object + status: + description: IPPoolStatus contains the IP ranges allocated to nodes + properties: + allocations: + description: IP allocations for Nodes + items: + description: Allocation contains IP Allocation for a specific Node + properties: + endIP: + type: string + nodeName: + type: string + startIP: + type: string + required: + - endIP + - nodeName + - startIP + type: object + type: array + required: + - allocations + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/examples/ippool-1.yaml b/examples/ippool-1.yaml new file mode 100644 index 0000000..8fd733b --- /dev/null +++ b/examples/ippool-1.yaml @@ -0,0 +1,16 @@ +apiVersion: nv-ipam.nvidia.com/v1alpha1 +kind: IPPool +metadata: + name: pool1 + namespace: kube-system +spec: + subnet: 192.168.0.0/16 + perNodeBlockSize: 128 + gateway: 192.168.0.1 + nodeSelector: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/role + operator: In + values: + - worker diff --git a/examples/ippool-2.yaml b/examples/ippool-2.yaml new file mode 100644 index 0000000..cb17207 --- /dev/null +++ b/examples/ippool-2.yaml @@ -0,0 +1,16 @@ +apiVersion: nv-ipam.nvidia.com/v1alpha1 +kind: IPPool +metadata: + name: pool2 + namespace: kube-system +spec: + subnet: 172.16.0.0/16 + perNodeBlockSize: 128 + gateway: 172.16.0.1 + nodeSelector: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/role + operator: In + values: + - worker