1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] ArangoRoute RC (#1690)

This commit is contained in:
Adam Janikowski 2024-08-01 15:53:48 +03:00 committed by GitHub
parent ae55994d68
commit ee5ea98638
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 3119 additions and 277 deletions

View file

@ -84,7 +84,7 @@ jobs:
echo "This is not a pull request. Skipping..."
exit 0
fi
make tidy update-generated synchronize-v2alpha1-with-v1 generate-internal sync fmt yamlfmt
make tidy update-generated synchronize-v2alpha1-with-v1 generate-internal sync fmt yamlfmt license
git checkout -- go.sum # ignore changes in go.sum
if [ ! -z "$(git status --porcelain)" ]; then
echo "There are uncommited changes!"

View file

@ -2,6 +2,7 @@
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- (Feature) ArangoRoute CRD
- (Feature) ArangoRoute Operator
## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23)
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries

View file

@ -777,7 +777,7 @@ tools-min: update-vendor
.PHONY: tools
tools: tools-min
@echo ">> Fetching gci"
@GOBIN=$(GOPATH)/bin go install github.com/daixiang0/gci@v0.3.0
@GOBIN=$(GOPATH)/bin go install github.com/daixiang0/gci@v0.13.4
@echo ">> Fetching yamlfmt"
@GOBIN=$(GOPATH)/bin go install github.com/google/yamlfmt/cmd/yamlfmt@v0.10.0
@echo ">> Downloading protobuf compiler..."

View file

@ -181,7 +181,7 @@ Flags:
--kubernetes.max-batch-size int Size of batch during objects read (default 256)
--kubernetes.qps float32 Number of queries per second for k8s API (default 15)
--log.format string Set log format. Allowed values: 'pretty', 'JSON'. If empty, default format is used (default "pretty")
--log.level stringArray Set log levels in format <level> or <logger>=<level>. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, http, inspector, integrations, k8s-client, monitor, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, pod_compare, root, root-event-recorder, server, server-authentication (default [info])
--log.level stringArray Set log levels in format <level> or <logger>=<level>. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, http, inspector, integrations, k8s-client, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, pod_compare, root, root-event-recorder, server, server-authentication (default [info])
--log.sampling If true, operator will try to minimize duplication of logging events (default true)
--memory-limit uint Define memory limit for hard shutdown and the dump of goroutines. Used for testing
--metrics.excluded-prefixes stringArray List of the excluded metrics prefixes
@ -192,6 +192,7 @@ Flags:
--operator.deployment Enable to run the ArangoDeployment operator
--operator.deployment-replication Enable to run the ArangoDeploymentReplication operator
--operator.ml Enable to run the ArangoML operator
--operator.networking Enable to run the Networking operator
--operator.reconciliation.retry.count int Count of retries during Object Update operations in the Reconciliation loop (default 25)
--operator.reconciliation.retry.delay duration Delay between Object Update operations in the Reconciliation loop (default 1s)
--operator.storage Enable to run the ArangoLocalStorage operator

View file

@ -117,6 +117,9 @@ spec:
{{ if .Values.operator.features.analytics }}
- --operator.analytics
{{- end }}
{{ if .Values.operator.features.networking }}
- --operator.networking
{{- end }}
{{ if .Values.operator.features.k8sToK8sClusterSync }}
- --operator.k2k-cluster-sync
{{- end }}

View file

@ -0,0 +1,26 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,22 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch"]
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,25 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "kube-arangodb.rbac" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,68 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups:
- "ml.arangodb.com"
resources:
- "arangomlextensions"
- "arangomlextensions/status"
- "arangomlbatchjobs"
- "arangomlbatchjobs/status"
- "arangomlcronjobs"
- "arangomlcronjobs/status"
- "arangomlstorages"
- "arangomlstorages/status"
verbs:
- "*"
- apiGroups:
- "scheduler.arangodb.com"
resources:
- "arangoprofiles"
- "arangoprofiles/status"
verbs:
- "*"
- apiGroups:
- "database.arangodb.com"
resources:
- "arangodeployments"
verbs:
- "get"
- "list"
- "watch"
- apiGroups:
- "rbac.authorization.k8s.io"
resources:
- "roles"
- "rolebindings"
verbs: ["*"]
- apiGroups:
- "batch"
resources:
- "cronjobs"
- "jobs"
verbs: ["*"]
- apiGroups: ["apps"]
resources:
- "statefulsets"
verbs: ["*"]
- apiGroups: [""]
resources:
- "pods"
- "secrets"
- "services"
- "serviceaccounts"
verbs: ["*"]
{{- end }}
{{- end }}

View file

@ -117,6 +117,9 @@ spec:
{{ if .Values.operator.features.analytics }}
- --operator.analytics
{{- end }}
{{ if .Values.operator.features.networking }}
- --operator.networking
{{- end }}
{{ if .Values.operator.features.k8sToK8sClusterSync }}
- --operator.k2k-cluster-sync
{{- end }}

View file

@ -0,0 +1,26 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,22 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch"]
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,25 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "kube-arangodb.rbac" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,68 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups:
- "ml.arangodb.com"
resources:
- "arangomlextensions"
- "arangomlextensions/status"
- "arangomlbatchjobs"
- "arangomlbatchjobs/status"
- "arangomlcronjobs"
- "arangomlcronjobs/status"
- "arangomlstorages"
- "arangomlstorages/status"
verbs:
- "*"
- apiGroups:
- "scheduler.arangodb.com"
resources:
- "arangoprofiles"
- "arangoprofiles/status"
verbs:
- "*"
- apiGroups:
- "database.arangodb.com"
resources:
- "arangodeployments"
verbs:
- "get"
- "list"
- "watch"
- apiGroups:
- "rbac.authorization.k8s.io"
resources:
- "roles"
- "rolebindings"
verbs: ["*"]
- apiGroups:
- "batch"
resources:
- "cronjobs"
- "jobs"
verbs: ["*"]
- apiGroups: ["apps"]
resources:
- "statefulsets"
verbs: ["*"]
- apiGroups: [""]
resources:
- "pods"
- "secrets"
- "services"
- "serviceaccounts"
verbs: ["*"]
{{- end }}
{{- end }}

View file

@ -117,6 +117,9 @@ spec:
{{ if .Values.operator.features.analytics }}
- --operator.analytics
{{- end }}
{{ if .Values.operator.features.networking }}
- --operator.networking
{{- end }}
{{ if .Values.operator.features.k8sToK8sClusterSync }}
- --operator.k2k-cluster-sync
{{- end }}

View file

@ -0,0 +1,26 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,22 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch"]
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,25 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "kube-arangodb.rbac" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,68 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups:
- "ml.arangodb.com"
resources:
- "arangomlextensions"
- "arangomlextensions/status"
- "arangomlbatchjobs"
- "arangomlbatchjobs/status"
- "arangomlcronjobs"
- "arangomlcronjobs/status"
- "arangomlstorages"
- "arangomlstorages/status"
verbs:
- "*"
- apiGroups:
- "scheduler.arangodb.com"
resources:
- "arangoprofiles"
- "arangoprofiles/status"
verbs:
- "*"
- apiGroups:
- "database.arangodb.com"
resources:
- "arangodeployments"
verbs:
- "get"
- "list"
- "watch"
- apiGroups:
- "rbac.authorization.k8s.io"
resources:
- "roles"
- "rolebindings"
verbs: ["*"]
- apiGroups:
- "batch"
resources:
- "cronjobs"
- "jobs"
verbs: ["*"]
- apiGroups: ["apps"]
resources:
- "statefulsets"
verbs: ["*"]
- apiGroups: [""]
resources:
- "pods"
- "secrets"
- "services"
- "serviceaccounts"
verbs: ["*"]
{{- end }}
{{- end }}

View file

@ -117,6 +117,9 @@ spec:
{{ if .Values.operator.features.analytics }}
- --operator.analytics
{{- end }}
{{ if .Values.operator.features.networking }}
- --operator.networking
{{- end }}
{{ if .Values.operator.features.k8sToK8sClusterSync }}
- --operator.k2k-cluster-sync
{{- end }}

View file

@ -0,0 +1,26 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,22 @@
{{ if .Values.rbac.enabled -}}
{{ if not (eq .Values.operator.scope "namespaced") -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template "kube-arangodb.rbac-cluster" . }}-networking
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get", "list", "watch"]
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,25 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "kube-arangodb.rbac" . }}-networking
subjects:
- kind: ServiceAccount
name: {{ template "kube-arangodb.operatorName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,68 @@
{{ if .Values.rbac.enabled -}}
{{ if .Values.operator.features.networking -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ template "kube-arangodb.rbac" . }}-networking
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
release: {{ .Release.Name }}
rules:
- apiGroups:
- "ml.arangodb.com"
resources:
- "arangomlextensions"
- "arangomlextensions/status"
- "arangomlbatchjobs"
- "arangomlbatchjobs/status"
- "arangomlcronjobs"
- "arangomlcronjobs/status"
- "arangomlstorages"
- "arangomlstorages/status"
verbs:
- "*"
- apiGroups:
- "scheduler.arangodb.com"
resources:
- "arangoprofiles"
- "arangoprofiles/status"
verbs:
- "*"
- apiGroups:
- "database.arangodb.com"
resources:
- "arangodeployments"
verbs:
- "get"
- "list"
- "watch"
- apiGroups:
- "rbac.authorization.k8s.io"
resources:
- "roles"
- "rolebindings"
verbs: ["*"]
- apiGroups:
- "batch"
resources:
- "cronjobs"
- "jobs"
verbs: ["*"]
- apiGroups: ["apps"]
resources:
- "statefulsets"
verbs: ["*"]
- apiGroups: [""]
resources:
- "pods"
- "secrets"
- "services"
- "serviceaccounts"
verbs: ["*"]
{{- end }}
{{- end }}

View file

@ -34,6 +34,7 @@ operator:
k8sToK8sClusterSync: false
ml: false
analytics: false
networking: true
tolerations: []
rbac:
enabled: true

View file

@ -119,6 +119,7 @@ var (
enableApps bool // Run apps operator
enableML bool // Run ml operator
enableAnalytics bool // Run analytics operator
enableNetworking bool // Run networking operator
versionOnly bool // Run only version endpoint, explicitly disabled with other
enableK2KClusterSync bool // Run k2kClusterSync operator
@ -184,6 +185,7 @@ var (
appsProbe probe.ReadyProbe
mlProbe probe.ReadyProbe
analyticsProbe probe.ReadyProbe
networkingProbe probe.ReadyProbe
k2KClusterSyncProbe probe.ReadyProbe
)
@ -210,6 +212,7 @@ func init() {
f.BoolVar(&operatorOptions.enableApps, "operator.apps", false, "Enable to run the ArangoApps operator")
f.BoolVar(&operatorOptions.enableML, "operator.ml", false, "Enable to run the ArangoML operator")
f.BoolVar(&operatorOptions.enableAnalytics, "operator.analytics", false, "Enable to run the Analytics operator")
f.BoolVar(&operatorOptions.enableNetworking, "operator.networking", false, "Enable to run the Networking operator")
f.BoolVar(&operatorOptions.enableK2KClusterSync, "operator.k2k-cluster-sync", false, "Enable to run the ListSimple operator")
f.MarkDeprecated("operator.k2k-cluster-sync", "Enabled within deployment operator")
f.BoolVar(&operatorOptions.versionOnly, "operator.version", false, "Enable only version endpoint in Operator")
@ -345,16 +348,17 @@ func executeMain(cmd *cobra.Command, args []string) {
// Check operating mode
if !operatorOptions.enableDeployment && !operatorOptions.enableDeploymentReplication && !operatorOptions.enableStorage &&
!operatorOptions.enableBackup && !operatorOptions.enableApps && !operatorOptions.enableK2KClusterSync && !operatorOptions.enableML && !operatorOptions.enableAnalytics {
!operatorOptions.enableBackup && !operatorOptions.enableApps && !operatorOptions.enableK2KClusterSync &&
!operatorOptions.enableML && !operatorOptions.enableAnalytics && !operatorOptions.enableNetworking {
if !operatorOptions.versionOnly {
if version.GetVersionV1().IsEnterprise() {
logger.Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml, --operator.analytics or any combination of these")
logger.Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml, --operator.analytics, --operator.networking or any combination of these")
} else {
logger.Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync or any combination of these")
logger.Fatal("Turn on --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.networking or any combination of these")
}
}
} else if operatorOptions.versionOnly {
logger.Fatal("Options --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml, --operator.analytics cannot be enabled together with --operator.version")
logger.Fatal("Options --operator.deployment, --operator.deployment-replication, --operator.storage, --operator.backup, --operator.apps, --operator.k2k-cluster-sync, --operator.ml, --operator.analytics, --operator.networking cannot be enabled together with --operator.version")
} else if !version.GetVersionV1().IsEnterprise() {
if operatorOptions.enableML || operatorOptions.enableAnalytics {
logger.Fatal("Options --operator.ml, --operator.analytics can be enabled only on the Enterprise Operator")
@ -492,6 +496,10 @@ func executeMain(cmd *cobra.Command, args []string) {
Enabled: cfg.EnableAnalytics,
Probe: &analyticsProbe,
},
Networking: server.OperatorDependency{
Enabled: cfg.EnableNetworking,
Probe: &analyticsProbe,
},
ClusterSync: server.OperatorDependency{
Enabled: cfg.EnableK2KClusterSync,
Probe: &k2KClusterSyncProbe,
@ -576,6 +584,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper
EnableApps: operatorOptions.enableApps,
EnableML: operatorOptions.enableML,
EnableAnalytics: operatorOptions.enableAnalytics,
EnableNetworking: operatorOptions.enableNetworking,
EnableK2KClusterSync: operatorOptions.enableK2KClusterSync,
AllowChaos: chaosOptions.allowed,
ScalingIntegrationEnabled: operatorOptions.scalingIntegrationEnabled,
@ -596,6 +605,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper
AppsProbe: &appsProbe,
MlProbe: &mlProbe,
AnalyticsProbe: &analyticsProbe,
NetworkingProbe: &networkingProbe,
K2KClusterSyncProbe: &k2KClusterSyncProbe,
}

View file

@ -12,7 +12,7 @@ title: ArangoRoute V1Alpha1
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec.go#L27)</sup>
Deployment specifies the ArangoDeployment object name
DeploymentName specifies the ArangoDeployment object name
***
@ -85,7 +85,53 @@ Path specifies the Path route
### .status.conditions
Type: `api.Conditions` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status.go#L28)</sup>
Type: `api.Conditions` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status.go#L31)</sup>
Conditions specific to the entire extension
***
### .status.deployment.checksum
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/shared/v1/object.go#L61)</sup>
UID keeps the information about object Checksum
***
### .status.deployment.name
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/shared/v1/object.go#L52)</sup>
Name of the object
***
### .status.deployment.namespace
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/shared/v1/object.go#L55)</sup>
Namespace of the object. Should default to the namespace of the parent object
***
### .status.deployment.uid
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/shared/v1/object.go#L58)</sup>
UID keeps the information about object UID
***
### .status.targets\[int\].tls.insecure
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_tls.go#L27)</sup>
Insecure allows Insecure traffic
***
### .status.targets\[int\].url
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target.go#L34)</sup>

View file

@ -0,0 +1,49 @@
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP{{ .id }}Func{{ .templateVars }} func(ctx context.Context {{- if .inputVars }}, {{ .inputVars }}{{ end }}) (bool, error)
type HandleP{{ .id }}ConditionFunc{{ .templateVars }} func(ctx context.Context {{- if .inputVars }}, {{ .inputVars }}{{ end }}) (*Condition, bool, error)
type HandleP{{ .id }}ConditionExtract{{ .templateVars }} func(ctx context.Context {{- if .inputVars }}, {{ .inputVars }}{{ end }}) *api.ConditionList
func HandleP{{ .id }}{{ .templateVars }}(ctx context.Context{{- if .inputVars }}, {{ .inputVars }}{{ end }}, handler ...HandleP{{ .id }}Func{{ .templateInputVars }}) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx{{- if .cleanRefs }}, {{ .cleanRefs }}{{ end }})
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP{{ .id }}WithStop{{ .templateVars }}(ctx context.Context{{- if .inputVars }}, {{ .inputVars }}{{ end }}, handler ...HandleP{{ .id }}Func{{ .templateInputVars }}) (bool, error) {
changed, err := HandleP{{ .id }}{{ .templateInputVars }}(ctx {{- if .cleanRefs }}, {{ .cleanRefs }}{{ end }}, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP{{ .id }}WithCondition{{ .templateVars }}(ctx context.Context, conditions *api.ConditionList, condition api.ConditionType{{- if .inputVars }}, {{ .inputVars }}{{ end }}, handler ...HandleP{{ .id }}Func{{ .templateInputVars }}) (bool, error) {
changed, err := HandleP{{ .id }}{{ .templateInputVars }}(ctx{{- if .cleanRefs }}, {{ .cleanRefs }}{{ end }}, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP{{ .id }}Condition{{ .templateVars }}(extract HandleP{{ .id }}ConditionExtract{{ .templateInputVars }}, condition api.ConditionType, handler HandleP{{ .id }}ConditionFunc{{ .templateInputVars }}) HandleP{{ .id }}Func{{ .templateInputVars }} {
return func(ctx context.Context {{- if .inputVars }}, {{ .inputVars }}{{ end }}) (bool, error) {
c, changed, err := handler(ctx{{- if .cleanRefs }}, {{ .cleanRefs }}{{ end }})
return WithConditionChange(extract(ctx{{- if .cleanRefs }}, {{ .cleanRefs }}{{ end }}), condition, c, changed, err)
}
}

View file

@ -0,0 +1,90 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package generators
import (
_ "embed"
"fmt"
"os"
"path"
"testing"
"text/template"
"github.com/stretchr/testify/require"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/strings"
)
//go:embed generator_pkg_operatorv2_handlers.go.tmpl
var generatorPKGOperatorV2Handlers []byte
func Test_Generate_PKG_OperatorV2_Handlers(t *testing.T) {
root := os.Getenv("ROOT")
require.NotEmpty(t, root)
i, err := template.New("metrics").Parse(string(generatorPKGOperatorV2Handlers))
require.NoError(t, err)
for id := 0; id < 10; id++ {
t.Run(fmt.Sprintf("%d", id), func(t *testing.T) {
out, err := os.OpenFile(path.Join(root, "pkg/operatorV2", fmt.Sprintf("handler_p%d.generated.go", id)), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
require.NoError(t, err)
var params []string
for z := 0; z < id; z++ {
params = append(params, fmt.Sprintf("P%d", z+1))
}
cleanVars := strings.Join(params, ", ")
cleanRefs := strings.Join(util.FormatList(params, func(a string) string {
return strings.ToLower(a)
}), ", ")
templateVars := strings.Join(params, ", ")
templateInputVars := strings.Join(params, ", ")
inputVars := strings.Join(util.FormatList(params, func(a string) string {
return fmt.Sprintf("%s %s", strings.ToLower(a), a)
}), ", ")
if templateVars != "" {
templateVars = fmt.Sprintf("[%s any]", templateVars)
}
if templateInputVars != "" {
templateInputVars = fmt.Sprintf("[%s]", templateInputVars)
}
require.NoError(t, i.Execute(out, map[string]interface{}{
"id": id,
"templateVars": templateVars,
"templateInputVars": templateInputVars,
"inputVars": inputVars,
"cleanVars": cleanVars,
"cleanRefs": cleanRefs,
}))
require.NoError(t, out.Close())
})
}
}

View file

@ -0,0 +1,30 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1alpha1
import api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
const (
ReadyCondition api.ConditionType = "Ready"
DeploymentFoundCondition api.ConditionType = "DeploymentFound"
DestinationValidCondition api.ConditionType = "DestinationValid"
SpecValidCondition api.ConditionType = "SpecValid"
)

View file

@ -23,8 +23,8 @@ package v1alpha1
import shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
type ArangoRouteSpec struct {
// Deployment specifies the ArangoDeployment object name
Deployment string `json:"deployment,omitempty"`
// DeploymentName specifies the ArangoDeployment object name
DeploymentName *string `json:"deployment,omitempty"`
// Destination defines the route destination
Destination *ArangoRouteSpecDestination `json:"destination,omitempty"`
@ -33,15 +33,30 @@ type ArangoRouteSpec struct {
Route *ArangoRouteSpecRoute `json:"route,omitempty"`
}
func (s *ArangoRouteSpec) GetDestination() *ArangoRouteSpecDestination {
if s == nil || s.Destination == nil {
return nil
}
return s.Destination
}
func (s *ArangoRouteSpec) GetRoute() *ArangoRouteSpecRoute {
if s == nil || s.Route == nil {
return nil
}
return s.Route
}
func (s *ArangoRouteSpec) Validate() error {
if s == nil {
s = &ArangoRouteSpec{}
}
if err := shared.WithErrors(shared.PrefixResourceErrors("spec",
shared.PrefixResourceError("deployment", shared.ValidateResourceName(s.Deployment)),
shared.PrefixResourceErrors("deployment", shared.ValidateResourceNamePointer(s.DeploymentName)),
shared.ValidateRequiredInterfacePath("destination", s.Destination),
shared.ValidateRequiredInterfacePath("route", s.Route),
shared.ValidateOptionalInterfacePath("route", s.Route),
)); err != nil {
return err
}

View file

@ -33,15 +33,39 @@ type ArangoRouteSpecDestination struct {
TLS *ArangoRouteSpecDestinationTLS `json:"tls,omitempty"`
}
func (s *ArangoRouteSpecDestination) Validate() error {
if s == nil {
s = &ArangoRouteSpecDestination{}
func (s *ArangoRouteSpecDestination) GetService() *ArangoRouteSpecDestinationService {
if s == nil || s.Service == nil {
return nil
}
return s.Service
}
func (s *ArangoRouteSpecDestination) GetSchema() *ArangoRouteSpecDestinationSchema {
if s == nil || s.Schema == nil {
return nil
}
return s.Schema
}
func (s *ArangoRouteSpecDestination) GetTLS() *ArangoRouteSpecDestinationTLS {
if s == nil || s.TLS == nil {
return nil
}
return s.TLS
}
func (a *ArangoRouteSpecDestination) Validate() error {
if a == nil {
a = &ArangoRouteSpecDestination{}
}
if err := shared.WithErrors(
shared.ValidateOptionalInterfacePath("service", s.Service),
shared.ValidateOptionalInterfacePath("schema", s.Schema),
shared.ValidateOptionalInterfacePath("tls", s.TLS),
shared.ValidateOptionalInterfacePath("service", a.Service),
shared.ValidateOptionalInterfacePath("schema", a.Schema),
shared.ValidateOptionalInterfacePath("tls", a.TLS),
); err != nil {
return err
}

View file

@ -36,12 +36,22 @@ type ArangoRouteSpecDestinationService struct {
Port *intstr.IntOrString `json:"port,omitempty"`
}
func (s *ArangoRouteSpecDestinationService) Validate() error {
if s == nil {
s = &ArangoRouteSpecDestinationService{}
func (a *ArangoRouteSpecDestinationService) GetPort() *intstr.IntOrString {
if a == nil || a.Port == nil {
return nil
}
if err := shared.WithErrors(s.Object.Validate()); err != nil {
return a.Port
}
func (a *ArangoRouteSpecDestinationService) Validate() error {
if a == nil {
a = &ArangoRouteSpecDestinationService{}
}
if err := shared.WithErrors(a.Object.Validate(), shared.ValidateRequiredPath("port", a.Port, func(i intstr.IntOrString) error {
return nil
})); err != nil {
return err
}

View file

@ -25,6 +25,14 @@ type ArangoRouteSpecDestinationTLS struct {
Insecure *bool `json:"insecure,omitempty"`
}
func (s *ArangoRouteSpecDestinationTLS) Validate() error {
func (a *ArangoRouteSpecDestinationTLS) GetInsecure() bool {
if a == nil || a.Insecure == nil {
return false
}
return true
}
func (a *ArangoRouteSpecDestinationTLS) Validate() error {
return nil
}

View file

@ -29,21 +29,21 @@ type ArangoRouteSpecRoute struct {
Path *string `json:"path,omitempty"`
}
func (s *ArangoRouteSpecRoute) GetPath() string {
if s == nil && s.Path == nil {
func (a *ArangoRouteSpecRoute) GetPath() string {
if a == nil || a.Path == nil {
return "/"
}
return *s.Path
return *a.Path
}
func (s *ArangoRouteSpecRoute) Validate() error {
if s == nil {
s = &ArangoRouteSpecRoute{}
func (a *ArangoRouteSpecRoute) Validate() error {
if a == nil {
a = &ArangoRouteSpecRoute{}
}
if err := shared.WithErrors(
shared.PrefixResourceError("path", shared.ValidateAPIPath(s.GetPath())),
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),
); err != nil {
return err
}

View file

@ -20,10 +20,19 @@
package v1alpha1
import api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
import (
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
)
type ArangoRouteStatus struct {
// Conditions specific to the entire extension
// +doc/type: api.Conditions
Conditions api.ConditionList `json:"conditions,omitempty"`
// Deployment keeps the ArangoDeployment reference
Deployment *sharedApi.Object `json:"deployment,omitempty"`
// Targets keeps the target details
Targets ArangoRouteStatusTargets `json:"targets,omitempty"`
}

View file

@ -0,0 +1,44 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1alpha1
import "github.com/arangodb/kube-arangodb/pkg/util"
type ArangoRouteStatusTargets []ArangoRouteStatusTarget
func (a ArangoRouteStatusTargets) Hash() string {
return util.SHA256FromExtract(func(t ArangoRouteStatusTarget) string {
return t.Hash()
}, a...)
}
type ArangoRouteStatusTarget struct {
Url string `json:"url,omitempty"`
TLS ArangoRouteStatusTargetTLS `json:"tls,omitempty"`
}
func (a *ArangoRouteStatusTarget) Hash() string {
if a == nil {
return ""
}
return util.SHA256FromStringArray(a.Url, a.TLS.Hash())
}

View file

@ -0,0 +1,36 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1alpha1
import "github.com/arangodb/kube-arangodb/pkg/util"
type ArangoRouteStatusTargetTLS struct {
// Insecure allows Insecure traffic
Insecure bool `json:"insecure"`
}
func (a *ArangoRouteStatusTargetTLS) Hash() string {
if a == nil {
return ""
}
return util.SHA256FromStringArray(util.BoolSwitch(a.Insecure, "true", "false"))
}

View file

@ -96,6 +96,11 @@ func (in *ArangoRouteList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteSpec) DeepCopyInto(out *ArangoRouteSpec) {
*out = *in
if in.DeploymentName != nil {
in, out := &in.DeploymentName, &out.DeploymentName
*out = new(string)
**out = **in
}
if in.Destination != nil {
in, out := &in.Destination, &out.Destination
*out = new(ArangoRouteSpecDestination)
@ -228,6 +233,16 @@ func (in *ArangoRouteStatus) DeepCopyInto(out *ArangoRouteStatus) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Deployment != nil {
in, out := &in.Deployment, &out.Deployment
*out = new(v1.Object)
(*in).DeepCopyInto(*out)
}
if in.Targets != nil {
in, out := &in.Targets, &out.Targets
*out = make(ArangoRouteStatusTargets, len(*in))
copy(*out, *in)
}
return
}
@ -240,3 +255,56 @@ func (in *ArangoRouteStatus) DeepCopy() *ArangoRouteStatus {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteStatusTarget) DeepCopyInto(out *ArangoRouteStatusTarget) {
*out = *in
out.TLS = in.TLS
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteStatusTarget.
func (in *ArangoRouteStatusTarget) DeepCopy() *ArangoRouteStatusTarget {
if in == nil {
return nil
}
out := new(ArangoRouteStatusTarget)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteStatusTargetTLS) DeepCopyInto(out *ArangoRouteStatusTargetTLS) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteStatusTargetTLS.
func (in *ArangoRouteStatusTargetTLS) DeepCopy() *ArangoRouteStatusTargetTLS {
if in == nil {
return nil
}
out := new(ArangoRouteStatusTargetTLS)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ArangoRouteStatusTargets) DeepCopyInto(out *ArangoRouteStatusTargets) {
{
in := &in
*out = make(ArangoRouteStatusTargets, len(*in))
copy(*out, *in)
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteStatusTargets.
func (in ArangoRouteStatusTargets) DeepCopy() ArangoRouteStatusTargets {
if in == nil {
return nil
}
out := new(ArangoRouteStatusTargets)
in.DeepCopyInto(out)
return *out
}

View file

@ -22,6 +22,7 @@ package shared
import (
"fmt"
"reflect"
"regexp"
"github.com/google/uuid"
@ -57,6 +58,15 @@ func ValidateResourceName(name string) error {
return errors.WithStack(errors.Errorf("Name '%s' is not a valid resource name", name))
}
// ValidateResourceNamePointer validates a kubernetes resource name.
// If not valid, an error is returned.
func ValidateResourceNamePointer(name *string) error {
if name == nil {
return errors.WithStack(errors.Errorf("Name is nil"))
}
return ValidateResourceName(*name)
}
// ValidateOptionalResourceName validates a kubernetes resource name.
// If not empty and not valid, an error is returned.
func ValidateOptionalResourceName(name string) error {
@ -98,7 +108,7 @@ func ValidatePullPolicy(in core.PullPolicy) error {
return errors.Errorf("Unknown pull policy: '%s'", string(in))
}
func Validate[T interface{}](in T) error {
func Validate[T any](in T) error {
res, _ := validate(in)
return res
}
@ -107,6 +117,9 @@ func validate(in any) (error, bool) {
if in == nil {
return nil, false
}
if reflect.ValueOf(in).IsZero() {
return nil, false
}
if v, ok := in.(ValidateInterface); ok {
return v.Validate(), true
}
@ -114,7 +127,7 @@ func validate(in any) (error, bool) {
}
// ValidateOptional Validates object if is not nil
func ValidateOptional[T interface{}](in *T, validator func(T) error) error {
func ValidateOptional[T any](in *T, validator func(T) error) error {
if in != nil {
return validator(*in)
}
@ -122,6 +135,11 @@ func ValidateOptional[T interface{}](in *T, validator func(T) error) error {
return nil
}
// ValidateOptionalPath Validates object if is not nil
func ValidateOptionalPath[T any](path string, in *T, validator func(T) error) error {
return PrefixResourceErrors(path, ValidateOptional(in, validator))
}
// ValidateOptionalInterface Validates object if is not nil
func ValidateOptionalInterface[T ValidateInterface](in T) error {
res, _ := validate(in)
@ -130,11 +148,11 @@ func ValidateOptionalInterface[T ValidateInterface](in T) error {
// ValidateOptionalInterfacePath Validates object if is not nil with path
func ValidateOptionalInterfacePath[T ValidateInterface](path string, in T) error {
return PrefixResourceError(path, ValidateOptionalInterface(in))
return PrefixResourceErrors(path, ValidateOptionalInterface(in))
}
// ValidateRequired Validates object and required not nil value
func ValidateRequired[T interface{}](in *T, validator func(T) error) error {
func ValidateRequired[T any](in *T, validator func(T) error) error {
if in != nil {
return validator(*in)
}
@ -142,6 +160,11 @@ func ValidateRequired[T interface{}](in *T, validator func(T) error) error {
return errors.Errorf("should be not nil")
}
// ValidateRequiredPath Validates object and required not nil value
func ValidateRequiredPath[T any](path string, in *T, validator func(T) error) error {
return PrefixResourceErrors(path, ValidateRequired(in, validator))
}
// ValidateRequiredInterface Validates object if is not nil
func ValidateRequiredInterface[T ValidateInterface](in T) error {
res, ok := validate(in)
@ -153,11 +176,11 @@ func ValidateRequiredInterface[T ValidateInterface](in T) error {
// ValidateRequiredInterfacePath Validates object if is not nil with path
func ValidateRequiredInterfacePath[T ValidateInterface](path string, in T) error {
return PrefixResourceError(path, ValidateRequiredInterface(in))
return PrefixResourceErrors(path, ValidateRequiredInterface(in))
}
// ValidateList validates all elements on the list
func ValidateList[T interface{}](in []T, validator func(T) error) error {
func ValidateList[T any](in []T, validator func(T) error) error {
errors := make([]error, len(in))
for id := range in {

View file

@ -4,7 +4,7 @@ v1alpha1:
spec:
properties:
deployment:
description: Deployment specifies the ArangoDeployment object name
description: DeploymentName specifies the ArangoDeployment object name
type: string
destination:
description: Destination defines the route destination

View file

@ -0,0 +1,123 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"context"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
arangoClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned"
"github.com/arangodb/kube-arangodb/pkg/logging"
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/event"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util"
)
var logger = logging.Global().RegisterAndGetLogger("networking-route-operator", logging.Info)
type handler struct {
client arangoClientSet.Interface
kubeClient kubernetes.Interface
eventRecorder event.RecorderInstance
operator operator.Operator
}
func (h *handler) Name() string {
return Kind()
}
func (h *handler) Handle(ctx context.Context, item operation.Item) error {
// Get Backup object. It also covers NotFound case
object, err := util.WithKubernetesContextTimeoutP2A2(ctx, h.client.NetworkingV1alpha1().ArangoRoutes(item.Namespace).Get, item.Name, meta.GetOptions{})
if err != nil {
if apiErrors.IsNotFound(err) {
return nil
}
return err
}
status := object.Status.DeepCopy()
changed, reconcileErr := operator.HandleP3WithStop(ctx, item, object, status, h.handle)
if reconcileErr != nil && !operator.IsReconcile(reconcileErr) {
logger.Err(reconcileErr).Warn("Fail for %s %s/%s",
item.Kind,
item.Namespace,
item.Name)
return reconcileErr
}
if !changed {
return reconcileErr
}
logger.Debug("Updating %s %s/%s",
item.Kind,
item.Namespace,
item.Name)
if _, err := operator.WithNetworkingArangoRouteUpdateStatusInterfaceRetry(context.Background(), h.client.NetworkingV1alpha1().ArangoRoutes(object.GetNamespace()), object, *status, meta.UpdateOptions{}); err != nil {
return err
}
return reconcileErr
}
func (h *handler) handle(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus) (bool, error) {
return operator.HandleP3WithCondition(ctx, &status.Conditions, networkingApi.ReadyCondition, item, extension, status, h.HandleSpecValidity, h.HandleArangoDeployment)
}
func (h *handler) HandleSpecValidity(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus) (bool, error) {
if err := extension.Spec.Validate(); err != nil {
// We have received an error in the spec!
logger.Err(err).Warn("Invalid Spec on %s", item.String())
if status.Conditions.Update(networkingApi.SpecValidCondition, false, "Spec is invalid", "Spec is invalid") {
return true, operator.Stop("Invalid spec")
}
return false, operator.Stop("Invalid spec")
}
if status.Conditions.Update(networkingApi.SpecValidCondition, true, "Spec is valid", "Spec is valid") {
return true, operator.Reconcile("Conditions updated")
}
return false, nil
}
func (h *handler) CanBeHandled(item operation.Item) bool {
return item.Group == Group() &&
item.Version == Version() &&
item.Kind == Kind()
}
func (h *handler) init() {}

View file

@ -0,0 +1,82 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"context"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util"
)
func (h *handler) HandleArangoDeployment(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus) (bool, error) {
var name = util.WithDefault(extension.Spec.DeploymentName)
if status.Deployment != nil {
name = status.Deployment.GetName()
}
deployment, err := util.WithKubernetesContextTimeoutP2A2(ctx, h.client.DatabaseV1().ArangoDeployments(item.Namespace).Get, name, meta.GetOptions{})
if err != nil {
if apiErrors.IsNotFound(err) {
// Condition for Found should be set to false
if util.Or(
status.Conditions.Update(networkingApi.DeploymentFoundCondition, false, "ArangoDeployment not found", "ArangoDeployment not found"),
) {
return true, operator.Reconcile("Conditions updated")
}
return false, nil
}
return false, err
}
if status.Deployment == nil {
status.Deployment = util.NewType(sharedApi.NewObject(deployment))
return true, operator.Reconcile("Deployment saved")
} else if !status.Deployment.Equals(deployment) {
if util.Or(
status.Conditions.Update(networkingApi.DeploymentFoundCondition, false, "ArangoDeployment changed", "ArangoDeployment changed"),
) {
return true, operator.Reconcile("Conditions updated")
}
return false, operator.Stop("ArangoDeployment Changed")
}
// Condition for Found should be set to true
if status.Conditions.Update(networkingApi.DeploymentFoundCondition, true, "ArangoDeployment found", "ArangoDeployment found") {
return true, operator.Reconcile("Conditions updated")
}
return operator.HandleP4(ctx, item, extension, status, deployment,
operator.HandleP4Condition(func(_ context.Context, _ operation.Item, _ *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus, _ *api.ArangoDeployment) *api.ConditionList {
return &status.Conditions
}, networkingApi.DestinationValidCondition, h.HandleArangoDestinationWithTargets), h.HandleDestinationRequired)
}

View file

@ -0,0 +1,145 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/uuid"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
)
func Test_Handler_Deployment(t *testing.T) {
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DeploymentFoundCondition))
}
func Test_Handler_MissingDeployment(t *testing.T) {
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test", func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment-missing")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.DeploymentFoundCondition))
}
func Test_Handler_Deployment_Changed(t *testing.T) {
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test", func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DeploymentFoundCondition))
deployment.UID = uuid.NewUUID()
tests.UpdateObjects(t, handler.kubeClient, handler.client, &deployment)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.DeploymentFoundCondition))
}

View file

@ -0,0 +1,171 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"context"
"fmt"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util"
)
func (h *handler) HandleArangoDestination(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus, _ *api.ArangoDeployment) (*operator.Condition, bool, error) {
if dest := extension.Spec.GetDestination(); dest != nil {
if svc := dest.GetService(); svc != nil {
port := svc.Port
if port == nil {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: "Missing Port definition",
}, false, nil
}
s, err := util.WithKubernetesContextTimeoutP2A2(ctx, h.kubeClient.CoreV1().Services(svc.GetNamespace(extension)).Get, svc.GetName(), meta.GetOptions{})
if err != nil {
if api.IsNotFound(err) {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: fmt.Sprintf("Service `%s/%s` Not found", svc.GetNamespace(extension), svc.GetName()),
}, false, nil
}
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: fmt.Sprintf("Unknown error for service `%s/%s`: %s", svc.GetNamespace(extension), svc.GetName(), err.Error()),
}, false, nil
}
if !svc.Equals(s) {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: fmt.Sprintf("Service `%s/%s` Changed", svc.GetNamespace(extension), svc.GetName()),
}, false, nil
}
var destPort int32
if port.Type == intstr.Int {
p, ok := util.PickFromList(s.Spec.Ports, func(v core.ServicePort) bool {
return v.Port == port.IntVal
})
if !ok {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: fmt.Sprintf("Port `%d` not defined on Service `%s/%s`", port.IntVal, svc.GetNamespace(extension), svc.GetName()),
}, false, nil
}
destPort = p.Port
} else if port.Type == intstr.String && port.StrVal != "" {
p, ok := util.PickFromList(s.Spec.Ports, func(v core.ServicePort) bool {
return v.Name == port.StrVal
})
if !ok {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: fmt.Sprintf("Port `%s` not defined on Service `%s/%s`", port.StrVal, svc.GetNamespace(extension), svc.GetName()),
}, false, nil
}
destPort = p.Port
} else {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: "Unknown Port definition",
}, false, nil
}
if destPort == -1 {
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: fmt.Sprintf("Unable to discover port on Service `%s/%s`", svc.GetNamespace(extension), svc.GetName()),
}, false, nil
}
var targets = networkingApi.ArangoRouteStatusTargets{
networkingApi.ArangoRouteStatusTarget{
Url: fmt.Sprintf("%s://%s.%s.svc:%d%s", dest.GetSchema().String(), s.GetName(), s.GetNamespace(), destPort, extension.Spec.GetRoute().GetPath()),
TLS: networkingApi.ArangoRouteStatusTargetTLS{
Insecure: extension.Spec.Destination.GetTLS().GetInsecure(),
},
},
}
if status.Targets.Hash() == targets.Hash() {
return &operator.Condition{
Status: true,
Reason: "Destination Found",
Message: "Destination Found",
Hash: targets.Hash(),
}, false, nil
}
status.Targets = targets
return &operator.Condition{
Status: true,
Reason: "Destination Found",
Message: "Destination Found",
Hash: targets.Hash(),
}, true, nil
}
}
return &operator.Condition{
Status: false,
Reason: "Destination Not Found",
Message: "Destination Not Found",
}, false, nil
}
func (h *handler) HandleArangoDestinationWithTargets(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus, depl *api.ArangoDeployment) (*operator.Condition, bool, error) {
c, changed, err := h.HandleArangoDestination(ctx, item, extension, status, depl)
if c == nil && !c.Status && status.Targets != nil {
status.Targets = nil
changed = true
}
return c, changed, err
}
func (h *handler) HandleDestinationRequired(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus, _ *api.ArangoDeployment) (bool, error) {
if !status.Conditions.IsTrue(networkingApi.DestinationValidCondition) {
return false, operator.Stop("Destination is not ready")
}
return false, nil
}

View file

@ -0,0 +1,422 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"testing"
"github.com/stretchr/testify/require"
core "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
)
func Test_Handler_Destination_Service_Missing(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Not Found")
require.EqualValues(t, c.Message, "Unknown error for service `fake/deployment`: services \"deployment\" not found")
}
func Test_Handler_Destination_Service_Valid(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
}
func Test_Handler_Destination_Service_ValidName(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromString("test")),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10241,
Name: "test1",
},
{
Port: 10244,
Name: "test",
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
}
func Test_Handler_Destination_Service_WrongPort(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10245,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Not Found")
require.EqualValues(t, c.Message, "Port `10244` not defined on Service `fake/deployment`")
}
func Test_Handler_Destination_Service_WrongPortName(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromString("test")),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10245,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.False(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Not Found")
require.EqualValues(t, c.Message, "Port `test` not defined on Service `fake/deployment`")
}
func Test_Handler_Destination_Service_Insecure_Default(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Testcense
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
require.Len(t, extension.Status.Targets, 1)
require.False(t, extension.Status.Targets[0].TLS.Insecure)
}
func Test_Handler_Destination_Service_Insecure_Nil(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
TLS: &networkingApi.ArangoRouteSpecDestinationTLS{
Insecure: nil,
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
require.Len(t, extension.Status.Targets, 1)
require.False(t, extension.Status.Targets[0].TLS.Insecure)
}
func Test_Handler_Destination_Service_Insecure_Override(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.DeploymentName = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
TLS: &networkingApi.ArangoRouteSpecDestinationTLS{
Insecure: util.NewType(true),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
require.Len(t, extension.Status.Targets, 1)
require.True(t, extension.Status.Targets[0].TLS.Insecure)
}

View file

@ -0,0 +1,59 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"testing"
"github.com/stretchr/testify/require"
apiErrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
)
func Test_ObjectNotFound(t *testing.T) {
// Arrange
handler := newFakeHandler()
i := newItem(operation.Add, "test", "test")
actions := map[operation.Operation]bool{
operation.Add: false,
operation.Update: false,
operation.Delete: false,
}
// Act
for op, shouldFail := range actions {
t.Run(string(op), func(t *testing.T) {
err := tests.Handle(handler, i)
// Assert
if shouldFail {
require.Error(t, err)
require.True(t, apiErrors.IsNotFound(err))
} else {
require.NoError(t, err)
}
})
}
}

View file

@ -0,0 +1,38 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"github.com/arangodb/kube-arangodb/pkg/apis/networking"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
)
func Kind() string {
return networking.ArangoRouteResourceKind
}
func Group() string {
return networkingApi.SchemeGroupVersion.Group
}
func Version() string {
return networkingApi.SchemeGroupVersion.Version
}

View file

@ -0,0 +1,60 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
arangoClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned"
arangoInformer "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions"
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/event"
)
// RegisterInformer into operator
func RegisterInformer(operator operator.Operator, recorder event.Recorder, client arangoClientSet.Interface,
kubeClient kubernetes.Interface, informer arangoInformer.SharedInformerFactory, kubeInformer informers.SharedInformerFactory) error {
if err := operator.RegisterInformer(informer.Networking().V1alpha1().ArangoRoutes().Informer(),
Group(),
Version(),
Kind()); err != nil {
return err
}
h := &handler{
client: client,
kubeClient: kubeClient,
eventRecorder: recorder.NewInstance(Group(), Version(), Kind()),
operator: operator,
}
h.init()
if err := operator.RegisterHandler(h); err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,61 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package route
import (
"k8s.io/client-go/kubernetes/fake"
"github.com/arangodb/kube-arangodb/pkg/apis/analytics"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
fakeClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/fake"
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/event"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
)
func newFakeHandler() *handler {
f := fakeClientSet.NewSimpleClientset()
k := fake.NewSimpleClientset()
h := &handler{
client: f,
kubeClient: k,
eventRecorder: event.NewEventRecorder("mock", k).NewInstance(Group(), Version(), Kind()),
operator: operator.NewOperator("mock", "mock", "mock"),
}
h.init()
return h
}
func newItem(o operation.Operation, namespace, name string) operation.Item {
return operation.Item{
Group: networkingApi.SchemeGroupVersion.Group,
Version: networkingApi.SchemeGroupVersion.Version,
Kind: analytics.GraphAnalyticsEngineResourceKind,
Operation: o,
Namespace: namespace,
Name: name,
}
}

View file

@ -37,6 +37,7 @@ import (
backupdef "github.com/arangodb/kube-arangodb/pkg/apis/backup"
depldef "github.com/arangodb/kube-arangodb/pkg/apis/deployment"
deplapi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/apis/networking"
repldef "github.com/arangodb/kube-arangodb/pkg/apis/replication"
replapi "github.com/arangodb/kube-arangodb/pkg/apis/replication/v1"
lsapi "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha"
@ -45,6 +46,7 @@ import (
arangoInformer "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions"
"github.com/arangodb/kube-arangodb/pkg/handlers/backup"
"github.com/arangodb/kube-arangodb/pkg/handlers/job"
"github.com/arangodb/kube-arangodb/pkg/handlers/networking/route"
"github.com/arangodb/kube-arangodb/pkg/handlers/policy"
"github.com/arangodb/kube-arangodb/pkg/logging"
"github.com/arangodb/kube-arangodb/pkg/operator/scope"
@ -71,6 +73,7 @@ const (
backupOperator operatorV2type = "backup"
mlOperator operatorV2type = "ml"
analyticsOperator operatorV2type = "analytics"
networkingOperator operatorV2type = "networking"
appsOperator operatorV2type = "apps"
)
@ -102,6 +105,7 @@ type Config struct {
EnableStorage bool
EnableML bool
EnableAnalytics bool
EnableNetworking bool
EnableBackup bool
EnableApps bool
EnableK2KClusterSync bool
@ -124,6 +128,7 @@ type Dependencies struct {
BackupProbe *probe.ReadyProbe
MlProbe *probe.ReadyProbe
AnalyticsProbe *probe.ReadyProbe
NetworkingProbe *probe.ReadyProbe
AppsProbe *probe.ReadyProbe
K2KClusterSyncProbe *probe.ReadyProbe
}
@ -192,6 +197,13 @@ func (o *Operator) Run() {
go o.runWithoutLeaderElection("arango-analytics-operator", constants.AnalyticsLabelRole, o.onStartAnalytics, o.Dependencies.AnalyticsProbe)
}
}
if o.Config.EnableNetworking {
if !o.Config.SingleMode {
go o.runLeaderElection("arango-networking-operator", constants.NetworkingLabelRole, o.onStartNetworking, o.Dependencies.NetworkingProbe)
} else {
go o.runWithoutLeaderElection("arango-networking-operator", constants.NetworkingLabelRole, o.onStartNetworking, o.Dependencies.NetworkingProbe)
}
}
if o.Config.EnableK2KClusterSync {
// Nothing to do
o.log.Warn("K2K Cluster sync is permanently disabled")
@ -262,6 +274,11 @@ func (o *Operator) onStartApps(stop <-chan struct{}) {
o.onStartOperatorV2(appsOperator, stop)
}
// onStartNetworking starts the operator and run till given channel is closed.
func (o *Operator) onStartNetworking(stop <-chan struct{}) {
o.onStartOperatorV2(networkingOperator, stop)
}
// onStartOperatorV2 run the operatorV2 type
func (o *Operator) onStartOperatorV2(operatorType operatorV2type, stop <-chan struct{}) {
operatorName := fmt.Sprintf("arangodb-%s-operator", operatorType)
@ -290,6 +307,9 @@ func (o *Operator) onStartOperatorV2(operatorType operatorV2type, stop <-chan st
case analyticsOperator:
o.onStartOperatorV2Analytics(operator, eventRecorder, o.Client.Arango(), o.Client.Kubernetes(), arangoInformer, kubeInformer)
o.Dependencies.AnalyticsProbe.SetReady()
case networkingOperator:
o.onStartOperatorV2Networking(operator, eventRecorder, o.Client.Arango(), o.Client.Kubernetes(), arangoInformer, kubeInformer)
o.Dependencies.NetworkingProbe.SetReady()
}
if err := operator.RegisterStarter(arangoInformer); err != nil {
@ -321,6 +341,18 @@ func (o *Operator) onStartOperatorV2Apps(operator operatorV2.Operator, recorder
}
}
func (o *Operator) onStartOperatorV2Networking(operator operatorV2.Operator, recorder event.Recorder, client arangoClientSet.Interface, kubeClient kubernetes.Interface, informer arangoInformer.SharedInformerFactory, kubeInformer informers.SharedInformerFactory) {
checkFn := func() error {
_, err := o.Client.Arango().NetworkingV1alpha1().ArangoRoutes(o.Namespace).List(context.Background(), meta.ListOptions{})
return err
}
o.waitForCRD(networking.ArangoRouteCRDName, checkFn)
if err := route.RegisterInformer(operator, recorder, client, kubeClient, informer, kubeInformer); err != nil {
panic(err)
}
}
func (o *Operator) onStartOperatorV2Backup(operator operatorV2.Operator, recorder event.Recorder, client arangoClientSet.Interface, kubeClient kubernetes.Interface, informer arangoInformer.SharedInformerFactory) {
checkFn := func() error {
_, err := o.Client.Arango().BackupV1().ArangoBackups(o.Namespace).List(context.Background(), meta.ListOptions{})

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -21,19 +21,26 @@
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type Condition struct {
Status bool
Reason string
Message string
Hash string
}
func WithCondition(conditions *api.ConditionList, condition api.ConditionType, changed bool, err error) (bool, error) {
var hash string
if changed || err != nil {
// Condition should be false
if conditions.Update(condition, false, "Not ready", "Not ready") {
if conditions.UpdateWithHash(condition, false, "Not ready", "Not ready", hash) {
changed = true
}
} else {
if conditions.Update(condition, true, "Ready", "Ready") {
if conditions.UpdateWithHash(condition, true, "Ready", "Ready", hash) {
changed = true
}
}
@ -47,234 +54,26 @@ func WithCondition(conditions *api.ConditionList, condition api.ConditionType, c
return changed, err
}
type HandleP0Func func(ctx context.Context) (bool, error)
func WithConditionChange(conditions *api.ConditionList, condition api.ConditionType, c *Condition, changed bool, err error) (bool, error) {
if c == nil {
if conditions.Remove(condition) {
changed = true
}
} else {
if conditions.UpdateWithHash(condition, c.Status, c.Reason, c.Message, c.Hash) {
changed = true
}
}
type HandleP1Func[P1 interface{}] func(ctx context.Context, p1 P1) (bool, error)
type HandleP2Func[P1, P2 interface{}] func(ctx context.Context, p1 P1, p2 P2) (bool, error)
type HandleP3Func[P1, P2, P3 interface{}] func(ctx context.Context, p1 P1, p2 P2, p3 P3) (bool, error)
type HandleP4Func[P1, P2, P3, P4 interface{}] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4) (bool, error)
type HandleP5Func[P1, P2, P3, P4, P5 interface{}] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5) (bool, error)
type HandleP6Func[P1, P2, P3, P4, P5, P6 interface{}] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6) (bool, error)
type HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9 interface{}] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9) (bool, error)
func HandleP0(ctx context.Context, handler ...HandleP0Func) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx)
if err == nil || IsStop(err) {
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
err = Reconcile("Condition changed")
}
}
return isChanged, nil
}
func HandleP1[P1 interface{}](ctx context.Context, p1 P1, handler ...HandleP1Func[P1]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP1WithStop[P1 interface{}](ctx context.Context, p1 P1, handler ...HandleP1Func[P1]) (bool, error) {
changed, err := HandleP1[P1](ctx, p1, handler...)
if IsStop(err) {
return changed, nil
if err == nil && changed {
err = Reconcile("Condition changed")
}
return changed, err
}
func HandleP2[P1, P2 interface{}](ctx context.Context, p1 P1, p2 P2, handler ...HandleP2Func[P1, P2]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP2WithStop[P1, P2 interface{}](ctx context.Context, p1 P1, p2 P2, handler ...HandleP2Func[P1, P2]) (bool, error) {
changed, err := HandleP2[P1, P2](ctx, p1, p2, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP3[P1, P2, P3 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, handler ...HandleP3Func[P1, P2, P3]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP3WithStop[P1, P2, P3 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, handler ...HandleP3Func[P1, P2, P3]) (bool, error) {
changed, err := HandleP3[P1, P2, P3](ctx, p1, p2, p3, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP3WithCondition[P1, P2, P3 interface{}](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, handler ...HandleP3Func[P1, P2, P3]) (bool, error) {
changed, err := HandleP3[P1, P2, P3](ctx, p1, p2, p3, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP4[P1, P2, P3, P4 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, handler ...HandleP4Func[P1, P2, P3, P4]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP4WithStop[P1, P2, P3, P4 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, handler ...HandleP4Func[P1, P2, P3, P4]) (bool, error) {
changed, err := HandleP4[P1, P2, P3, P4](ctx, p1, p2, p3, p4, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP4WithCondition[P1, P2, P3, P4 interface{}](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, handler ...HandleP4Func[P1, P2, P3, P4]) (bool, error) {
changed, err := HandleP4[P1, P2, P3, P4](ctx, p1, p2, p3, p4, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP5[P1, P2, P3, P4, P5 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, handler ...HandleP5Func[P1, P2, P3, P4, P5]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP5WithStop[P1, P2, P3, P4, P5 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, handler ...HandleP5Func[P1, P2, P3, P4, P5]) (bool, error) {
changed, err := HandleP5[P1, P2, P3, P4, P5](ctx, p1, p2, p3, p4, p5, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP5WithCondition[P1, P2, P3, P4, P5 interface{}](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, handler ...HandleP5Func[P1, P2, P3, P4, P5]) (bool, error) {
changed, err := HandleP5[P1, P2, P3, P4, P5](ctx, p1, p2, p3, p4, p5, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP6[P1, P2, P3, P4, P5, P6 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, handler ...HandleP6Func[P1, P2, P3, P4, P5, P6]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5, p6)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP6WithStop[P1, P2, P3, P4, P5, P6 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, handler ...HandleP6Func[P1, P2, P3, P4, P5, P6]) (bool, error) {
changed, err := HandleP6[P1, P2, P3, P4, P5, P6](ctx, p1, p2, p3, p4, p5, p6, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP6WithCondition[P1, P2, P3, P4, P5, P6 interface{}](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, handler ...HandleP6Func[P1, P2, P3, P4, P5, P6]) (bool, error) {
changed, err := HandleP6[P1, P2, P3, P4, P5, P6](ctx, p1, p2, p3, p4, p5, p6, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP9[P1, P2, P3, P4, P5, P6, P7, P8, P9 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9, handler ...HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP9WithStop[P1, P2, P3, P4, P5, P6, P7, P8, P9 interface{}](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9, handler ...HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9]) (bool, error) {
changed, err := HandleP9[P1, P2, P3, P4, P5, P6, P7, P8, P9](ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP9WithCondition[P1, P2, P3, P4, P5, P6, P7, P8, P9 interface{}](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9, handler ...HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9]) (bool, error) {
changed, err := HandleP9[P1, P2, P3, P4, P5, P6, P7, P8, P9](ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9, handler...)
return WithCondition(conditions, condition, changed, err)
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP0Func func(ctx context.Context) (bool, error)
type HandleP0ConditionFunc func(ctx context.Context) (*Condition, bool, error)
type HandleP0ConditionExtract func(ctx context.Context) *api.ConditionList
func HandleP0(ctx context.Context, handler ...HandleP0Func) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP0WithStop(ctx context.Context, handler ...HandleP0Func) (bool, error) {
changed, err := HandleP0(ctx, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP0WithCondition(ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, handler ...HandleP0Func) (bool, error) {
changed, err := HandleP0(ctx, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP0Condition(extract HandleP0ConditionExtract, condition api.ConditionType, handler HandleP0ConditionFunc) HandleP0Func {
return func(ctx context.Context) (bool, error) {
c, changed, err := handler(ctx)
return WithConditionChange(extract(ctx), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP1Func[P1 any] func(ctx context.Context, p1 P1) (bool, error)
type HandleP1ConditionFunc[P1 any] func(ctx context.Context, p1 P1) (*Condition, bool, error)
type HandleP1ConditionExtract[P1 any] func(ctx context.Context, p1 P1) *api.ConditionList
func HandleP1[P1 any](ctx context.Context, p1 P1, handler ...HandleP1Func[P1]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP1WithStop[P1 any](ctx context.Context, p1 P1, handler ...HandleP1Func[P1]) (bool, error) {
changed, err := HandleP1[P1](ctx, p1, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP1WithCondition[P1 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, handler ...HandleP1Func[P1]) (bool, error) {
changed, err := HandleP1[P1](ctx, p1, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP1Condition[P1 any](extract HandleP1ConditionExtract[P1], condition api.ConditionType, handler HandleP1ConditionFunc[P1]) HandleP1Func[P1] {
return func(ctx context.Context, p1 P1) (bool, error) {
c, changed, err := handler(ctx, p1)
return WithConditionChange(extract(ctx, p1), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP2Func[P1, P2 any] func(ctx context.Context, p1 P1, p2 P2) (bool, error)
type HandleP2ConditionFunc[P1, P2 any] func(ctx context.Context, p1 P1, p2 P2) (*Condition, bool, error)
type HandleP2ConditionExtract[P1, P2 any] func(ctx context.Context, p1 P1, p2 P2) *api.ConditionList
func HandleP2[P1, P2 any](ctx context.Context, p1 P1, p2 P2, handler ...HandleP2Func[P1, P2]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP2WithStop[P1, P2 any](ctx context.Context, p1 P1, p2 P2, handler ...HandleP2Func[P1, P2]) (bool, error) {
changed, err := HandleP2[P1, P2](ctx, p1, p2, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP2WithCondition[P1, P2 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, handler ...HandleP2Func[P1, P2]) (bool, error) {
changed, err := HandleP2[P1, P2](ctx, p1, p2, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP2Condition[P1, P2 any](extract HandleP2ConditionExtract[P1, P2], condition api.ConditionType, handler HandleP2ConditionFunc[P1, P2]) HandleP2Func[P1, P2] {
return func(ctx context.Context, p1 P1, p2 P2) (bool, error) {
c, changed, err := handler(ctx, p1, p2)
return WithConditionChange(extract(ctx, p1, p2), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP3Func[P1, P2, P3 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3) (bool, error)
type HandleP3ConditionFunc[P1, P2, P3 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3) (*Condition, bool, error)
type HandleP3ConditionExtract[P1, P2, P3 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3) *api.ConditionList
func HandleP3[P1, P2, P3 any](ctx context.Context, p1 P1, p2 P2, p3 P3, handler ...HandleP3Func[P1, P2, P3]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP3WithStop[P1, P2, P3 any](ctx context.Context, p1 P1, p2 P2, p3 P3, handler ...HandleP3Func[P1, P2, P3]) (bool, error) {
changed, err := HandleP3[P1, P2, P3](ctx, p1, p2, p3, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP3WithCondition[P1, P2, P3 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, handler ...HandleP3Func[P1, P2, P3]) (bool, error) {
changed, err := HandleP3[P1, P2, P3](ctx, p1, p2, p3, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP3Condition[P1, P2, P3 any](extract HandleP3ConditionExtract[P1, P2, P3], condition api.ConditionType, handler HandleP3ConditionFunc[P1, P2, P3]) HandleP3Func[P1, P2, P3] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3)
return WithConditionChange(extract(ctx, p1, p2, p3), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP4Func[P1, P2, P3, P4 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4) (bool, error)
type HandleP4ConditionFunc[P1, P2, P3, P4 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4) (*Condition, bool, error)
type HandleP4ConditionExtract[P1, P2, P3, P4 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4) *api.ConditionList
func HandleP4[P1, P2, P3, P4 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, handler ...HandleP4Func[P1, P2, P3, P4]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP4WithStop[P1, P2, P3, P4 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, handler ...HandleP4Func[P1, P2, P3, P4]) (bool, error) {
changed, err := HandleP4[P1, P2, P3, P4](ctx, p1, p2, p3, p4, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP4WithCondition[P1, P2, P3, P4 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, handler ...HandleP4Func[P1, P2, P3, P4]) (bool, error) {
changed, err := HandleP4[P1, P2, P3, P4](ctx, p1, p2, p3, p4, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP4Condition[P1, P2, P3, P4 any](extract HandleP4ConditionExtract[P1, P2, P3, P4], condition api.ConditionType, handler HandleP4ConditionFunc[P1, P2, P3, P4]) HandleP4Func[P1, P2, P3, P4] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3, p4)
return WithConditionChange(extract(ctx, p1, p2, p3, p4), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP5Func[P1, P2, P3, P4, P5 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5) (bool, error)
type HandleP5ConditionFunc[P1, P2, P3, P4, P5 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5) (*Condition, bool, error)
type HandleP5ConditionExtract[P1, P2, P3, P4, P5 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5) *api.ConditionList
func HandleP5[P1, P2, P3, P4, P5 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, handler ...HandleP5Func[P1, P2, P3, P4, P5]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP5WithStop[P1, P2, P3, P4, P5 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, handler ...HandleP5Func[P1, P2, P3, P4, P5]) (bool, error) {
changed, err := HandleP5[P1, P2, P3, P4, P5](ctx, p1, p2, p3, p4, p5, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP5WithCondition[P1, P2, P3, P4, P5 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, handler ...HandleP5Func[P1, P2, P3, P4, P5]) (bool, error) {
changed, err := HandleP5[P1, P2, P3, P4, P5](ctx, p1, p2, p3, p4, p5, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP5Condition[P1, P2, P3, P4, P5 any](extract HandleP5ConditionExtract[P1, P2, P3, P4, P5], condition api.ConditionType, handler HandleP5ConditionFunc[P1, P2, P3, P4, P5]) HandleP5Func[P1, P2, P3, P4, P5] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3, p4, p5)
return WithConditionChange(extract(ctx, p1, p2, p3, p4, p5), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP6Func[P1, P2, P3, P4, P5, P6 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6) (bool, error)
type HandleP6ConditionFunc[P1, P2, P3, P4, P5, P6 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6) (*Condition, bool, error)
type HandleP6ConditionExtract[P1, P2, P3, P4, P5, P6 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6) *api.ConditionList
func HandleP6[P1, P2, P3, P4, P5, P6 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, handler ...HandleP6Func[P1, P2, P3, P4, P5, P6]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5, p6)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP6WithStop[P1, P2, P3, P4, P5, P6 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, handler ...HandleP6Func[P1, P2, P3, P4, P5, P6]) (bool, error) {
changed, err := HandleP6[P1, P2, P3, P4, P5, P6](ctx, p1, p2, p3, p4, p5, p6, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP6WithCondition[P1, P2, P3, P4, P5, P6 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, handler ...HandleP6Func[P1, P2, P3, P4, P5, P6]) (bool, error) {
changed, err := HandleP6[P1, P2, P3, P4, P5, P6](ctx, p1, p2, p3, p4, p5, p6, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP6Condition[P1, P2, P3, P4, P5, P6 any](extract HandleP6ConditionExtract[P1, P2, P3, P4, P5, P6], condition api.ConditionType, handler HandleP6ConditionFunc[P1, P2, P3, P4, P5, P6]) HandleP6Func[P1, P2, P3, P4, P5, P6] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3, p4, p5, p6)
return WithConditionChange(extract(ctx, p1, p2, p3, p4, p5, p6), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP7Func[P1, P2, P3, P4, P5, P6, P7 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7) (bool, error)
type HandleP7ConditionFunc[P1, P2, P3, P4, P5, P6, P7 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7) (*Condition, bool, error)
type HandleP7ConditionExtract[P1, P2, P3, P4, P5, P6, P7 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7) *api.ConditionList
func HandleP7[P1, P2, P3, P4, P5, P6, P7 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, handler ...HandleP7Func[P1, P2, P3, P4, P5, P6, P7]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5, p6, p7)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP7WithStop[P1, P2, P3, P4, P5, P6, P7 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, handler ...HandleP7Func[P1, P2, P3, P4, P5, P6, P7]) (bool, error) {
changed, err := HandleP7[P1, P2, P3, P4, P5, P6, P7](ctx, p1, p2, p3, p4, p5, p6, p7, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP7WithCondition[P1, P2, P3, P4, P5, P6, P7 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, handler ...HandleP7Func[P1, P2, P3, P4, P5, P6, P7]) (bool, error) {
changed, err := HandleP7[P1, P2, P3, P4, P5, P6, P7](ctx, p1, p2, p3, p4, p5, p6, p7, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP7Condition[P1, P2, P3, P4, P5, P6, P7 any](extract HandleP7ConditionExtract[P1, P2, P3, P4, P5, P6, P7], condition api.ConditionType, handler HandleP7ConditionFunc[P1, P2, P3, P4, P5, P6, P7]) HandleP7Func[P1, P2, P3, P4, P5, P6, P7] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3, p4, p5, p6, p7)
return WithConditionChange(extract(ctx, p1, p2, p3, p4, p5, p6, p7), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP8Func[P1, P2, P3, P4, P5, P6, P7, P8 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8) (bool, error)
type HandleP8ConditionFunc[P1, P2, P3, P4, P5, P6, P7, P8 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8) (*Condition, bool, error)
type HandleP8ConditionExtract[P1, P2, P3, P4, P5, P6, P7, P8 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8) *api.ConditionList
func HandleP8[P1, P2, P3, P4, P5, P6, P7, P8 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, handler ...HandleP8Func[P1, P2, P3, P4, P5, P6, P7, P8]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5, p6, p7, p8)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP8WithStop[P1, P2, P3, P4, P5, P6, P7, P8 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, handler ...HandleP8Func[P1, P2, P3, P4, P5, P6, P7, P8]) (bool, error) {
changed, err := HandleP8[P1, P2, P3, P4, P5, P6, P7, P8](ctx, p1, p2, p3, p4, p5, p6, p7, p8, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP8WithCondition[P1, P2, P3, P4, P5, P6, P7, P8 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, handler ...HandleP8Func[P1, P2, P3, P4, P5, P6, P7, P8]) (bool, error) {
changed, err := HandleP8[P1, P2, P3, P4, P5, P6, P7, P8](ctx, p1, p2, p3, p4, p5, p6, p7, p8, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP8Condition[P1, P2, P3, P4, P5, P6, P7, P8 any](extract HandleP8ConditionExtract[P1, P2, P3, P4, P5, P6, P7, P8], condition api.ConditionType, handler HandleP8ConditionFunc[P1, P2, P3, P4, P5, P6, P7, P8]) HandleP8Func[P1, P2, P3, P4, P5, P6, P7, P8] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3, p4, p5, p6, p7, p8)
return WithConditionChange(extract(ctx, p1, p2, p3, p4, p5, p6, p7, p8), condition, c, changed, err)
}
}

View file

@ -0,0 +1,70 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package operator
import (
"context"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
)
type HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9) (bool, error)
type HandleP9ConditionFunc[P1, P2, P3, P4, P5, P6, P7, P8, P9 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9) (*Condition, bool, error)
type HandleP9ConditionExtract[P1, P2, P3, P4, P5, P6, P7, P8, P9 any] func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9) *api.ConditionList
func HandleP9[P1, P2, P3, P4, P5, P6, P7, P8, P9 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9, handler ...HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9]) (bool, error) {
isChanged := false
for _, h := range handler {
changed, err := h(ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9)
if changed {
isChanged = true
}
if err != nil {
return isChanged, err
}
}
return isChanged, nil
}
func HandleP9WithStop[P1, P2, P3, P4, P5, P6, P7, P8, P9 any](ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9, handler ...HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9]) (bool, error) {
changed, err := HandleP9[P1, P2, P3, P4, P5, P6, P7, P8, P9](ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9, handler...)
if IsStop(err) {
return changed, nil
}
return changed, err
}
func HandleP9WithCondition[P1, P2, P3, P4, P5, P6, P7, P8, P9 any](ctx context.Context, conditions *api.ConditionList, condition api.ConditionType, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9, handler ...HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9]) (bool, error) {
changed, err := HandleP9[P1, P2, P3, P4, P5, P6, P7, P8, P9](ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9, handler...)
return WithCondition(conditions, condition, changed, err)
}
func HandleP9Condition[P1, P2, P3, P4, P5, P6, P7, P8, P9 any](extract HandleP9ConditionExtract[P1, P2, P3, P4, P5, P6, P7, P8, P9], condition api.ConditionType, handler HandleP9ConditionFunc[P1, P2, P3, P4, P5, P6, P7, P8, P9]) HandleP9Func[P1, P2, P3, P4, P5, P6, P7, P8, P9] {
return func(ctx context.Context, p1 P1, p2 P2, p3 P3, p4 P4, p5 P5, p6 P6, p7 P7, p8 P8, p9 P9) (bool, error) {
c, changed, err := handler(ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9)
return WithConditionChange(extract(ctx, p1, p2, p3, p4, p5, p6, p7, p8, p9), condition, c, changed, err)
}
}

View file

@ -29,6 +29,7 @@ import (
backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1"
mlApiv1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1alpha1"
mlApi "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1beta1"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
)
func WithArangoBackupUpdateStatusInterfaceRetry(ctx context.Context, client UpdateStatusInterface[backupApi.ArangoBackupStatus, *backupApi.ArangoBackup], obj *backupApi.ArangoBackup, status backupApi.ArangoBackupStatus, opts meta.UpdateOptions) (*backupApi.ArangoBackup, error) {
@ -51,6 +52,10 @@ func WithAnalyticsGAEUpdateStatusInterfaceRetry(ctx context.Context, client Upda
return WithUpdateStatusInterfaceRetry[analyticsApi.GraphAnalyticsEngineStatus, *analyticsApi.GraphAnalyticsEngine](ctx, client, obj, status, opts)
}
func WithNetworkingArangoRouteUpdateStatusInterfaceRetry(ctx context.Context, client UpdateStatusInterface[networkingApi.ArangoRouteStatus, *networkingApi.ArangoRoute], obj *networkingApi.ArangoRoute, status networkingApi.ArangoRouteStatus, opts meta.UpdateOptions) (*networkingApi.ArangoRoute, error) {
return WithUpdateStatusInterfaceRetry[networkingApi.ArangoRouteStatus, *networkingApi.ArangoRoute](ctx, client, obj, status, opts)
}
func WithArangoStorageUpdateStatusInterfaceRetry(ctx context.Context, client UpdateStatusInterface[mlApi.ArangoMLStorageStatus, *mlApi.ArangoMLStorage], obj *mlApi.ArangoMLStorage, status mlApi.ArangoMLStorageStatus, opts meta.UpdateOptions) (*mlApi.ArangoMLStorage, error) {
return WithUpdateStatusInterfaceRetry[mlApi.ArangoMLStorageStatus, *mlApi.ArangoMLStorage](ctx, client, obj, status, opts)
}

View file

@ -70,6 +70,7 @@ type Dependencies struct {
Apps OperatorDependency
ML OperatorDependency
Analytics OperatorDependency
Networking OperatorDependency
ClusterSync OperatorDependency
Operators Operators
Secrets typedCore.SecretInterface
@ -194,6 +195,10 @@ func NewServer(cli typedCore.CoreV1Interface, cfg Config, deps Dependencies) (*S
r.GET("/ready/analytics", gin.WrapF(deps.Analytics.Probe.ReadyHandler))
readyProbes = append(readyProbes, deps.Analytics.Probe)
}
if deps.Networking.Enabled {
r.GET("/ready/networking", gin.WrapF(deps.Networking.Probe.ReadyHandler))
readyProbes = append(readyProbes, deps.Networking.Probe)
}
r.GET("/ready", gin.WrapF(ready(readyProbes...)))
r.GET("/metrics", gin.WrapF(metrics.Handler()))
r.POST("/login", s.auth.handleLogin)

View file

@ -26,8 +26,28 @@ import (
"fmt"
"k8s.io/apimachinery/pkg/util/json"
"github.com/arangodb/kube-arangodb/pkg/util/strings"
)
type Hash interface {
Hash() string
}
func SHA256FromExtract[T any](extract func(T) string, obj ...T) string {
return SHA256FromStringArray(strings.Join(FormatList(obj, extract), "|"))
}
func SHA256FromHashArray[T Hash](data []T) string {
return SHA256FromExtract(func(t T) string {
return t.Hash()
}, data...)
}
func SHA256FromStringArray(data ...string) string {
return SHA256FromString(strings.Join(data, "|"))
}
func SHA256FromString(data string) string {
return SHA256([]byte(data))
}

View file

@ -73,6 +73,7 @@ const (
BackupLabelRole = "backup/role"
MLLabelRole = "ml/role"
AnalyticsLabelRole = "analytics/role"
NetworkingLabelRole = "networking/role"
AppsLabelRole = "apps/role"
ClusterSyncLabelRole = "clustersync/role"
LabelRole = "role"

View file

@ -21,6 +21,7 @@
package util
import (
"maps"
"reflect"
"sort"
)
@ -50,7 +51,7 @@ func CopyFullMap[K comparable, V any](src map[K]V) map[K]V {
r := map[K]V{}
CopyMap(r, src)
maps.Copy(r, src)
return r
}
@ -73,13 +74,6 @@ func MergeMaps[K comparable, V any](override bool, maps ...map[K]V) map[K]V {
return r
}
func CopyMap[K comparable, V any](dst, src map[K]V) {
// TODO: replace with maps.Copy when switching to go1.21
for k, v := range src {
dst[k] = v
}
}
func IterateSorted[V any](m map[string]V, cb func(string, V)) {
for _, k := range SortKeys(m) {
cb(k, m[k])

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ package util
import "sort"
type List[T any] []T
type List[T comparable] []T
func (l List[T]) Filter(fn func(T) bool) List[T] {
if l == nil {
@ -57,6 +57,16 @@ func (l List[T]) Sort(fn func(T, T) bool) List[T] {
return clone
}
func PickFromList[V any](in []V, q func(v V) bool) (V, bool) {
for _, v := range in {
if q(v) {
return v, true
}
}
return Default[V](), false
}
func MapList[T, V comparable](in List[T], fn func(T) V) List[V] {
if in == nil {
return nil
@ -67,3 +77,27 @@ func MapList[T, V comparable](in List[T], fn func(T) V) List[V] {
}
return result
}
func FormatList[A, B any](in []A, format func(A) B) []B {
var r = make([]B, len(in))
for id := range in {
r[id] = format(in[id])
}
return r
}
func FormatListErr[A, B any](in []A, format func(A) (B, error)) ([]B, error) {
var r = make([]B, len(in))
for id := range in {
if o, err := format(in[id]); err != nil {
return nil, err
} else {
r[id] = o
}
}
return r, nil
}

View file

@ -45,6 +45,8 @@ import (
"github.com/arangodb/kube-arangodb/pkg/apis/ml"
mlApiv1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1alpha1"
mlApi "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1beta1"
"github.com/arangodb/kube-arangodb/pkg/apis/networking"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
"github.com/arangodb/kube-arangodb/pkg/apis/scheduler"
schedulerApiv1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1"
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
@ -243,6 +245,12 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
vl := *v
_, err := arango.AnalyticsV1alpha1().GraphAnalyticsEngines(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
require.NoError(t, err)
case **networkingApi.ArangoRoute:
require.NotNil(t, v)
vl := *v
_, err := arango.NetworkingV1alpha1().ArangoRoutes(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
require.NoError(t, err)
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}
@ -397,6 +405,12 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
vl := *v
_, err := arango.AnalyticsV1alpha1().GraphAnalyticsEngines(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
require.NoError(t, err)
case **networkingApi.ArangoRoute:
require.NotNil(t, v)
vl := *v
_, err := arango.NetworkingV1alpha1().ArangoRoutes(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
require.NoError(t, err)
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}
@ -525,6 +539,11 @@ func DeleteObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
vl := *v
require.NoError(t, arango.AnalyticsV1alpha1().GraphAnalyticsEngines(vl.GetNamespace()).Delete(context.Background(), vl.GetName(), meta.DeleteOptions{}))
case **networkingApi.ArangoRoute:
require.NotNil(t, v)
vl := *v
require.NoError(t, arango.NetworkingV1alpha1().ArangoRoutes(vl.GetNamespace()).Delete(context.Background(), vl.GetName(), meta.DeleteOptions{}))
default:
require.Fail(t, fmt.Sprintf("Unable to delete object: %s", reflect.TypeOf(v).String()))
}
@ -882,6 +901,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
} else {
*v = vn
}
case **networkingApi.ArangoRoute:
require.NotNil(t, v)
vl := *v
vn, err := arango.NetworkingV1alpha1().ArangoRoutes(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
if err != nil {
if kerrors.IsNotFound(err) {
*v = nil
} else {
require.NoError(t, err)
}
} else {
*v = vn
}
default:
require.Fail(t, fmt.Sprintf("Unable to get object: %s", reflect.TypeOf(v).String()))
}
@ -1054,6 +1088,14 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
analytics.GraphAnalyticsEngineResourcePlural,
object.GetNamespace(),
object.GetName()))
case *networkingApi.ArangoRoute:
v.Kind = networking.ArangoRouteResourceKind
v.APIVersion = networkingApi.SchemeGroupVersion.String()
v.SetSelfLink(fmt.Sprintf("/api/%s/%s/%s/%s",
networkingApi.SchemeGroupVersion.String(),
networking.ArangoRouteResourcePlural,
object.GetNamespace(),
object.GetName()))
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
}
@ -1230,6 +1272,12 @@ func GVK(t *testing.T, object meta.Object) schema.GroupVersionKind {
Version: analyticsApi.ArangoAnalyticsVersion,
Kind: analytics.GraphAnalyticsEngineResourceKind,
}
case *networkingApi.ArangoRoute:
return schema.GroupVersionKind{
Group: networking.ArangoNetworkingGroupName,
Version: networkingApi.ArangoNetworkingVersion,
Kind: networking.ArangoRouteResourceKind,
}
default:
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
return schema.GroupVersionKind{}

View file

@ -36,6 +36,7 @@ import (
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
mlApiv1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1alpha1"
mlApi "github.com/arangodb/kube-arangodb/pkg/apis/ml/v1beta1"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
@ -87,4 +88,5 @@ func Test_NewMetaObject(t *testing.T) {
NewMetaObjectRun[*mlApiv1alpha1.ArangoMLCronJob](t)
NewMetaObjectRun[*schedulerApi.ArangoProfile](t)
NewMetaObjectRun[*analyticsApi.GraphAnalyticsEngine](t)
NewMetaObjectRun[*networkingApi.ArangoRoute](t)
}