diff --git a/.golangci.yml b/.golangci.yml
index 22deb05..ed003c9 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -57,6 +57,8 @@ linters:
alias: metav1
- pkg: k8s.io/api/core/v1
alias: corev1
+ - pkg: k8s.io/api/rbac/v1
+ alias: rbacv1
- pkg: k8s.io/api/apps/v1
alias: appsv1
- pkg: k8s.io/api/admission/v1
@@ -67,6 +69,8 @@ linters:
alias: metav1ac
- pkg: k8s.io/client-go/applyconfigurations/core/v1
alias: corev1ac
+ - pkg: k8s.io/client-go/applyconfigurations/rbac/v1
+ alias: rbacv1ac
- pkg: k8s.io/client-go/applyconfigurations/apps/v1
alias: appsv1ac
- pkg: k8s.io/client-go/applyconfigurations/policy/v1
diff --git a/PROJECT b/PROJECT
index 68b0780..5564e55 100644
--- a/PROJECT
+++ b/PROJECT
@@ -115,4 +115,12 @@ resources:
kind: SidecarProfile
path: github.com/netbirdio/kubernetes-operator/api/v1alpha1
version: v1alpha1
+- api:
+ crdVersion: v1
+ namespaced: true
+ controller: true
+ domain: netbird.io
+ kind: ClusterProxy
+ path: github.com/netbirdio/kubernetes-operator/api/v1alpha1
+ version: v1alpha1
version: "3"
diff --git a/api/v1alpha1/clusterproxy_types.go b/api/v1alpha1/clusterproxy_types.go
new file mode 100644
index 0000000..e799bf2
--- /dev/null
+++ b/api/v1alpha1/clusterproxy_types.go
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+package v1alpha1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// ClusterProxySpec defines the desired state of ClusterProxy.
+type ClusterProxySpec struct {
+ // ClusterName is the name of the Kubernetes cluster.
+ // +required
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
+ ClusterName string `json:"clusterName"`
+
+ // APIServer is the URL of the Kubernetes API server to proxy requests to.
+ // +required
+ // +kubebuilder:default="https://kubernetes.default.svc.cluster.local"
+ APIServer string `json:"apiServer"`
+
+ // ServiceAccountName is a reference to the service account used for impersonation.
+ // +required
+ ServiceAccountName string `json:"serviceAccountName"`
+}
+
+// ClusterProxyStatus defines the observed state of ClusterProxy.
+type ClusterProxyStatus struct {
+ // ObservedGeneration is the last reconciled generation.
+ // +optional
+ ObservedGeneration int64 `json:"observedGeneration,omitempty"`
+
+ // Conditions holds the conditions for the ClusterProxy.
+ // +listType=map
+ // +listMapKey=type
+ // +optional
+ Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:resource
+// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
+// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
+
+// ClusterProxy is the Schema for the clusterproxies API
+type ClusterProxy struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ // +required
+ Spec ClusterProxySpec `json:"spec"`
+
+ // +kubebuilder:default={"observedGeneration":-1}
+ Status ClusterProxyStatus `json:"status,omitempty"`
+}
+
+// GetConditions returns the status conditions of the object.
+func (n *ClusterProxy) GetConditions() []metav1.Condition {
+ return n.Status.Conditions
+}
+
+// SetConditions sets the status conditions on the object.
+func (n *ClusterProxy) SetConditions(conditions []metav1.Condition) {
+ n.Status.Conditions = conditions
+}
+
+// +kubebuilder:object:root=true
+
+// ClusterProxyList contains a list of ClusterProxy
+type ClusterProxyList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitzero"`
+ Items []ClusterProxy `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ClusterProxy{}, &ClusterProxyList{})
+}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 8b2d340..29058ee 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -7,39 +7,135 @@
package v1alpha1
import (
- "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/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 *ClusterProxy) DeepCopyInto(out *ClusterProxy) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ out.Spec = in.Spec
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProxy.
+func (in *ClusterProxy) DeepCopy() *ClusterProxy {
+ if in == nil {
+ return nil
+ }
+ out := new(ClusterProxy)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterProxy) 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 *ClusterProxyList) DeepCopyInto(out *ClusterProxyList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ClusterProxy, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProxyList.
+func (in *ClusterProxyList) DeepCopy() *ClusterProxyList {
+ if in == nil {
+ return nil
+ }
+ out := new(ClusterProxyList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterProxyList) 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 *ClusterProxySpec) DeepCopyInto(out *ClusterProxySpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProxySpec.
+func (in *ClusterProxySpec) DeepCopy() *ClusterProxySpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ClusterProxySpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClusterProxyStatus) DeepCopyInto(out *ClusterProxyStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]v1.Condition, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProxyStatus.
+func (in *ClusterProxyStatus) DeepCopy() *ClusterProxyStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ClusterProxyStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContainerOverride) DeepCopyInto(out *ContainerOverride) {
*out = *in
if in.Env != nil {
in, out := &in.Env, &out.Env
- *out = make([]v1.EnvVar, len(*in))
+ *out = make([]corev1.EnvVar, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.SecurityContext != nil {
in, out := &in.SecurityContext, &out.SecurityContext
- *out = new(v1.SecurityContext)
+ *out = new(corev1.SecurityContext)
(*in).DeepCopyInto(*out)
}
if in.StartupProbe != nil {
in, out := &in.StartupProbe, &out.StartupProbe
- *out = new(v1.Probe)
+ *out = new(corev1.Probe)
(*in).DeepCopyInto(*out)
}
if in.LivenessProbe != nil {
in, out := &in.LivenessProbe, &out.LivenessProbe
- *out = new(v1.Probe)
+ *out = new(corev1.Probe)
(*in).DeepCopyInto(*out)
}
if in.ReadinessProbe != nil {
in, out := &in.ReadinessProbe, &out.ReadinessProbe
- *out = new(v1.Probe)
+ *out = new(corev1.Probe)
(*in).DeepCopyInto(*out)
}
}
@@ -158,7 +254,7 @@ func (in *GroupReference) DeepCopyInto(out *GroupReference) {
}
if in.LocalRef != nil {
in, out := &in.LocalRef, &out.LocalRef
- *out = new(v1.LocalObjectReference)
+ *out = new(corev1.LocalObjectReference)
**out = **in
}
}
@@ -193,7 +289,7 @@ func (in *GroupStatus) DeepCopyInto(out *GroupStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
- *out = make([]metav1.Condition, len(*in))
+ *out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -298,7 +394,7 @@ func (in *NetworkResourceStatus) DeepCopyInto(out *NetworkResourceStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
- *out = make([]metav1.Condition, len(*in))
+ *out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -400,7 +496,7 @@ func (in *NetworkRouterStatus) DeepCopyInto(out *NetworkRouterStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
- *out = make([]metav1.Condition, len(*in))
+ *out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -481,7 +577,7 @@ func (in *SetupKeySpec) DeepCopyInto(out *SetupKeySpec) {
*out = *in
if in.Duration != nil {
in, out := &in.Duration, &out.Duration
- *out = new(metav1.Duration)
+ *out = new(v1.Duration)
**out = **in
}
if in.AutoGroups != nil {
@@ -508,7 +604,7 @@ func (in *SetupKeyStatus) DeepCopyInto(out *SetupKeyStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
- *out = make([]metav1.Condition, len(*in))
+ *out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -590,7 +686,7 @@ func (in *SidecarProfileSpec) DeepCopyInto(out *SidecarProfileSpec) {
out.SetupKeyRef = in.SetupKeyRef
if in.PodSelector != nil {
in, out := &in.PodSelector, &out.PodSelector
- *out = new(metav1.LabelSelector)
+ *out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
if in.ExtraDNSLabels != nil {
@@ -620,7 +716,7 @@ func (in *SidecarProfileStatus) DeepCopyInto(out *SidecarProfileStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
- *out = make([]metav1.Condition, len(*in))
+ *out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -661,7 +757,7 @@ func (in *WorkloadOverride) DeepCopyInto(out *WorkloadOverride) {
}
if in.PodTemplate != nil {
in, out := &in.PodTemplate, &out.PodTemplate
- *out = new(v1.PodTemplateSpec)
+ *out = new(corev1.PodTemplateSpec)
(*in).DeepCopyInto(*out)
}
}
diff --git a/charts/netbird-operator/crds/netbird.io_clusterproxies.yaml b/charts/netbird-operator/crds/netbird.io_clusterproxies.yaml
new file mode 100644
index 0000000..8ea4b4c
--- /dev/null
+++ b/charts/netbird-operator/crds/netbird.io_clusterproxies.yaml
@@ -0,0 +1,145 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.1
+ name: clusterproxies.netbird.io
+spec:
+ group: netbird.io
+ names:
+ kind: ClusterProxy
+ listKind: ClusterProxyList
+ plural: clusterproxies
+ singular: clusterproxy
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .status.conditions[?(@.type=="Ready")].status
+ name: Ready
+ type: string
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: ClusterProxy is the Schema for the clusterproxies 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: ClusterProxySpec defines the desired state of ClusterProxy.
+ properties:
+ apiServer:
+ default: https://kubernetes.default.svc.cluster.local
+ description: APIServer is the URL of the Kubernetes API server to
+ proxy requests to.
+ type: string
+ clusterName:
+ description: ClusterName is the name of the Kubernetes cluster.
+ type: string
+ x-kubernetes-validations:
+ - message: Value is immutable
+ rule: self == oldSelf
+ serviceAccountName:
+ description: ServiceAccountName is a reference to the service account
+ used for impersonation.
+ type: string
+ required:
+ - apiServer
+ - clusterName
+ - serviceAccountName
+ type: object
+ status:
+ default:
+ observedGeneration: -1
+ description: ClusterProxyStatus defines the observed state of ClusterProxy.
+ properties:
+ conditions:
+ description: Conditions holds the conditions for the ClusterProxy.
+ items:
+ description: Condition contains details for one aspect of the current
+ state of this API Resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+ This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message is a human readable message indicating details about the transition.
+ This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: |-
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: |-
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+ Producers of specific condition types may define expected values and meanings for this field,
+ and whether the values are considered a guaranteed API.
+ The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ observedGeneration:
+ description: ObservedGeneration is the last reconciled generation.
+ format: int64
+ type: integer
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/charts/netbird-operator/templates/rbac.yaml b/charts/netbird-operator/templates/rbac.yaml
index 9d4c860..8909c43 100644
--- a/charts/netbird-operator/templates/rbac.yaml
+++ b/charts/netbird-operator/templates/rbac.yaml
@@ -39,6 +39,7 @@ rules:
- networkrouters
- networkresources
- sidecarprofiles
+ - clusterproxies
verbs:
- get
- patch
@@ -59,6 +60,7 @@ rules:
- networkrouters/status
- networkresources/status
- sidecarprofiles/status
+ - clusterproxies/status
verbs:
- get
- patch
diff --git a/cmd/main.go b/cmd/main.go
index 3e9967a..bf84da9 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -60,7 +60,7 @@ func main() {
var (
runtimeNamespace string
managementURL string
- clientImage string
+ netbirdClientImage string
clusterName string
namespacedNetworks bool
clusterDNS string
@@ -71,7 +71,7 @@ func main() {
)
flag.StringVar(&runtimeNamespace, "runtime-namespace", "", "Namespace the controller is running in")
flag.StringVar(&managementURL, "netbird-management-url", "https://api.netbird.io", "Management service URL")
- flag.StringVar(&clientImage, "netbird-client-image", "", "Image for netbird client container")
+ flag.StringVar(&netbirdClientImage, "netbird-client-image", "", "Image for netbird client container")
flag.StringVar(
&clusterName,
"cluster-name",
@@ -139,8 +139,8 @@ func main() {
setupLog.Error(err, "unable to get runtime namespace")
os.Exit(1)
}
- if clientImage == "" {
- clientImage = version.ClientImage()
+ if netbirdClientImage == "" {
+ netbirdClientImage = version.NetbirdClientImage
}
defaultLabelsMap := make(map[string]string)
@@ -210,7 +210,7 @@ func main() {
}
if enableWebhooks {
- if err = nbwebhookv1.SetupPodWebhookWithManager(mgr, managementURL, clientImage); err != nil {
+ if err = nbwebhookv1.SetupPodWebhookWithManager(mgr, managementURL, netbirdClientImage); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Pod")
os.Exit(1)
}
@@ -226,7 +226,7 @@ func main() {
if err = (&controller.NBRoutingPeerReconciler{
Client: mgr.GetClient(),
Netbird: nbClient,
- ClientImage: clientImage,
+ ClientImage: netbirdClientImage,
ClusterName: clusterName,
ManagementURL: managementURL,
NamespacedNetworks: namespacedNetworks,
@@ -299,7 +299,7 @@ func main() {
if err := (&controller.NetworkRouterReconciler{
Client: mgr.GetClient(),
Netbird: nbClient,
- ClientImage: clientImage,
+ ClientImage: netbirdClientImage,
ManagementURL: managementURL,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "NetworkRouter")
@@ -312,6 +312,13 @@ func main() {
setupLog.Error(err, "Failed to create controller", "controller", "NetworkResource")
os.Exit(1)
}
+ if err := (&controller.ClusterProxyReconciler{
+ Client: mgr.GetClient(),
+ ApiKey: netbirdAPIKey,
+ }).SetupWithManager(mgr); err != nil {
+ setupLog.Error(err, "Failed to create controller", "controller", "ClusterProxy")
+ os.Exit(1)
+ }
if gatewayAPIEnabled {
if err = (&controller.GatewayClassReconciler{
diff --git a/config/crd/bases/netbird.io_clusterproxies.yaml b/config/crd/bases/netbird.io_clusterproxies.yaml
new file mode 100644
index 0000000..8ea4b4c
--- /dev/null
+++ b/config/crd/bases/netbird.io_clusterproxies.yaml
@@ -0,0 +1,145 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.1
+ name: clusterproxies.netbird.io
+spec:
+ group: netbird.io
+ names:
+ kind: ClusterProxy
+ listKind: ClusterProxyList
+ plural: clusterproxies
+ singular: clusterproxy
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .status.conditions[?(@.type=="Ready")].status
+ name: Ready
+ type: string
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: ClusterProxy is the Schema for the clusterproxies 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: ClusterProxySpec defines the desired state of ClusterProxy.
+ properties:
+ apiServer:
+ default: https://kubernetes.default.svc.cluster.local
+ description: APIServer is the URL of the Kubernetes API server to
+ proxy requests to.
+ type: string
+ clusterName:
+ description: ClusterName is the name of the Kubernetes cluster.
+ type: string
+ x-kubernetes-validations:
+ - message: Value is immutable
+ rule: self == oldSelf
+ serviceAccountName:
+ description: ServiceAccountName is a reference to the service account
+ used for impersonation.
+ type: string
+ required:
+ - apiServer
+ - clusterName
+ - serviceAccountName
+ type: object
+ status:
+ default:
+ observedGeneration: -1
+ description: ClusterProxyStatus defines the observed state of ClusterProxy.
+ properties:
+ conditions:
+ description: Conditions holds the conditions for the ClusterProxy.
+ items:
+ description: Condition contains details for one aspect of the current
+ state of this API Resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+ This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message is a human readable message indicating details about the transition.
+ This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: |-
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: |-
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+ Producers of specific condition types may define expected values and meanings for this field,
+ and whether the values are considered a guaranteed API.
+ The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ observedGeneration:
+ description: ObservedGeneration is the last reconciled generation.
+ format: int64
+ type: integer
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index f883e06..0e7f6bc 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -11,4 +11,5 @@ resources:
- bases/netbird.io_networkrouters.yaml
- bases/netbird.io_setupkeys.yaml
- bases/netbird.io_sidecarprofiles.yaml
+- bases/netbird.io_clusterproxies.yaml
# +kubebuilder:scaffold:crdkustomizeresource
diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml
new file mode 100644
index 0000000..61361ff
--- /dev/null
+++ b/config/crd/kustomizeconfig.yaml
@@ -0,0 +1,12 @@
+# This file is for teaching kustomize how to substitute name and namespace reference in CRD
+nameReference:
+- kind: Service
+ version: v1
+ fieldSpecs:
+ - kind: CustomResourceDefinition
+ version: v1
+ group: apiextensions.k8s.io
+ path: spec/conversion/webhook/clientConfig/service/name
+
+varReference:
+- path: metadata/annotations
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 0f98018..90c0493 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -9,6 +9,7 @@
Package v1alpha1 contains API Schema definitions for the v1alpha1 API group.
### Resource Types
+- [ClusterProxy](#clusterproxy)
- [Group](#group)
- [NetworkResource](#networkresource)
- [NetworkRouter](#networkrouter)
@@ -17,6 +18,62 @@ Package v1alpha1 contains API Schema definitions for the v1alpha1 API group.
+#### ClusterProxy
+
+
+
+ClusterProxy is the Schema for the clusterproxies API
+
+
+
+
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiVersion` _string_ | `netbird.io/v1alpha1` | | |
+| `kind` _string_ | `ClusterProxy` | | |
+| `kind` _string_ | 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 | | Optional: \{\}
|
+| `apiVersion` _string_ | 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 | | Optional: \{\}
|
+| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
+| `spec` _[ClusterProxySpec](#clusterproxyspec)_ | | | Required: \{\}
|
+| `status` _[ClusterProxyStatus](#clusterproxystatus)_ | | \{ observedGeneration:-1 \} | |
+
+
+#### ClusterProxySpec
+
+
+
+ClusterProxySpec defines the desired state of ClusterProxy.
+
+
+
+_Appears in:_
+- [ClusterProxy](#clusterproxy)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `clusterName` _string_ | ClusterName is the name of the Kubernetes cluster. | | Required: \{\}
|
+| `apiServer` _string_ | APIServer is the URL of the Kubernetes API server to proxy requests to. | https://kubernetes.default.svc.cluster.local | Required: \{\}
|
+| `serviceAccountName` _string_ | ServiceAccountName is a reference to the service account used for impersonation. | | Required: \{\}
|
+
+
+#### ClusterProxyStatus
+
+
+
+ClusterProxyStatus defines the observed state of ClusterProxy.
+
+
+
+_Appears in:_
+- [ClusterProxy](#clusterproxy)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `observedGeneration` _integer_ | ObservedGeneration is the last reconciled generation. | | Optional: \{\}
|
+| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | Conditions holds the conditions for the ClusterProxy. | | Optional: \{\}
|
+
+
#### ContainerOverride
diff --git a/examples/api-proxy/api-proxy.yaml b/examples/api-proxy/api-proxy.yaml
new file mode 100644
index 0000000..0cc2d15
--- /dev/null
+++ b/examples/api-proxy/api-proxy.yaml
@@ -0,0 +1,70 @@
+apiVersion: netbird.io/v1alpha1
+kind: ClusterProxy
+metadata:
+ name: prod
+ namespace: netbird
+spec:
+ clusterName: prod
+ serviceAccountName: clusterproxy-prod
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: clusterproxy-prod
+ namespace: netbird
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: clusterproxy-prod
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - users
+ - groups
+ verbs:
+ - impersonate
+
+ - apiGroups:
+ - authentication.k8s.io
+ resources:
+ - userextras/*
+ - uids
+ verbs:
+ - impersonate
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: clusterproxy-prod
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: clusterproxy-prod
+subjects:
+ - kind: ServiceAccount
+ name: clusterproxy-prod
+ namespace: netbird
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: netbird-cluster-reader
+rules:
+ - apiGroups: ["*"]
+ resources: ["*"]
+ verbs: ["get", "list", "watch"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: netbird-cluster-reader
+subjects:
+ - kind: Group
+ name: kubernetes-read
+ apiGroup: rbac.authorization.k8s.io
+roleRef:
+ kind: ClusterRole
+ name: netbird-cluster-reader
+ apiGroup: rbac.authorization.k8s.io
diff --git a/internal/controller/clusterproxy_controller.go b/internal/controller/clusterproxy_controller.go
new file mode 100644
index 0000000..79b3cbe
--- /dev/null
+++ b/internal/controller/clusterproxy_controller.go
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+package controller
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+
+ "github.com/fluxcd/pkg/runtime/conditions"
+ "github.com/fluxcd/pkg/runtime/patch"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/resource"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ appsv1ac "k8s.io/client-go/applyconfigurations/apps/v1"
+ corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
+ metav1ac "k8s.io/client-go/applyconfigurations/meta/v1"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1"
+ "github.com/netbirdio/kubernetes-operator/internal/k8sutil"
+ "github.com/netbirdio/kubernetes-operator/internal/version"
+ nbv1alpha1ac "github.com/netbirdio/kubernetes-operator/pkg/applyconfigurations/api/v1alpha1"
+)
+
+// ClusterProxyReconciler reconciles a ClusterProxy object
+type ClusterProxyReconciler struct {
+ client.Client
+
+ ApiKey string
+}
+
+// +kubebuilder:rbac:groups=netbird.io,resources=clusterproxies,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=netbird.io,resources=clusterproxies/status,verbs=get;update;patch
+// +kubebuilder:rbac:groups=netbird.io,resources=clusterproxies/finalizers,verbs=update
+
+func (r *ClusterProxyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ clusterProxy := &nbv1alpha1.ClusterProxy{}
+ err := r.Get(ctx, req.NamespacedName, clusterProxy)
+ if err != nil {
+ return ctrl.Result{}, client.IgnoreNotFound(err)
+ }
+ sp := patch.NewSerialPatcher(clusterProxy, r.Client)
+
+ if !clusterProxy.DeletionTimestamp.IsZero() {
+ return ctrl.Result{}, nil
+ }
+ ownerRef, err := k8sutil.ControllerReference(clusterProxy, r.Scheme())
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ // Calculate unique suffix used for Netbird resources.
+ sum := sha256.Sum256([]byte(clusterProxy.UID))
+ uniqueSuffix := fmt.Sprintf("%x", sum[:4])[:8]
+
+ // Create the setup key used by routing peers.
+ setupKeyAC := nbv1alpha1ac.SetupKey(fmt.Sprintf("clusterproxy-%s", clusterProxy.Name), req.Namespace).
+ WithOwnerReferences(ownerRef).
+ WithSpec(
+ nbv1alpha1ac.SetupKeySpec().
+ WithName(fmt.Sprintf("clusterproxy-%s", uniqueSuffix)).
+ WithEphemeral(true).
+ WithAllowExtraDnsLabels(true),
+ )
+ err = r.Client.Apply(ctx, setupKeyAC)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+ setupKey := nbv1alpha1.SetupKey{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: *setupKeyAC.Name,
+ Namespace: *setupKeyAC.Namespace,
+ },
+ }
+ err = r.Get(ctx, client.ObjectKeyFromObject(&setupKey), &setupKey)
+ if err != nil {
+ return ctrl.Result{}, client.IgnoreNotFound(err)
+ }
+ if setupKey.Status.SetupKeyID == "" {
+ return ctrl.Result{}, nil
+ }
+
+ // Create secret for api token.
+ secretAC := corev1ac.Secret(fmt.Sprintf("clusterproxy-%s", req.Name), req.Namespace).
+ WithOwnerReferences(ownerRef).
+ WithStringData(map[string]string{"api-key": r.ApiKey})
+ err = r.Client.Apply(ctx, secretAC)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ // Create the API proxy deployment.
+ selectorLabels := map[string]string{
+ "app.kubernetes.io/name": "clusterproxy",
+ "app.kubernetes.io/instance": req.Name,
+ }
+ podTemplateSpecAC := corev1ac.PodTemplateSpec().
+ WithLabels(selectorLabels).
+ WithSpec(corev1ac.PodSpec().
+ WithTopologySpreadConstraints(
+ corev1ac.TopologySpreadConstraint().
+ WithMaxSkew(1).
+ WithTopologyKey(corev1.LabelHostname).
+ WithWhenUnsatisfiable(corev1.ScheduleAnyway).
+ WithLabelSelector(metav1ac.LabelSelector().
+ WithMatchLabels(selectorLabels),
+ ),
+ ).
+ WithServiceAccountName(clusterProxy.Spec.ServiceAccountName).
+ WithContainers(corev1ac.Container().
+ WithName("proxy").
+ WithImage(version.KubeApiProxyImage).
+ WithArgs(
+ "--setup-key",
+ "$(SETUP_KEY)",
+ "--api-key",
+ "$(API_KEY)",
+ "--instance-name",
+ "$(POD_NAME)",
+ "--cluster-name",
+ clusterProxy.Spec.ClusterName,
+ "--kubernetes-api-server",
+ clusterProxy.Spec.APIServer,
+ ).
+ WithEnv(
+ corev1ac.EnvVar().
+ WithName("POD_NAME").
+ WithValueFrom(corev1ac.EnvVarSource().
+ WithFieldRef(corev1ac.ObjectFieldSelector().WithFieldPath("metadata.name")),
+ ),
+ corev1ac.EnvVar().
+ WithName("SETUP_KEY").
+ WithValueFrom(corev1ac.EnvVarSource().
+ WithSecretKeyRef(corev1ac.SecretKeySelector().
+ WithName(setupKey.SecretName()).
+ WithKey(SetupKeySecretKey),
+ ),
+ ),
+ corev1ac.EnvVar().
+ WithName("API_KEY").
+ WithValueFrom(corev1ac.EnvVarSource().
+ WithSecretKeyRef(corev1ac.SecretKeySelector().
+ WithName(*secretAC.Name).
+ WithKey("api-key"),
+ ),
+ ),
+ ).
+ WithSecurityContext(corev1ac.SecurityContext().
+ WithAllowPrivilegeEscalation(false).
+ WithReadOnlyRootFilesystem(true).
+ WithRunAsNonRoot(true).
+ WithCapabilities(corev1ac.Capabilities().WithDrop("ALL")),
+ ).
+ WithResources(corev1ac.ResourceRequirements().
+ WithRequests(corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("100m"),
+ corev1.ResourceMemory: resource.MustParse("128Mi"),
+ }),
+ ),
+ ),
+ )
+
+ depAC := appsv1ac.Deployment(fmt.Sprintf("clusterproxy-%s", req.Name), req.Namespace).
+ WithOwnerReferences(ownerRef).
+ WithLabels(selectorLabels).
+ WithSpec(appsv1ac.DeploymentSpec().WithReplicas(1).WithSelector(metav1ac.LabelSelector().WithMatchLabels(selectorLabels)).WithTemplate(podTemplateSpecAC))
+ err = r.Client.Apply(ctx, depAC)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ conditions.MarkTrue(clusterProxy, nbv1alpha1.ReadyCondition, nbv1alpha1.ReconciledReason, "")
+ err = sp.Patch(ctx, clusterProxy, patch.WithStatusObservedGeneration{})
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+ return ctrl.Result{}, nil
+}
+
+func (r *ClusterProxyReconciler) SetupWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewControllerManagedBy(mgr).
+ For(&nbv1alpha1.ClusterProxy{}).
+ Owns(&nbv1alpha1.SetupKey{}).
+ Owns(&appsv1.Deployment{}).
+ Complete(r)
+}
diff --git a/internal/version/version.go b/internal/version/version.go
index c25275a..2958523 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -6,9 +6,10 @@ import (
"runtime/debug"
)
-func ClientImage() string {
- return "ghcr.io/netbirdio/netbird:0.71.4@sha256:c4195811bf9999544db5176950a0d6513c880d0195450b59eb156c254e0dd3b5"
-}
+const (
+ NetbirdClientImage = "ghcr.io/netbirdio/netbird:0.71.4@sha256:c4195811bf9999544db5176950a0d6513c880d0195450b59eb156c254e0dd3b5"
+ KubeApiProxyImage = "ghcr.io/netbirdio/netbird-kubeapi-proxy:v0.0.1@sha256:aa5bbdfc2eca51438f3d50ed4441d61388e9a8d2d5dc886cc4988dacd36ad648"
+)
func BuildVersion() string {
bi, ok := debug.ReadBuildInfo()
diff --git a/internal/version/version_test.go b/internal/version/version_test.go
index d1250da..56521f1 100644
--- a/internal/version/version_test.go
+++ b/internal/version/version_test.go
@@ -13,7 +13,7 @@ import (
"github.com/go-openapi/testify/v2/require"
)
-func TestClientImage(t *testing.T) {
+func TestNetbirdClientImage(t *testing.T) {
t.Parallel()
b, err := os.ReadFile("../../go.mod")
@@ -26,10 +26,9 @@ func TestClientImage(t *testing.T) {
require.GreaterT(t, idx, -1)
modVersion := strings.TrimPrefix(f.Require[idx].Mod.Version, "v")
- clientImg := ClientImage()
- start := strings.Index(clientImg, ":") + 1
- end := strings.Index(clientImg, "@")
- imgVersion := clientImg[start:end]
+ start := strings.Index(NetbirdClientImage, ":") + 1
+ end := strings.Index(NetbirdClientImage, "@")
+ imgVersion := NetbirdClientImage[start:end]
require.EqualT(t, modVersion, imgVersion)
}
diff --git a/pkg/applyconfigurations/api/v1alpha1/clusterproxy.go b/pkg/applyconfigurations/api/v1alpha1/clusterproxy.go
new file mode 100644
index 0000000..cd1b79d
--- /dev/null
+++ b/pkg/applyconfigurations/api/v1alpha1/clusterproxy.go
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
+ v1 "k8s.io/client-go/applyconfigurations/meta/v1"
+)
+
+// ClusterProxyApplyConfiguration represents a declarative configuration of the ClusterProxy type for use
+// with apply.
+//
+// ClusterProxy is the Schema for the clusterproxies API
+type ClusterProxyApplyConfiguration struct {
+ v1.TypeMetaApplyConfiguration `json:",inline"`
+ *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
+ Spec *ClusterProxySpecApplyConfiguration `json:"spec,omitempty"`
+ Status *ClusterProxyStatusApplyConfiguration `json:"status,omitempty"`
+}
+
+// ClusterProxy constructs a declarative configuration of the ClusterProxy type for use with
+// apply.
+func ClusterProxy(name, namespace string) *ClusterProxyApplyConfiguration {
+ b := &ClusterProxyApplyConfiguration{}
+ b.WithName(name)
+ b.WithNamespace(namespace)
+ b.WithKind("ClusterProxy")
+ b.WithAPIVersion("netbird.io/v1alpha1")
+ return b
+}
+
+func (b ClusterProxyApplyConfiguration) IsApplyConfiguration() {}
+
+// WithKind sets the Kind field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Kind field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithKind(value string) *ClusterProxyApplyConfiguration {
+ b.TypeMetaApplyConfiguration.Kind = &value
+ return b
+}
+
+// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the APIVersion field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithAPIVersion(value string) *ClusterProxyApplyConfiguration {
+ b.TypeMetaApplyConfiguration.APIVersion = &value
+ return b
+}
+
+// WithName sets the Name field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Name field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithName(value string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.Name = &value
+ return b
+}
+
+// WithGenerateName sets the GenerateName field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the GenerateName field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithGenerateName(value string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.GenerateName = &value
+ return b
+}
+
+// WithNamespace sets the Namespace field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Namespace field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithNamespace(value string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.Namespace = &value
+ return b
+}
+
+// WithUID sets the UID field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the UID field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithUID(value types.UID) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.UID = &value
+ return b
+}
+
+// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ResourceVersion field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithResourceVersion(value string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.ResourceVersion = &value
+ return b
+}
+
+// WithGeneration sets the Generation field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Generation field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithGeneration(value int64) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.Generation = &value
+ return b
+}
+
+// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the CreationTimestamp field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.CreationTimestamp = &value
+ return b
+}
+
+// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the DeletionTimestamp field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value
+ return b
+}
+
+// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value
+ return b
+}
+
+// WithLabels puts the entries into the Labels field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, the entries provided by each call will be put on the Labels field,
+// overwriting an existing map entries in Labels field with the same key.
+func (b *ClusterProxyApplyConfiguration) WithLabels(entries map[string]string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 {
+ b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries))
+ }
+ for k, v := range entries {
+ b.ObjectMetaApplyConfiguration.Labels[k] = v
+ }
+ return b
+}
+
+// WithAnnotations puts the entries into the Annotations field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, the entries provided by each call will be put on the Annotations field,
+// overwriting an existing map entries in Annotations field with the same key.
+func (b *ClusterProxyApplyConfiguration) WithAnnotations(entries map[string]string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 {
+ b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries))
+ }
+ for k, v := range entries {
+ b.ObjectMetaApplyConfiguration.Annotations[k] = v
+ }
+ return b
+}
+
+// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the OwnerReferences field.
+func (b *ClusterProxyApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ for i := range values {
+ if values[i] == nil {
+ panic("nil value passed to WithOwnerReferences")
+ }
+ b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i])
+ }
+ return b
+}
+
+// WithFinalizers adds the given value to the Finalizers field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the Finalizers field.
+func (b *ClusterProxyApplyConfiguration) WithFinalizers(values ...string) *ClusterProxyApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ for i := range values {
+ b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i])
+ }
+ return b
+}
+
+func (b *ClusterProxyApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
+ if b.ObjectMetaApplyConfiguration == nil {
+ b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{}
+ }
+}
+
+// WithSpec sets the Spec field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Spec field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithSpec(value *ClusterProxySpecApplyConfiguration) *ClusterProxyApplyConfiguration {
+ b.Spec = value
+ return b
+}
+
+// WithStatus sets the Status field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Status field is set to the value of the last call.
+func (b *ClusterProxyApplyConfiguration) WithStatus(value *ClusterProxyStatusApplyConfiguration) *ClusterProxyApplyConfiguration {
+ b.Status = value
+ return b
+}
+
+// GetKind retrieves the value of the Kind field in the declarative configuration.
+func (b *ClusterProxyApplyConfiguration) GetKind() *string {
+ return b.TypeMetaApplyConfiguration.Kind
+}
+
+// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration.
+func (b *ClusterProxyApplyConfiguration) GetAPIVersion() *string {
+ return b.TypeMetaApplyConfiguration.APIVersion
+}
+
+// GetName retrieves the value of the Name field in the declarative configuration.
+func (b *ClusterProxyApplyConfiguration) GetName() *string {
+ b.ensureObjectMetaApplyConfigurationExists()
+ return b.ObjectMetaApplyConfiguration.Name
+}
+
+// GetNamespace retrieves the value of the Namespace field in the declarative configuration.
+func (b *ClusterProxyApplyConfiguration) GetNamespace() *string {
+ b.ensureObjectMetaApplyConfigurationExists()
+ return b.ObjectMetaApplyConfiguration.Namespace
+}
diff --git a/pkg/applyconfigurations/api/v1alpha1/clusterproxyspec.go b/pkg/applyconfigurations/api/v1alpha1/clusterproxyspec.go
new file mode 100644
index 0000000..5be3f70
--- /dev/null
+++ b/pkg/applyconfigurations/api/v1alpha1/clusterproxyspec.go
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+// ClusterProxySpecApplyConfiguration represents a declarative configuration of the ClusterProxySpec type for use
+// with apply.
+//
+// ClusterProxySpec defines the desired state of ClusterProxy.
+type ClusterProxySpecApplyConfiguration struct {
+ // ClusterName is the name of the Kubernetes cluster.
+ ClusterName *string `json:"clusterName,omitempty"`
+ // APIServer is the URL of the Kubernetes API server to proxy requests to.
+ APIServer *string `json:"apiServer,omitempty"`
+ // ServiceAccountName is a reference to the service account used for impersonation.
+ ServiceAccountName *string `json:"serviceAccountName,omitempty"`
+}
+
+// ClusterProxySpecApplyConfiguration constructs a declarative configuration of the ClusterProxySpec type for use with
+// apply.
+func ClusterProxySpec() *ClusterProxySpecApplyConfiguration {
+ return &ClusterProxySpecApplyConfiguration{}
+}
+
+// WithClusterName sets the ClusterName field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ClusterName field is set to the value of the last call.
+func (b *ClusterProxySpecApplyConfiguration) WithClusterName(value string) *ClusterProxySpecApplyConfiguration {
+ b.ClusterName = &value
+ return b
+}
+
+// WithAPIServer sets the APIServer field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the APIServer field is set to the value of the last call.
+func (b *ClusterProxySpecApplyConfiguration) WithAPIServer(value string) *ClusterProxySpecApplyConfiguration {
+ b.APIServer = &value
+ return b
+}
+
+// WithServiceAccountName sets the ServiceAccountName field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ServiceAccountName field is set to the value of the last call.
+func (b *ClusterProxySpecApplyConfiguration) WithServiceAccountName(value string) *ClusterProxySpecApplyConfiguration {
+ b.ServiceAccountName = &value
+ return b
+}
diff --git a/pkg/applyconfigurations/api/v1alpha1/clusterproxystatus.go b/pkg/applyconfigurations/api/v1alpha1/clusterproxystatus.go
new file mode 100644
index 0000000..1928f17
--- /dev/null
+++ b/pkg/applyconfigurations/api/v1alpha1/clusterproxystatus.go
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ v1 "k8s.io/client-go/applyconfigurations/meta/v1"
+)
+
+// ClusterProxyStatusApplyConfiguration represents a declarative configuration of the ClusterProxyStatus type for use
+// with apply.
+//
+// ClusterProxyStatus defines the observed state of ClusterProxy.
+type ClusterProxyStatusApplyConfiguration struct {
+ // ObservedGeneration is the last reconciled generation.
+ ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
+ // Conditions holds the conditions for the ClusterProxy.
+ Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
+}
+
+// ClusterProxyStatusApplyConfiguration constructs a declarative configuration of the ClusterProxyStatus type for use with
+// apply.
+func ClusterProxyStatus() *ClusterProxyStatusApplyConfiguration {
+ return &ClusterProxyStatusApplyConfiguration{}
+}
+
+// WithObservedGeneration sets the ObservedGeneration field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ObservedGeneration field is set to the value of the last call.
+func (b *ClusterProxyStatusApplyConfiguration) WithObservedGeneration(value int64) *ClusterProxyStatusApplyConfiguration {
+ b.ObservedGeneration = &value
+ return b
+}
+
+// WithConditions adds the given value to the Conditions field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the Conditions field.
+func (b *ClusterProxyStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *ClusterProxyStatusApplyConfiguration {
+ for i := range values {
+ if values[i] == nil {
+ panic("nil value passed to WithConditions")
+ }
+ b.Conditions = append(b.Conditions, *values[i])
+ }
+ return b
+}
diff --git a/pkg/applyconfigurations/utils.go b/pkg/applyconfigurations/utils.go
index 9ecc3ad..7a18c17 100644
--- a/pkg/applyconfigurations/utils.go
+++ b/pkg/applyconfigurations/utils.go
@@ -18,6 +18,12 @@ import (
func ForKind(kind schema.GroupVersionKind) interface{} {
switch kind {
// Group=netbird.io, Version=v1alpha1
+ case v1alpha1.SchemeGroupVersion.WithKind("ClusterProxy"):
+ return &apiv1alpha1.ClusterProxyApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("ClusterProxySpec"):
+ return &apiv1alpha1.ClusterProxySpecApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("ClusterProxyStatus"):
+ return &apiv1alpha1.ClusterProxyStatusApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("ContainerOverride"):
return &apiv1alpha1.ContainerOverrideApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("CrossNamespaceReference"):