diff --git a/crd/overlayextensionconfig/Makefile b/crd/overlayextensionconfig/Makefile new file mode 100644 index 0000000000..c1fd004a43 --- /dev/null +++ b/crd/overlayextensionconfig/Makefile @@ -0,0 +1,19 @@ +.DEFAULT_GOAL = all + +REPO_ROOT = $(shell git rev-parse --show-toplevel) +TOOLS_DIR = $(REPO_ROOT)/build/tools +TOOLS_BIN_DIR = $(REPO_ROOT)/build/tools/bin +CONTROLLER_GEN = $(TOOLS_BIN_DIR)/controller-gen + +all: generate manifests + +generate: $(CONTROLLER_GEN) + $(CONTROLLER_GEN) object paths="./..." + +.PHONY: manifests +manifests: $(CONTROLLER_GEN) + mkdir -p manifests + $(CONTROLLER_GEN) crd paths="./..." output:crd:artifacts:config=manifests/ + +$(CONTROLLER_GEN): + @make -C $(REPO_ROOT) $(CONTROLLER_GEN) diff --git a/crd/overlayextensionconfig/README.md b/crd/overlayextensionconfig/README.md new file mode 100644 index 0000000000..a155b3055b --- /dev/null +++ b/crd/overlayextensionconfig/README.md @@ -0,0 +1,5 @@ +List of included CRDs + +# OverlayExtensionConfig CRD + +OverlayExtensionConfig CRD defines an IP address range (usually an Azure subnet) from which it is possible to reach routing domain IPs (usually pods running in Azure CNI Overlay cluster). diff --git a/crd/overlayextensionconfig/api/v1alpha1/groupversion_info.go b/crd/overlayextensionconfig/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000000..88c30b03ed --- /dev/null +++ b/crd/overlayextensionconfig/api/v1alpha1/groupversion_info.go @@ -0,0 +1,23 @@ +//go:build !ignore_uncovered +// +build !ignore_uncovered + +// Package v1alpha1 contains API Schema definitions for the acn v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=acn.azure.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: "acn.azure.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/crd/overlayextensionconfig/api/v1alpha1/overlayextensionconfig_types.go b/crd/overlayextensionconfig/api/v1alpha1/overlayextensionconfig_types.go new file mode 100644 index 0000000000..c3d256e5d8 --- /dev/null +++ b/crd/overlayextensionconfig/api/v1alpha1/overlayextensionconfig_types.go @@ -0,0 +1,59 @@ +//go:build !ignore_uncovered +// +build !ignore_uncovered + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// OverlayExtensionConfig is the Schema for the overlayextensionconfigs API +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Namespaced +// +kubebuilder:resource:shortName=oec +// +kubebuilder:printcolumn:name="OverlayExtensionConfig IP range",type=string,priority=1,JSONPath=`.spec.extensionIPRange` +type OverlayExtensionConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec OverlayExtensionConfigSpec `json:"spec,omitempty"` + Status OverlayExtensionConfigStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// OverlayExtensionConfigList contains a list of OverlayExtensionConfig +type OverlayExtensionConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []OverlayExtensionConfig `json:"items"` +} + +// OverlayExtensionConfigSpec defines the desired state of OverlayExtensionConfig. +type OverlayExtensionConfigSpec struct { + // ExtensionIPRange field defines a CIDR that should be able to reach routing domain ip addresses. + // +kubebuilder:validation:Optional + ExtensionIPRange string `json:"extensionIPRange,omitempty"` +} + +type OECState string + +const ( + None OECState = "None" + Pending OECState = "Pending" + Succeeded OECState = "Succeeded" + Failed OECState = "Failed" +) + +// OverlayExtensionConfigStatus defines the observed state of OverlayExtensionConfig +type OverlayExtensionConfigStatus struct { + // +kubebuilder:validation:Enum=None;Pending;Succeeded;Failed + // +kubebuilder:default="None" + State OECState `json:"state,omitempty"` + Message string `json:"message,omitempty"` +} + +func init() { + SchemeBuilder.Register(&OverlayExtensionConfig{}, &OverlayExtensionConfigList{}) +} diff --git a/crd/overlayextensionconfig/api/v1alpha1/zz_generated.deepcopy.go b/crd/overlayextensionconfig/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..07d3c48fe4 --- /dev/null +++ b/crd/overlayextensionconfig/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,98 @@ +//go:build !ignore_autogenerated + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + 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 *OverlayExtensionConfig) DeepCopyInto(out *OverlayExtensionConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlayExtensionConfig. +func (in *OverlayExtensionConfig) DeepCopy() *OverlayExtensionConfig { + if in == nil { + return nil + } + out := new(OverlayExtensionConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OverlayExtensionConfig) 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 *OverlayExtensionConfigList) DeepCopyInto(out *OverlayExtensionConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OverlayExtensionConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlayExtensionConfigList. +func (in *OverlayExtensionConfigList) DeepCopy() *OverlayExtensionConfigList { + if in == nil { + return nil + } + out := new(OverlayExtensionConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OverlayExtensionConfigList) 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 *OverlayExtensionConfigSpec) DeepCopyInto(out *OverlayExtensionConfigSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlayExtensionConfigSpec. +func (in *OverlayExtensionConfigSpec) DeepCopy() *OverlayExtensionConfigSpec { + if in == nil { + return nil + } + out := new(OverlayExtensionConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverlayExtensionConfigStatus) DeepCopyInto(out *OverlayExtensionConfigStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverlayExtensionConfigStatus. +func (in *OverlayExtensionConfigStatus) DeepCopy() *OverlayExtensionConfigStatus { + if in == nil { + return nil + } + out := new(OverlayExtensionConfigStatus) + in.DeepCopyInto(out) + return out +} diff --git a/crd/overlayextensionconfig/client.go b/crd/overlayextensionconfig/client.go new file mode 100644 index 0000000000..97f7b16d30 --- /dev/null +++ b/crd/overlayextensionconfig/client.go @@ -0,0 +1,75 @@ +package overlayextensionconfig + +import ( + "context" + "reflect" + + "github.com/Azure/azure-container-networking/crd" + "github.com/Azure/azure-container-networking/crd/overlayextensionconfig/api/v1alpha1" + "github.com/pkg/errors" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + typedv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" +) + +// Scheme is a runtime scheme containing the client-go scheme and the OverlayExtensionConfig scheme. +var Scheme = runtime.NewScheme() + +func init() { + _ = scheme.AddToScheme(Scheme) + _ = v1alpha1.AddToScheme(Scheme) +} + +// Installer provides methods to manage the lifecycle of the OverlayExtensionConfig resource definition. +type Installer struct { + cli typedv1.CustomResourceDefinitionInterface +} + +func NewInstaller(c *rest.Config) (*Installer, error) { + cli, err := crd.NewCRDClientFromConfig(c) + if err != nil { + return nil, errors.Wrap(err, "failed to init crd client") + } + return &Installer{ + cli: cli, + }, nil +} + +func (i *Installer) create(ctx context.Context, res *v1.CustomResourceDefinition) (*v1.CustomResourceDefinition, error) { + res, err := i.cli.Create(ctx, res, metav1.CreateOptions{}) + if err != nil { + return nil, errors.Wrap(err, "failed to create oec crd") + } + return res, nil +} + +// InstallOrUpdate installs the embedded OverlayExtensionConfig CRD definition in the cluster or updates it if present. +func (i *Installer) InstallOrUpdate(ctx context.Context) (*v1.CustomResourceDefinition, error) { + oec, err := GetOverlayExtensionConfigs() + if err != nil { + return nil, errors.Wrap(err, "failed to get embedded oec crd") + } + current, err := i.create(ctx, oec) + if !apierrors.IsAlreadyExists(err) { + return current, err + } + if current == nil { + current, err = i.cli.Get(ctx, oec.Name, metav1.GetOptions{}) + if err != nil { + return nil, errors.Wrap(err, "failed to get existing oec crd") + } + } + if !reflect.DeepEqual(oec.Spec.Versions, current.Spec.Versions) { + oec.SetResourceVersion(current.GetResourceVersion()) + previous := *current + current, err = i.cli.Update(ctx, oec, metav1.UpdateOptions{}) + if err != nil { + return &previous, errors.Wrap(err, "failed to update existing oec crd") + } + } + return current, nil +} diff --git a/crd/overlayextensionconfig/embed.go b/crd/overlayextensionconfig/embed.go new file mode 100644 index 0000000000..d4ab04fee4 --- /dev/null +++ b/crd/overlayextensionconfig/embed.go @@ -0,0 +1,26 @@ +package overlayextensionconfig + +import ( + _ "embed" + + // import the manifests package so that caller of this package have the manifests compiled in as a side-effect. + _ "github.com/Azure/azure-container-networking/crd/nodenetworkconfig/manifests" + "github.com/pkg/errors" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/yaml" +) + +// OverlayExtensionConfigsYAML embeds the CRD YAML for downstream consumers. +// +//go:embed manifests/acn.azure.com_overlayextensionconfigs.yaml +var OverlayExtensionConfigsYAML []byte + +// GetOverlayExtensionConfigs parses the raw []byte NodeNetworkConfigs in +// to a CustomResourceDefinition and returns it or an unmarshalling error. +func GetOverlayExtensionConfigs() (*apiextensionsv1.CustomResourceDefinition, error) { + overlayExtensionConfigs := &apiextensionsv1.CustomResourceDefinition{} + if err := yaml.Unmarshal(OverlayExtensionConfigsYAML, &overlayExtensionConfigs); err != nil { + return nil, errors.Wrap(err, "error unmarshalling embedded nnc") + } + return overlayExtensionConfigs, nil +} diff --git a/crd/overlayextensionconfig/embed_test.go b/crd/overlayextensionconfig/embed_test.go new file mode 100644 index 0000000000..7084b5f7c3 --- /dev/null +++ b/crd/overlayextensionconfig/embed_test.go @@ -0,0 +1,22 @@ +package overlayextensionconfig + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const filename = "manifests/acn.azure.com_overlayextensionconfigs.yaml" + +func TestEmbed(t *testing.T) { + b, err := os.ReadFile(filename) + require.NoError(t, err) + assert.Equal(t, b, OverlayExtensionConfigsYAML) +} + +func TestGetOverlayExtensionConfigs(t *testing.T) { + _, err := GetOverlayExtensionConfigs() + require.NoError(t, err) +} diff --git a/crd/overlayextensionconfig/manifests/acn.azure.com_overlayextensionconfigs.yaml b/crd/overlayextensionconfig/manifests/acn.azure.com_overlayextensionconfigs.yaml new file mode 100644 index 0000000000..4bc9964254 --- /dev/null +++ b/crd/overlayextensionconfig/manifests/acn.azure.com_overlayextensionconfigs.yaml @@ -0,0 +1,69 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: overlayextensionconfigs.acn.azure.com +spec: + group: acn.azure.com + names: + kind: OverlayExtensionConfig + listKind: OverlayExtensionConfigList + plural: overlayextensionconfigs + shortNames: + - oec + singular: overlayextensionconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.extensionIPRange + name: OverlayExtensionConfig IP range + priority: 1 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: OverlayExtensionConfig is the Schema for the overlayextensionconfigs + API + 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: OverlayExtensionConfigSpec defines the desired state of OverlayExtensionConfig. + properties: + extensionIPRange: + description: ExtensionIPRange field defines a CIDR that should be + able to reach routing domain ip addresses. + type: string + type: object + status: + description: OverlayExtensionConfigStatus defines the observed state of + OverlayExtensionConfig + properties: + message: + type: string + state: + default: None + enum: + - None + - Pending + - Succeeded + - Failed + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/crd/overlayextensionconfig/manifests/doc.go b/crd/overlayextensionconfig/manifests/doc.go new file mode 100644 index 0000000000..b08acc397f --- /dev/null +++ b/crd/overlayextensionconfig/manifests/doc.go @@ -0,0 +1,3 @@ +// Package manifests exists to allow the rendered CRD manifests to be +// packaged in to dependent components. +package manifests