diff --git a/.gitignore b/.gitignore index ada68ff..6cc05d1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ go.work *.swp *.swo *~ + +# CRDs generated for testing +crds/ \ No newline at end of file diff --git a/Makefile b/Makefile index d0d6368..10b8f2f 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ help: ## Display this help. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) crd paths="./..." output:crd:artifacts:config=helm/kubernetes-operator/crds + $(CONTROLLER_GEN) crd paths="./..." output:crd:artifacts:config=crds .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. @@ -123,32 +123,36 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform - $(CONTAINER_TOOL) buildx rm operator-builder rm Dockerfile.cross -.PHONY: build-installer -build-installer: manifests ## Generate a consolidated YAML with CRDs and deployment. - mkdir -p manifests - $(HELM) template --include-crds kubernetes-operator helm/kubernetes-operator > manifests/install.yaml - ##@ Deployment ifndef ignore-not-found ignore-not-found = false endif -.PHONY: install -install: manifests ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUBECTL) apply -f helm/kubernetes-operator/crds - -.PHONY: uninstall -uninstall: manifests ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUBECTL) delete -f helm/kubernetes-operator/crds - .PHONY: deploy deploy: manifests ## Deploy controller to the K8s cluster specified in ~/.kube/config. - $(HELM) install -n netbird --create-namespace kubernetes-operator --set operator.image.tag=$(word 2,$(subst :, ,${IMG})) helm/kubernetes-operator + $(HELM) install -n netbird --create-namespace kubernetes-operator --set operator.image.tag=$(word 2,$(subst :, ,${IMG})) --repo https://netbirdio.github.io/helms kubernetes-operator + +.PHONY: deploy-e2e +deploy-e2e: manifests ## Deploy controller to the K8s cluster specified in ~/.kube/config. + $(HELM) install -n netbird --create-namespace kubernetes-operator -f ./test/utils/values.yaml --set operator.image.tag=$(word 2,$(subst :, ,${IMG})) --set managementURL=${MGMT_HOST} --repo https://netbirdio.github.io/helms kubernetes-operator .PHONY: undeploy undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(HELM) uninstall -n netbird kubernetes-operator + $(HELM) uninstall -n netbird kubernetes-operator --no-hooks + +.PHONY: undeploy-e2e +undeploy-e2e: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + $(HELM) uninstall -n netbird kubernetes-operator --no-hooks || true + kubectl get NBResource -n default -o "custom-columns=NAME:.metadata.name" --no-headers | xargs -r -n 1 kubectl patch NBResource -n default -p '{"metadata":{"finalizers":null}}' --type=merge + kubectl get NBGroup -n default -o "custom-columns=NAME:.metadata.name" --no-headers | xargs -r -n 1 kubectl patch NBGroup -n default -p '{"metadata":{"finalizers":null}}' --type=merge + kubectl get NBGroup -n netbird -o "custom-columns=NAME:.metadata.name" --no-headers | xargs -r -n 1 kubectl patch NBGroup -n netbird -p '{"metadata":{"finalizers":null}}' --type=merge + kubectl get NBRoutingPeer -n netbird -o "custom-columns=NAME:.metadata.name" --no-headers | xargs -r -n 1 kubectl patch NBRoutingPeer -n netbird -p '{"metadata":{"finalizers":null}}' --type=merge + kubectl get NBPolicy -o "custom-columns=NAME:.metadata.name" --no-headers | xargs -r -n 1 kubectl patch NBPolicy -p '{"metadata":{"finalizers":null}}' --type=merge + kubectl delete NBGroup -A --all + kubectl delete NBResource -A --all + kubectl delete NBRoutingPeer -A --all + kubectl delete NBPolicy --all ##@ Dependencies diff --git a/README.md b/README.md index b8c825e..5441006 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ This operator easily provides NetBird access on Kubernetes clusters, allowing us 1. Add helm repository. ```sh -helm repo add netbirdio https://netbirdio.github.io/kubernetes-operator +helm repo add netbirdio https://netbirdio.github.io/helms ``` 2. (Recommended) Install [cert-manager](https://cert-manager.io/docs/installation/#default-static-install) for k8s API to communicate with the NetBird operator. ```sh @@ -36,7 +36,7 @@ kubectl create namespace netbird kubectl -n netbird create secret generic netbird-mgmt-api-key --from-literal=NB_API_KEY=$(cat ~/nb-pat.secret) ``` 4. (Recommended) Create a [`values.yaml`](examples/ingress/values.yaml) file, check `helm show values netbirdio/kubernetes-operator` for more info. -5. Install using `helm install --create-namespace -f values.yaml -n netbird netbird-operator netbirdio/kubernetes-operator`. +5. Install using `helm install --create-namespace -f values.yaml -n netbird kubernetes-operator netbirdio/kubernetes-operator`. 6. (Recommended) Check pod status using `kubectl get pods -n netbird`. 6. (Optional) Create an [`exposed-nginx.yaml`](examples/ingress/exposed-nginx.yaml) file to create a Nginx service for testing. 7. (Optional) Apply the Nginx service: @@ -45,16 +45,6 @@ kubectl apply -f exposed-nginx.yaml ``` > 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 -kubectl create namespace netbird -kubectl apply -n netbird -f https://raw.githubusercontent.com/netbirdio/kubernetes-operator/refs/heads/main/manifests/install.yaml -``` ### Version We have developed and executed tests against Kubernetes v1.31, but it should work with most recent Kubernetes version. diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 4e0db20..2e1d5ef 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -71,7 +71,7 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "helm", "kubernetes-operator", "crds")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "crds")}, ErrorIfCRDPathMissing: true, } diff --git a/internal/webhook/v1/webhook_suite_test.go b/internal/webhook/v1/webhook_suite_test.go index 85236e9..85433e3 100644 --- a/internal/webhook/v1/webhook_suite_test.go +++ b/internal/webhook/v1/webhook_suite_test.go @@ -82,7 +82,7 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "helm", "kubernetes-operator", "crds")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "crds")}, ErrorIfCRDPathMissing: false, // WebhookInstallOptions: envtest.WebhookInstallOptions{ diff --git a/manifests/install.yaml b/manifests/install.yaml deleted file mode 100644 index c675914..0000000 --- a/manifests/install.yaml +++ /dev/null @@ -1,1164 +0,0 @@ ---- -# 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 using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - type: object - 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 ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: nbsetupkeys.netbird.io -spec: - group: netbird.io - names: - kind: NBSetupKey - listKind: NBSetupKeyList - plural: nbsetupkeys - singular: nbsetupkey - scope: Namespaced - versions: - - name: v1 - schema: - openAPIV3Schema: - description: NBSetupKey is the Schema for the nbsetupkeys 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: NBSetupKeySpec defines the desired state of NBSetupKey. - properties: - managementURL: - description: ManagementURL optional, override operator management - URL - type: string - secretKeyRef: - description: SecretKeyRef is a reference to the secret containing - the setup key - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - required: - - secretKeyRef - type: object - status: - description: NBSetupKeyStatus defines the observed state of NBSetupKey. - 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 - type: object - type: object - served: true - storage: true - subresources: - status: {} - ---- -# Source: kubernetes-operator/templates/serviceaccount.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kubernetes-operator - labels: - 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 -automountServiceAccountToken: true ---- -# Source: kubernetes-operator/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kubernetes-operator - labels: - 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 -rules: -- apiGroups: - - netbird.io - resources: - - nbsetupkeys - verbs: - - get - - list - - watch -- apiGroups: - - netbird.io - resources: - - nbsetupkeys/finalizers - verbs: - - update -- apiGroups: - - netbird.io - resources: - - nbsetupkeys/status - verbs: - - get - - patch - - update -- apiGroups: - - "" - resources: - - pods - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch ---- -# Source: kubernetes-operator/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kubernetes-operator - labels: - 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 -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kubernetes-operator -subjects: -- kind: ServiceAccount - name: kubernetes-operator - namespace: production ---- -# Source: kubernetes-operator/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: kubernetes-operator - labels: - 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 -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -# Source: kubernetes-operator/templates/rbac.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: kubernetes-operator - labels: - 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 -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: kubernetes-operator -subjects: -- kind: ServiceAccount - name: kubernetes-operator - namespace: production ---- -# Source: kubernetes-operator/templates/service.yaml -apiVersion: v1 -kind: Service -metadata: - name: kubernetes-operator-metrics - labels: - 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: - type: ClusterIP - ports: - - name: http - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - app.kubernetes.io/name: kubernetes-operator - app.kubernetes.io/instance: kubernetes-operator ---- -# Source: kubernetes-operator/templates/service.yaml -apiVersion: v1 -kind: Service -metadata: - name: kubernetes-operator-webhook-service - labels: - 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: - type: ClusterIP - ports: - - name: https - port: 443 - protocol: TCP - targetPort: 9443 - selector: - app.kubernetes.io/name: kubernetes-operator - app.kubernetes.io/instance: kubernetes-operator ---- -# Source: kubernetes-operator/templates/deployment.yaml -apiVersion: apps/v1 -kind: Deployment -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: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: kubernetes-operator - app.kubernetes.io/instance: kubernetes-operator - template: - metadata: - 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: - serviceAccountName: kubernetes-operator - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - containers: - - name: kubernetes-operator - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - image: "docker.io/netbirdio/kubernetes-operator:v0.1.0" - imagePullPolicy: IfNotPresent - command: - - /manager - args: - - --metrics-bind-address=:8080 - - --leader-elect - - --health-probe-bind-address=:8081 - - --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs - ports: - - name: webhook-server - containerPort: 443 - protocol: TCP - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthz - port: 8081 - scheme: HTTP - initialDelaySeconds: 15 - periodSeconds: 20 - successThreshold: 1 - timeoutSeconds: 1 - readinessProbe: - failureThreshold: 3 - httpGet: - path: /readyz - port: 8081 - scheme: HTTP - initialDelaySeconds: 5 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - resources: - {} - volumeMounts: - - mountPath: /tmp/k8s-webhook-server/serving-certs - name: webhook-certs - readOnly: true - volumes: - - name: webhook-certs - secret: - defaultMode: 420 - secretName: kubernetes-operator-tls ---- -# Source: kubernetes-operator/templates/webhook.yaml -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: kubernetes-operator-serving-cert - namespace: production - labels: - 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: - dnsNames: - - kubernetes-operator-webhook-service.production.svc - - kubernetes-operator-webhook-service.production.svc.cluster.local - issuerRef: - kind: Issuer - name: kubernetes-operator-selfsigned-issuer - secretName: kubernetes-operator-tls ---- -# Source: kubernetes-operator/templates/webhook.yaml -apiVersion: cert-manager.io/v1 -kind: Issuer -metadata: - name: kubernetes-operator-selfsigned-issuer - namespace: production - labels: - 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: - selfSigned: {} ---- -# Source: kubernetes-operator/templates/webhook.yaml -apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration -metadata: - annotations: - cert-manager.io/inject-ca-from: production/kubernetes-operator-serving-cert - name: kubernetes-operator-mpod-webhook - labels: - 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 -webhooks: -- clientConfig: - service: - name: kubernetes-operator-webhook-service - namespace: production - path: /mutate--v1-pod - failurePolicy: Fail - name: mpod-v1.netbird.io - admissionReviewVersions: - - v1 - objectSelector: - matchExpressions: - - key: app.kubernetes.io/name - operator: NotIn - values: - - kubernetes-operator - rules: - - apiGroups: - - "" - apiVersions: - - v1 - operations: - - CREATE - resources: - - pods - sideEffects: None ---- -# Source: kubernetes-operator/templates/webhook.yaml -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - annotations: - cert-manager.io/inject-ca-from: production/kubernetes-operator-serving-cert - name: kubernetes-operator-vnbsetupkey-webhook - labels: - 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 -webhooks: -- clientConfig: - service: - name: kubernetes-operator-webhook-service - namespace: production - path: /validate-netbird-io-v1-nbsetupkey - failurePolicy: Fail - name: vnbsetupkey-v1.netbird.io - admissionReviewVersions: - - v1 - rules: - - apiGroups: - - netbird.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - "nbsetupkeys" - 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 diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 512f52f..cdd4a7c 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -17,17 +17,22 @@ limitations under the License. package e2e import ( + "context" "fmt" "os" "os/exec" + "path" "testing" + netbird "github.com/netbirdio/netbird/management/client/rest" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/netbirdio/kubernetes-operator/test/utils" ) +const apiToken = "nbp_apTmlmUXHSC4PKmHwtIZNaGr8eqcVI2gMURp" + var ( // Optional Environment Variables: // - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup. @@ -72,6 +77,20 @@ var _ = BeforeSuite(func() { _, _ = fmt.Fprintf(GinkgoWriter, "WARNING: CertManager is already installed. Skipping installation...\n") } } + + By("starting up the test management") + cmd = exec.Command("docker", "compose", "up", "-d") + curDir, err := utils.GetProjectDir() + Expect(err).NotTo(HaveOccurred()) + cmd.Dir = path.Join(curDir, "test", "utils", "management") + out, err := cmd.CombinedOutput() + Expect(err).NotTo(HaveOccurred(), string(out)) + + Eventually(func() error { + client := netbird.New("http://127.0.0.1:8080", apiToken) + _, err = client.Accounts.List(context.Background()) + return err + }).Should(Succeed()) }) var _ = AfterSuite(func() { @@ -80,4 +99,11 @@ var _ = AfterSuite(func() { _, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n") utils.UninstallCertManager() } + + cmd := exec.Command("docker", "compose", "down") + curDir, err := utils.GetProjectDir() + Expect(err).NotTo(HaveOccurred()) + cmd.Dir = path.Join(curDir, "test", "utils", "management") + out, err := cmd.CombinedOutput() + Expect(err).NotTo(HaveOccurred(), string(out)) }) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 9c40486..649876f 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -17,11 +17,15 @@ limitations under the License. package e2e import ( + "context" + "encoding/json" "fmt" "os/exec" "strings" "time" + netbird "github.com/netbirdio/netbird/management/client/rest" + "github.com/netbirdio/netbird/management/server/http/api" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -36,6 +40,7 @@ const metricsServiceName = "kubernetes-operator-metrics" var _ = Describe("Manager", Ordered, func() { var controllerPodName string + var netbirdClient *netbird.Client // Before running the tests, set up the environment by creating the namespace, // enforce the restricted security policy to the namespace, installing CRDs, @@ -52,18 +57,38 @@ var _ = Describe("Manager", Ordered, func() { _, err = utils.Run(cmd) Expect(err).NotTo(HaveOccurred(), "Failed to label namespace with restricted policy") - By("installing CRDs") - cmd = exec.Command("make", "install", fmt.Sprintf("IMG=%s", projectImage)) - _, err = utils.Run(cmd) - Expect(err).NotTo(HaveOccurred(), "Failed to install CRDs") - By("deploying the kubernetes-operator") - cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectImage)) - out, err := utils.Run(cmd) + out, err := utils.Run(exec.Command("kubectl", "get", "node", "-o", "json")) + Expect(err).NotTo(HaveOccurred(), "Failed to get nodes") + nodesGetOutput := make(map[string]any) + err = json.Unmarshal([]byte(out), &nodesGetOutput) + Expect(err).NotTo(HaveOccurred(), "Failed to get nodes") + nodeIPs := (nodesGetOutput["items"].([]any))[0].(map[string]any)["status"].(map[string]any)["addresses"].([]any) + managementIP := "" + for _, v := range nodeIPs { + addrType := v.(map[string]any)["type"] + if addrType == "InternalIP" { + managementIP = v.(map[string]any)["address"].(string) + break + } + } + + Expect(managementIP).NotTo(BeEmpty()) + managementIPParts := strings.Split(managementIP, ".") + managementIP = fmt.Sprintf("http://%s.%s.0.1:8080", managementIPParts[0], managementIPParts[1]) + cmd = exec.Command( + "make", + "deploy-e2e", + fmt.Sprintf("IMG=%s", projectImage), + fmt.Sprintf("MGMT_HOST=%s", managementIP), + ) + out, err = utils.Run(cmd) if err != nil { fmt.Println(out) } Expect(err).NotTo(HaveOccurred(), "Failed to deploy the kubernetes-operator") + + netbirdClient = netbird.New("http://127.0.0.1:8080", apiToken) }) // After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs, @@ -74,11 +99,7 @@ var _ = Describe("Manager", Ordered, func() { _, _ = utils.Run(cmd) By("undeploying the kubernetes-operator") - cmd = exec.Command("make", "undeploy") - _, _ = utils.Run(cmd) - - By("uninstalling CRDs") - cmd = exec.Command("make", "uninstall") + cmd = exec.Command("make", "undeploy-e2e") _, _ = utils.Run(cmd) By("removing manager namespace") @@ -458,6 +479,181 @@ var _ = Describe("Manager", Ordered, func() { }) }) + Context("Ingress", Ordered, func() { + BeforeAll(func() { + _, err := utils.Run(exec.Command("kubectl", "create", "deployment", "--image=nginx", "exposable")) + Expect(err).NotTo(HaveOccurred()) + _, err = utils.Run(exec.Command("kubectl", "expose", "deployment", "--port=80", "exposable")) + Expect(err).NotTo(HaveOccurred()) + }) + + AfterAll(func() { + _, err := utils.Run(exec.Command("kubectl", "delete", "deployment", "--ignore-not-found", "exposable")) + Expect(err).NotTo(HaveOccurred()) + _, err = utils.Run(exec.Command("kubectl", "delete", "service", "--ignore-not-found", "exposable")) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should create Network", func() { + Eventually(func(g Gomega) { + networks, err := netbirdClient.Networks.List(context.Background()) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(networks).To(HaveLen(1)) + }).Should(Succeed()) + }) + + networkID := func() string { + defer GinkgoHelper() + networks, err := netbirdClient.Networks.List(context.Background()) + Expect(err).NotTo(HaveOccurred()) + Expect(networks).To(HaveLen(1)) + return networks[0].Id + } + + It("should create NetworkRouter", func() { + Eventually(func(g Gomega) { + routers, err := netbirdClient.Networks.Routers(networkID()).List(context.Background()) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(routers).To(HaveLen(1)) + }).Should(Succeed()) + }) + + It("should create router deployment", func() { + Eventually(func(g Gomega) { + _, err := utils.Run(exec.Command("kubectl", "get", "deployment", "router", "-n", "netbird")) + Expect(err).NotTo(HaveOccurred()) + }).Should(Succeed()) + }) + + groupsToNames := func(i []api.Group) []string { + ret := make([]string, len(i)) + for j, k := range i { + ret[j] = k.Name + } + return ret + } + + It("should create router group", func() { + Eventually(func(g Gomega) { + groups, err := netbirdClient.Groups.List(context.Background()) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(groups).To(WithTransform(groupsToNames, ContainElement("kubernetes"))) + }).Should(Succeed()) + }) + + It("should not expose service by default", func() { + _, err := utils.Run(exec.Command("kubectl", "get", "NBResource", "exposable")) + Expect(err).To(HaveOccurred()) + }) + + When("Service is annotated with expose", Ordered, func() { + BeforeAll(func() { + _, err := utils.Run(exec.Command("kubectl", "annotate", "service", "exposable", "netbird.io/expose=true")) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should create NBResource", func() { + Eventually(func(g Gomega) { + _, err := utils.Run(exec.Command("kubectl", "get", "NBResource", "exposable")) + g.Expect(err).NotTo(HaveOccurred()) + }).Should(Succeed()) + }) + + It("should create Network Resource", func() { + Eventually(func(g Gomega) { + resources, err := netbirdClient.Networks.Resources(networkID()).List(context.Background()) + Expect(err).NotTo(HaveOccurred()) + resourcesToNames := func(r []api.NetworkResource) []string { + ret := make([]string, len(r)) + for i, j := range r { + ret[i] = j.Name + } + return ret + } + Expect(resources).To(WithTransform(resourcesToNames, ContainElement("default-exposable"))) + }).Should(Succeed()) + }) + + It("should create Group", func() { + Eventually(func(g Gomega) { + groups, err := netbirdClient.Groups.List(context.Background()) + Expect(err).NotTo(HaveOccurred()) + Expect(groups).To(WithTransform(groupsToNames, ContainElement("kubernetes-default-exposable"))) + }).Should(Succeed()) + }) + }) + + When("Service is annotated with policy", Ordered, func() { + BeforeAll(func() { + _, err := utils.Run(exec.Command("kubectl", "annotate", "service", "exposable", "netbird.io/policy=default")) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should add service to policy status", func() { + Eventually(func(g Gomega) { + out, err := utils.Run(exec.Command( + "kubectl", "get", "NBPolicy", "default", "-o", "jsonpath={.status.managedServiceList}", + )) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(out).To(ContainSubstring("default/exposable")) + }).Should(Succeed()) + }) + + It("should create policy on NetBird", func() { + Eventually(func(g Gomega) { + out, err := utils.Run(exec.Command( + "kubectl", "get", "NBPolicy", "default", "-o", "jsonpath={.status.tcpPolicyID}", + )) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(out).NotTo(BeEmpty()) + }).Should(Succeed()) + + Eventually(func(g Gomega) { + policies, err := netbirdClient.Policies.List(context.Background()) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(policies).To(HaveLen(1)) + g.Expect(policies[0].Name).To(ContainSubstring("Kubernetes Default Group")) + }).Should(Succeed()) + }) + }) + + When("Service is annotated with a non-existent policy", Ordered, func() { + BeforeAll(func() { + _, err := utils.Run(exec.Command( + "kubectl", "annotate", "service", "exposable", "--overwrite", + "netbird.io/policy=custom", "netbird.io/policy-source-groups=All", "netbird.io/policy-name=custom:E2E", + )) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should create NBPolicy", func() { + Eventually(func(g Gomega) { + out, err := utils.Run(exec.Command( + "kubectl", "get", "NBPolicy", "custom-default-exposable", "-o", "jsonpath={.status.managedServiceList}", + )) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(out).To(ContainSubstring("default/exposable")) + }).Should(Succeed()) + }) + + It("should create policy on NetBird", func() { + Eventually(func(g Gomega) { + out, err := utils.Run(exec.Command( + "kubectl", "get", "NBPolicy", "custom-default-exposable", "-o", "jsonpath={.status.tcpPolicyID}", + )) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(out).NotTo(BeEmpty()) + }).Should(Succeed()) + + Eventually(func(g Gomega) { + policies, err := netbirdClient.Policies.List(context.Background()) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(policies).To(HaveLen(1)) + g.Expect(policies[0].Name).To(ContainSubstring("E2E")) + }).Should(Succeed()) + }) + }) + }) }) }) diff --git a/test/utils/management/compose.yml b/test/utils/management/compose.yml new file mode 100644 index 0000000..75bd69b --- /dev/null +++ b/test/utils/management/compose.yml @@ -0,0 +1,85 @@ +services: + mock-jwt-provider: + image: nginx:alpine + configs: + - source: nginx_conf + target: /etc/nginx/nginx.conf + networks: + transfer_net: + ipv4_address: 192.168.1.11 + healthcheck: + test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/.well-known/jwks.json" ] + interval: 3s + timeout: 1s + retries: 15 + + netbird-mgmt: + image: netbirdio/management:0.38.0 + environment: + - NB_LOG_LEVEL=debug + - NETBIRD_STORE_ENGINE=sqlite + volumes: + - ./seed_database.sql:/app/seed_database.sql + - ./management.json:/etc/netbird/management.json + - ./setup_mgmt.sh:/etc/netbird/setup_mgmt.sh + - /tmp/empty:/var/lib/netbird/GeoLite2-City_20240101.mmdb + - /tmp/empty:/var/lib/netbird/geonames_20240101.db + - netbird_data:/var/lib/netbird + entrypoint: [] + command: + - /bin/bash + - -c + - /etc/netbird/setup_mgmt.sh & /go/bin/netbird-mgmt management --log-file console + networks: + transfer_net: + ipv4_address: 192.168.1.10 + depends_on: + mock-jwt-provider: + condition: service_healthy + healthcheck: + test: [ "CMD", "sh", "-c", "grep -q '0:0050' /proc/net/tcp*" ] + interval: 3s + timeout: 1s + retries: 10 + ports: + # local debugging only + - "8080:80" + +networks: + transfer_net: + ipam: + config: + - subnet: 192.168.1.0/24 + +volumes: + netbird_data: + name: "netbird_data_${COMPOSE_PROJECT_NAME:-default}_tmp" + external: false + driver: local + driver_opts: + type: tmpfs + device: tmpfs + +configs: + nginx_conf: + content: | + user nginx; + worker_processes auto; + pid /var/run/nginx.pid; + events {} + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + + server { + listen 8080; + listen [::]:8080; + server_name localhost; + + location /.well-known/jwks.json { + return 200 '{"keys":[{"kid":"mockKid","kty":"RSA","alg":"RS256","use":"sig","n":"mockModulus","e":"AQAB"}]}'; + } + } + } \ No newline at end of file diff --git a/test/utils/management/management.json b/test/utils/management/management.json new file mode 100644 index 0000000..3834bbd --- /dev/null +++ b/test/utils/management/management.json @@ -0,0 +1,67 @@ +{ + "Stuns": [ + ], + "TURNConfig": { + "TimeBasedCredentials": true, + "CredentialsTTL": "12h0m0s", + "Secret": "", + "Turns": [ + ] + }, + "Signal": { + "Proto": "http", + "URI": "192.168.1.12:80", + "Username": "", + "Password": "" + }, + "Datadir": "/var/lib/netbird", + "DataStoreEncryptionKey": "0DStg6EdSwXQDOnr7uZHNBfJmzDsoqmR", + "HttpConfig": { + "AuthIssuer": "http://192.168.1.11:8080", + "AuthAudience": "mock-audience", + "AuthUserIDClaim": "sub", + "AuthKeysLocation": "http://192.168.1.11:8080/.well-known/jwks.json", + "IdpSignKeyRefreshEnabled": false + }, + "IdpManagerConfig": { + "ManagerType": "", + "ClientConfig": { + "Issuer": "", + "TokenEndpoint": "", + "ClientID": "", + "ClientSecret": "", + "GrantType": "" + }, + "ExtraConfig": { + "Audience": "" + }, + "Auth0ClientCredentials": null, + "AzureClientCredentials": null, + "KeycloakClientCredentials": null, + "ZitadelClientCredentials": null + }, + "DeviceAuthorizationFlow": { + "Provider": "", + "ProviderConfig": { + "ClientID": "", + "ClientSecret": "", + "Domain": "", + "Audience": "", + "TokenEndpoint": "", + "DeviceAuthEndpoint": "", + "AuthorizationEndpoint": "", + "Scope": "", + "UseIDToken": false, + "RedirectURLs": null + } + }, + "PKCEAuthorizationFlow": null, + "StoreConfig": { + "Engine": "" + }, + "ReverseProxy": { + "TrustedHTTPProxies": null, + "TrustedHTTPProxiesCount": 0, + "TrustedPeers": null + } +} diff --git a/test/utils/management/seed_database.sql b/test/utils/management/seed_database.sql new file mode 100644 index 0000000..65256ff --- /dev/null +++ b/test/utils/management/seed_database.sql @@ -0,0 +1,15 @@ +-- Seed Accounts table +INSERT INTO accounts (id, created_by, created_at, domain, domain_category, is_domain_primary_account, network_identifier, network_serial, settings_peer_login_expiration_enabled, settings_peer_login_expiration, settings_regular_users_view_blocked, settings_groups_propagation_enabled, settings_jwt_groups_enabled, settings_extra_peer_approval_enabled, network_net) +VALUES ('account1', 'user1', '2024-04-17 09:35:50.651027026+00:00', 'netbird.selfhosted', 'private', 1, 'network1', 694, 1, 86400000000000, 1, 1, 0, 0, '{"IP":"100.64.0.0","Mask":"//8AAA=="}'); + +-- Seed Users table +INSERT INTO users (id, account_id, role, is_service_user, non_deletable, blocked, created_at, issued) +VALUES ('user1', 'account1', 'owner', 0, 0, 0, '2024-08-12 00:00:00', 'api'); + +-- Seed Groups table +INSERT INTO groups (id, account_id, name, issued, peers, integration_ref_id, integration_ref_integration_type) +VALUES ('group-all', 'account1', 'All', 'api', '[]', 0, NULL); + +-- Seed Personal Access Tokens (API Keys) table +INSERT INTO personal_access_tokens (id, user_id, name, hashed_token, expiration_date, created_by, created_at, last_used) +VALUES ('1', 'user1', 'Test API Key', 'smJvzexPcQ3NRezrVDUmF++0XqvFvXzx8Rsn2y9r1z0=', '2124-08-12 00:00:00', 'user1', '2024-08-12 00:00:00', NULL); diff --git a/test/utils/management/setup_mgmt.sh b/test/utils/management/setup_mgmt.sh new file mode 100755 index 0000000..d59dcda --- /dev/null +++ b/test/utils/management/setup_mgmt.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -e + +# Install sqlite3 +apt-get update && apt-get install -y sqlite3 curl jq + +while true +do + # Check if the schema is ready + if sqlite3 /var/lib/netbird/store.db "SELECT name FROM sqlite_master WHERE type='table' AND name='accounts';" | grep -q accounts; then + echo "Database schema detected." + + # Check if the database is empty + if [ $(sqlite3 /var/lib/netbird/store.db "SELECT COUNT(*) FROM accounts;") -eq 0 ]; then + echo "Seeding the database..." + sqlite3 /var/lib/netbird/store.db < /app/seed_database.sql + echo "Database seeded successfully." + exit 0 + else + echo "Database already contains data, skipping seeding." + exit 1 + fi + else + echo "Database schema not found. Waiting..." + fi +done \ No newline at end of file diff --git a/test/utils/values.yaml b/test/utils/values.yaml new file mode 100644 index 0000000..65631dd --- /dev/null +++ b/test/utils/values.yaml @@ -0,0 +1,15 @@ +netbirdAPI: + key: "nbp_apTmlmUXHSC4PKmHwtIZNaGr8eqcVI2gMURp" + +ingress: + enabled: true + allowAutomaticPolicyCreation: true + kubernetesAPI: + enabled: false + router: + enabled: true + policies: + default: + name: Kubernetes Default Group + sourceGroups: + - All \ No newline at end of file