mirror of
https://github.com/YuzuZensai/netbird-kubernetes-operator.git
synced 2026-09-13 18:59:09 +00:00
Add ingress feature to controller (#5)
Co-authored-by: Maycon Santos <mlsmaycon@gmail.com>
This commit is contained in:
co-authored by
Maycon Santos
parent
cea60745d2
commit
166091b8e0
@@ -29,4 +29,50 @@ resources:
|
|||||||
webhooks:
|
webhooks:
|
||||||
defaulting: true
|
defaulting: true
|
||||||
webhookVersion: v1
|
webhookVersion: v1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
namespaced: true
|
||||||
|
controller: true
|
||||||
|
domain: netbird.io
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
path: github.com/netbirdio/kubernetes-operator/api/v1
|
||||||
|
version: v1
|
||||||
|
webhooks:
|
||||||
|
validation: true
|
||||||
|
webhookVersion: v1
|
||||||
|
- controller: true
|
||||||
|
external: true
|
||||||
|
kind: Service
|
||||||
|
path: k8s.io/api/core/v1
|
||||||
|
version: v1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
namespaced: true
|
||||||
|
controller: true
|
||||||
|
domain: netbird.io
|
||||||
|
kind: NBResource
|
||||||
|
path: github.com/netbirdio/kubernetes-operator/api/v1
|
||||||
|
version: v1
|
||||||
|
webhooks:
|
||||||
|
validation: true
|
||||||
|
webhookVersion: v1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
namespaced: true
|
||||||
|
controller: true
|
||||||
|
domain: netbird.io
|
||||||
|
kind: NBGroup
|
||||||
|
path: github.com/netbirdio/kubernetes-operator/api/v1
|
||||||
|
version: v1
|
||||||
|
webhooks:
|
||||||
|
validation: true
|
||||||
|
webhookVersion: v1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
namespaced: true
|
||||||
|
controller: true
|
||||||
|
domain: netbird.io
|
||||||
|
kind: NBPolicy
|
||||||
|
path: github.com/netbirdio/kubernetes-operator/api/v1
|
||||||
|
version: v1
|
||||||
version: "3"
|
version: "3"
|
||||||
|
|||||||
@@ -1,107 +1,69 @@
|
|||||||
# NetBird Kubernetes Operator
|
# NetBird Kubernetes Operator
|
||||||
For easily provisioning access to Kubernetes resources using NetBird.
|
For easily provisioning access to Kubernetes resources using NetBird.
|
||||||
|
|
||||||
|
https://github.com/user-attachments/assets/5472a499-e63d-4301-a513-ad84cfe5ca7b
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
This operator enables easily provisioning NetBird access on kubernetes clusters, allowing users to access internal resources directly.
|
This operator easily provides NetBird access on Kubernetes clusters, allowing users to access internal resources directly.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
- helm version 3+
|
- (Recommended) helm version 3+
|
||||||
- kubectl version v1.11.3+.
|
- kubectl version v1.11.3+.
|
||||||
- Access to a Kubernetes v1.11.3+ cluster.
|
- Access to a Kubernetes v1.11.3+ cluster.
|
||||||
- (Optional for Helm chart installation) Cert Manager.
|
- (Recommended) Cert Manager.
|
||||||
|
|
||||||
### To Deploy on the cluster
|
|
||||||
|
|
||||||
**Using the install.yaml**
|
### Deployment
|
||||||
|
> [!NOTE]
|
||||||
|
> Helm Installation method is recommended due to the automation of multiple settings within the deployment.
|
||||||
|
|
||||||
|
#### Using Helm
|
||||||
|
|
||||||
|
1. Add helm repository.
|
||||||
|
```sh
|
||||||
|
helm repo add netbirdio https://netbirdio.github.io/kubernetes-operator
|
||||||
|
```
|
||||||
|
2. (Recommended) Install [cert-manager](https://cert-manager.io/docs/installation/#default-static-install).
|
||||||
|
3. (Recommended) Create a values.yaml file, check `helm show values netbirdio/kubernetes-operator` for more info.
|
||||||
|
4. Install using `helm install --create-namespace -f values.yaml -n netbird netbird-operator netbirdio/kubernetes-operator`.
|
||||||
|
|
||||||
|
> Learn more about the values.yaml options [here](helm/kubernetes-operator/values.yaml) and [Granting controller access to NetBird Management](docs/usage.md#granting-controller-access-to-netbird-management).
|
||||||
|
#### Using install.yaml
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> install.yaml only includes a very basic template for deploying a stripped-down version of Kubernetes-operator.
|
||||||
|
> This excludes any and all configurations for ingress capabilities and requires the cert-manager to be installed.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
kubectl create namespace netbird
|
kubectl create namespace netbird
|
||||||
kubectl apply -n netbird -f https://github.com/netbirdio/kubernetes-operator/releases/latest/manifests/install.yaml
|
kubectl apply -n netbird -f https://raw.githubusercontent.com/netbirdio/kubernetes-operator/refs/heads/main/manifests/install.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
**Using the Helm Chart**
|
### Version
|
||||||
|
Latest version: v0.1.0
|
||||||
|
|
||||||
```sh
|
Tested against:
|
||||||
helm repo add netbirdio https://netbirdio.github.io/kubernetes-operator
|
|Distribution|Test status|
|
||||||
helm install -n netbird kubernetes-operator netbirdio/kubernetes-operator
|
|---|---|
|
||||||
```
|
|Google GKE|Pass|
|
||||||
|
|AWS EKS|Pass|
|
||||||
|
|Azure AKS|Not tested|
|
||||||
|
|OpenShift|Not tested|
|
||||||
|
|
||||||
For more options, check the default values by running
|
> We would love community feedback to improve the test matrix. Please submit a PR with your test results.
|
||||||
```sh
|
|
||||||
helm show values netbirdio/kubernetes-operator
|
|
||||||
```
|
|
||||||
|
|
||||||
### To Uninstall
|
### Usage
|
||||||
**Using install.yaml**
|
|
||||||
|
|
||||||
```sh
|
Check the usage of [usage.md](docs/usage.md) and examples.
|
||||||
kubectl delete -n netbird -f https://github.com/netbirdio/kubernetes-operator/releases/latest/manifests/install.yaml
|
|
||||||
kubectl delete namespace netbird
|
|
||||||
```
|
|
||||||
|
|
||||||
**Using helm**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
helm uninstall -n netbird kubernetes-operator
|
|
||||||
```
|
|
||||||
|
|
||||||
### Provision pods with NetBird access
|
|
||||||
|
|
||||||
1. Create a Setup Key in your [NetBird console](https://docs.netbird.io/how-to/register-machines-using-setup-keys#using-setup-keys).
|
|
||||||
1. Create a Secret object in the namespace where you need to provision NetBird access (secret name and field can be anything).
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
stringData:
|
|
||||||
setupkey: EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: test
|
|
||||||
```
|
|
||||||
1. Create an NBSetupKey object referring to your secret.
|
|
||||||
```yaml
|
|
||||||
apiVersion: netbird.io/v1
|
|
||||||
kind: NBSetupKey
|
|
||||||
metadata:
|
|
||||||
name: test
|
|
||||||
spec:
|
|
||||||
# Optional, overrides management URL for this setupkey only
|
|
||||||
# defaults to https://api.netbird.io
|
|
||||||
managementURL: https://netbird.example.com
|
|
||||||
secretKeyRef:
|
|
||||||
name: test # Required
|
|
||||||
key: setupkey # Required
|
|
||||||
```
|
|
||||||
1. Annotate the pods you need to inject NetBird into with `netbird.io/setup-key`.
|
|
||||||
```yaml
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: deployment
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: myapp
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: myapp
|
|
||||||
annotations:
|
|
||||||
netbird.io/setup-key: test # Must match the name of an NBSetupKey object in the same namespace
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: yourimage
|
|
||||||
name: container
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
To be able to develop on this project, you need to have the following tools installed:
|
To be able to develop this project, you need to have the following tools installed:
|
||||||
|
|
||||||
- [Git](https://git-scm.com/).
|
- [Git](https://git-scm.com/).
|
||||||
- [Make](https://www.gnu.org/software/make/).
|
- [Make](https://www.gnu.org/software/make/).
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBGroupSpec defines the desired state of NBGroup.
|
||||||
|
type NBGroupSpec struct {
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBGroupStatus defines the observed state of NBGroup.
|
||||||
|
type NBGroupStatus struct {
|
||||||
|
// +optional
|
||||||
|
GroupID *string `json:"groupID"`
|
||||||
|
// +optional
|
||||||
|
Conditions []NBCondition `json:"conditions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns if NBGroupStatus is equal to this one
|
||||||
|
func (a NBGroupStatus) Equal(b NBGroupStatus) bool {
|
||||||
|
return a.GroupID == b.GroupID && slices.Equal(a.Conditions, b.Conditions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
|
||||||
|
// NBGroup is the Schema for the nbgroups API.
|
||||||
|
type NBGroup struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec NBGroupSpec `json:"spec,omitempty"`
|
||||||
|
Status NBGroupStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// NBGroupList contains a list of NBGroup.
|
||||||
|
type NBGroupList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []NBGroup `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&NBGroup{}, &NBGroupList{})
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBPolicySpec defines the desired state of NBPolicy.
|
||||||
|
type NBPolicySpec struct {
|
||||||
|
// Name Policy name
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Name string `json:"name"`
|
||||||
|
// +optional
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
// +optional
|
||||||
|
// +kubebuilder:validation:items:MinLength=1
|
||||||
|
SourceGroups []string `json:"sourceGroups,omitempty"`
|
||||||
|
// +optional
|
||||||
|
// +kubebuilder:validation:items:MinLength=1
|
||||||
|
DestinationGroups []string `json:"destinationGroups,omitempty"`
|
||||||
|
// +optional
|
||||||
|
// +kubebuilder:validation:items:Enum=tcp;udp
|
||||||
|
Protocols []string `json:"protocols,omitempty"`
|
||||||
|
// +optional
|
||||||
|
// +kubebuilder:validation:items:Minimum=0
|
||||||
|
// +kubebuilder:validation:items:Maximum=65535
|
||||||
|
Ports []int32 `json:"ports,omitempty"`
|
||||||
|
// +optional
|
||||||
|
// +default:value=true
|
||||||
|
Bidirectional bool `json:"bidirectional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBPolicyStatus defines the observed state of NBPolicy.
|
||||||
|
type NBPolicyStatus struct {
|
||||||
|
// +optional
|
||||||
|
TCPPolicyID *string `json:"tcpPolicyID"`
|
||||||
|
// +optional
|
||||||
|
UDPPolicyID *string `json:"udpPolicyID"`
|
||||||
|
// +optional
|
||||||
|
LastUpdatedAt *metav1.Time `json:"lastUpdatedAt"`
|
||||||
|
// +optional
|
||||||
|
ManagedServiceList []string `json:"managedServiceList"`
|
||||||
|
// +optional
|
||||||
|
Conditions []NBCondition `json:"conditions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns if NBPolicyStatus is equal to this one
|
||||||
|
func (a NBPolicyStatus) Equal(b NBPolicyStatus) bool {
|
||||||
|
return a.TCPPolicyID == b.TCPPolicyID &&
|
||||||
|
a.UDPPolicyID == b.UDPPolicyID &&
|
||||||
|
a.LastUpdatedAt == b.LastUpdatedAt &&
|
||||||
|
slices.Equal(a.ManagedServiceList, b.ManagedServiceList) &&
|
||||||
|
slices.Equal(a.Conditions, b.Conditions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
// +kubebuilder:resource:scope=Cluster
|
||||||
|
|
||||||
|
// NBPolicy is the Schema for the nbpolicies API.
|
||||||
|
type NBPolicy struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec NBPolicySpec `json:"spec,omitempty"`
|
||||||
|
Status NBPolicyStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// NBPolicyList contains a list of NBPolicy.
|
||||||
|
type NBPolicyList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []NBPolicy `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&NBPolicy{}, &NBPolicyList{})
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBResourceSpec defines the desired state of NBResource.
|
||||||
|
type NBResourceSpec struct {
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Name string `json:"name"`
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
|
||||||
|
NetworkID string `json:"networkID"`
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Address string `json:"address"`
|
||||||
|
// +kubebuilder:validation:items:MinLength=1
|
||||||
|
Groups []string `json:"groups"`
|
||||||
|
// +optional
|
||||||
|
PolicyName string `json:"policyName,omitempty"`
|
||||||
|
// +optional
|
||||||
|
TCPPorts []int32 `json:"tcpPorts,omitempty"`
|
||||||
|
// +optional
|
||||||
|
UDPPorts []int32 `json:"udpPorts,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBResourceStatus defines the observed state of NBResource.
|
||||||
|
type NBResourceStatus struct {
|
||||||
|
// +optional
|
||||||
|
NetworkResourceID *string `json:"networkResourceID,omitempty"`
|
||||||
|
// +optional
|
||||||
|
PolicyName *string `json:"policyName,omitempty"`
|
||||||
|
// +optional
|
||||||
|
TCPPorts []int32 `json:"tcpPorts,omitempty"`
|
||||||
|
// +optional
|
||||||
|
UDPPorts []int32 `json:"udpPorts,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Conditions []NBCondition `json:"conditions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns if NBResourceStatus is equal to this one
|
||||||
|
func (a NBResourceStatus) Equal(b NBResourceStatus) bool {
|
||||||
|
return a.NetworkResourceID == b.NetworkResourceID &&
|
||||||
|
a.PolicyName == b.PolicyName &&
|
||||||
|
slices.Equal(a.TCPPorts, b.TCPPorts) &&
|
||||||
|
slices.Equal(a.UDPPorts, b.UDPPorts) &&
|
||||||
|
slices.Equal(a.Groups, b.Groups) &&
|
||||||
|
slices.Equal(a.Conditions, b.Conditions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
|
||||||
|
// NBResource is the Schema for the nbresources API.
|
||||||
|
type NBResource struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec NBResourceSpec `json:"spec,omitempty"`
|
||||||
|
Status NBResourceStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// NBResourceList contains a list of NBResource.
|
||||||
|
type NBResourceList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []NBResource `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&NBResource{}, &NBResourceList{})
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBRoutingPeerSpec defines the desired state of NBRoutingPeer.
|
||||||
|
type NBRoutingPeerSpec struct {
|
||||||
|
// +optional
|
||||||
|
Replicas *int32 `json:"replicas"`
|
||||||
|
// +optional
|
||||||
|
Resources corev1.ResourceRequirements `json:"resources"`
|
||||||
|
// +optional
|
||||||
|
Labels map[string]string `json:"labels"`
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations"`
|
||||||
|
// +optional
|
||||||
|
NodeSelector map[string]string `json:"nodeSelector"`
|
||||||
|
// +optional
|
||||||
|
Tolerations []corev1.Toleration `json:"tolerations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBRoutingPeerStatus defines the observed state of NBRoutingPeer.
|
||||||
|
type NBRoutingPeerStatus struct {
|
||||||
|
// +optional
|
||||||
|
NetworkID *string `json:"networkID"`
|
||||||
|
// +optional
|
||||||
|
SetupKeyID *string `json:"setupKeyID"`
|
||||||
|
// +optional
|
||||||
|
RouterID *string `json:"routerID"`
|
||||||
|
// +optional
|
||||||
|
Conditions []NBCondition `json:"conditions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal returns if NBRoutingPeerStatus is equal to this one
|
||||||
|
func (a NBRoutingPeerStatus) Equal(b NBRoutingPeerStatus) bool {
|
||||||
|
return a.NetworkID == b.NetworkID &&
|
||||||
|
a.SetupKeyID == b.SetupKeyID &&
|
||||||
|
a.RouterID == b.RouterID &&
|
||||||
|
slices.Equal(a.Conditions, b.Conditions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
|
||||||
|
// NBRoutingPeer is the Schema for the nbroutingpeers API.
|
||||||
|
type NBRoutingPeer struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Spec NBRoutingPeerSpec `json:"spec,omitempty"`
|
||||||
|
Status NBRoutingPeerStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// NBRoutingPeerList contains a list of NBRoutingPeer.
|
||||||
|
type NBRoutingPeerList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
Items []NBRoutingPeer `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(&NBRoutingPeer{}, &NBRoutingPeerList{})
|
||||||
|
}
|
||||||
+40
-13
@@ -21,13 +21,13 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NBSetupKeyConditionType is a valid value for PodCondition.Type
|
// NBConditionType is a valid value for PodCondition.Type
|
||||||
type NBSetupKeyConditionType string
|
type NBConditionType string
|
||||||
|
|
||||||
// These are built-in conditions of pod. An application may use a custom condition not listed here.
|
// These are built-in conditions of pod. An application may use a custom condition not listed here.
|
||||||
const (
|
const (
|
||||||
// Ready indicates whether NBSetupKey is valid and ready to use.
|
// NBSetupKeyReady indicates whether NBSetupKey is valid and ready to use.
|
||||||
Ready NBSetupKeyConditionType = "Ready"
|
NBSetupKeyReady NBConditionType = "Ready"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NBSetupKeySpec defines the desired state of NBSetupKey.
|
// NBSetupKeySpec defines the desired state of NBSetupKey.
|
||||||
@@ -40,28 +40,55 @@ type NBSetupKeySpec struct {
|
|||||||
|
|
||||||
// NBSetupKeyStatus defines the observed state of NBSetupKey.
|
// NBSetupKeyStatus defines the observed state of NBSetupKey.
|
||||||
type NBSetupKeyStatus struct {
|
type NBSetupKeyStatus struct {
|
||||||
Conditions []NBSetupKeyCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,2,rep,name=conditions"`
|
// +optional
|
||||||
|
Conditions []NBCondition `json:"conditions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NBSetupKeyCondition defines a condition in NBSetupKey status.
|
// NBCondition defines a condition in NBSetupKey status.
|
||||||
type NBSetupKeyCondition struct {
|
type NBCondition struct {
|
||||||
// Type is the type of the condition.
|
// Type is the type of the condition.
|
||||||
Type NBSetupKeyConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=NBSetupKeyConditionType"`
|
Type NBConditionType `json:"type"`
|
||||||
// Status is the status of the condition.
|
// Status is the status of the condition.
|
||||||
// Can be True, False, Unknown.
|
// Can be True, False, Unknown.
|
||||||
Status corev1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"`
|
Status corev1.ConditionStatus `json:"status"`
|
||||||
// Last time we probed the condition.
|
// Last time we probed the condition.
|
||||||
// +optional
|
// +optional
|
||||||
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty" protobuf:"bytes,3,opt,name=lastProbeTime"`
|
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"`
|
||||||
// Last time the condition transitioned from one status to another.
|
// Last time the condition transitioned from one status to another.
|
||||||
// +optional
|
// +optional
|
||||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,4,opt,name=lastTransitionTime"`
|
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
|
||||||
// Unique, one-word, CamelCase reason for the condition's last transition.
|
// Unique, one-word, CamelCase reason for the condition's last transition.
|
||||||
// +optional
|
// +optional
|
||||||
Reason string `json:"reason,omitempty" protobuf:"bytes,5,opt,name=reason"`
|
Reason string `json:"reason,omitempty"`
|
||||||
// Human-readable message indicating details about last transition.
|
// Human-readable message indicating details about last transition.
|
||||||
// +optional
|
// +optional
|
||||||
Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"`
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBConditionTrue returns default true condition
|
||||||
|
func NBConditionTrue() []NBCondition {
|
||||||
|
return []NBCondition{
|
||||||
|
{
|
||||||
|
Type: NBSetupKeyReady,
|
||||||
|
LastProbeTime: metav1.Now(),
|
||||||
|
LastTransitionTime: metav1.Now(),
|
||||||
|
Status: corev1.ConditionTrue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBConditionFalse returns default false condition
|
||||||
|
func NBConditionFalse(reason, msg string) []NBCondition {
|
||||||
|
return []NBCondition{
|
||||||
|
{
|
||||||
|
Type: NBSetupKeyReady,
|
||||||
|
LastProbeTime: metav1.Now(),
|
||||||
|
LastTransitionTime: metav1.Now(),
|
||||||
|
Status: corev1.ConditionFalse,
|
||||||
|
Reason: reason,
|
||||||
|
Message: msg,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|||||||
+536
-18
@@ -5,9 +5,544 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
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 *NBCondition) DeepCopyInto(out *NBCondition) {
|
||||||
|
*out = *in
|
||||||
|
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
||||||
|
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBCondition.
|
||||||
|
func (in *NBCondition) DeepCopy() *NBCondition {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBCondition)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBGroup) DeepCopyInto(out *NBGroup) {
|
||||||
|
*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 NBGroup.
|
||||||
|
func (in *NBGroup) DeepCopy() *NBGroup {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBGroup)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBGroup) 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 *NBGroupList) DeepCopyInto(out *NBGroupList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]NBGroup, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBGroupList.
|
||||||
|
func (in *NBGroupList) DeepCopy() *NBGroupList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBGroupList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBGroupList) 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 *NBGroupSpec) DeepCopyInto(out *NBGroupSpec) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBGroupSpec.
|
||||||
|
func (in *NBGroupSpec) DeepCopy() *NBGroupSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBGroupSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBGroupStatus) DeepCopyInto(out *NBGroupStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.GroupID != nil {
|
||||||
|
in, out := &in.GroupID, &out.GroupID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]NBCondition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBGroupStatus.
|
||||||
|
func (in *NBGroupStatus) DeepCopy() *NBGroupStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBGroupStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBPolicy) DeepCopyInto(out *NBPolicy) {
|
||||||
|
*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 NBPolicy.
|
||||||
|
func (in *NBPolicy) DeepCopy() *NBPolicy {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBPolicy)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBPolicy) 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 *NBPolicyList) DeepCopyInto(out *NBPolicyList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]NBPolicy, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBPolicyList.
|
||||||
|
func (in *NBPolicyList) DeepCopy() *NBPolicyList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBPolicyList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBPolicyList) 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 *NBPolicySpec) DeepCopyInto(out *NBPolicySpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.SourceGroups != nil {
|
||||||
|
in, out := &in.SourceGroups, &out.SourceGroups
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.DestinationGroups != nil {
|
||||||
|
in, out := &in.DestinationGroups, &out.DestinationGroups
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Protocols != nil {
|
||||||
|
in, out := &in.Protocols, &out.Protocols
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Ports != nil {
|
||||||
|
in, out := &in.Ports, &out.Ports
|
||||||
|
*out = make([]int32, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBPolicySpec.
|
||||||
|
func (in *NBPolicySpec) DeepCopy() *NBPolicySpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBPolicySpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBPolicyStatus) DeepCopyInto(out *NBPolicyStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.TCPPolicyID != nil {
|
||||||
|
in, out := &in.TCPPolicyID, &out.TCPPolicyID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.UDPPolicyID != nil {
|
||||||
|
in, out := &in.UDPPolicyID, &out.UDPPolicyID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.LastUpdatedAt != nil {
|
||||||
|
in, out := &in.LastUpdatedAt, &out.LastUpdatedAt
|
||||||
|
*out = (*in).DeepCopy()
|
||||||
|
}
|
||||||
|
if in.ManagedServiceList != nil {
|
||||||
|
in, out := &in.ManagedServiceList, &out.ManagedServiceList
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]NBCondition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBPolicyStatus.
|
||||||
|
func (in *NBPolicyStatus) DeepCopy() *NBPolicyStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBPolicyStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBResource) DeepCopyInto(out *NBResource) {
|
||||||
|
*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 NBResource.
|
||||||
|
func (in *NBResource) DeepCopy() *NBResource {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBResource)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBResource) 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 *NBResourceList) DeepCopyInto(out *NBResourceList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]NBResource, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBResourceList.
|
||||||
|
func (in *NBResourceList) DeepCopy() *NBResourceList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBResourceList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBResourceList) 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 *NBResourceSpec) DeepCopyInto(out *NBResourceSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Groups != nil {
|
||||||
|
in, out := &in.Groups, &out.Groups
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.TCPPorts != nil {
|
||||||
|
in, out := &in.TCPPorts, &out.TCPPorts
|
||||||
|
*out = make([]int32, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.UDPPorts != nil {
|
||||||
|
in, out := &in.UDPPorts, &out.UDPPorts
|
||||||
|
*out = make([]int32, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBResourceSpec.
|
||||||
|
func (in *NBResourceSpec) DeepCopy() *NBResourceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBResourceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBResourceStatus) DeepCopyInto(out *NBResourceStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.NetworkResourceID != nil {
|
||||||
|
in, out := &in.NetworkResourceID, &out.NetworkResourceID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.PolicyName != nil {
|
||||||
|
in, out := &in.PolicyName, &out.PolicyName
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.TCPPorts != nil {
|
||||||
|
in, out := &in.TCPPorts, &out.TCPPorts
|
||||||
|
*out = make([]int32, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.UDPPorts != nil {
|
||||||
|
in, out := &in.UDPPorts, &out.UDPPorts
|
||||||
|
*out = make([]int32, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Groups != nil {
|
||||||
|
in, out := &in.Groups, &out.Groups
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]NBCondition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBResourceStatus.
|
||||||
|
func (in *NBResourceStatus) DeepCopy() *NBResourceStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBResourceStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBRoutingPeer) DeepCopyInto(out *NBRoutingPeer) {
|
||||||
|
*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 NBRoutingPeer.
|
||||||
|
func (in *NBRoutingPeer) DeepCopy() *NBRoutingPeer {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBRoutingPeer)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBRoutingPeer) 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 *NBRoutingPeerList) DeepCopyInto(out *NBRoutingPeerList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]NBRoutingPeer, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBRoutingPeerList.
|
||||||
|
func (in *NBRoutingPeerList) DeepCopy() *NBRoutingPeerList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBRoutingPeerList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *NBRoutingPeerList) 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 *NBRoutingPeerSpec) DeepCopyInto(out *NBRoutingPeerSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Replicas != nil {
|
||||||
|
in, out := &in.Replicas, &out.Replicas
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
in.Resources.DeepCopyInto(&out.Resources)
|
||||||
|
if in.Labels != nil {
|
||||||
|
in, out := &in.Labels, &out.Labels
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Annotations != nil {
|
||||||
|
in, out := &in.Annotations, &out.Annotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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([]corev1.Toleration, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBRoutingPeerSpec.
|
||||||
|
func (in *NBRoutingPeerSpec) DeepCopy() *NBRoutingPeerSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBRoutingPeerSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NBRoutingPeerStatus) DeepCopyInto(out *NBRoutingPeerStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.NetworkID != nil {
|
||||||
|
in, out := &in.NetworkID, &out.NetworkID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.SetupKeyID != nil {
|
||||||
|
in, out := &in.SetupKeyID, &out.SetupKeyID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.RouterID != nil {
|
||||||
|
in, out := &in.RouterID, &out.RouterID
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]NBCondition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBRoutingPeerStatus.
|
||||||
|
func (in *NBRoutingPeerStatus) DeepCopy() *NBRoutingPeerStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NBRoutingPeerStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *NBSetupKey) DeepCopyInto(out *NBSetupKey) {
|
func (in *NBSetupKey) DeepCopyInto(out *NBSetupKey) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -35,23 +570,6 @@ func (in *NBSetupKey) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *NBSetupKeyCondition) DeepCopyInto(out *NBSetupKeyCondition) {
|
|
||||||
*out = *in
|
|
||||||
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
|
||||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NBSetupKeyCondition.
|
|
||||||
func (in *NBSetupKeyCondition) DeepCopy() *NBSetupKeyCondition {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(NBSetupKeyCondition)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *NBSetupKeyList) DeepCopyInto(out *NBSetupKeyList) {
|
func (in *NBSetupKeyList) DeepCopyInto(out *NBSetupKeyList) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -105,7 +623,7 @@ func (in *NBSetupKeyStatus) DeepCopyInto(out *NBSetupKeyStatus) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
if in.Conditions != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.Conditions, &out.Conditions
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = make([]NBSetupKeyCondition, len(*in))
|
*out = make([]NBCondition, len(*in))
|
||||||
for i := range *in {
|
for i := range *in {
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
|
|||||||
+121
@@ -19,6 +19,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -45,6 +46,10 @@ import (
|
|||||||
// +kubebuilder:scaffold:imports
|
// +kubebuilder:scaffold:imports
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
scheme = runtime.NewScheme()
|
scheme = runtime.NewScheme()
|
||||||
setupLog = ctrl.Log.WithName("setup")
|
setupLog = ctrl.Log.WithName("setup")
|
||||||
@@ -64,9 +69,27 @@ func main() {
|
|||||||
var (
|
var (
|
||||||
managementURL string
|
managementURL string
|
||||||
clientImage string
|
clientImage string
|
||||||
|
clusterName string
|
||||||
|
namespacedNetworks bool
|
||||||
|
clusterDNS string
|
||||||
|
netbirdAPIKey string
|
||||||
)
|
)
|
||||||
flag.StringVar(&managementURL, "netbird-management-url", "https://api.netbird.io", "Management service URL")
|
flag.StringVar(&managementURL, "netbird-management-url", "https://api.netbird.io", "Management service URL")
|
||||||
flag.StringVar(&clientImage, "netbird-client-image", "netbirdio/netbird:latest", "Image for netbird client container")
|
flag.StringVar(&clientImage, "netbird-client-image", "netbirdio/netbird:latest", "Image for netbird client container")
|
||||||
|
flag.StringVar(
|
||||||
|
&clusterName,
|
||||||
|
"cluster-name",
|
||||||
|
"kubernetes",
|
||||||
|
"User-friendly name for kubernetes cluster for NetBird resource creation",
|
||||||
|
)
|
||||||
|
flag.BoolVar(
|
||||||
|
&namespacedNetworks,
|
||||||
|
"namespaced-networks",
|
||||||
|
false,
|
||||||
|
"Create NetBird Network per namespace, set to true if a NetworkPolicy exists that would require this",
|
||||||
|
)
|
||||||
|
flag.StringVar(&clusterDNS, "cluster-dns", "svc.cluster.local", "Cluster DNS name")
|
||||||
|
flag.StringVar(&netbirdAPIKey, "netbird-api-key", "", "API key for NetBird API operations")
|
||||||
|
|
||||||
// Controller generic flags
|
// Controller generic flags
|
||||||
var (
|
var (
|
||||||
@@ -177,6 +200,87 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(netbirdAPIKey) > 0 {
|
||||||
|
if err = (&controller.NBRoutingPeerReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
ClientImage: clientImage,
|
||||||
|
ClusterName: clusterName,
|
||||||
|
APIKey: netbirdAPIKey,
|
||||||
|
ManagementURL: managementURL,
|
||||||
|
NamespacedNetworks: namespacedNetworks,
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "NBRoutingPeer")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerNamespace, err := getInClusterNamespace()
|
||||||
|
if err != nil {
|
||||||
|
setupLog.Error(err, "unable to get main namespace", "controller", "Service")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = (&controller.ServiceReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
ClusterName: clusterName,
|
||||||
|
ClusterDNS: clusterDNS,
|
||||||
|
NamespacedNetworks: namespacedNetworks,
|
||||||
|
ControllerNamespace: controllerNamespace,
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "Service")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = (&controller.NBResourceReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
APIKey: netbirdAPIKey,
|
||||||
|
ManagementURL: managementURL,
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "NBResource")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = (&controller.NBGroupReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
APIKey: netbirdAPIKey,
|
||||||
|
ManagementURL: managementURL,
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "NBGroup")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = (&controller.NBPolicyReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
APIKey: netbirdAPIKey,
|
||||||
|
ManagementURL: managementURL,
|
||||||
|
}).SetupWithManager(mgr); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create controller", "controller", "NBPolicy")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if enableWebhooks {
|
||||||
|
if err = webhooknetbirdiov1.SetupNBResourceWebhookWithManager(mgr, managementURL, netbirdAPIKey); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create webhook", "webhook", "NBResource")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = webhooknetbirdiov1.SetupNBRoutingPeerWebhookWithManager(mgr, managementURL, netbirdAPIKey); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create webhook", "webhook", "NBRoutingPeer")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = webhooknetbirdiov1.SetupNBGroupWebhookWithManager(mgr, managementURL, netbirdAPIKey); err != nil {
|
||||||
|
setupLog.Error(err, "unable to create webhook", "webhook", "NBGroup")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setupLog.Info("netbird API key not provided, ingress capabilities disabled")
|
||||||
|
}
|
||||||
// +kubebuilder:scaffold:builder
|
// +kubebuilder:scaffold:builder
|
||||||
|
|
||||||
if webhookCertWatcher != nil {
|
if webhookCertWatcher != nil {
|
||||||
@@ -202,3 +306,20 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getInClusterNamespace() (string, error) {
|
||||||
|
// Check whether the namespace file exists.
|
||||||
|
// If not, we are not running in cluster so can't guess the namespace.
|
||||||
|
if _, err := os.Stat(inClusterNamespacePath); os.IsNotExist(err) {
|
||||||
|
return "", fmt.Errorf("not running in-cluster, please specify LeaderElectionNamespace")
|
||||||
|
} else if err != nil {
|
||||||
|
return "", fmt.Errorf("error checking namespace file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the namespace file and return its content
|
||||||
|
namespace, err := os.ReadFile(inClusterNamespacePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error reading namespace file: %w", err)
|
||||||
|
}
|
||||||
|
return string(namespace), nil
|
||||||
|
}
|
||||||
|
|||||||
+168
@@ -0,0 +1,168 @@
|
|||||||
|
# Usage
|
||||||
|
|
||||||
|
## Provision pods with NetBird access using side-cars
|
||||||
|
|
||||||
|
1. Create a Setup Key in your [NetBird console](https://docs.netbird.io/how-to/register-machines-using-setup-keys#using-setup-keys).
|
||||||
|
1. Create a Secret object in the namespace where you need to provision NetBird access (secret name and field can be anything).
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
stringData:
|
||||||
|
setupkey: EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
```
|
||||||
|
1. Create an NBSetupKey object referring to your secret.
|
||||||
|
```yaml
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBSetupKey
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
spec:
|
||||||
|
# Optional, overrides management URL for this setupkey only
|
||||||
|
# defaults to https://api.netbird.io
|
||||||
|
managementURL: https://netbird.example.com
|
||||||
|
secretKeyRef:
|
||||||
|
name: test # Required
|
||||||
|
key: setupkey # Required
|
||||||
|
```
|
||||||
|
1. Annotate the pods you need to inject NetBird into with `netbird.io/setup-key`.
|
||||||
|
```yaml
|
||||||
|
kind: Deployment
|
||||||
|
...
|
||||||
|
spec:
|
||||||
|
...
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
netbird.io/setup-key: test # Must match the name of an NBSetupKey object in the same namespace
|
||||||
|
...
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Since v0.27.0, NetBird supports extra DNS labels, which extends the DNS names that you can link to peers by grouping them and load balancing access using DNS round-robin. To enable this feature, add the following annotation to the pod:
|
||||||
|
```yaml
|
||||||
|
netbird.io/extra-dns-labels: "label1,label2"
|
||||||
|
```
|
||||||
|
With this setup, all peers with the same extra label would be used in a DNS round-robin fashion.
|
||||||
|
|
||||||
|
## Provisioning Networks (Ingress Functionality)
|
||||||
|
|
||||||
|
### Granting controller access to NetBird Management
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The NetBird Kubernetes operator generates configurations using NetBird API; editing or deleting these configurations in the NetBird console may cause temporary network disconnection until the operator reconciles the configuration.
|
||||||
|
|
||||||
|
1. Create a Service User on your NetBird dashboard (Must be Admin). [Doc](https://docs.netbird.io/how-to/access-netbird-public-api#creating-a-service-user).
|
||||||
|
1. Create an access token for the Service User (Must be Admin). [Doc](https://docs.netbird.io/how-to/access-netbird-public-api#creating-a-service-user).
|
||||||
|
1. Add access token to your helm values file under `netbirdAPI.key`.
|
||||||
|
1. Alternatively, provision secret in the same namespace as the operator and set the key `NB_API_KEY` to the access token generated.
|
||||||
|
1. Set `netbirdAPI.keyFromSecret` to the name of the secret created.
|
||||||
|
1. Set `ingress.enabled` to `true`.
|
||||||
|
1. Optionally, to provision the network immediately, set `ingress.router.enabled` to `true`.
|
||||||
|
1. Optionally, to provision 1 network per > The NetBird Kubernetes operator generates configurations using NetBird API; editing or deleting these configurations in the NetBird console may cause temporary network disconnection until the operator reconciles the configuration. namespace, set `ingress.namespacedNetworks` to `true`.
|
||||||
|
1. Run `helm install` or `helm upgrade`.
|
||||||
|
|
||||||
|
Minimum values.yaml example:
|
||||||
|
```yaml
|
||||||
|
netbirdAPI:
|
||||||
|
key: "nbp_XXxxxxxxXXXXxxxxXXXXXxxx"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
cluster:
|
||||||
|
name: kubernetes
|
||||||
|
```
|
||||||
|
> Learn more about the values.yaml options [here](../helm/kubernetes-operator/values.yaml).
|
||||||
|
### Exposing a Service
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Ingress DNS Resolution requires DNS Wildcard Routing to be enabled and at least one DNS Nameserver configured for clients.
|
||||||
|
|
||||||
|
|Annotation|Description|Default|Valid Values|
|
||||||
|
|---|---|---|---|
|
||||||
|
|`netbird.io/expose`| Expose service using NetBird Network Resource ||(`null`, `true`)|
|
||||||
|
|`netbird.io/groups`| Comma-separated list of group names to assign to Network Resource |`{ClusterName}-{Namespace}-{Service}`|Any comma-separated list of strings.|
|
||||||
|
|`netbird.io/resource-name`| Network Resource name |`{Namespace}-{Service}`|Any valid network resource name, make sure they're unique!|
|
||||||
|
|`netbird.io/policy`| Name of NBPolicy to propagate service ports as destination. ||Name of any NBPolicy resource|
|
||||||
|
|`netbird.io/policy-ports`| Narrow down exposed ports in a policy. Leave empty for all ports. ||Comma-separated integer list, integers must be between 0-65535|
|
||||||
|
|`netbird.io/policy-protocol`| Narrow down protocol for use in a policy. Leave empty for all protocols. ||(`tcp`,`udp`)|
|
||||||
|
|
||||||
|
Example service:
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nginx-deployment
|
||||||
|
spec:
|
||||||
|
replicas: 0
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: nginx-service
|
||||||
|
annotations:
|
||||||
|
netbird.io/expose: "true"
|
||||||
|
netbird.io/groups: "groupA,groupB"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 8080
|
||||||
|
targetPort: 80
|
||||||
|
type: ClusterIP
|
||||||
|
```
|
||||||
|
### Notes
|
||||||
|
* `netbird.io/expose` will interpret any string as a `true` value; the only `false` value is `null`.
|
||||||
|
* The operator does **not** handle duplicate resource names within the same network, it is up to you to ensure resource names are unique within the same network.
|
||||||
|
* While the NetBird console will allow group names to contain commas, this is not allowed in `netbird.io/groups` annotation as commas are used as separators.
|
||||||
|
* If a group already exists on NetBird console with the same name, NetBird Operator will use that group ID instead of creating a new group.
|
||||||
|
* NetBird Operator will attempt to clean up any resources created, including groups created for resources.
|
||||||
|
* If a group is used by resources that the operator cannot clean up, the operator will eventually ignore the group in NetBird.
|
||||||
|
* It's recommended that unique groups be used per NetBird Operator installation to remove any possible conflicts.
|
||||||
|
* The Operator does not validate service annotations on updates, as this may cause unnecessary overhead on any Service update.
|
||||||
|
|
||||||
|
### Managing Policies
|
||||||
|
|
||||||
|
Simply add policies under `ingress.policies`, for example:
|
||||||
|
1. Add the following configuration in your `values.yaml` file.
|
||||||
|
```yaml
|
||||||
|
ingress:
|
||||||
|
policies:
|
||||||
|
default:
|
||||||
|
name: Kubernetes Default Policy # Required, name of policy in NetBird console
|
||||||
|
description: Default # Optional
|
||||||
|
sourceGroups: # Required, name of groups to assign as source in Policy.
|
||||||
|
- All
|
||||||
|
ports: # Optional, resources annotated 'netbird.io/policy=default' will append to this.
|
||||||
|
- 443
|
||||||
|
protocols: # Optional, restricts protocols allowed to resources, defaults to ['tcp', 'udp'].
|
||||||
|
- tcp
|
||||||
|
- udp
|
||||||
|
bidirectional: true # Optional, defaults to true
|
||||||
|
```
|
||||||
|
2. Reference policy in Services using `netbird.io/policy=default`, this will add relevant ports and destination groups to policy.
|
||||||
|
3. (Optional) Limit specific ports in exposed service by adding `netbird.io/policy-ports=443`.
|
||||||
|
4. (Optional) Limit specific protocol in exposed service by adding `netbird.io/policy-protocol=tcp`.
|
||||||
|
|
||||||
|
#### Notes
|
||||||
|
* Each NBPolicy will only create policies in the NetBird console when the information provided is enough to create one. If no services act as a destination or specified services do not conform to the protocol(s) defined, the policy will not be created.
|
||||||
|
* Each NBPolicy will create one policy in the NetBird console per protocol specified as long as the protocol has destinations; this ensures better-secured policies by separating ports for TCP and UDP.
|
||||||
|
* Policies currently do not support ICMP protocol, as ICMP is not supported in Kubernetes services, and there are [no current plans to support it](https://discuss.kubernetes.io/t/icmp-support-for-kubernetes-service/21738).
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: test
|
||||||
|
name: test
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: test
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 25%
|
||||||
|
maxUnavailable: 25%
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: test
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: nginx
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
netbird.io/expose: "true"
|
||||||
|
netbird.io/policy: default
|
||||||
|
netbird.io/resource-name: nginx
|
||||||
|
labels:
|
||||||
|
app: test
|
||||||
|
name: test
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 80
|
||||||
|
selector:
|
||||||
|
app: test
|
||||||
|
type: ClusterIP
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
router:
|
||||||
|
enabled: true
|
||||||
|
policies:
|
||||||
|
default:
|
||||||
|
name: Kubernetes Default Policy
|
||||||
|
sourceGroups:
|
||||||
|
- All
|
||||||
|
|
||||||
|
netbirdAPI:
|
||||||
|
key: "nbp_m0LM9ZZvDUzFO0pY50iChDOTxJgKFM3DIqmZ" # Replace with valid NetBird Service Account token
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
namespace: default
|
||||||
|
stringData:
|
||||||
|
SETUP_KEY: 50445ABC-8901-4050-8047-0A390658A79B # Replace with valid setup key
|
||||||
|
---
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBSetupKey
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
secretKeyRef:
|
||||||
|
name: test
|
||||||
|
key: SETUP_KEY
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: test
|
||||||
|
name: test
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: test
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 25%
|
||||||
|
maxUnavailable: 25%
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: test
|
||||||
|
annotations:
|
||||||
|
netbird.io/setup-key: test
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: ubuntu
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: ubuntu
|
||||||
|
command:
|
||||||
|
- sleep
|
||||||
|
- inf
|
||||||
@@ -5,7 +5,9 @@ go 1.23.0
|
|||||||
godebug default=go1.23
|
godebug default=go1.23
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/go-logr/logr v1.4.2
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/netbirdio/netbird v0.36.7
|
||||||
github.com/onsi/ginkgo/v2 v2.21.0
|
github.com/onsi/ginkgo/v2 v2.21.0
|
||||||
github.com/onsi/gomega v1.35.1
|
github.com/onsi/gomega v1.35.1
|
||||||
k8s.io/api v0.32.0
|
k8s.io/api v0.32.0
|
||||||
@@ -22,7 +24,6 @@ require (
|
|||||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
|
||||||
github.com/go-logr/zapr v1.3.0 // indirect
|
github.com/go-logr/zapr v1.3.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
@@ -46,16 +47,17 @@ require (
|
|||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.55.0 // indirect
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/net v0.30.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/oauth2 v0.23.0 // indirect
|
golang.org/x/oauth2 v0.23.0 // indirect
|
||||||
golang.org/x/sync v0.8.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.26.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
golang.org/x/term v0.25.0 // indirect
|
golang.org/x/term v0.28.0 // indirect
|
||||||
golang.org/x/text v0.19.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||||
|
|||||||
@@ -1,26 +1,110 @@
|
|||||||
|
cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs=
|
||||||
|
cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w=
|
||||||
|
cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
|
||||||
|
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
|
||||||
|
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||||
|
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
|
github.com/Microsoft/hcsshim v0.12.3 h1:LS9NXqXhMoqNCplK1ApmVSfB4UnVLRDWRapB6EIlxE0=
|
||||||
|
github.com/Microsoft/hcsshim v0.12.3/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
|
||||||
|
github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible h1:hqcTK6ZISdip65SR792lwYJTa/axESA0889D3UlZbLo=
|
||||||
|
github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible/go.mod h1:6B1nuc1MUs6c62ODZDl7hVE5Pv7O2XGSkgg2olnq34I=
|
||||||
|
github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 h1:pami0oPhVosjOu/qRHepRmdjD6hGILF7DBr+qQZeP10=
|
||||||
|
github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2/go.mod h1:jNIx5ykW1MroBuaTja9+VpglmaJOUzezumfhLlER3oY=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 h1:MmLCRqP4U4Cw9gJ4bNrCG0mWqEtBlmAVleyelcHARMU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3/go.mod h1:AMPjK2YnRh0YgOID3PqhJA1BRNfXDfGOnSsKHtAe8yA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
|
||||||
|
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
|
||||||
|
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw=
|
||||||
|
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
|
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
||||||
|
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
||||||
|
github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0=
|
||||||
|
github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
|
||||||
|
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||||
|
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/containerd/containerd v1.7.16 h1:7Zsfe8Fkj4Wi2My6DXGQ87hiqIrmOXolm72ZEkFU5Mg=
|
||||||
|
github.com/containerd/containerd v1.7.16/go.mod h1:NL49g7A/Fui7ccmxV6zkBWwqMgmMxFWzujYCc+JLt7k=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
|
github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g=
|
||||||
|
github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/eko/gocache/v3 v3.1.1 h1:r3CBwLnqPkcK56h9Do2CWw1kZ4TeKK0wDE1Oo/YZnhs=
|
||||||
|
github.com/eko/gocache/v3 v3.1.1/go.mod h1:UpP/LyHAioP/a/dizgl0MpgZ3A3CkS4NbG/mWkGTQ9M=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
||||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
@@ -29,10 +113,18 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
|
|||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
@@ -47,14 +139,55 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
|||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
|
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||||
|
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
|
||||||
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240212192251-757544f21357 h1:Fkzd8ktnpOR9h47SXHe2AYPwelXLH2GjGsjlAloiWfo=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240212192251-757544f21357/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
|
||||||
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||||
|
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||||
|
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
@@ -62,24 +195,68 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||||
|
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||||
|
github.com/libdns/route53 v1.5.0 h1:2SKdpPFl/qgWsXQvsLNJJAoX7rSxlk7zgoL4jnWdXVA=
|
||||||
|
github.com/libdns/route53 v1.5.0/go.mod h1:joT4hKmaTNKHEwb7GmZ65eoDz1whTu7KKYPS8ZqIh6Q=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||||
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k=
|
||||||
|
github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U=
|
||||||
|
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||||
|
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
|
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||||
|
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||||
|
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||||
|
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||||
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250115083837-a09722b8d2a6 h1:I/ODkZ8rSDOzlJbhEjD2luSI71zl+s5JgNvFHY0+mBU=
|
||||||
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250115083837-a09722b8d2a6/go.mod h1:izUUs1NT7ja+PwSX3kJ7ox8Kkn478tboBJSjL4kU6J0=
|
||||||
|
github.com/netbirdio/netbird v0.36.7 h1:ndJ+ab0D2PG33kvgd/p7XekOjKR2yy6wb+I9BJlK6Rc=
|
||||||
|
github.com/netbirdio/netbird v0.36.7/go.mod h1:6O7o2wr2MyD1O8V7Z8/FtO0/aHvcy5wt4eBwRRj3U4c=
|
||||||
|
github.com/okta/okta-sdk-golang/v2 v2.18.0 h1:cfDasMb7CShbZvOrF6n+DnLevWwiHgedWMGJ8M8xKDc=
|
||||||
|
github.com/okta/okta-sdk-golang/v2 v2.18.0/go.mod h1:dz30v3ctAiMb7jpsCngGfQUAEGm1/NsWT92uTbNDQIs=
|
||||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
|
github.com/pegasus-kv/thrift v0.13.0 h1:4ESwaNoHImfbHa9RUGJiJZ4hrxorihZHk5aarYwY8d4=
|
||||||
|
github.com/pegasus-kv/thrift v0.13.0/go.mod h1:Gl9NT/WHG6ABm6NsrbfE8LiJN0sAyneCrvB4qN4NPqQ=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
@@ -90,56 +267,108 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
|
|||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
|
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
|
||||||
|
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
|
||||||
|
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
||||||
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||||
|
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U=
|
||||||
|
github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 h1:790+S8ewZYCbG+o8IiFlZ8ZZ33XbNO6zV9qhU6xhlRk=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0/go.mod h1:REFmO+lSG9S6uSBEwIMZCxeI36uhScjTwChYADeO3JA=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0 h1:isAwFS3KNKRbJMbWv+wolWqOFUECmjYZ+sIRZCIBc/E=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0/go.mod h1:ZNYY8vumNCEG9YI59A9d6/YaMY49uwRhmeU563EzFGw=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||||
|
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||||
|
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||||
|
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
|
||||||
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||||
|
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||||
|
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.48.0 h1:sBQe3VNGUjY9IKWQC6z2lNqa5iGbDSxhs60ABwK4y0s=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.48.0/go.mod h1:DtrbMzoZWwQHyrQmCfLam5DZbnmorsGbOtTbYHycU5o=
|
||||||
|
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||||
|
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.26.0 h1:cWSks5tfriHPdWFnl+qpX3P681aAYqlZHcAyHw5aU9Y=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.26.0/go.mod h1:ClMFFknnThJCksebJwz7KIyEDHO+nTB6gK8obLy8RyE=
|
||||||
|
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||||
|
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
goauthentik.io/api/v3 v3.2023051.3 h1:NebAhD/TeTWNo/9X3/Uj+rM5fG1HaiLOlKTNLQv9Qq4=
|
||||||
|
goauthentik.io/api/v3 v3.2023051.3/go.mod h1:nYECml4jGbp/541hj8GcylKQG1gVBsKppHy4+7G8u4U=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||||
|
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||||
|
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||||
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -152,8 +381,20 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 h1:EY138uSo1JYlDq+97u1FtcOUwPpIU6WL1Lkt7WpYjPA=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||||
|
google.golang.org/api v0.177.0 h1:8a0p/BbPa65GlqGWtUKxot4p0TV8OGOfyTjtmkXNXmk=
|
||||||
|
google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw=
|
||||||
|
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||||
|
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||||
|
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -163,9 +404,23 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP
|
|||||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
|
||||||
|
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
|
||||||
|
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
|
||||||
|
gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
|
||||||
|
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
|
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
|
||||||
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
|
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
|
||||||
k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0=
|
k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0=
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ apiVersion: v2
|
|||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
description: A Helm chart for Kubernetes
|
description: A Helm chart for Kubernetes
|
||||||
type: application
|
type: application
|
||||||
version: 0.1.0
|
version: 0.1.2
|
||||||
appVersion: "v0.1.0"
|
appVersion: "v0.1.0-rc.3"
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbgroups.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBGroup
|
||||||
|
listKind: NBGroupList
|
||||||
|
plural: nbgroups
|
||||||
|
singular: nbgroup
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBGroup is the Schema for the nbgroups 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: NBGroupSpec defines the desired state of NBGroup.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Value is immutable
|
||||||
|
rule: self == oldSelf
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: NBGroupStatus defines the observed state of NBGroup.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
groupID:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbpolicies.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBPolicy
|
||||||
|
listKind: NBPolicyList
|
||||||
|
plural: nbpolicies
|
||||||
|
singular: nbpolicy
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBPolicy is the Schema for the nbpolicies 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: NBPolicySpec defines the desired state of NBPolicy.
|
||||||
|
properties:
|
||||||
|
bidirectional:
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
destinationGroups:
|
||||||
|
items:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
name:
|
||||||
|
description: Name Policy name
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
ports:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
maximum: 65535
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
protocols:
|
||||||
|
items:
|
||||||
|
enum:
|
||||||
|
- tcp
|
||||||
|
- udp
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
sourceGroups:
|
||||||
|
items:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: NBPolicyStatus defines the observed state of NBPolicy.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
lastUpdatedAt:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
managedServiceList:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
tcpPolicyID:
|
||||||
|
type: string
|
||||||
|
udpPolicyID:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbresources.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBResource
|
||||||
|
listKind: NBResourceList
|
||||||
|
plural: nbresources
|
||||||
|
singular: nbresource
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBResource is the Schema for the nbresources 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: NBResourceSpec defines the desired state of NBResource.
|
||||||
|
properties:
|
||||||
|
address:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
groups:
|
||||||
|
items:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
name:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
networkID:
|
||||||
|
type: string
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Value is immutable
|
||||||
|
rule: self == oldSelf
|
||||||
|
policyName:
|
||||||
|
type: string
|
||||||
|
tcpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
udpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- address
|
||||||
|
- groups
|
||||||
|
- name
|
||||||
|
- networkID
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: NBResourceStatus defines the observed state of NBResource.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
groups:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
networkResourceID:
|
||||||
|
type: string
|
||||||
|
policyName:
|
||||||
|
type: string
|
||||||
|
tcpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
udpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbroutingpeers.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
listKind: NBRoutingPeerList
|
||||||
|
plural: nbroutingpeers
|
||||||
|
singular: nbroutingpeer
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBRoutingPeer is the Schema for the nbroutingpeers 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: NBRoutingPeerSpec defines the desired state of NBRoutingPeer.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
nodeSelector:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
replicas:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
resources:
|
||||||
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
|
properties:
|
||||||
|
claims:
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
request:
|
||||||
|
description: |-
|
||||||
|
Request is the name chosen for a request in the referenced claim.
|
||||||
|
If empty, everything from the claim is made available, otherwise
|
||||||
|
only the result of this request.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- name
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- 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/
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- 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/
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
tolerations:
|
||||||
|
items:
|
||||||
|
description: |-
|
||||||
|
The pod this Toleration is attached to tolerates any taint that matches
|
||||||
|
the triple <key,value,effect> using the matching operator <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
|
||||||
|
status:
|
||||||
|
description: NBRoutingPeerStatus defines the observed state of NBRoutingPeer.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
networkID:
|
||||||
|
type: string
|
||||||
|
routerID:
|
||||||
|
type: string
|
||||||
|
setupKeyID:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
@@ -75,8 +75,7 @@ spec:
|
|||||||
properties:
|
properties:
|
||||||
conditions:
|
conditions:
|
||||||
items:
|
items:
|
||||||
description: NBSetupKeyCondition defines a condition in NBSetupKey
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
status.
|
|
||||||
properties:
|
properties:
|
||||||
lastProbeTime:
|
lastProbeTime:
|
||||||
description: Last time we probed the condition.
|
description: Last time we probed the condition.
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ caCert: {{ index $secret.data "ca.crt" }}
|
|||||||
clientCert: {{ index $secret.data "tls.crt" }}
|
clientCert: {{ index $secret.data "tls.crt" }}
|
||||||
clientKey: {{ index $secret.data "tls.key" }}
|
clientKey: {{ index $secret.data "tls.key" }}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{- $altNames := list (printf "%s.%s" $serviceName .Release.Namespace) (printf "%s.%s.svc" $serviceName .Release.Namespace) (printf "%s.%s.svc.%s" $serviceName .Release.Namespace .Values.webhook.cluster.dnsDomain) -}}
|
{{- $altNames := list (printf "%s.%s" $serviceName .Release.Namespace) (printf "%s.%s.svc" $serviceName .Release.Namespace) (printf "%s.%s.%s" $serviceName .Release.Namespace .Values.cluster.dns) -}}
|
||||||
{{- $ca := genCA "kubernetes-operator-ca" 3650 -}}
|
{{- $ca := genCA "kubernetes-operator-ca" 3650 -}}
|
||||||
{{- $cert := genSignedCert (include "kubernetes-operator.fullname" .) nil $altNames 3650 $ca -}}
|
{{- $cert := genSignedCert (include "kubernetes-operator.fullname" .) nil $altNames 3650 $ca -}}
|
||||||
caCert: {{ $ca.Cert | b64enc }}
|
caCert: {{ $ca.Cert | b64enc }}
|
||||||
|
|||||||
@@ -48,6 +48,18 @@ spec:
|
|||||||
{{- if .Values.managementURL }}
|
{{- if .Values.managementURL }}
|
||||||
- --netbird-management-url={{.Values.managementURL}}
|
- --netbird-management-url={{.Values.managementURL}}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.cluster.name }}
|
||||||
|
- --cluster-name={{.Values.cluster.name}}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.namespacedNetworks }}
|
||||||
|
- --namespaced-networks={{.Values.ingress.namespacedNetworks}}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.cluster.dns }}
|
||||||
|
- --cluster-dns={{.Values.cluster.dns}}
|
||||||
|
{{- end }}
|
||||||
|
{{- if or .Values.netbirdAPI.key .Values.netbirdAPI.keyFromSecret }}
|
||||||
|
- --netbird-api-key=$(NB_API_KEY)
|
||||||
|
{{- end }}
|
||||||
ports:
|
ports:
|
||||||
- name: webhook-server
|
- name: webhook-server
|
||||||
containerPort: {{ .Values.webhook.service.port }}
|
containerPort: {{ .Values.webhook.service.port }}
|
||||||
@@ -62,6 +74,15 @@ spec:
|
|||||||
periodSeconds: {{ .Values.operator.livenessProbe.periodSeconds }}
|
periodSeconds: {{ .Values.operator.livenessProbe.periodSeconds }}
|
||||||
successThreshold: {{ .Values.operator.livenessProbe.successThreshold }}
|
successThreshold: {{ .Values.operator.livenessProbe.successThreshold }}
|
||||||
timeoutSeconds: {{ .Values.operator.livenessProbe.timeoutSeconds }}
|
timeoutSeconds: {{ .Values.operator.livenessProbe.timeoutSeconds }}
|
||||||
|
{{- if or .Values.netbirdAPI.key .Values.netbirdAPI.keyFromSecret }}
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
{{- if .Values.netbirdAPI.keyFromSecret }}
|
||||||
|
name: {{.Values.netbirdAPI.keyFromSecret}}
|
||||||
|
{{- else }}
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
httpGet:
|
httpGet:
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{{- range $k, $v := $.Values.ingress.policies }}
|
||||||
|
---
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBPolicy
|
||||||
|
metadata:
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
||||||
|
name: {{ $k }}
|
||||||
|
spec:
|
||||||
|
name: {{ $v.name }}
|
||||||
|
sourceGroups:
|
||||||
|
{{ toYaml $v.sourceGroups | nindent 4}}
|
||||||
|
{{- if $v.description }}
|
||||||
|
description: {{ $v.description }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.protocols }}
|
||||||
|
protocols: {{ $v.protocols }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.ports }}
|
||||||
|
ports: {{ $v.ports }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if hasKey $v "bidirectional" }}
|
||||||
|
bidirectional: {{ $v.bidirectional }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{{- if and .Values.ingress.enabled .Values.ingress.router.enabled }}
|
||||||
|
{{- if .Values.ingress.namespacedNetworks }}
|
||||||
|
{{ $defaults := .Values.ingress.router }}
|
||||||
|
{{ range $k, $v := .Values.ingress.router.namespaces }}
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
metadata:
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
||||||
|
name: router
|
||||||
|
namespace: {{ $k }}
|
||||||
|
{{ $spec := merge $defaults $v }}
|
||||||
|
{{- if or (or (or $spec.replicas $spec.resources) (or $spec.labels $spec.annotations)) (or $spec.nodeSelector $spec.tolerations) }}
|
||||||
|
spec:
|
||||||
|
{{- if $spec.replicas }}
|
||||||
|
replicas: {{ $spec.replicas }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.resources }}
|
||||||
|
resources: {{ $spec.resources }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.labels }}
|
||||||
|
labels: {{ $spec.labels }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.annotations }}
|
||||||
|
annotations: {{ $spec.annotations }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.nodeSelector }}
|
||||||
|
nodeSelector: {{ $spec.nodeSelector }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $spec.tolerations }}
|
||||||
|
tolerations: {{ $spec.tolerations }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with .Values.ingress.router }}
|
||||||
|
apiVersion: netbird.io/v1
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
metadata:
|
||||||
|
finalizers:
|
||||||
|
- netbird.io/cleanup
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" $ | nindent 4 }}
|
||||||
|
name: router
|
||||||
|
{{- if or (or (or .replicas .resources) (or .labels .annotations)) (or .nodeSelector .tolerations) }}
|
||||||
|
spec:
|
||||||
|
{{- if .replicas }}
|
||||||
|
replicas: {{ .replicas }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .resources }}
|
||||||
|
resources: {{ .resources }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .labels }}
|
||||||
|
labels: {{ .labels }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .annotations }}
|
||||||
|
annotations: {{ .annotations }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .nodeSelector }}
|
||||||
|
nodeSelector: {{ .nodeSelector }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .tolerations }}
|
||||||
|
tolerations: {{ .tolerations }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
spec: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}-delete-routers
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: pre-delete
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||||
|
spec:
|
||||||
|
backOffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 8 }}
|
||||||
|
{{- with .Values.operator.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pre-delete
|
||||||
|
image: "bitnami/kubectl:latest"
|
||||||
|
args:
|
||||||
|
- delete
|
||||||
|
- --all
|
||||||
|
- -A
|
||||||
|
- --cascade=foreground
|
||||||
|
- --ignore-not-found
|
||||||
|
- NBRoutingPeer
|
||||||
|
serviceAccountName: {{ include "kubernetes-operator.serviceAccountName" . }}
|
||||||
|
restartPolicy: Never
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}-delete-policies
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: pre-delete
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||||
|
spec:
|
||||||
|
backOffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 8 }}
|
||||||
|
{{- with .Values.operator.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pre-delete
|
||||||
|
image: "bitnami/kubectl:latest"
|
||||||
|
args:
|
||||||
|
- delete
|
||||||
|
- --all
|
||||||
|
- --cascade=foreground
|
||||||
|
- --ignore-not-found
|
||||||
|
- NBPolicy
|
||||||
|
serviceAccountName: {{ include "kubernetes-operator.serviceAccountName" . }}
|
||||||
|
restartPolicy: Never
|
||||||
|
---
|
||||||
@@ -27,6 +27,79 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
resources:
|
||||||
|
- nbgroups
|
||||||
|
- nbresources
|
||||||
|
- nbroutingpeers
|
||||||
|
- nbpolicies
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
resources:
|
||||||
|
- nbgroups/status
|
||||||
|
- nbresources/status
|
||||||
|
- nbroutingpeers/status
|
||||||
|
- nbpolicies/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
resources:
|
||||||
|
- nbgroups/finalizers
|
||||||
|
- nbresources/finalizers
|
||||||
|
- nbroutingpeers/finalizers
|
||||||
|
- nbpolicies/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- namespaces
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
resources:
|
||||||
|
- deployments
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
{{- end }}
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
@@ -35,7 +108,7 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
{{- if .Values.clusterSecretsPermissions.allowAllSecrets }}
|
{{- if or .Values.ingress.enabled .Values.clusterSecretsPermissions.allowAllSecrets }}
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
@@ -44,6 +117,12 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{{- if .Values.netbirdAPI.key }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
|
stringData:
|
||||||
|
NB_API_KEY: {{ .Values.netbirdAPI.key }}
|
||||||
|
{{- end }}
|
||||||
@@ -12,7 +12,7 @@ metadata:
|
|||||||
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
webhooks:
|
webhooks:
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
{{- if not $.Values.webhook.enableCertManager -}}
|
{{- if not $.Values.webhook.enableCertManager }}
|
||||||
caBundle: {{ $tls.caCert }}
|
caBundle: {{ $tls.caCert }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
service:
|
service:
|
||||||
@@ -64,7 +64,7 @@ metadata:
|
|||||||
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
webhooks:
|
webhooks:
|
||||||
- clientConfig:
|
- clientConfig:
|
||||||
{{- if not $.Values.webhook.enableCertManager -}}
|
{{- if not $.Values.webhook.enableCertManager }}
|
||||||
caBundle: {{ $tls.caCert }}
|
caBundle: {{ $tls.caCert }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
service:
|
service:
|
||||||
@@ -89,8 +89,127 @@ webhooks:
|
|||||||
- CREATE
|
- CREATE
|
||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- "*/*"
|
- "nbsetupkeys"
|
||||||
sideEffects: None
|
sideEffects: None
|
||||||
|
{{- if and $.Values.ingress.enabled (or .Values.netbirdAPI.key .Values.netbirdAPI.keyFromSecret) }}
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
{{- if $.Values.webhook.enableCertManager }}
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
||||||
|
{{- end }}
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}-vnbresource-webhook
|
||||||
|
labels:
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
|
webhooks:
|
||||||
|
- clientConfig:
|
||||||
|
{{- if not $.Values.webhook.enableCertManager }}
|
||||||
|
caBundle: {{ $tls.caCert }}
|
||||||
|
{{ end }}
|
||||||
|
service:
|
||||||
|
name: {{ template "kubernetes-operator.webhookService" . }}
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
path: /validate-netbird-io-v1-nbresource
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: vnbresource-v1.netbird.io
|
||||||
|
admissionReviewVersions:
|
||||||
|
- v1
|
||||||
|
{{- if .Values.webhook.namespaceSelectors }}
|
||||||
|
namespaceSelector:
|
||||||
|
matchExpressions:
|
||||||
|
{{ toYaml .Values.webhook.namespaceSelectors | nindent 4 }}
|
||||||
|
{{ end }}
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
apiVersions:
|
||||||
|
- v1
|
||||||
|
operations:
|
||||||
|
- DELETE
|
||||||
|
resources:
|
||||||
|
- "nbresources"
|
||||||
|
sideEffects: None
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
{{- if $.Values.webhook.enableCertManager }}
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
||||||
|
{{- end }}
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}-vnbroutingpeer-webhook
|
||||||
|
labels:
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
|
webhooks:
|
||||||
|
- clientConfig:
|
||||||
|
{{- if not $.Values.webhook.enableCertManager }}
|
||||||
|
caBundle: {{ $tls.caCert }}
|
||||||
|
{{ end }}
|
||||||
|
service:
|
||||||
|
name: {{ template "kubernetes-operator.webhookService" . }}
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
path: /validate-netbird-io-v1-nbroutingpeer
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: vnbroutingpeer-v1.netbird.io
|
||||||
|
admissionReviewVersions:
|
||||||
|
- v1
|
||||||
|
{{- if .Values.webhook.namespaceSelectors }}
|
||||||
|
namespaceSelector:
|
||||||
|
matchExpressions:
|
||||||
|
{{ toYaml .Values.webhook.namespaceSelectors | nindent 4 }}
|
||||||
|
{{ end }}
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
apiVersions:
|
||||||
|
- v1
|
||||||
|
operations:
|
||||||
|
- DELETE
|
||||||
|
resources:
|
||||||
|
- "nbroutingpeers"
|
||||||
|
sideEffects: None
|
||||||
|
---
|
||||||
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
|
kind: ValidatingWebhookConfiguration
|
||||||
|
metadata:
|
||||||
|
{{- if $.Values.webhook.enableCertManager }}
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "kubernetes-operator.fullname" . }}-serving-cert
|
||||||
|
{{- end }}
|
||||||
|
name: {{ include "kubernetes-operator.fullname" . }}-vnbgroup-webhook
|
||||||
|
labels:
|
||||||
|
{{- include "kubernetes-operator.labels" . | nindent 4 }}
|
||||||
|
webhooks:
|
||||||
|
- clientConfig:
|
||||||
|
{{- if not $.Values.webhook.enableCertManager }}
|
||||||
|
caBundle: {{ $tls.caCert }}
|
||||||
|
{{ end }}
|
||||||
|
service:
|
||||||
|
name: {{ template "kubernetes-operator.webhookService" . }}
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
path: /validate-netbird-io-v1-nbgroup
|
||||||
|
failurePolicy: Fail
|
||||||
|
name: vnbgroup-v1.netbird.io
|
||||||
|
admissionReviewVersions:
|
||||||
|
- v1
|
||||||
|
{{- if .Values.webhook.namespaceSelectors }}
|
||||||
|
namespaceSelector:
|
||||||
|
matchExpressions:
|
||||||
|
{{ toYaml .Values.webhook.namespaceSelectors | nindent 4 }}
|
||||||
|
{{ end }}
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- netbird.io
|
||||||
|
apiVersions:
|
||||||
|
- v1
|
||||||
|
operations:
|
||||||
|
- DELETE
|
||||||
|
resources:
|
||||||
|
- "nbgroups"
|
||||||
|
sideEffects: None
|
||||||
|
{{- end }}
|
||||||
---
|
---
|
||||||
{{- if not $.Values.webhook.enableCertManager }}
|
{{- if not $.Values.webhook.enableCertManager }}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -116,7 +235,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- {{ template "kubernetes-operator.webhookService" . }}.{{ .Release.Namespace }}.svc
|
- {{ template "kubernetes-operator.webhookService" . }}.{{ .Release.Namespace }}.svc
|
||||||
- {{ template "kubernetes-operator.webhookService" . }}.{{ .Release.Namespace }}.svc.{{ .Values.webhook.cluster.dnsDomain }}
|
- {{ template "kubernetes-operator.webhookService" . }}.{{ .Release.Namespace }}.{{ .Values.cluster.dns }}
|
||||||
issuerRef:
|
issuerRef:
|
||||||
kind: Issuer
|
kind: Issuer
|
||||||
name: {{ template "kubernetes-operator.fullname" . }}-selfsigned-issuer
|
name: {{ template "kubernetes-operator.fullname" . }}-selfsigned-issuer
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
clusterSecretsPermissions:
|
clusterSecretsPermissions:
|
||||||
|
# Required for NBSetupKey validation
|
||||||
|
# Required for Ingress functionality to create and validate secrets for routing peers
|
||||||
allowAllSecrets: true
|
allowAllSecrets: true
|
||||||
|
|
||||||
webhook:
|
webhook:
|
||||||
@@ -7,22 +9,21 @@ webhook:
|
|||||||
port: 443
|
port: 443
|
||||||
targetPort: 9443
|
targetPort: 9443
|
||||||
|
|
||||||
cluster:
|
|
||||||
# Cluster DNS domain (required for requesting TLS certificates)
|
|
||||||
dnsDomain: cluster.local
|
|
||||||
|
|
||||||
# TLS configuration for webhook
|
# TLS configuration for webhook
|
||||||
|
# Optional, unused if webhook.enableCertManager is set to true
|
||||||
tls: {}
|
tls: {}
|
||||||
|
|
||||||
# Use cert-manager to provision webhook certificates
|
# Use cert-manager to provision webhook certificates (recommended)
|
||||||
enableCertManager: true
|
enableCertManager: true
|
||||||
|
|
||||||
|
# Narrow down validation and mutation webhooks namespaces
|
||||||
namespaceSelectors: []
|
namespaceSelectors: []
|
||||||
# - key: foo
|
# - key: foo
|
||||||
# operator: In
|
# operator: In
|
||||||
# values:
|
# values:
|
||||||
# - bar
|
# - bar
|
||||||
|
|
||||||
|
# Narrow down validation and mutation webhooks objects
|
||||||
objectSelector:
|
objectSelector:
|
||||||
matchExpressions: []
|
matchExpressions: []
|
||||||
# - key: app.kubernetes.io/name
|
# - key: app.kubernetes.io/name
|
||||||
@@ -128,3 +129,56 @@ operator:
|
|||||||
tolerations: []
|
tolerations: []
|
||||||
|
|
||||||
affinity: {}
|
affinity: {}
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
# Enable ingress capabilities to expose services
|
||||||
|
enabled: false
|
||||||
|
# Create router per namespace, useful for strict networking requirements
|
||||||
|
namespacedNetworks: false
|
||||||
|
router:
|
||||||
|
# Deploy routing peer(s)
|
||||||
|
enabled: false
|
||||||
|
# replicas: 3
|
||||||
|
# resources:
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# labels: {}
|
||||||
|
# annotations: {}
|
||||||
|
# nodeSelector: {}
|
||||||
|
# tolerations: []
|
||||||
|
# Only needed if namespacedNetworks is set to true
|
||||||
|
namespaces: {}
|
||||||
|
# default:
|
||||||
|
# replicas: 3
|
||||||
|
# resources:
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 100Mi
|
||||||
|
# labels: {}
|
||||||
|
# annotations: {}
|
||||||
|
# nodeSelector: {}
|
||||||
|
# tolerations: []
|
||||||
|
# NetBird Policies for use with exposed services
|
||||||
|
policies: {}
|
||||||
|
# default:
|
||||||
|
# name: Kubernetes Default Policy
|
||||||
|
# sourceGroups:
|
||||||
|
# - All
|
||||||
|
|
||||||
|
cluster:
|
||||||
|
# Cluster DNS name (used for webhooks certificates and for network resource DNS names)
|
||||||
|
dns: svc.cluster.local
|
||||||
|
# Cluster name (used for generating network and network resource names in NetBird)
|
||||||
|
# name: kubernetes
|
||||||
|
|
||||||
|
netbirdAPI: {}
|
||||||
|
# NetBird Service Account Token
|
||||||
|
# key: "nbp_m0LM9ZZvDUzFO0pY50iChDOTxJgKFM3DIqmZ"
|
||||||
|
# keyFromSecret: "Secret name with NB_API_KEY=Service Account Token"
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
"github.com/netbirdio/kubernetes-operator/internal/util"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBGroupReconciler reconciles a NBGroup object
|
||||||
|
type NBGroupReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
APIKey string
|
||||||
|
ManagementURL string
|
||||||
|
netbird *netbird.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defaultRequeueAfter default requeue duration
|
||||||
|
// due to controller-runtime limitations, sync periods may reach up to 10 hours if no changes are detected
|
||||||
|
// in watched resources.
|
||||||
|
// This may cause issues when NetBird-side resources are out-of-sync and need to be reconciled, this is a temporary
|
||||||
|
// fix to this issue by syncing with NetBird more frequently.
|
||||||
|
defaultRequeueAfter = 15 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *NBGroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) {
|
||||||
|
logger := ctrl.Log.WithName("NBGroup").WithValues("namespace", req.Namespace, "name", req.Name)
|
||||||
|
logger.Info("Reconciling NBGroup")
|
||||||
|
|
||||||
|
nbGroup := netbirdiov1.NBGroup{}
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBGroup", "err", err)
|
||||||
|
}
|
||||||
|
return ctrl.Result{RequeueAfter: defaultRequeueAfter}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
originalGroup := nbGroup.DeepCopy()
|
||||||
|
defer func() {
|
||||||
|
if !originalGroup.Status.Equal(nbGroup.Status) {
|
||||||
|
updateErr := r.Client.Status().Update(ctx, &nbGroup)
|
||||||
|
if updateErr != nil {
|
||||||
|
err = updateErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !res.Requeue && res.RequeueAfter == 0 {
|
||||||
|
res.RequeueAfter = defaultRequeueAfter
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if nbGroup.DeletionTimestamp != nil {
|
||||||
|
if len(nbGroup.Finalizers) == 0 {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, r.handleDelete(ctx, nbGroup, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.syncNetBirdGroup(ctx, &nbGroup, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncNetBirdGroup reconciliation logic for non-deleted objects.
|
||||||
|
func (r *NBGroupReconciler) syncNetBirdGroup(ctx context.Context, nbGroup *netbirdiov1.NBGroup, logger logr.Logger) (ctrl.Result, error) {
|
||||||
|
// Get all NetBird groups to ensure no group duplication
|
||||||
|
groups, err := r.netbird.Groups.List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error listing groups", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
var group *api.Group
|
||||||
|
for _, g := range groups {
|
||||||
|
if g.Name == nbGroup.Spec.Name {
|
||||||
|
group = &g
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create group if not exists, and update status.groupId
|
||||||
|
if nbGroup.Status.GroupID == nil && group == nil {
|
||||||
|
logger.Info("NBGroup: Creating group on NetBird", "name", nbGroup.Spec.Name)
|
||||||
|
group, err := r.netbird.Groups.Create(ctx, api.GroupRequest{
|
||||||
|
Name: nbGroup.Spec.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
nbGroup.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("NetBird API Error: %v", err))
|
||||||
|
logger.Error(errNetBirdAPI, "error creating group", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("NBGroup: Created group on NetBird", "name", nbGroup.Spec.Name, "id", group.Id)
|
||||||
|
nbGroup.Status.GroupID = &group.Id
|
||||||
|
nbGroup.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
} else if nbGroup.Status.GroupID == nil && group != nil {
|
||||||
|
logger.Info("NBGroup: Found group with same name on NetBird", "name", nbGroup.Spec.Name, "id", group.Id)
|
||||||
|
nbGroup.Status.GroupID = &group.Id
|
||||||
|
nbGroup.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
} else if group == nil {
|
||||||
|
logger.Info("NBGroup: Group was deleted", "name", nbGroup.Spec.Name, "id", *nbGroup.Status.GroupID)
|
||||||
|
nbGroup.Status.GroupID = nil
|
||||||
|
nbGroup.Status.Conditions = netbirdiov1.NBConditionFalse("GroupGone", "Group was deleted from NetBird API")
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
} else {
|
||||||
|
nbGroup.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbGroup.Status.GroupID != nil && group != nil && *nbGroup.Status.GroupID != group.Id {
|
||||||
|
// There are two possibilities here, either someone deleted and created the group in NetBird, thus the changed ID
|
||||||
|
// Or there's a conflict with something else, either way, we just need to take the new ID here
|
||||||
|
nbGroup.Status.GroupID = &group.Id
|
||||||
|
nbGroup.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NBGroupReconciler) handleDelete(ctx context.Context, nbGroup netbirdiov1.NBGroup, logger logr.Logger) error {
|
||||||
|
// Group doesn't exist on NetBird, no need for cleanup
|
||||||
|
if nbGroup.Status.GroupID == nil {
|
||||||
|
nbGroup.Finalizers = util.Without(nbGroup.Finalizers, "netbird.io/group-cleanup")
|
||||||
|
err := r.Client.Update(ctx, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBGroup", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.netbird.Groups.Delete(ctx, *nbGroup.Status.GroupID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") && !strings.Contains(err.Error(), "linked") {
|
||||||
|
logger.Error(errNetBirdAPI, "error deleting group", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil && strings.Contains(err.Error(), "linked") {
|
||||||
|
logger.Info("group still linked to resources on netbird", "err", err)
|
||||||
|
// Check if group is defined elsewhere in the cluster
|
||||||
|
var groups netbirdiov1.NBGroupList
|
||||||
|
listErr := r.Client.List(ctx, &groups)
|
||||||
|
if listErr != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error listing NBGroups", "err", listErr)
|
||||||
|
return listErr
|
||||||
|
}
|
||||||
|
for _, v := range groups.Items {
|
||||||
|
if v.UID == nbGroup.UID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v.Status.GroupID != nil && nbGroup.Status.GroupID != nil && *v.Status.GroupID == *nbGroup.Status.GroupID {
|
||||||
|
// Same group, multiple resources
|
||||||
|
logger.Info("group exists in another namespace", "namespace", v.Namespace, "name", v.Name)
|
||||||
|
nbGroup.Finalizers = util.Without(nbGroup.Finalizers, "netbird.io/group-cleanup")
|
||||||
|
err = r.Client.Update(ctx, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBGroup", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No other NBGroup with same name on the cluster
|
||||||
|
// This could be a group created by user elsewhere or some resources belonging to the group are still deleting.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbGroup.Finalizers = util.Without(nbGroup.Finalizers, "netbird.io/group-cleanup")
|
||||||
|
err = r.Client.Update(ctx, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBGroup", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *NBGroupReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
r.netbird = netbird.New(r.ManagementURL, r.APIKey)
|
||||||
|
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&netbirdiov1.NBGroup{}).
|
||||||
|
Named("nbgroup").
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBGroup Controller", func() {
|
||||||
|
Context("When reconciling a resource", func() {
|
||||||
|
const resourceName = "test-resource"
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
typeNamespacedName := types.NamespacedName{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default", // TODO(user):Modify as needed
|
||||||
|
}
|
||||||
|
nbgroup := &netbirdiov1.NBGroup{}
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("creating the custom resource for the Kind NBGroup")
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, nbgroup)
|
||||||
|
if err != nil && errors.IsNotFound(err) {
|
||||||
|
resource := &netbirdiov1.NBGroup{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
// TODO(user): Specify other spec details if needed.
|
||||||
|
}
|
||||||
|
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO(user): Cleanup logic after each test, like removing the resource instance.
|
||||||
|
resource := &netbirdiov1.NBGroup{}
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, resource)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("Cleanup the specific resource instance NBGroup")
|
||||||
|
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
|
||||||
|
})
|
||||||
|
It("should successfully reconcile the resource", func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("Reconciling the created resource")
|
||||||
|
controllerReconciler := &NBGroupReconciler{
|
||||||
|
Client: k8sClient,
|
||||||
|
Scheme: k8sClient.Scheme(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||||
|
NamespacedName: typeNamespacedName,
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
|
||||||
|
// Example: If you expect a certain status condition after reconciliation, verify it here.
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,378 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
"github.com/netbirdio/kubernetes-operator/internal/util"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBPolicyReconciler reconciles a NBPolicy object
|
||||||
|
type NBPolicyReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
ClusterName string
|
||||||
|
APIKey string
|
||||||
|
ManagementURL string
|
||||||
|
netbird *netbird.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errUnknownProtocol = fmt.Errorf("Unknown protocol")
|
||||||
|
errKubernetesAPI = fmt.Errorf("kubernetes API error")
|
||||||
|
errNetBirdAPI = fmt.Errorf("netbird API error")
|
||||||
|
)
|
||||||
|
|
||||||
|
// getResources get all NBResource objects in policy.status.managedServiceList
|
||||||
|
func (r *NBPolicyReconciler) getResources(ctx context.Context, nbPolicy *netbirdiov1.NBPolicy, logger logr.Logger) ([]netbirdiov1.NBResource, error) {
|
||||||
|
var resourceList []netbirdiov1.NBResource
|
||||||
|
var updatedManagedServiceList []string
|
||||||
|
for _, rss := range nbPolicy.Status.ManagedServiceList {
|
||||||
|
var resource netbirdiov1.NBResource
|
||||||
|
namespacedName := types.NamespacedName{Namespace: strings.Split(rss, "/")[0], Name: strings.Split(rss, "/")[1]}
|
||||||
|
err := r.Client.Get(ctx, namespacedName, &resource)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "Error getting NBResource", "namespace", namespacedName.Namespace, "name", namespacedName.Name)
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error getting NBResource: %v", err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil && resource.DeletionTimestamp == nil {
|
||||||
|
updatedManagedServiceList = append(updatedManagedServiceList, rss)
|
||||||
|
resourceList = append(resourceList, resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nbPolicy.Status.ManagedServiceList = updatedManagedServiceList
|
||||||
|
|
||||||
|
return resourceList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapResources map each NBResource ports and protocols into one object to generate the policy
|
||||||
|
// returns map[protocol] => ports, destination group IDs
|
||||||
|
func (r *NBPolicyReconciler) mapResources(ctx context.Context, nbPolicy *netbirdiov1.NBPolicy, resources []netbirdiov1.NBResource, logger logr.Logger) (map[string][]int32, []string, error) {
|
||||||
|
portMapping := map[string]map[int32]interface{}{
|
||||||
|
"tcp": make(map[int32]interface{}),
|
||||||
|
"udp": make(map[int32]interface{}),
|
||||||
|
}
|
||||||
|
groups, err := r.groupNamesToIDs(ctx, nbPolicy.Spec.DestinationGroups, logger)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, resource := range resources {
|
||||||
|
if resource.Status.PolicyName != nil && *resource.Status.PolicyName == nbPolicy.Name {
|
||||||
|
// Groups
|
||||||
|
groups = append(groups, resource.Status.Groups...)
|
||||||
|
|
||||||
|
for _, p := range resource.Spec.TCPPorts {
|
||||||
|
portMapping["tcp"][p] = nil
|
||||||
|
}
|
||||||
|
for _, p := range resource.Spec.UDPPorts {
|
||||||
|
portMapping["udp"][p] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ports := make(map[string][]int32)
|
||||||
|
for k, vs := range portMapping {
|
||||||
|
for v := range vs {
|
||||||
|
ports[k] = append(ports[k], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ports, groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createPolicy helper for creating policy with settings
|
||||||
|
func (r *NBPolicyReconciler) createPolicy(ctx context.Context, nbPolicy *netbirdiov1.NBPolicy, protocol string, sourceGroupIDs, destinationGroupIDs, ports []string, logger logr.Logger) (*string, error) {
|
||||||
|
policyName := fmt.Sprintf("%s %s", nbPolicy.Spec.Name, strings.ToUpper(protocol))
|
||||||
|
logger.Info("Creating NetBird Policy", "name", policyName, "description", nbPolicy.Spec.Description, "protocol", protocol, "sources", sourceGroupIDs, "destinations", destinationGroupIDs, "ports", ports, "bidirectional", nbPolicy.Spec.Bidirectional)
|
||||||
|
policy, err := r.netbird.Policies.Create(ctx, api.PostApiPoliciesJSONRequestBody{
|
||||||
|
Enabled: true,
|
||||||
|
Name: policyName,
|
||||||
|
Description: &nbPolicy.Spec.Description,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Name: policyName,
|
||||||
|
Description: &nbPolicy.Spec.Description,
|
||||||
|
Action: api.PolicyRuleUpdateActionAccept,
|
||||||
|
Protocol: api.PolicyRuleUpdateProtocol(protocol),
|
||||||
|
Bidirectional: nbPolicy.Spec.Bidirectional,
|
||||||
|
Sources: &sourceGroupIDs,
|
||||||
|
Destinations: &destinationGroupIDs,
|
||||||
|
Ports: &ports,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "Error creating Policy", "err", err)
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("Error creating policy: %v", err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return policy.Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updatePolicy helper for updating policy with settings
|
||||||
|
func (r *NBPolicyReconciler) updatePolicy(ctx context.Context, policyID *string, nbPolicy *netbirdiov1.NBPolicy, protocol string, sourceGroupIDs, destinationGroupIDs, ports []string, logger logr.Logger) (*string, bool, error) {
|
||||||
|
policyName := fmt.Sprintf("%s %s", nbPolicy.Spec.Name, strings.ToUpper(protocol))
|
||||||
|
logger.Info("Updating NetBird Policy", "name", policyName, "description", nbPolicy.Spec.Description, "protocol", protocol, "sources", sourceGroupIDs, "destinations", destinationGroupIDs, "ports", ports, "bidirectional", nbPolicy.Spec.Bidirectional)
|
||||||
|
policy, err := r.netbird.Policies.Update(ctx, *policyID, api.PutApiPoliciesPolicyIdJSONRequestBody{
|
||||||
|
Enabled: true,
|
||||||
|
Name: policyName,
|
||||||
|
Description: &nbPolicy.Spec.Description,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Enabled: true,
|
||||||
|
Name: policyName,
|
||||||
|
Description: &nbPolicy.Spec.Description,
|
||||||
|
Action: api.PolicyRuleUpdateActionAccept,
|
||||||
|
Protocol: api.PolicyRuleUpdateProtocol(protocol),
|
||||||
|
Bidirectional: nbPolicy.Spec.Bidirectional,
|
||||||
|
Sources: &sourceGroupIDs,
|
||||||
|
Destinations: &destinationGroupIDs,
|
||||||
|
Ports: &ports,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "Error updating Policy", "err", err)
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("Error updating policy: %v", err))
|
||||||
|
return policyID, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requeue := false
|
||||||
|
|
||||||
|
if err != nil && strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Info("Policy deleted from NetBird API, recreating", "protocol", protocol)
|
||||||
|
policyID = nil
|
||||||
|
requeue = true
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("Gone", "Policy deleted from NetBird API")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && (policyID == nil || *policy.Id != *policyID) {
|
||||||
|
policyID = policy.Id
|
||||||
|
}
|
||||||
|
return policyID, requeue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *NBPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) {
|
||||||
|
logger := ctrl.Log.WithName("NBPolicy").WithValues("namespace", req.Namespace, "name", req.Name)
|
||||||
|
logger.Info("Reconciling NBPolicy")
|
||||||
|
|
||||||
|
var nbPolicy netbirdiov1.NBPolicy
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, &nbPolicy)
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err)
|
||||||
|
}
|
||||||
|
return ctrl.Result{RequeueAfter: defaultRequeueAfter}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
originalPolicy := nbPolicy.DeepCopy()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if !originalPolicy.Status.Equal(nbPolicy.Status) {
|
||||||
|
updateErr := r.Client.Status().Update(ctx, &nbPolicy)
|
||||||
|
if updateErr != nil {
|
||||||
|
err = updateErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !res.Requeue && res.RequeueAfter == 0 {
|
||||||
|
res.RequeueAfter = defaultRequeueAfter
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if nbPolicy.DeletionTimestamp != nil {
|
||||||
|
if len(nbPolicy.Finalizers) == 0 {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, r.handleDelete(ctx, nbPolicy, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceList, err := r.getResources(ctx, &nbPolicy, logger)
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
portMapping, destGroups, err := r.mapResources(ctx, &nbPolicy, resourceList, logger)
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceGroupIDs, err := r.groupNamesToIDs(ctx, nbPolicy.Spec.SourceGroups, logger)
|
||||||
|
if err != nil {
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("Error getting group IDs: %v", err))
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requeue, err := r.syncPolicy(ctx, &nbPolicy, sourceGroupIDs, destGroups, portMapping, logger)
|
||||||
|
|
||||||
|
if requeue || err != nil {
|
||||||
|
return ctrl.Result{Requeue: requeue}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncPolicy ensure upstream policy is up-to-date
|
||||||
|
func (r *NBPolicyReconciler) syncPolicy(ctx context.Context, nbPolicy *netbirdiov1.NBPolicy, sourceGroups, destGroups []string, portMapping map[string][]int32, logger logr.Logger) (bool, error) {
|
||||||
|
requeue := false
|
||||||
|
|
||||||
|
for protocol, ports := range portMapping {
|
||||||
|
var policyID *string
|
||||||
|
switch protocol {
|
||||||
|
case "tcp":
|
||||||
|
policyID = nbPolicy.Status.TCPPolicyID
|
||||||
|
case "udp":
|
||||||
|
policyID = nbPolicy.Status.UDPPolicyID
|
||||||
|
default:
|
||||||
|
logger.Error(errKubernetesAPI, "Unknown protocol", "protocol", protocol)
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("ConfigError", fmt.Sprintf("Unknown protocol: %s", protocol))
|
||||||
|
return requeue, errUnknownProtocol
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nbPolicy.Spec.Protocols) > 0 && !util.Contains(nbPolicy.Spec.Protocols, protocol) {
|
||||||
|
if policyID != nil {
|
||||||
|
logger.Info("Deleting protocol policy as NBPolicy has restricted protocols", "protocol", protocol)
|
||||||
|
err := r.netbird.Policies.Delete(ctx, *policyID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("Error deleting policy: %v", err))
|
||||||
|
return requeue, err
|
||||||
|
}
|
||||||
|
policyID = nil
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.Info("Ignoring protocol as NBPolicy has restricted protocols", "protocol", protocol)
|
||||||
|
}
|
||||||
|
} else if len(ports) == 0 && policyID == nil {
|
||||||
|
logger.Info("0 ports found for protocol in policy", "protocol", protocol)
|
||||||
|
continue
|
||||||
|
} else if len(destGroups) == 0 && policyID == nil {
|
||||||
|
logger.Info("no destinations found for protocol in policy", "protocol", protocol)
|
||||||
|
continue
|
||||||
|
} else if len(sourceGroups) == 0 && policyID == nil {
|
||||||
|
logger.Info("no sources found for protocol in policy", "protocol", protocol)
|
||||||
|
continue
|
||||||
|
} else if len(ports) == 0 || len(destGroups) == 0 || len(sourceGroups) == 0 {
|
||||||
|
// Delete policy
|
||||||
|
logger.Info("Deleting policy", "protocol", protocol)
|
||||||
|
err := r.netbird.Policies.Delete(ctx, *policyID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("Error deleting policy: %v", err))
|
||||||
|
return requeue, err
|
||||||
|
}
|
||||||
|
policyID = nil
|
||||||
|
} else {
|
||||||
|
var stringPorts []string
|
||||||
|
for _, v := range ports {
|
||||||
|
stringPorts = append(stringPorts, strconv.FormatInt(int64(v), 10))
|
||||||
|
}
|
||||||
|
for _, v := range nbPolicy.Spec.Ports {
|
||||||
|
stringPorts = append(stringPorts, strconv.FormatInt(int64(v), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if policyID == nil {
|
||||||
|
policyID, err = r.createPolicy(ctx, nbPolicy, protocol, sourceGroups, destGroups, stringPorts, logger)
|
||||||
|
} else {
|
||||||
|
policyID, requeue, err = r.updatePolicy(ctx, policyID, nbPolicy, protocol, sourceGroups, destGroups, stringPorts, logger)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return requeue, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch protocol {
|
||||||
|
case "tcp":
|
||||||
|
nbPolicy.Status.TCPPolicyID = policyID
|
||||||
|
case "udp":
|
||||||
|
nbPolicy.Status.UDPPolicyID = policyID
|
||||||
|
default:
|
||||||
|
logger.Error(errKubernetesAPI, "Unknown protocol", "protocol", protocol)
|
||||||
|
nbPolicy.Status.Conditions = netbirdiov1.NBConditionFalse("ConfigError", fmt.Sprintf("Unknown protocol: %s", protocol))
|
||||||
|
return requeue, errUnknownProtocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return requeue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NBPolicyReconciler) handleDelete(ctx context.Context, nbPolicy netbirdiov1.NBPolicy, logger logr.Logger) error {
|
||||||
|
if nbPolicy.Status.TCPPolicyID != nil {
|
||||||
|
err := r.netbird.Policies.Delete(ctx, *nbPolicy.Status.TCPPolicyID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nbPolicy.Status.TCPPolicyID = nil
|
||||||
|
}
|
||||||
|
if nbPolicy.Status.UDPPolicyID != nil {
|
||||||
|
err := r.netbird.Policies.Delete(ctx, *nbPolicy.Status.UDPPolicyID)
|
||||||
|
if err != nil && !strings.Contains("not found", err.Error()) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nbPolicy.Status.UDPPolicyID = nil
|
||||||
|
}
|
||||||
|
if util.Contains(nbPolicy.Finalizers, "netbird.io/cleanup") {
|
||||||
|
nbPolicy.Finalizers = util.Without(nbPolicy.Finalizers, "netbird.io/cleanup")
|
||||||
|
err := r.Client.Update(ctx, &nbPolicy)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "Error updating NBPolicy", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// groupNamesToIDs map list of NetBird group names to group IDs
|
||||||
|
func (r *NBPolicyReconciler) groupNamesToIDs(ctx context.Context, groupNames []string, logger logr.Logger) ([]string, error) {
|
||||||
|
groups, err := r.netbird.Groups.List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "Error listing Groups", "err", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
groupNameIDMapping := make(map[string]string)
|
||||||
|
for _, g := range groups {
|
||||||
|
groupNameIDMapping[g.Name] = g.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := make([]string, 0, len(groupNames))
|
||||||
|
for _, g := range groupNames {
|
||||||
|
ret = append(ret, groupNameIDMapping[g])
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *NBPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
r.netbird = netbird.New(r.ManagementURL, r.APIKey)
|
||||||
|
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&netbirdiov1.NBPolicy{}).
|
||||||
|
Named("nbpolicy").
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBPolicy Controller", func() {
|
||||||
|
Context("When reconciling a resource", func() {
|
||||||
|
const resourceName = "test-resource"
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
typeNamespacedName := types.NamespacedName{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default", // TODO(user):Modify as needed
|
||||||
|
}
|
||||||
|
nbpolicy := &netbirdiov1.NBPolicy{}
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("creating the custom resource for the Kind NBPolicy")
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, nbpolicy)
|
||||||
|
if err != nil && errors.IsNotFound(err) {
|
||||||
|
resource := &netbirdiov1.NBPolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
// TODO(user): Specify other spec details if needed.
|
||||||
|
}
|
||||||
|
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO(user): Cleanup logic after each test, like removing the resource instance.
|
||||||
|
resource := &netbirdiov1.NBPolicy{}
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, resource)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("Cleanup the specific resource instance NBPolicy")
|
||||||
|
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
|
||||||
|
})
|
||||||
|
It("should successfully reconcile the resource", func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("Reconciling the created resource")
|
||||||
|
controllerReconciler := &NBPolicyReconciler{
|
||||||
|
Client: k8sClient,
|
||||||
|
Scheme: k8sClient.Scheme(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||||
|
NamespacedName: typeNamespacedName,
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
|
||||||
|
// Example: If you expect a certain status condition after reconciliation, verify it here.
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,413 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
"github.com/netbirdio/kubernetes-operator/internal/util"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBResourceReconciler reconciles a NBResource object
|
||||||
|
type NBResourceReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
APIKey string
|
||||||
|
ManagementURL string
|
||||||
|
netbird *netbird.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *NBResourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) {
|
||||||
|
logger := ctrl.Log.WithName("NBResource").WithValues("namespace", req.Namespace, "name", req.Name)
|
||||||
|
logger.Info("Reconciling NBResource")
|
||||||
|
|
||||||
|
nbResource := &netbirdiov1.NBResource{}
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, nbResource)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBResource", "err", err)
|
||||||
|
}
|
||||||
|
return ctrl.Result{RequeueAfter: defaultRequeueAfter}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
originalResource := nbResource.DeepCopy()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if !originalResource.Status.Equal(nbResource.Status) {
|
||||||
|
updateErr := r.Client.Status().Update(ctx, nbResource)
|
||||||
|
if updateErr != nil {
|
||||||
|
err = updateErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !res.Requeue && res.RequeueAfter == 0 {
|
||||||
|
res.RequeueAfter = defaultRequeueAfter
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if nbResource.DeletionTimestamp != nil {
|
||||||
|
if len(nbResource.Finalizers) == 0 {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, r.handleDelete(ctx, req, nbResource, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
groupIDs, result, err := r.handleGroups(ctx, req, nbResource, logger)
|
||||||
|
if result != nil {
|
||||||
|
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error occurred handling groups: %v", err))
|
||||||
|
return *result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resource, err := r.handleNetBirdResource(ctx, nbResource, groupIDs, logger)
|
||||||
|
if err != nil {
|
||||||
|
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error occurred handling NetBird Network Resource: %v", err))
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// resource is only nil if requeue is expected
|
||||||
|
if resource == nil {
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.handleGroupUpdate(ctx, nbResource, groupIDs, resource, logger)
|
||||||
|
if err != nil {
|
||||||
|
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error occurred handling groups: %v", err))
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.handlePolicy(ctx, req, nbResource, groupIDs, logger)
|
||||||
|
if err != nil {
|
||||||
|
nbResource.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("Error occurred handling policy changes: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
nbResource.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handlePolicy update NBPolicy if defined to add self reference to policy status
|
||||||
|
func (r *NBResourceReconciler) handlePolicy(ctx context.Context, req ctrl.Request, nbResource *netbirdiov1.NBResource, groupIDs []string, logger logr.Logger) error {
|
||||||
|
if nbResource.Status.PolicyName == nil && nbResource.Spec.PolicyName == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePolicyStatus := false
|
||||||
|
|
||||||
|
var nbPolicy netbirdiov1.NBPolicy
|
||||||
|
if nbResource.Spec.PolicyName == "" && nbResource.Status.PolicyName != nil {
|
||||||
|
// Remove self reference from policy status
|
||||||
|
nbResource.Status.PolicyName = nil
|
||||||
|
err := r.Client.Get(ctx, types.NamespacedName{Name: *nbResource.Status.PolicyName}, &nbPolicy)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||||
|
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||||
|
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||||
|
updatePolicyStatus = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Update policy settings if any difference is found
|
||||||
|
// TODO: Handle updated policy name by removing reference from old policy name in status.policyName
|
||||||
|
err := r.Client.Get(ctx, types.NamespacedName{Name: nbResource.Spec.PolicyName}, &nbPolicy)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbResource.Status.PolicyName == nil || *nbResource.Status.PolicyName != nbPolicy.Name {
|
||||||
|
nbResource.Status.PolicyName = &nbPolicy.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||||
|
nbPolicy.Status.ManagedServiceList = append(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||||
|
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||||
|
updatePolicyStatus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.Equivalent(nbResource.Spec.TCPPorts, nbResource.Status.TCPPorts) {
|
||||||
|
nbResource.Status.TCPPorts = nbResource.Spec.TCPPorts
|
||||||
|
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||||
|
updatePolicyStatus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.Equivalent(nbResource.Spec.UDPPorts, nbResource.Status.UDPPorts) {
|
||||||
|
nbResource.Status.UDPPorts = nbResource.Spec.UDPPorts
|
||||||
|
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||||
|
updatePolicyStatus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.Equivalent(nbResource.Status.Groups, groupIDs) {
|
||||||
|
nbResource.Status.Groups = groupIDs
|
||||||
|
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||||
|
updatePolicyStatus = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatePolicyStatus {
|
||||||
|
err := r.Client.Status().Update(ctx, &nbPolicy)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupUpdate update network resource groups
|
||||||
|
func (r *NBResourceReconciler) handleGroupUpdate(ctx context.Context, nbResource *netbirdiov1.NBResource, groupIDs []string, resource *api.NetworkResource, logger logr.Logger) error {
|
||||||
|
// Handle possible updated group IDs
|
||||||
|
groupIDMap := make(map[string]interface{})
|
||||||
|
for _, g := range groupIDs {
|
||||||
|
groupIDMap[g] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
diffFound := len(groupIDs) != len(resource.Groups)
|
||||||
|
for _, g := range resource.Groups {
|
||||||
|
if _, ok := groupIDMap[g.Id]; !ok {
|
||||||
|
diffFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if diffFound {
|
||||||
|
_, err := r.netbird.Networks.Resources(nbResource.Spec.NetworkID).Update(ctx, resource.Id, api.NetworkResourceRequest{
|
||||||
|
Name: nbResource.Spec.Name,
|
||||||
|
Description: &networkDescription,
|
||||||
|
Address: nbResource.Spec.Address,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: groupIDs,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error updating resource", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleNetBirdResource sync NetBird Network Resource
|
||||||
|
func (r *NBResourceReconciler) handleNetBirdResource(ctx context.Context, nbResource *netbirdiov1.NBResource, groupIDs []string, logger logr.Logger) (*api.NetworkResource, error) {
|
||||||
|
var resource *api.NetworkResource
|
||||||
|
var err error
|
||||||
|
if nbResource.Status.NetworkResourceID != nil {
|
||||||
|
resource, err = r.netbird.Networks.Resources(nbResource.Spec.NetworkID).Get(ctx, *nbResource.Status.NetworkResourceID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "error getting network resource", "err", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create/Update upstream network resource
|
||||||
|
if nbResource.Status.NetworkResourceID == nil && resource == nil {
|
||||||
|
resource, err := r.netbird.Networks.Resources(nbResource.Spec.NetworkID).Create(ctx, api.NetworkResourceRequest{
|
||||||
|
Address: nbResource.Spec.Address,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: groupIDs,
|
||||||
|
Description: &networkDescription,
|
||||||
|
Name: nbResource.Spec.Name,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error creating resource", "err", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbResource.Status.NetworkResourceID = &resource.Id
|
||||||
|
} else if nbResource.Status.NetworkResourceID == nil && resource != nil {
|
||||||
|
nbResource.Status.NetworkResourceID = &resource.Id
|
||||||
|
} else if resource == nil {
|
||||||
|
// Status remembers networkResourceID but resource was deleted elsewhere
|
||||||
|
// remove networkID from status and re-enqueue
|
||||||
|
nbResource.Status.NetworkResourceID = nil
|
||||||
|
} else {
|
||||||
|
resourceGroups := make([]string, 0, len(resource.Groups))
|
||||||
|
for _, v := range resource.Groups {
|
||||||
|
resourceGroups = append(resourceGroups, v.Id)
|
||||||
|
}
|
||||||
|
if resource.Address != nbResource.Spec.Address ||
|
||||||
|
!resource.Enabled ||
|
||||||
|
!util.Equivalent(resourceGroups, groupIDs) ||
|
||||||
|
*resource.Description != networkDescription ||
|
||||||
|
resource.Name != nbResource.Spec.Name {
|
||||||
|
_, err = r.netbird.Networks.Resources(nbResource.Spec.NetworkID).Update(ctx, *nbResource.Status.NetworkResourceID, api.NetworkResourceRequest{
|
||||||
|
Address: nbResource.Spec.Address,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: groupIDs,
|
||||||
|
Description: &networkDescription,
|
||||||
|
Name: nbResource.Spec.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return resource, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroups create NBGroup objects for each group specified in NBResource
|
||||||
|
func (r *NBResourceReconciler) handleGroups(ctx context.Context, req ctrl.Request, nbResource *netbirdiov1.NBResource, logger logr.Logger) ([]string, *ctrl.Result, error) {
|
||||||
|
var groupIDs []string
|
||||||
|
|
||||||
|
for _, groupName := range nbResource.Spec.Groups {
|
||||||
|
nbGroup := netbirdiov1.NBGroup{}
|
||||||
|
groupNameRFC := strings.ToLower(groupName)
|
||||||
|
groupNameRFC = strings.ReplaceAll(groupNameRFC, " ", "-")
|
||||||
|
err := r.Client.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: groupNameRFC}, &nbGroup)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBGroup", "err", err)
|
||||||
|
return nil, &ctrl.Result{}, err
|
||||||
|
} else if errors.IsNotFound(err) {
|
||||||
|
// Create NBGroup
|
||||||
|
nbGroup = netbirdiov1.NBGroup{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: groupNameRFC,
|
||||||
|
Namespace: nbResource.Namespace,
|
||||||
|
OwnerReferences: []v1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: nbResource.APIVersion,
|
||||||
|
Kind: nbResource.Kind,
|
||||||
|
Name: nbResource.Name,
|
||||||
|
UID: nbResource.UID,
|
||||||
|
BlockOwnerDeletion: util.Ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Finalizers: []string{"netbird.io/group-cleanup", "netbird.io/resource-cleanup"},
|
||||||
|
},
|
||||||
|
Spec: netbirdiov1.NBGroupSpec{
|
||||||
|
Name: groupName,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.Client.Create(ctx, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error creating NBGroup", "err", err)
|
||||||
|
return nil, &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
// Add NBResource as owner to NBGroup if not already done
|
||||||
|
ownerExists := false
|
||||||
|
for _, o := range nbGroup.OwnerReferences {
|
||||||
|
if o.UID == nbResource.UID {
|
||||||
|
ownerExists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ownerExists {
|
||||||
|
nbGroup.OwnerReferences = append(nbGroup.OwnerReferences, v1.OwnerReference{
|
||||||
|
APIVersion: nbResource.APIVersion,
|
||||||
|
Kind: nbResource.Kind,
|
||||||
|
Name: nbResource.Name,
|
||||||
|
UID: nbResource.UID,
|
||||||
|
BlockOwnerDeletion: util.Ptr(true),
|
||||||
|
})
|
||||||
|
|
||||||
|
err = r.Client.Update(ctx, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBGroup", "err", err)
|
||||||
|
return nil, &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbGroup.Status.GroupID != nil {
|
||||||
|
groupIDs = append(groupIDs, *nbGroup.Status.GroupID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not all groups are ready, requeue
|
||||||
|
if len(groupIDs) != len(nbResource.Spec.Groups) {
|
||||||
|
return nil, &ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupIDs, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NBResourceReconciler) handleDelete(ctx context.Context, req ctrl.Request, nbResource *netbirdiov1.NBResource, logger logr.Logger) error {
|
||||||
|
if nbResource.Status.PolicyName != nil {
|
||||||
|
var nbPolicy netbirdiov1.NBPolicy
|
||||||
|
err := r.Client.Get(ctx, types.NamespacedName{Name: *nbResource.Status.PolicyName}, &nbPolicy)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.IsNotFound(err) && util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||||
|
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||||
|
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||||
|
err = r.Client.Status().Update(ctx, &nbPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbResource.Status.NetworkResourceID != nil {
|
||||||
|
err := r.netbird.Networks.Resources(nbResource.Spec.NetworkID).Delete(ctx, *nbResource.Status.NetworkResourceID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "error deleting resource", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbResource.Status.NetworkResourceID = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nbGroupList := netbirdiov1.NBGroupList{}
|
||||||
|
err := r.Client.List(ctx, &nbGroupList, &client.ListOptions{Namespace: req.Namespace})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error listing NBGroup", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range nbGroupList.Items {
|
||||||
|
// TODO: Handle multiple owners
|
||||||
|
if len(g.OwnerReferences) > 0 && g.OwnerReferences[0].UID == nbResource.UID {
|
||||||
|
g.Finalizers = util.Without(g.Finalizers, "netbird.io/resource-cleanup")
|
||||||
|
err = r.Client.Update(ctx, &g)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBGroup", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nbResource.Finalizers = nil
|
||||||
|
err = r.Client.Update(ctx, nbResource)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBGroup", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *NBResourceReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
r.netbird = netbird.New(r.ManagementURL, r.APIKey)
|
||||||
|
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&netbirdiov1.NBResource{}).
|
||||||
|
Named("nbresource").
|
||||||
|
Watches(&netbirdiov1.NBGroup{}, handler.EnqueueRequestForOwner(r.Scheme, mgr.GetRESTMapper(), &netbirdiov1.NBResource{})).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBResource Controller", func() {
|
||||||
|
Context("When reconciling a resource", func() {
|
||||||
|
const resourceName = "test-resource"
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
typeNamespacedName := types.NamespacedName{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default", // TODO(user):Modify as needed
|
||||||
|
}
|
||||||
|
nbresource := &netbirdiov1.NBResource{}
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("creating the custom resource for the Kind NBResource")
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, nbresource)
|
||||||
|
if err != nil && errors.IsNotFound(err) {
|
||||||
|
resource := &netbirdiov1.NBResource{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
// TODO(user): Specify other spec details if needed.
|
||||||
|
}
|
||||||
|
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO(user): Cleanup logic after each test, like removing the resource instance.
|
||||||
|
resource := &netbirdiov1.NBResource{}
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, resource)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("Cleanup the specific resource instance NBResource")
|
||||||
|
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
|
||||||
|
})
|
||||||
|
It("should successfully reconcile the resource", func() {
|
||||||
|
By("Reconciling the created resource")
|
||||||
|
controllerReconciler := &NBResourceReconciler{
|
||||||
|
Client: k8sClient,
|
||||||
|
Scheme: k8sClient.Scheme(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||||
|
NamespacedName: typeNamespacedName,
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
|
||||||
|
// Example: If you expect a certain status condition after reconciliation, verify it here.
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,641 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
"github.com/netbirdio/kubernetes-operator/internal/util"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NBRoutingPeerReconciler reconciles a NBRoutingPeer object
|
||||||
|
type NBRoutingPeerReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
ClientImage string
|
||||||
|
ClusterName string
|
||||||
|
APIKey string
|
||||||
|
ManagementURL string
|
||||||
|
NamespacedNetworks bool
|
||||||
|
netbird *netbird.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *NBRoutingPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) {
|
||||||
|
logger := ctrl.Log.WithName("NBRoutingPeer").WithValues("namespace", req.Namespace, "name", req.Name)
|
||||||
|
logger.Info("Reconciling NBRoutingPeer")
|
||||||
|
|
||||||
|
nbrp := &netbirdiov1.NBRoutingPeer{}
|
||||||
|
err = r.Get(ctx, req.NamespacedName, nbrp)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBRoutingPeer", "err", err)
|
||||||
|
}
|
||||||
|
return ctrl.Result{RequeueAfter: defaultRequeueAfter}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
originalNBRP := nbrp.DeepCopy()
|
||||||
|
defer func() {
|
||||||
|
if originalNBRP.Status.NetworkID != nbrp.Status.NetworkID ||
|
||||||
|
originalNBRP.Status.RouterID != nbrp.Status.RouterID ||
|
||||||
|
originalNBRP.Status.SetupKeyID != nbrp.Status.SetupKeyID ||
|
||||||
|
!util.Equivalent(originalNBRP.Status.Conditions, nbrp.Status.Conditions) {
|
||||||
|
err = r.Client.Status().Update(ctx, nbrp)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBRoutingPeer Status", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !res.Requeue && res.RequeueAfter == 0 {
|
||||||
|
res.RequeueAfter = defaultRequeueAfter
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if nbrp.DeletionTimestamp != nil {
|
||||||
|
if len(nbrp.Finalizers) == 0 {
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
return r.handleDelete(ctx, req, nbrp, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("NBRoutingPeer: Checking network")
|
||||||
|
err = r.handleNetwork(ctx, req, nbrp, logger)
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("NBRoutingPeer: Checking groups")
|
||||||
|
nbGroup, result, err := r.handleGroup(ctx, req, nbrp, logger)
|
||||||
|
if nbGroup == nil {
|
||||||
|
return *result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("NBRoutingPeer: Checking setup keys")
|
||||||
|
result, err = r.handleSetupKey(ctx, req, nbrp, *nbGroup, logger)
|
||||||
|
if result != nil {
|
||||||
|
return *result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("NBRoutingPeer: Checking network router")
|
||||||
|
err = r.handleRouter(ctx, nbrp, *nbGroup, logger)
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("NBRoutingPeer: Checking deployment")
|
||||||
|
err = r.handleDeployment(ctx, req, nbrp, logger)
|
||||||
|
if err != nil {
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionTrue()
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleDeployment reconcile routing peer Deployment
|
||||||
|
func (r *NBRoutingPeerReconciler) handleDeployment(ctx context.Context, req ctrl.Request, nbrp *netbirdiov1.NBRoutingPeer, logger logr.Logger) error {
|
||||||
|
routingPeerDeployment := appsv1.Deployment{}
|
||||||
|
err := r.Client.Get(ctx, req.NamespacedName, &routingPeerDeployment)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting Deployment", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error getting Deployment: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create deployment
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
var replicas int32 = 3
|
||||||
|
if nbrp.Spec.Replicas != nil {
|
||||||
|
replicas = *nbrp.Spec.Replicas
|
||||||
|
}
|
||||||
|
routingPeerDeployment = appsv1.Deployment{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: nbrp.Name,
|
||||||
|
Namespace: nbrp.Namespace,
|
||||||
|
OwnerReferences: []v1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: nbrp.APIVersion,
|
||||||
|
Kind: nbrp.Kind,
|
||||||
|
Name: nbrp.Name,
|
||||||
|
UID: nbrp.UID,
|
||||||
|
BlockOwnerDeletion: util.Ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Labels: nbrp.Spec.Labels,
|
||||||
|
Annotations: nbrp.Spec.Annotations,
|
||||||
|
},
|
||||||
|
Spec: appsv1.DeploymentSpec{
|
||||||
|
Replicas: &replicas,
|
||||||
|
Selector: &v1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"app.kubernetes.io/name": "netbird-router",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Template: corev1.PodTemplateSpec{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"app.kubernetes.io/name": "netbird-router",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: "netbird",
|
||||||
|
Image: r.ClientImage,
|
||||||
|
Env: []corev1.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "NB_SETUP_KEY",
|
||||||
|
ValueFrom: &corev1.EnvVarSource{
|
||||||
|
SecretKeyRef: &corev1.SecretKeySelector{
|
||||||
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
|
Name: nbrp.Name,
|
||||||
|
},
|
||||||
|
Key: "setupKey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NB_MANAGEMENT_URL",
|
||||||
|
Value: r.ManagementURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SecurityContext: &corev1.SecurityContext{
|
||||||
|
Capabilities: &corev1.Capabilities{
|
||||||
|
Add: []corev1.Capability{
|
||||||
|
"NET_ADMIN",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.Client.Create(ctx, &routingPeerDeployment)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error creating Deployment", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error creating Deployment: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updatedDeployment := routingPeerDeployment.DeepCopy()
|
||||||
|
updatedDeployment.ObjectMeta.Name = nbrp.Name
|
||||||
|
updatedDeployment.ObjectMeta.Namespace = nbrp.Namespace
|
||||||
|
updatedDeployment.ObjectMeta.OwnerReferences = []v1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: nbrp.APIVersion,
|
||||||
|
Kind: nbrp.Kind,
|
||||||
|
Name: nbrp.Name,
|
||||||
|
UID: nbrp.UID,
|
||||||
|
BlockOwnerDeletion: util.Ptr(true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
updatedDeployment.ObjectMeta.Labels = nbrp.Spec.Labels
|
||||||
|
for k, v := range nbrp.Spec.Annotations {
|
||||||
|
updatedDeployment.ObjectMeta.Annotations[k] = nbrp.Spec.Annotations[v]
|
||||||
|
}
|
||||||
|
var replicas int32 = 3
|
||||||
|
if nbrp.Spec.Replicas != nil {
|
||||||
|
replicas = *nbrp.Spec.Replicas
|
||||||
|
}
|
||||||
|
updatedDeployment.Spec.Replicas = &replicas
|
||||||
|
updatedDeployment.Spec.Selector = &v1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"app.kubernetes.io/name": "netbird-router",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
updatedDeployment.Spec.Template.ObjectMeta.Labels = map[string]string{
|
||||||
|
"app.kubernetes.io/name": "netbird-router",
|
||||||
|
}
|
||||||
|
if len(updatedDeployment.Spec.Template.Spec.Containers) != 1 {
|
||||||
|
updatedDeployment.Spec.Template.Spec.Containers = []corev1.Container{}
|
||||||
|
}
|
||||||
|
updatedDeployment.Spec.Template.Spec.Containers[0].Name = "netbird"
|
||||||
|
updatedDeployment.Spec.Template.Spec.Containers[0].Image = r.ClientImage
|
||||||
|
updatedDeployment.Spec.Template.Spec.Containers[0].Env = []corev1.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "NB_SETUP_KEY",
|
||||||
|
ValueFrom: &corev1.EnvVarSource{
|
||||||
|
SecretKeyRef: &corev1.SecretKeySelector{
|
||||||
|
LocalObjectReference: corev1.LocalObjectReference{
|
||||||
|
Name: nbrp.Name,
|
||||||
|
},
|
||||||
|
Key: "setupKey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NB_MANAGEMENT_URL",
|
||||||
|
Value: r.ManagementURL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
updatedDeployment.Spec.Template.Spec.Containers[0].SecurityContext = &corev1.SecurityContext{
|
||||||
|
Capabilities: &corev1.Capabilities{
|
||||||
|
Add: []corev1.Capability{
|
||||||
|
"NET_ADMIN",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
patch := client.StrategicMergeFrom(&routingPeerDeployment)
|
||||||
|
bs, _ := patch.Data(updatedDeployment)
|
||||||
|
// To ensure no useless patching is done to the deployment being watched
|
||||||
|
// Minimum patch size is 2 for "{}"
|
||||||
|
if len(bs) <= 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = r.Client.Patch(ctx, updatedDeployment, patch)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating Deployment", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error updating Deployment: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleRouter reconcile network routing peer in NetBird management API
|
||||||
|
func (r *NBRoutingPeerReconciler) handleRouter(ctx context.Context, nbrp *netbirdiov1.NBRoutingPeer, nbGroup netbirdiov1.NBGroup, logger logr.Logger) error {
|
||||||
|
// Check NetworkRouter exists
|
||||||
|
routers, err := r.netbird.Networks.Routers(*nbrp.Status.NetworkID).List(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error listing network routers", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error listing network routers: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbrp.Status.RouterID == nil || len(routers) == 0 {
|
||||||
|
if len(routers) > 0 {
|
||||||
|
// Router exists but isn't saved to status
|
||||||
|
nbrp.Status.RouterID = &routers[0].Id
|
||||||
|
} else {
|
||||||
|
// Create network router
|
||||||
|
router, err := r.netbird.Networks.Routers(*nbrp.Status.NetworkID).Create(ctx, api.NetworkRouterRequest{
|
||||||
|
Enabled: true,
|
||||||
|
Masquerade: true,
|
||||||
|
Metric: 9999,
|
||||||
|
PeerGroups: &[]string{*nbGroup.Status.GroupID},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error creating network router", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error creating network router: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.RouterID = &router.Id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Ensure network router settings are correct
|
||||||
|
if !routers[0].Enabled || !routers[0].Masquerade || routers[0].Metric != 9999 || len(*routers[0].PeerGroups) != 1 || (*routers[0].PeerGroups)[0] != *nbGroup.Status.GroupID {
|
||||||
|
_, err = r.netbird.Networks.Routers(*nbrp.Status.NetworkID).Update(ctx, routers[0].Id, api.NetworkRouterRequest{
|
||||||
|
Enabled: true,
|
||||||
|
Masquerade: true,
|
||||||
|
Metric: 9999,
|
||||||
|
PeerGroups: &[]string{*nbGroup.Status.GroupID},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error updating network router", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error updating network router: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSetupKey reconcile setup key and regenerate if invalid
|
||||||
|
func (r *NBRoutingPeerReconciler) handleSetupKey(ctx context.Context, req ctrl.Request, nbrp *netbirdiov1.NBRoutingPeer, nbGroup netbirdiov1.NBGroup, logger logr.Logger) (*ctrl.Result, error) {
|
||||||
|
networkName := r.ClusterName
|
||||||
|
if r.NamespacedNetworks {
|
||||||
|
networkName += "-" + req.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if setup key exists
|
||||||
|
if nbrp.Status.SetupKeyID == nil {
|
||||||
|
// Create new setup key with group Status.GroupID
|
||||||
|
setupKey, err := r.netbird.SetupKeys.Create(ctx, api.CreateSetupKeyRequest{
|
||||||
|
AutoGroups: []string{*nbGroup.Status.GroupID},
|
||||||
|
Ephemeral: util.Ptr(true),
|
||||||
|
Name: networkName,
|
||||||
|
Type: "reusable",
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error creating setup key", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error creating setup key: %v", err))
|
||||||
|
return &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.SetupKeyID = &setupKey.Id
|
||||||
|
|
||||||
|
skSecret := corev1.Secret{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: nbrp.Name,
|
||||||
|
Namespace: nbrp.Namespace,
|
||||||
|
OwnerReferences: []v1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: nbrp.APIVersion,
|
||||||
|
Kind: nbrp.Kind,
|
||||||
|
Name: nbrp.Name,
|
||||||
|
UID: nbrp.UID,
|
||||||
|
BlockOwnerDeletion: util.Ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
StringData: map[string]string{
|
||||||
|
"setupKey": setupKey.Key,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = r.Client.Create(ctx, &skSecret)
|
||||||
|
if errors.IsAlreadyExists(err) {
|
||||||
|
err = r.Client.Update(ctx, &skSecret)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error creating Secret", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error creating secret: %v", err))
|
||||||
|
return &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check SetupKey is not revoked
|
||||||
|
setupKey, err := r.netbird.SetupKeys.Get(ctx, *nbrp.Status.SetupKeyID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "error getting setup key", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error getting setup key: %v", err))
|
||||||
|
return &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != nil && strings.Contains(err.Error(), "not found")) || setupKey.Revoked {
|
||||||
|
nbrp.Status.SetupKeyID = nil
|
||||||
|
|
||||||
|
// Requeue to avoid repeating code
|
||||||
|
return &ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if secret is valid
|
||||||
|
skSecret := corev1.Secret{}
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, &skSecret)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting Secret", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error getting secret: %v", err))
|
||||||
|
return &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := skSecret.Data["setupKey"]; errors.IsNotFound(err) || !ok {
|
||||||
|
// Someone deleted setup key secret
|
||||||
|
// Revoke SK from NetBird and re-generate
|
||||||
|
err = r.netbird.SetupKeys.Delete(ctx, *nbrp.Status.SetupKeyID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error deleting setup key", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error deleting setup key: %v", err))
|
||||||
|
return &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.SetupKeyID = nil
|
||||||
|
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("Gone", "generated secret was deleted")
|
||||||
|
// Requeue to avoid repeating code
|
||||||
|
return &ctrl.Result{Requeue: true}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroup creates/updates NBGroup for routing peer
|
||||||
|
func (r *NBRoutingPeerReconciler) handleGroup(ctx context.Context, req ctrl.Request, nbrp *netbirdiov1.NBRoutingPeer, logger logr.Logger) (*netbirdiov1.NBGroup, *ctrl.Result, error) {
|
||||||
|
networkName := r.ClusterName
|
||||||
|
if r.NamespacedNetworks {
|
||||||
|
networkName += "-" + req.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if NetBird Group exists
|
||||||
|
nbGroup := netbirdiov1.NBGroup{}
|
||||||
|
err := r.Client.Get(ctx, req.NamespacedName, &nbGroup)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBGroup", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error getting NBGroup: %v", err))
|
||||||
|
return nil, &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
nbGroup = netbirdiov1.NBGroup{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: nbrp.Name,
|
||||||
|
Namespace: nbrp.Namespace,
|
||||||
|
OwnerReferences: []v1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: nbrp.APIVersion,
|
||||||
|
Kind: nbrp.Kind,
|
||||||
|
Name: nbrp.Name,
|
||||||
|
UID: nbrp.UID,
|
||||||
|
BlockOwnerDeletion: util.Ptr(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Finalizers: []string{"netbird.io/group-cleanup", "netbird.io/routing-peer-cleanup"},
|
||||||
|
},
|
||||||
|
Spec: netbirdiov1.NBGroupSpec{
|
||||||
|
Name: networkName,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.Client.Create(ctx, &nbGroup)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error creating NBGroup", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("internalError", fmt.Sprintf("error creating NBGroup: %v", err))
|
||||||
|
return nil, &ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requeue after 5 seconds to ensure group creation is successful by NBGroup controller.
|
||||||
|
return nil, &ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbGroup.Status.GroupID == nil {
|
||||||
|
// Group is not yet created successfully, requeue
|
||||||
|
return nil, &ctrl.Result{RequeueAfter: 10 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &nbGroup, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleNetwork Create/Update NetBird Network
|
||||||
|
func (r *NBRoutingPeerReconciler) handleNetwork(ctx context.Context, req ctrl.Request, nbrp *netbirdiov1.NBRoutingPeer, logger logr.Logger) error {
|
||||||
|
networkName := r.ClusterName
|
||||||
|
if r.NamespacedNetworks {
|
||||||
|
networkName += "-" + req.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbrp.Status.NetworkID == nil {
|
||||||
|
// Check if network exists
|
||||||
|
networks, err := r.netbird.Networks.List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error listing networks", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error listing networks: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var network *api.Network
|
||||||
|
for _, n := range networks {
|
||||||
|
if n.Name == networkName {
|
||||||
|
logger.Info("network already exists", "network-id", n.Id)
|
||||||
|
network = &n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if network != nil {
|
||||||
|
nbrp.Status.NetworkID = &network.Id
|
||||||
|
} else {
|
||||||
|
logger.Info("creating network", "name", networkName)
|
||||||
|
network, err := r.netbird.Networks.Create(ctx, api.NetworkRequest{
|
||||||
|
Name: networkName,
|
||||||
|
Description: &networkDescription,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errNetBirdAPI, "error creating network", "err", err)
|
||||||
|
nbrp.Status.Conditions = netbirdiov1.NBConditionFalse("APIError", fmt.Sprintf("error creating network: %v", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.NetworkID = &network.Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NBRoutingPeerReconciler) handleDelete(ctx context.Context, req ctrl.Request, nbrp *netbirdiov1.NBRoutingPeer, logger logr.Logger) (ctrl.Result, error) {
|
||||||
|
nbDeployment := appsv1.Deployment{}
|
||||||
|
err := r.Client.Get(ctx, req.NamespacedName, &nbDeployment)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting Deployment", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
err = r.Client.Delete(ctx, &nbDeployment)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error deleting Deployment", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbrp.Status.SetupKeyID != nil {
|
||||||
|
logger.Info("Deleting setup key", "id", *nbrp.Status.SetupKeyID)
|
||||||
|
err = r.netbird.SetupKeys.Delete(ctx, *nbrp.Status.SetupKeyID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "error deleting setupKey", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
setupKeyID := *nbrp.Status.SetupKeyID
|
||||||
|
nbrp.Status.SetupKeyID = nil
|
||||||
|
logger.Info("Setup key deleted", "id", setupKeyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbrp.Status.RouterID != nil {
|
||||||
|
err = r.netbird.Networks.Routers(*nbrp.Status.NetworkID).Delete(ctx, *nbrp.Status.RouterID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "error deleting Network Router", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.RouterID = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nbGroup := netbirdiov1.NBGroup{}
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, &nbGroup)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBGroup", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbrp.Status.NetworkID != nil {
|
||||||
|
nbResourceList := netbirdiov1.NBResourceList{}
|
||||||
|
err = r.Client.List(ctx, &nbResourceList)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error listing NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, nbrs := range nbResourceList.Items {
|
||||||
|
if nbrs.Spec.NetworkID == *nbrp.Status.NetworkID {
|
||||||
|
logger.Info("Deleting NBResource", "namespace", nbrs.Namespace, "name", nbrs.Name)
|
||||||
|
err = r.Client.Delete(ctx, &nbrs)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error deleting NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nbResourceList.Items) == 0 {
|
||||||
|
logger.Info("Deleting NetBird Network", "id", *nbrp.Status.NetworkID)
|
||||||
|
err = r.netbird.Networks.Delete(ctx, *nbrp.Status.NetworkID)
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||||
|
logger.Error(errNetBirdAPI, "error deleting Network", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrp.Status.NetworkID = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbGroup.Spec.Name != "" && util.Contains(nbGroup.Finalizers, "netbird.io/routing-peer-cleanup") {
|
||||||
|
nbGroup.Finalizers = util.Without(nbGroup.Finalizers, "netbird.io/routing-peer-cleanup")
|
||||||
|
logger.Info("Removing netbird.io/routing-peer-cleanup finalizer NBGroup", "namespace", nbGroup.Namespace, "name", nbGroup.Name)
|
||||||
|
err = r.Client.Update(ctx, &nbGroup)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error deleting NBGroup", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nbrp.Status.NetworkID != nil {
|
||||||
|
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nbrp.Finalizers) > 0 {
|
||||||
|
logger.Info("Removing finalizers", "namespace", nbrp.Namespace, "name", nbrp.Name)
|
||||||
|
nbrp.Finalizers = nil
|
||||||
|
err = r.Client.Update(ctx, nbrp)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBRoutingPeer finalizers", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *NBRoutingPeerReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
r.netbird = netbird.New(r.ManagementURL, r.APIKey)
|
||||||
|
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&netbirdiov1.NBRoutingPeer{}).
|
||||||
|
Named("nbroutingpeer").
|
||||||
|
Watches(&appsv1.Deployment{}, handler.EnqueueRequestForOwner(r.Scheme, mgr.GetRESTMapper(), &netbirdiov1.NBRoutingPeer{})).
|
||||||
|
Watches(&corev1.Secret{}, handler.EnqueueRequestForOwner(r.Scheme, mgr.GetRESTMapper(), &netbirdiov1.NBRoutingPeer{})).
|
||||||
|
Watches(&netbirdiov1.NBGroup{}, handler.EnqueueRequestForOwner(r.Scheme, mgr.GetRESTMapper(), &netbirdiov1.NBRoutingPeer{})).
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBRoutingPeer Controller", func() {
|
||||||
|
Context("When reconciling a resource", func() {
|
||||||
|
const resourceName = "test-resource"
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
typeNamespacedName := types.NamespacedName{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default", // TODO(user):Modify as needed
|
||||||
|
}
|
||||||
|
nbroutingpeer := &netbirdiov1.NBRoutingPeer{}
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("creating the custom resource for the Kind NBRoutingPeer")
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, nbroutingpeer)
|
||||||
|
if err != nil && errors.IsNotFound(err) {
|
||||||
|
resource := &netbirdiov1.NBRoutingPeer{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: resourceName,
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
// TODO(user): Specify other spec details if needed.
|
||||||
|
}
|
||||||
|
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO(user): Cleanup logic after each test, like removing the resource instance.
|
||||||
|
resource := &netbirdiov1.NBRoutingPeer{}
|
||||||
|
err := k8sClient.Get(ctx, typeNamespacedName, resource)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
By("Cleanup the specific resource instance NBRoutingPeer")
|
||||||
|
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
|
||||||
|
})
|
||||||
|
It("should successfully reconcile the resource", func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
By("Reconciling the created resource")
|
||||||
|
controllerReconciler := &NBRoutingPeerReconciler{
|
||||||
|
Client: k8sClient,
|
||||||
|
Scheme: k8sClient.Scheme(),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||||
|
NamespacedName: typeNamespacedName,
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
|
||||||
|
// Example: If you expect a certain status condition after reconciliation, verify it here.
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -29,7 +29,6 @@ import (
|
|||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
@@ -45,21 +44,22 @@ type NBSetupKeyReconciler struct {
|
|||||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
// move the current state of the cluster closer to the desired state.
|
// move the current state of the cluster closer to the desired state.
|
||||||
func (r *NBSetupKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (r *NBSetupKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
_ = log.FromContext(ctx)
|
logger := ctrl.Log.WithName("NBSetupKey").WithValues("namespace", req.Namespace, "name", req.Name)
|
||||||
|
logger.Info("Reconciling NBSetupKey")
|
||||||
|
|
||||||
nbSetupKey := netbirdiov1.NBSetupKey{}
|
nbSetupKey := netbirdiov1.NBSetupKey{}
|
||||||
err := r.Get(ctx, req.NamespacedName, &nbSetupKey)
|
err := r.Get(ctx, req.NamespacedName, &nbSetupKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.Log.Error(fmt.Errorf("internalError"), "error getting NBSetupKey", "err", err, "namespace", req.Namespace, "name", req.Name)
|
logger.Error(fmt.Errorf("internalError"), "error getting NBSetupKey", "err", err)
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if nbSetupKey.Spec.SecretKeyRef.Name == "" || nbSetupKey.Spec.SecretKeyRef.Key == "" {
|
if nbSetupKey.Spec.SecretKeyRef.Name == "" || nbSetupKey.Spec.SecretKeyRef.Key == "" {
|
||||||
ctrl.Log.Error(fmt.Errorf("invalid NBSetupKey"), "secretKeyRef must contain both secret name and secret key", "namespace", req.Namespace, "name", req.Name)
|
logger.Error(fmt.Errorf("invalid NBSetupKey"), "secretKeyRef must contain both secret name and secret key")
|
||||||
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{
|
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{
|
||||||
Conditions: []netbirdiov1.NBSetupKeyCondition{
|
Conditions: []netbirdiov1.NBCondition{
|
||||||
{
|
{
|
||||||
Type: netbirdiov1.Ready,
|
Type: netbirdiov1.NBSetupKeyReady,
|
||||||
Status: corev1.ConditionFalse,
|
Status: corev1.ConditionFalse,
|
||||||
LastProbeTime: v1.Now(),
|
LastProbeTime: v1.Now(),
|
||||||
Reason: "InvalidConfig",
|
Reason: "InvalidConfig",
|
||||||
@@ -82,12 +82,12 @@ func (r *NBSetupKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
|
|||||||
err = r.Get(ctx, types.NamespacedName{Namespace: nbSetupKey.Namespace, Name: nbSetupKey.Spec.SecretKeyRef.Name}, &secret)
|
err = r.Get(ctx, types.NamespacedName{Namespace: nbSetupKey.Namespace, Name: nbSetupKey.Spec.SecretKeyRef.Name}, &secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
ctrl.Log.Error(fmt.Errorf("internalError"), "error getting secret", "err", err, "namespace", req.Namespace, "name", req.Name)
|
logger.Error(fmt.Errorf("internalError"), "error getting secret", "err", err)
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
ctrl.Log.Error(fmt.Errorf("invalid NBSetupKey"), "secret referenced not found", "err", err, "namespace", req.Namespace, "name", req.Name)
|
logger.Error(fmt.Errorf("invalid NBSetupKey"), "secret referenced not found", "err", err)
|
||||||
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBSetupKeyCondition{{
|
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBCondition{{
|
||||||
Type: netbirdiov1.Ready,
|
Type: netbirdiov1.NBSetupKeyReady,
|
||||||
Status: corev1.ConditionFalse,
|
Status: corev1.ConditionFalse,
|
||||||
LastProbeTime: v1.Now(),
|
LastProbeTime: v1.Now(),
|
||||||
Reason: "SecretNotExists",
|
Reason: "SecretNotExists",
|
||||||
@@ -97,9 +97,9 @@ func (r *NBSetupKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
|
|||||||
|
|
||||||
uuidBytes, ok := secret.Data[nbSetupKey.Spec.SecretKeyRef.Key]
|
uuidBytes, ok := secret.Data[nbSetupKey.Spec.SecretKeyRef.Key]
|
||||||
if !ok {
|
if !ok {
|
||||||
ctrl.Log.Error(fmt.Errorf("invalid NBSetupKey"), "secret key referenced not found", "namespace", req.Namespace, "name", req.Name)
|
logger.Error(fmt.Errorf("invalid NBSetupKey"), "secret key referenced not found")
|
||||||
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBSetupKeyCondition{{
|
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBCondition{{
|
||||||
Type: netbirdiov1.Ready,
|
Type: netbirdiov1.NBSetupKeyReady,
|
||||||
Status: corev1.ConditionFalse,
|
Status: corev1.ConditionFalse,
|
||||||
LastProbeTime: v1.Now(),
|
LastProbeTime: v1.Now(),
|
||||||
Reason: "SecretKeyNotExists",
|
Reason: "SecretKeyNotExists",
|
||||||
@@ -109,17 +109,17 @@ func (r *NBSetupKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request)
|
|||||||
|
|
||||||
_, err = uuid.Parse(string(uuidBytes))
|
_, err = uuid.Parse(string(uuidBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.Log.Error(fmt.Errorf("invalid NBSetupKey"), "setupKey is not a valid UUID", "err", err, "namespace", req.Namespace, "name", req.Name)
|
logger.Error(fmt.Errorf("invalid NBSetupKey"), "setupKey is not a valid UUID", "err", err)
|
||||||
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBSetupKeyCondition{{
|
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBCondition{{
|
||||||
Type: netbirdiov1.Ready,
|
Type: netbirdiov1.NBSetupKeyReady,
|
||||||
Status: corev1.ConditionFalse,
|
Status: corev1.ConditionFalse,
|
||||||
LastProbeTime: v1.Now(),
|
LastProbeTime: v1.Now(),
|
||||||
Reason: "InvalidSetupKey",
|
Reason: "InvalidSetupKey",
|
||||||
Message: "Referenced secret is not a valid SetupKey",
|
Message: "Referenced secret is not a valid SetupKey",
|
||||||
}}})
|
}}})
|
||||||
}
|
}
|
||||||
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBSetupKeyCondition{{
|
return ctrl.Result{}, r.setStatus(ctx, &nbSetupKey, netbirdiov1.NBSetupKeyStatus{Conditions: []netbirdiov1.NBCondition{{
|
||||||
Type: netbirdiov1.Ready,
|
Type: netbirdiov1.NBSetupKeyReady,
|
||||||
Status: corev1.ConditionTrue,
|
Status: corev1.ConditionTrue,
|
||||||
LastProbeTime: v1.Now(),
|
LastProbeTime: v1.Now(),
|
||||||
}}})
|
}}})
|
||||||
@@ -151,6 +151,6 @@ func (r *NBSetupKeyReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}),
|
}),
|
||||||
). // Trigger reconciliation when the labeled Busybox resource changes
|
). // Trigger reconciliation when a referenced secret changes
|
||||||
Complete(r)
|
Complete(r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,259 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
"github.com/netbirdio/kubernetes-operator/internal/util"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceReconciler reconciles a Service object
|
||||||
|
type ServiceReconciler struct {
|
||||||
|
client.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
ClusterName string
|
||||||
|
ClusterDNS string
|
||||||
|
NamespacedNetworks bool
|
||||||
|
ControllerNamespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ServiceExposeAnnotation Service annotation for exposing
|
||||||
|
ServiceExposeAnnotation = "netbird.io/expose"
|
||||||
|
serviceGroupsAnnotation = "netbird.io/groups"
|
||||||
|
serviceResourceAnnotation = "netbird.io/resource-name"
|
||||||
|
servicePolicyAnnotation = "netbird.io/policy"
|
||||||
|
servicePortsAnnotation = "netbird.io/policy-ports"
|
||||||
|
serviceProtocolAnnotation = "netbird.io/policy-protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
networkDescription = "Created by kubernetes-operator"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
|
// move the current state of the cluster closer to the desired state.
|
||||||
|
func (r *ServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
|
logger := ctrl.Log.WithName("Service").WithValues("namespace", req.Namespace, "name", req.Name)
|
||||||
|
logger.Info("Reconciling Service")
|
||||||
|
|
||||||
|
svc := corev1.Service{}
|
||||||
|
err := r.Get(ctx, req.NamespacedName, &svc)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting Service", "err", err)
|
||||||
|
}
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, shouldExpose := svc.Annotations[ServiceExposeAnnotation]
|
||||||
|
|
||||||
|
// If Service is being deleted, un-expose
|
||||||
|
shouldExpose = shouldExpose && svc.DeletionTimestamp == nil
|
||||||
|
|
||||||
|
if shouldExpose {
|
||||||
|
return r.exposeService(ctx, req, svc, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.hideService(ctx, req, svc, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hideService deletes NBResource for Service
|
||||||
|
func (r *ServiceReconciler) hideService(ctx context.Context, req ctrl.Request, svc corev1.Service, logger logr.Logger) (ctrl.Result, error) {
|
||||||
|
var nbResource netbirdiov1.NBResource
|
||||||
|
err := r.Client.Get(ctx, req.NamespacedName, &nbResource)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
err = r.Client.Delete(ctx, &nbResource)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error deleting NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if util.Contains(svc.Finalizers, "netbird.io/cleanup") {
|
||||||
|
svc.Finalizers = util.Without(svc.Finalizers, "netbird.io/cleanup")
|
||||||
|
err := r.Client.Update(ctx, &svc)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating Service", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// exposeService creates/updates NBResource for Service
|
||||||
|
func (r *ServiceReconciler) exposeService(ctx context.Context, req ctrl.Request, svc corev1.Service, logger logr.Logger) (ctrl.Result, error) {
|
||||||
|
routerNamespace := r.ControllerNamespace
|
||||||
|
if r.NamespacedNetworks {
|
||||||
|
routerNamespace = req.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
if !util.Contains(svc.Finalizers, "netbird.io/cleanup") {
|
||||||
|
svc.Finalizers = append(svc.Finalizers, "netbird.io/cleanup")
|
||||||
|
err := r.Client.Update(ctx, &svc)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating Service", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var routingPeer netbirdiov1.NBRoutingPeer
|
||||||
|
// Check if NBRoutingPeer exists
|
||||||
|
err := r.Client.Get(ctx, types.NamespacedName{Namespace: routerNamespace, Name: "router"}, &routingPeer)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBRoutingPeer", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create NBRoutingPeer with default values if not exists
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
routingPeer = netbirdiov1.NBRoutingPeer{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: "router",
|
||||||
|
Namespace: routerNamespace,
|
||||||
|
Finalizers: []string{"netbird.io/cleanup"},
|
||||||
|
},
|
||||||
|
Spec: netbirdiov1.NBRoutingPeerSpec{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.Client.Create(ctx, &routingPeer)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error creating NBRoutingPeer", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Network not available")
|
||||||
|
// Requeue to make sure network is created
|
||||||
|
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if routingPeer.Status.NetworkID == nil {
|
||||||
|
logger.Info("Network not available")
|
||||||
|
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var nbResource netbirdiov1.NBResource
|
||||||
|
err = r.Client.Get(ctx, req.NamespacedName, &nbResource)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
logger.Error(errKubernetesAPI, "error getting NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nbrsErr := r.reconcileNBResource(&nbResource, req, svc, routingPeer)
|
||||||
|
if nbrsErr != nil {
|
||||||
|
return ctrl.Result{}, nbrsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
err = r.Client.Create(ctx, &nbResource)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error creating NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = r.Client.Update(ctx, &nbResource)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(errKubernetesAPI, "error updating NBResource", "err", err)
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconcileNBResource ensures NBResource settings are in-line with Service definition and annotations
|
||||||
|
func (r *ServiceReconciler) reconcileNBResource(nbResource *netbirdiov1.NBResource, req ctrl.Request, svc corev1.Service, routingPeer netbirdiov1.NBRoutingPeer) error {
|
||||||
|
groups := []string{fmt.Sprintf("%s-%s-%s", r.ClusterName, req.Namespace, req.Name)}
|
||||||
|
if v, ok := svc.Annotations[serviceGroupsAnnotation]; ok {
|
||||||
|
groups = nil
|
||||||
|
for _, g := range strings.Split(v, ",") {
|
||||||
|
groups = append(groups, strings.TrimSpace(g))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceName := fmt.Sprintf("%s-%s", req.Namespace, req.Name)
|
||||||
|
if v, ok := svc.Annotations[serviceResourceAnnotation]; ok {
|
||||||
|
resourceName = v
|
||||||
|
}
|
||||||
|
|
||||||
|
nbResource.ObjectMeta.Name = req.Name
|
||||||
|
nbResource.ObjectMeta.Namespace = req.Namespace
|
||||||
|
nbResource.Finalizers = []string{"netbird.io/cleanup"}
|
||||||
|
nbResource.Spec.Name = resourceName
|
||||||
|
nbResource.Spec.NetworkID = *routingPeer.Status.NetworkID
|
||||||
|
nbResource.Spec.Address = fmt.Sprintf("%s.%s.%s", svc.Name, svc.Namespace, r.ClusterDNS)
|
||||||
|
nbResource.Spec.Groups = groups
|
||||||
|
|
||||||
|
if v, ok := svc.Annotations[servicePolicyAnnotation]; ok {
|
||||||
|
nbResource.Spec.PolicyName = v
|
||||||
|
var filterProtocols []string
|
||||||
|
if v, ok := svc.Annotations[serviceProtocolAnnotation]; ok {
|
||||||
|
filterProtocols = []string{v}
|
||||||
|
}
|
||||||
|
var filterPorts []int32
|
||||||
|
if v, ok := svc.Annotations[servicePortsAnnotation]; ok {
|
||||||
|
for _, v := range strings.Split(v, ",") {
|
||||||
|
port, err := strconv.ParseInt(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filterPorts = append(filterPorts, int32(port))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range svc.Spec.Ports {
|
||||||
|
if len(filterProtocols) > 0 && !util.Contains(filterProtocols, string(p.Protocol)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(filterPorts) > 0 && !util.Contains(filterPorts, p.Port) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch p.Protocol {
|
||||||
|
case corev1.ProtocolSCTP:
|
||||||
|
if !util.Contains(nbResource.Spec.TCPPorts, p.Port) {
|
||||||
|
nbResource.Spec.TCPPorts = append(nbResource.Spec.TCPPorts, p.Port)
|
||||||
|
}
|
||||||
|
case corev1.ProtocolTCP:
|
||||||
|
if !util.Contains(nbResource.Spec.TCPPorts, p.Port) {
|
||||||
|
nbResource.Spec.TCPPorts = append(nbResource.Spec.TCPPorts, p.Port)
|
||||||
|
}
|
||||||
|
case corev1.ProtocolUDP:
|
||||||
|
if !util.Contains(nbResource.Spec.UDPPorts, p.Port) {
|
||||||
|
nbResource.Spec.UDPPorts = append(nbResource.Spec.UDPPorts, p.Port)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return errUnknownProtocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Handle removed policy name
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
|
func (r *ServiceReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
For(&corev1.Service{}).
|
||||||
|
Named("service").
|
||||||
|
Complete(r)
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Service Controller", func() {
|
||||||
|
Context("When reconciling a resource", func() {
|
||||||
|
|
||||||
|
It("should successfully reconcile the resource", func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
|
||||||
|
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
|
||||||
|
// Example: If you expect a certain status condition after reconciliation, verify it here.
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -32,6 +32,8 @@ import (
|
|||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
|
||||||
|
foobarv1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
// +kubebuilder:scaffold:imports
|
// +kubebuilder:scaffold:imports
|
||||||
)
|
)
|
||||||
@@ -62,6 +64,9 @@ var _ = BeforeSuite(func() {
|
|||||||
err = netbirdiov1.AddToScheme(scheme.Scheme)
|
err = netbirdiov1.AddToScheme(scheme.Scheme)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
err = foobarv1.AddToScheme(scheme.Scheme)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// +kubebuilder:scaffold:scheme
|
// +kubebuilder:scaffold:scheme
|
||||||
|
|
||||||
By("bootstrapping test environment")
|
By("bootstrapping test environment")
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
// Ptr return pointer to any value for API purposes
|
||||||
|
func Ptr[T any, PT *T](x T) PT {
|
||||||
|
return &x
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
// Contains return if y is in slice x
|
||||||
|
func Contains[T comparable](x []T, y T) bool {
|
||||||
|
for _, v := range x {
|
||||||
|
if v == y {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Without return all of x in same order without y
|
||||||
|
func Without[T comparable](x []T, y T) []T {
|
||||||
|
var ret []T
|
||||||
|
for _, v := range x {
|
||||||
|
if v != y {
|
||||||
|
ret = append(ret, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equivalent return true if x and y are equal when sorted
|
||||||
|
func Equivalent[T comparable](x, y []T) bool {
|
||||||
|
if len(x) != len(y) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
mp := make(map[T]interface{})
|
||||||
|
for _, v := range x {
|
||||||
|
mp[v] = nil
|
||||||
|
}
|
||||||
|
for _, v := range y {
|
||||||
|
if _, ok := mp[v]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nolint:unused
|
||||||
|
// log is for logging in this package.
|
||||||
|
var nbgrouplog = logf.Log.WithName("nbgroup-resource")
|
||||||
|
|
||||||
|
// SetupNBGroupWebhookWithManager registers the webhook for NBGroup in the manager.
|
||||||
|
func SetupNBGroupWebhookWithManager(mgr ctrl.Manager, managementURL, apiKey string) error {
|
||||||
|
return ctrl.NewWebhookManagedBy(mgr).For(&netbirdiov1.NBGroup{}).
|
||||||
|
WithValidator(&NBGroupCustomValidator{netbird: netbird.New(managementURL, apiKey), client: mgr.GetClient()}).
|
||||||
|
Complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBGroupCustomValidator struct is responsible for validating the NBGroup resource
|
||||||
|
// when it is created, updated, or deleted.
|
||||||
|
type NBGroupCustomValidator struct {
|
||||||
|
netbird *netbird.Client
|
||||||
|
client client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ webhook.CustomValidator = &NBGroupCustomValidator{}
|
||||||
|
|
||||||
|
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type NBGroup.
|
||||||
|
func (v *NBGroupCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type NBGroup.
|
||||||
|
func (v *NBGroupCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type NBGroup.
|
||||||
|
func (v *NBGroupCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||||
|
nbgroup, ok := obj.(*netbirdiov1.NBGroup)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expected a NBGroup object but got %T", obj)
|
||||||
|
}
|
||||||
|
nbgrouplog.Info("Validation for NBGroup upon deletion", "name", nbgroup.GetName())
|
||||||
|
|
||||||
|
for _, o := range nbgroup.OwnerReferences {
|
||||||
|
if o.Kind == (&netbirdiov1.NBResource{}).Kind {
|
||||||
|
var nbResource netbirdiov1.NBResource
|
||||||
|
err := v.client.Get(ctx, types.NamespacedName{Namespace: nbgroup.Namespace, Name: o.Name}, &nbResource)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil && nbResource.DeletionTimestamp == nil {
|
||||||
|
return nil, fmt.Errorf("group attached to NBResource %s/%s", nbgroup.Namespace, o.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if o.Kind == (&netbirdiov1.NBRoutingPeer{}).Kind {
|
||||||
|
var nbResource netbirdiov1.NBRoutingPeer
|
||||||
|
err := v.client.Get(ctx, types.NamespacedName{Namespace: nbgroup.Namespace, Name: o.Name}, &nbResource)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err == nil && nbResource.DeletionTimestamp == nil {
|
||||||
|
return nil, fmt.Errorf("group attached to NBRoutingPeer %s/%s", nbgroup.Namespace, o.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
// TODO (user): Add any additional imports if needed
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBGroup Webhook", func() {
|
||||||
|
var (
|
||||||
|
obj *netbirdiov1.NBGroup
|
||||||
|
oldObj *netbirdiov1.NBGroup
|
||||||
|
validator NBGroupCustomValidator
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
obj = &netbirdiov1.NBGroup{}
|
||||||
|
oldObj = &netbirdiov1.NBGroup{}
|
||||||
|
validator = NBGroupCustomValidator{}
|
||||||
|
Expect(validator).NotTo(BeNil(), "Expected validator to be initialized")
|
||||||
|
Expect(oldObj).NotTo(BeNil(), "Expected oldObj to be initialized")
|
||||||
|
Expect(obj).NotTo(BeNil(), "Expected obj to be initialized")
|
||||||
|
// TODO (user): Add any setup logic common to all tests
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO (user): Add any teardown logic common to all tests
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("When creating or updating NBGroup under Validating Webhook", func() {
|
||||||
|
// TODO (user): Add logic for validating webhooks
|
||||||
|
// Example:
|
||||||
|
// It("Should deny creation if a required field is missing", func() {
|
||||||
|
// By("simulating an invalid creation scenario")
|
||||||
|
// obj.SomeRequiredField = ""
|
||||||
|
// Expect(validator.ValidateCreate(ctx, obj)).Error().To(HaveOccurred())
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It("Should admit creation if all required fields are present", func() {
|
||||||
|
// By("simulating an invalid creation scenario")
|
||||||
|
// obj.SomeRequiredField = "valid_value"
|
||||||
|
// Expect(validator.ValidateCreate(ctx, obj)).To(BeNil())
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It("Should validate updates correctly", func() {
|
||||||
|
// By("simulating a valid update scenario")
|
||||||
|
// oldObj.SomeRequiredField = "updated_value"
|
||||||
|
// obj.SomeRequiredField = "updated_value"
|
||||||
|
// Expect(validator.ValidateUpdate(ctx, oldObj, obj)).To(BeNil())
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
"github.com/netbirdio/kubernetes-operator/internal/controller"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nolint:unused
|
||||||
|
// log is for logging in this package.
|
||||||
|
var nbresourcelog = logf.Log.WithName("nbresource-resource")
|
||||||
|
|
||||||
|
// SetupNBResourceWebhookWithManager registers the webhook for NBResource in the manager.
|
||||||
|
func SetupNBResourceWebhookWithManager(mgr ctrl.Manager, managementURL, apiKey string) error {
|
||||||
|
return ctrl.NewWebhookManagedBy(mgr).For(&netbirdiov1.NBResource{}).
|
||||||
|
WithValidator(&NBResourceCustomValidator{netbird: netbird.New(managementURL, apiKey), client: mgr.GetClient()}).
|
||||||
|
Complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBResourceCustomValidator struct is responsible for validating the NBResource resource
|
||||||
|
// when it is created, updated, or deleted.
|
||||||
|
type NBResourceCustomValidator struct {
|
||||||
|
netbird *netbird.Client
|
||||||
|
client client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ webhook.CustomValidator = &NBResourceCustomValidator{}
|
||||||
|
|
||||||
|
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type NBResource.
|
||||||
|
func (v *NBResourceCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type NBResource.
|
||||||
|
func (v *NBResourceCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type NBResource.
|
||||||
|
func (v *NBResourceCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||||
|
nbresource, ok := obj.(*netbirdiov1.NBResource)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expected a NBResource object but got %T", obj)
|
||||||
|
}
|
||||||
|
nbresourcelog.Info("Validation for NBResource upon deletion", "name", nbresource.GetName())
|
||||||
|
|
||||||
|
var svc corev1.Service
|
||||||
|
err := v.client.Get(ctx, types.NamespacedName{Namespace: nbresource.Namespace, Name: nbresource.Name}, &svc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := svc.Annotations[controller.ServiceExposeAnnotation]; ok && svc.DeletionTimestamp == nil {
|
||||||
|
return nil, fmt.Errorf("service %s/%s still has netbird.io/expose annotation", svc.Namespace, svc.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
// TODO (user): Add any additional imports if needed
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBResource Webhook", func() {
|
||||||
|
var (
|
||||||
|
obj *netbirdiov1.NBResource
|
||||||
|
oldObj *netbirdiov1.NBResource
|
||||||
|
validator NBResourceCustomValidator
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
obj = &netbirdiov1.NBResource{}
|
||||||
|
oldObj = &netbirdiov1.NBResource{}
|
||||||
|
validator = NBResourceCustomValidator{}
|
||||||
|
Expect(validator).NotTo(BeNil(), "Expected validator to be initialized")
|
||||||
|
Expect(oldObj).NotTo(BeNil(), "Expected oldObj to be initialized")
|
||||||
|
Expect(obj).NotTo(BeNil(), "Expected obj to be initialized")
|
||||||
|
// TODO (user): Add any setup logic common to all tests
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO (user): Add any teardown logic common to all tests
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("When creating or updating NBResource under Validating Webhook", func() {
|
||||||
|
// TODO (user): Add logic for validating webhooks
|
||||||
|
// Example:
|
||||||
|
// It("Should deny creation if a required field is missing", func() {
|
||||||
|
// By("simulating an invalid creation scenario")
|
||||||
|
// obj.SomeRequiredField = ""
|
||||||
|
// Expect(validator.ValidateCreate(ctx, obj)).Error().To(HaveOccurred())
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It("Should admit creation if all required fields are present", func() {
|
||||||
|
// By("simulating an invalid creation scenario")
|
||||||
|
// obj.SomeRequiredField = "valid_value"
|
||||||
|
// Expect(validator.ValidateCreate(ctx, obj)).To(BeNil())
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It("Should validate updates correctly", func() {
|
||||||
|
// By("simulating a valid update scenario")
|
||||||
|
// oldObj.SomeRequiredField = "updated_value"
|
||||||
|
// obj.SomeRequiredField = "updated_value"
|
||||||
|
// Expect(validator.ValidateUpdate(ctx, oldObj, obj)).To(BeNil())
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
netbird "github.com/netbirdio/netbird/management/client/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nolint:unused
|
||||||
|
// log is for logging in this package.
|
||||||
|
var nbroutingpeerlog = logf.Log.WithName("nbroutingpeer-resource")
|
||||||
|
|
||||||
|
// SetupNBRoutingPeerWebhookWithManager registers the webhook for NBRoutingPeer in the manager.
|
||||||
|
func SetupNBRoutingPeerWebhookWithManager(mgr ctrl.Manager, managementURL, apiKey string) error {
|
||||||
|
return ctrl.NewWebhookManagedBy(mgr).For(&netbirdiov1.NBRoutingPeer{}).
|
||||||
|
WithValidator(&NBRoutingPeerCustomValidator{netbird: netbird.New(managementURL, apiKey), client: mgr.GetClient()}).
|
||||||
|
Complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NBRoutingPeerCustomValidator struct is responsible for validating the NBRoutingPeer resource
|
||||||
|
// when it is created, updated, or deleted.
|
||||||
|
type NBRoutingPeerCustomValidator struct {
|
||||||
|
netbird *netbird.Client
|
||||||
|
client client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ webhook.CustomValidator = &NBRoutingPeerCustomValidator{}
|
||||||
|
|
||||||
|
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type NBRoutingPeer.
|
||||||
|
func (v *NBRoutingPeerCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type NBRoutingPeer.
|
||||||
|
func (v *NBRoutingPeerCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type NBRoutingPeer.
|
||||||
|
func (v *NBRoutingPeerCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||||
|
nbroutingpeer, ok := obj.(*netbirdiov1.NBRoutingPeer)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expected a NBRoutingPeer object but got %T", obj)
|
||||||
|
}
|
||||||
|
nbroutingpeerlog.Info("Validation for NBRoutingPeer upon deletion", "name", nbroutingpeer.GetName())
|
||||||
|
|
||||||
|
if nbroutingpeer.Status.NetworkID == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var nbResources netbirdiov1.NBResourceList
|
||||||
|
err := v.client.List(ctx, &nbResources)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range nbResources.Items {
|
||||||
|
if r.Spec.NetworkID == *nbroutingpeer.Status.NetworkID {
|
||||||
|
err = v.client.Delete(ctx, &r, client.DryRunAll)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s/%s: %w", r.Namespace, r.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
netbirdiov1 "github.com/netbirdio/kubernetes-operator/api/v1"
|
||||||
|
// TODO (user): Add any additional imports if needed
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("NBRoutingPeer Webhook", func() {
|
||||||
|
var (
|
||||||
|
obj *netbirdiov1.NBRoutingPeer
|
||||||
|
oldObj *netbirdiov1.NBRoutingPeer
|
||||||
|
validator NBRoutingPeerCustomValidator
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
Skip("Not implemented yet")
|
||||||
|
obj = &netbirdiov1.NBRoutingPeer{}
|
||||||
|
oldObj = &netbirdiov1.NBRoutingPeer{}
|
||||||
|
validator = NBRoutingPeerCustomValidator{}
|
||||||
|
Expect(validator).NotTo(BeNil(), "Expected validator to be initialized")
|
||||||
|
Expect(oldObj).NotTo(BeNil(), "Expected oldObj to be initialized")
|
||||||
|
Expect(obj).NotTo(BeNil(), "Expected obj to be initialized")
|
||||||
|
// TODO (user): Add any setup logic common to all tests
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
// TODO (user): Add any teardown logic common to all tests
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("When creating or updating NBRoutingPeer under Validating Webhook", func() {
|
||||||
|
// TODO (user): Add logic for validating webhooks
|
||||||
|
// Example:
|
||||||
|
// It("Should deny creation if a required field is missing", func() {
|
||||||
|
// By("simulating an invalid creation scenario")
|
||||||
|
// obj.SomeRequiredField = ""
|
||||||
|
// Expect(validator.ValidateCreate(ctx, obj)).Error().To(HaveOccurred())
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It("Should admit creation if all required fields are present", func() {
|
||||||
|
// By("simulating an invalid creation scenario")
|
||||||
|
// obj.SomeRequiredField = "valid_value"
|
||||||
|
// Expect(validator.ValidateCreate(ctx, obj)).To(BeNil())
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It("Should validate updates correctly", func() {
|
||||||
|
// By("simulating a valid update scenario")
|
||||||
|
// oldObj.SomeRequiredField = "updated_value"
|
||||||
|
// obj.SomeRequiredField = "updated_value"
|
||||||
|
// Expect(validator.ValidateUpdate(ctx, oldObj, obj)).To(BeNil())
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
@@ -83,7 +83,7 @@ func (d *PodNetbirdInjector) Default(ctx context.Context, obj runtime.Object) er
|
|||||||
// ensure the NBSetupKey is ready.
|
// ensure the NBSetupKey is ready.
|
||||||
ready := false
|
ready := false
|
||||||
for _, c := range nbSetupKey.Status.Conditions {
|
for _, c := range nbSetupKey.Status.Conditions {
|
||||||
if c.Type == netbirdiov1.Ready {
|
if c.Type == netbirdiov1.NBSetupKeyReady {
|
||||||
ready = c.Status == corev1.ConditionTrue
|
ready = c.Status == corev1.ConditionTrue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ var _ = Describe("Pod Webhook", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
sk.Status = netbirdiov1.NBSetupKeyStatus{
|
sk.Status = netbirdiov1.NBSetupKeyStatus{
|
||||||
Conditions: []netbirdiov1.NBSetupKeyCondition{
|
Conditions: []netbirdiov1.NBCondition{
|
||||||
{
|
{
|
||||||
Type: netbirdiov1.Ready,
|
Type: netbirdiov1.NBSetupKeyReady,
|
||||||
Status: corev1.ConditionTrue,
|
Status: corev1.ConditionTrue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -124,6 +124,15 @@ var _ = BeforeSuite(func() {
|
|||||||
err = SetupNBSetupKeyWebhookWithManager(mgr)
|
err = SetupNBSetupKeyWebhookWithManager(mgr)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
err = SetupNBResourceWebhookWithManager(mgr, "", "")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
err = SetupNBRoutingPeerWebhookWithManager(mgr, "", "")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
err = SetupNBGroupWebhookWithManager(mgr, "", "")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// +kubebuilder:scaffold:webhook
|
// +kubebuilder:scaffold:webhook
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
+683
-26
@@ -1,3 +1,580 @@
|
|||||||
|
---
|
||||||
|
# Source: kubernetes-operator/crds/netbird.io_nbgroups.yaml
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbgroups.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBGroup
|
||||||
|
listKind: NBGroupList
|
||||||
|
plural: nbgroups
|
||||||
|
singular: nbgroup
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBGroup is the Schema for the nbgroups 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: NBGroupSpec defines the desired state of NBGroup.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Value is immutable
|
||||||
|
rule: self == oldSelf
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: NBGroupStatus defines the observed state of NBGroup.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
groupID:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
# Source: kubernetes-operator/crds/netbird.io_nbpolicies.yaml
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbpolicies.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBPolicy
|
||||||
|
listKind: NBPolicyList
|
||||||
|
plural: nbpolicies
|
||||||
|
singular: nbpolicy
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBPolicy is the Schema for the nbpolicies 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: NBPolicySpec defines the desired state of NBPolicy.
|
||||||
|
properties:
|
||||||
|
bidirectional:
|
||||||
|
default: true
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
destinationGroups:
|
||||||
|
items:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
name:
|
||||||
|
description: Name Policy name
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
ports:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
maximum: 65535
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
protocols:
|
||||||
|
items:
|
||||||
|
enum:
|
||||||
|
- tcp
|
||||||
|
- udp
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
sourceGroups:
|
||||||
|
items:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: NBPolicyStatus defines the observed state of NBPolicy.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
lastUpdatedAt:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
managedServiceList:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
tcpPolicyID:
|
||||||
|
type: string
|
||||||
|
udpPolicyID:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
# Source: kubernetes-operator/crds/netbird.io_nbresources.yaml
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbresources.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBResource
|
||||||
|
listKind: NBResourceList
|
||||||
|
plural: nbresources
|
||||||
|
singular: nbresource
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBResource is the Schema for the nbresources 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: NBResourceSpec defines the desired state of NBResource.
|
||||||
|
properties:
|
||||||
|
address:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
groups:
|
||||||
|
items:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
name:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
networkID:
|
||||||
|
type: string
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: Value is immutable
|
||||||
|
rule: self == oldSelf
|
||||||
|
policyName:
|
||||||
|
type: string
|
||||||
|
tcpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
udpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- address
|
||||||
|
- groups
|
||||||
|
- name
|
||||||
|
- networkID
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: NBResourceStatus defines the observed state of NBResource.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
groups:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
networkResourceID:
|
||||||
|
type: string
|
||||||
|
policyName:
|
||||||
|
type: string
|
||||||
|
tcpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
udpPorts:
|
||||||
|
items:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
# Source: kubernetes-operator/crds/netbird.io_nbroutingpeers.yaml
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.17.1
|
||||||
|
name: nbroutingpeers.netbird.io
|
||||||
|
spec:
|
||||||
|
group: netbird.io
|
||||||
|
names:
|
||||||
|
kind: NBRoutingPeer
|
||||||
|
listKind: NBRoutingPeerList
|
||||||
|
plural: nbroutingpeers
|
||||||
|
singular: nbroutingpeer
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: NBRoutingPeer is the Schema for the nbroutingpeers 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: NBRoutingPeerSpec defines the desired state of NBRoutingPeer.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
labels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
nodeSelector:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
replicas:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
resources:
|
||||||
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
|
properties:
|
||||||
|
claims:
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
request:
|
||||||
|
description: |-
|
||||||
|
Request is the name chosen for a request in the referenced claim.
|
||||||
|
If empty, everything from the claim is made available, otherwise
|
||||||
|
only the result of this request.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- name
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
limits:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- 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/
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
additionalProperties:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- 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/
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
tolerations:
|
||||||
|
items:
|
||||||
|
description: |-
|
||||||
|
The pod this Toleration is attached to tolerates any taint that matches
|
||||||
|
the triple <key,value,effect> using the matching operator <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
|
||||||
|
status:
|
||||||
|
description: NBRoutingPeerStatus defines the observed state of NBRoutingPeer.
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
|
properties:
|
||||||
|
lastProbeTime:
|
||||||
|
description: Last time we probed the condition.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: Human-readable message indicating details about
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: Unique, one-word, CamelCase reason for the condition's
|
||||||
|
last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: |-
|
||||||
|
Status is the status of the condition.
|
||||||
|
Can be True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is the type of the condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
networkID:
|
||||||
|
type: string
|
||||||
|
routerID:
|
||||||
|
type: string
|
||||||
|
setupKeyID:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
|
||||||
---
|
---
|
||||||
# Source: kubernetes-operator/crds/netbird.io_nbsetupkeys.yaml
|
# Source: kubernetes-operator/crds/netbird.io_nbsetupkeys.yaml
|
||||||
---
|
---
|
||||||
@@ -77,8 +654,7 @@ spec:
|
|||||||
properties:
|
properties:
|
||||||
conditions:
|
conditions:
|
||||||
items:
|
items:
|
||||||
description: NBSetupKeyCondition defines a condition in NBSetupKey
|
description: NBCondition defines a condition in NBSetupKey status.
|
||||||
status.
|
|
||||||
properties:
|
properties:
|
||||||
lastProbeTime:
|
lastProbeTime:
|
||||||
description: Last time we probed the condition.
|
description: Last time we probed the condition.
|
||||||
@@ -124,7 +700,7 @@ kind: ServiceAccount
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -137,7 +713,7 @@ kind: ClusterRole
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -188,7 +764,7 @@ kind: ClusterRoleBinding
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -200,7 +776,7 @@ roleRef:
|
|||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
namespace: default
|
namespace: production
|
||||||
---
|
---
|
||||||
# Source: kubernetes-operator/templates/rbac.yaml
|
# Source: kubernetes-operator/templates/rbac.yaml
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
@@ -208,7 +784,7 @@ kind: Role
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -252,7 +828,7 @@ kind: RoleBinding
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -264,7 +840,7 @@ roleRef:
|
|||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
namespace: default
|
namespace: production
|
||||||
---
|
---
|
||||||
# Source: kubernetes-operator/templates/service.yaml
|
# Source: kubernetes-operator/templates/service.yaml
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -272,7 +848,7 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator-metrics
|
name: kubernetes-operator-metrics
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -294,7 +870,7 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator-webhook-service
|
name: kubernetes-operator-webhook-service
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -317,7 +893,7 @@ metadata:
|
|||||||
name: kubernetes-operator
|
name: kubernetes-operator
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/component: operator
|
app.kubernetes.io/component: operator
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -332,7 +908,7 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/component: operator
|
app.kubernetes.io/component: operator
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -400,17 +976,17 @@ apiVersion: cert-manager.io/v1
|
|||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator-serving-cert
|
name: kubernetes-operator-serving-cert
|
||||||
namespace: default
|
namespace: production
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
app.kubernetes.io/managed-by: Helm
|
app.kubernetes.io/managed-by: Helm
|
||||||
spec:
|
spec:
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- kubernetes-operator-webhook-service.default.svc
|
- kubernetes-operator-webhook-service.production.svc
|
||||||
- kubernetes-operator-webhook-service.default.svc.cluster.local
|
- kubernetes-operator-webhook-service.production.svc.cluster.local
|
||||||
issuerRef:
|
issuerRef:
|
||||||
kind: Issuer
|
kind: Issuer
|
||||||
name: kubernetes-operator-selfsigned-issuer
|
name: kubernetes-operator-selfsigned-issuer
|
||||||
@@ -421,9 +997,9 @@ apiVersion: cert-manager.io/v1
|
|||||||
kind: Issuer
|
kind: Issuer
|
||||||
metadata:
|
metadata:
|
||||||
name: kubernetes-operator-selfsigned-issuer
|
name: kubernetes-operator-selfsigned-issuer
|
||||||
namespace: default
|
namespace: production
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -436,10 +1012,10 @@ apiVersion: admissionregistration.k8s.io/v1
|
|||||||
kind: MutatingWebhookConfiguration
|
kind: MutatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/inject-ca-from: default/kubernetes-operator-serving-cert
|
cert-manager.io/inject-ca-from: production/kubernetes-operator-serving-cert
|
||||||
name: kubernetes-operator-mpod-webhook
|
name: kubernetes-operator-mpod-webhook
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -448,7 +1024,7 @@ webhooks:
|
|||||||
- clientConfig:
|
- clientConfig:
|
||||||
service:
|
service:
|
||||||
name: kubernetes-operator-webhook-service
|
name: kubernetes-operator-webhook-service
|
||||||
namespace: default
|
namespace: production
|
||||||
path: /mutate--v1-pod
|
path: /mutate--v1-pod
|
||||||
failurePolicy: Fail
|
failurePolicy: Fail
|
||||||
name: mpod-v1.netbird.io
|
name: mpod-v1.netbird.io
|
||||||
@@ -476,10 +1052,10 @@ apiVersion: admissionregistration.k8s.io/v1
|
|||||||
kind: ValidatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/inject-ca-from: default/kubernetes-operator-serving-cert
|
cert-manager.io/inject-ca-from: production/kubernetes-operator-serving-cert
|
||||||
name: kubernetes-operator-vnbsetupkey-webhook
|
name: kubernetes-operator-vnbsetupkey-webhook
|
||||||
labels:
|
labels:
|
||||||
helm.sh/chart: kubernetes-operator-0.1.0
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
app.kubernetes.io/name: kubernetes-operator
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
app.kubernetes.io/instance: kubernetes-operator
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
app.kubernetes.io/version: "v0.1.0"
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
@@ -488,7 +1064,7 @@ webhooks:
|
|||||||
- clientConfig:
|
- clientConfig:
|
||||||
service:
|
service:
|
||||||
name: kubernetes-operator-webhook-service
|
name: kubernetes-operator-webhook-service
|
||||||
namespace: default
|
namespace: production
|
||||||
path: /validate-netbird-io-v1-nbsetupkey
|
path: /validate-netbird-io-v1-nbsetupkey
|
||||||
failurePolicy: Fail
|
failurePolicy: Fail
|
||||||
name: vnbsetupkey-v1.netbird.io
|
name: vnbsetupkey-v1.netbird.io
|
||||||
@@ -503,5 +1079,86 @@ webhooks:
|
|||||||
- CREATE
|
- CREATE
|
||||||
- UPDATE
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- "*/*"
|
- "nbsetupkeys"
|
||||||
sideEffects: None
|
sideEffects: None
|
||||||
|
---
|
||||||
|
# Source: kubernetes-operator/templates/pre-delete.yaml
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: kubernetes-operator-delete-routers
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: pre-delete
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||||
|
spec:
|
||||||
|
backOffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: kubernetes-operator
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pre-delete
|
||||||
|
image: "bitnami/kubectl:latest"
|
||||||
|
args:
|
||||||
|
- delete
|
||||||
|
- --all
|
||||||
|
- -A
|
||||||
|
- --cascade=foreground
|
||||||
|
- --ignore-not-found
|
||||||
|
- NBRoutingPeer
|
||||||
|
serviceAccountName: kubernetes-operator
|
||||||
|
restartPolicy: Never
|
||||||
|
---
|
||||||
|
# Source: kubernetes-operator/templates/pre-delete.yaml
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: kubernetes-operator-delete-policies
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: pre-delete
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||||
|
spec:
|
||||||
|
backOffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: kubernetes-operator
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/component: operator
|
||||||
|
helm.sh/chart: kubernetes-operator-0.1.1
|
||||||
|
app.kubernetes.io/name: kubernetes-operator
|
||||||
|
app.kubernetes.io/instance: kubernetes-operator
|
||||||
|
app.kubernetes.io/version: "v0.1.0"
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pre-delete
|
||||||
|
image: "bitnami/kubectl:latest"
|
||||||
|
args:
|
||||||
|
- delete
|
||||||
|
- --all
|
||||||
|
- --cascade=foreground
|
||||||
|
- --ignore-not-found
|
||||||
|
- NBPolicy
|
||||||
|
serviceAccountName: kubernetes-operator
|
||||||
|
restartPolicy: Never
|
||||||
|
|||||||
Reference in New Issue
Block a user