mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] Envoy Config Update (#1711)
This commit is contained in:
parent
2a62af3d23
commit
1095567432
75 changed files with 4887 additions and 937 deletions
|
@ -19,6 +19,7 @@
|
||||||
- (Feature) PongV1 Integration Service
|
- (Feature) PongV1 Integration Service
|
||||||
- (Feature) Custom Gateway image
|
- (Feature) Custom Gateway image
|
||||||
- (Bugfix) Fix race condition in ArangoBackup
|
- (Bugfix) Fix race condition in ArangoBackup
|
||||||
|
- (Feature) Improve Gateway Config gen
|
||||||
|
|
||||||
## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23)
|
## [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
|
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -803,10 +803,12 @@ set-typed-api-version/%:
|
||||||
"$(ROOT)/pkg/deployment/" \
|
"$(ROOT)/pkg/deployment/" \
|
||||||
"$(ROOT)/pkg/replication/" \
|
"$(ROOT)/pkg/replication/" \
|
||||||
"$(ROOT)/pkg/operator/" \
|
"$(ROOT)/pkg/operator/" \
|
||||||
|
"$(ROOT)/pkg/operatorV2/" \
|
||||||
"$(ROOT)/pkg/server/" \
|
"$(ROOT)/pkg/server/" \
|
||||||
"$(ROOT)/pkg/util/" \
|
"$(ROOT)/pkg/util/" \
|
||||||
"$(ROOT)/pkg/handlers/" \
|
"$(ROOT)/pkg/handlers/" \
|
||||||
"$(ROOT)/pkg/apis/backup/" \
|
"$(ROOT)/pkg/apis/backup/" \
|
||||||
|
"$(ROOT)/pkg/apis/networking/" \
|
||||||
"$(ROOT)/pkg/upgrade/" \
|
"$(ROOT)/pkg/upgrade/" \
|
||||||
| cut -d ':' -f 1 | sort | uniq \
|
| cut -d ':' -f 1 | sort | uniq \
|
||||||
| xargs -n 1 $(SED) -i "s#github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/$*/v[A-Za-z0-9]\+#github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/$*/v$(API_VERSION)#g"
|
| xargs -n 1 $(SED) -i "s#github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/$*/v[A-Za-z0-9]\+#github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/typed/$*/v$(API_VERSION)#g"
|
||||||
|
@ -817,10 +819,12 @@ set-api-version/%:
|
||||||
"$(ROOT)/pkg/deployment/" \
|
"$(ROOT)/pkg/deployment/" \
|
||||||
"$(ROOT)/pkg/replication/" \
|
"$(ROOT)/pkg/replication/" \
|
||||||
"$(ROOT)/pkg/operator/" \
|
"$(ROOT)/pkg/operator/" \
|
||||||
|
"$(ROOT)/pkg/operatorV2/" \
|
||||||
"$(ROOT)/pkg/server/" \
|
"$(ROOT)/pkg/server/" \
|
||||||
"$(ROOT)/pkg/util/" \
|
"$(ROOT)/pkg/util/" \
|
||||||
"$(ROOT)/pkg/handlers/" \
|
"$(ROOT)/pkg/handlers/" \
|
||||||
"$(ROOT)/pkg/apis/backup/" \
|
"$(ROOT)/pkg/apis/backup/" \
|
||||||
|
"$(ROOT)/pkg/apis/networking/" \
|
||||||
"$(ROOT)/pkg/upgrade/" \
|
"$(ROOT)/pkg/upgrade/" \
|
||||||
| cut -d ':' -f 1 | sort | uniq \
|
| cut -d ':' -f 1 | sort | uniq \
|
||||||
| xargs -n 1 $(SED) -i "s#github.com/arangodb/kube-arangodb/pkg/apis/$*/v[A-Za-z0-9]\+#github.com/arangodb/kube-arangodb/pkg/apis/$*/v$(API_VERSION)#g"
|
| xargs -n 1 $(SED) -i "s#github.com/arangodb/kube-arangodb/pkg/apis/$*/v[A-Za-z0-9]\+#github.com/arangodb/kube-arangodb/pkg/apis/$*/v$(API_VERSION)#g"
|
||||||
|
@ -828,10 +832,12 @@ set-api-version/%:
|
||||||
"$(ROOT)/pkg/deployment/" \
|
"$(ROOT)/pkg/deployment/" \
|
||||||
"$(ROOT)/pkg/replication/" \
|
"$(ROOT)/pkg/replication/" \
|
||||||
"$(ROOT)/pkg/operator/" \
|
"$(ROOT)/pkg/operator/" \
|
||||||
|
"$(ROOT)/pkg/operatorV2/" \
|
||||||
"$(ROOT)/pkg/server/" \
|
"$(ROOT)/pkg/server/" \
|
||||||
"$(ROOT)/pkg/util/" \
|
"$(ROOT)/pkg/util/" \
|
||||||
"$(ROOT)/pkg/handlers/" \
|
"$(ROOT)/pkg/handlers/" \
|
||||||
"$(ROOT)/pkg/apis/backup/" \
|
"$(ROOT)/pkg/apis/backup/" \
|
||||||
|
"$(ROOT)/pkg/apis/networking/" \
|
||||||
"$(ROOT)/pkg/upgrade/" \
|
"$(ROOT)/pkg/upgrade/" \
|
||||||
| cut -d ':' -f 1 | sort | uniq \
|
| cut -d ':' -f 1 | sort | uniq \
|
||||||
| xargs -n 1 $(SED) -i "s#DatabaseV[A-Za-z0-9]\+()\.#DatabaseV$(API_VERSION)().#g"
|
| xargs -n 1 $(SED) -i "s#DatabaseV[A-Za-z0-9]\+()\.#DatabaseV$(API_VERSION)().#g"
|
||||||
|
@ -839,10 +845,12 @@ set-api-version/%:
|
||||||
"$(ROOT)/pkg/deployment/" \
|
"$(ROOT)/pkg/deployment/" \
|
||||||
"$(ROOT)/pkg/replication/" \
|
"$(ROOT)/pkg/replication/" \
|
||||||
"$(ROOT)/pkg/operator/" \
|
"$(ROOT)/pkg/operator/" \
|
||||||
|
"$(ROOT)/pkg/operatorV2/" \
|
||||||
"$(ROOT)/pkg/server/" \
|
"$(ROOT)/pkg/server/" \
|
||||||
"$(ROOT)/pkg/util/" \
|
"$(ROOT)/pkg/util/" \
|
||||||
"$(ROOT)/pkg/handlers" \
|
"$(ROOT)/pkg/handlers" \
|
||||||
"$(ROOT)/pkg/apis/backup/" \
|
"$(ROOT)/pkg/apis/backup/" \
|
||||||
|
"$(ROOT)/pkg/apis/networking/" \
|
||||||
"$(ROOT)/pkg/upgrade/" \
|
"$(ROOT)/pkg/upgrade/" \
|
||||||
| cut -d ':' -f 1 | sort | uniq \
|
| cut -d ':' -f 1 | sort | uniq \
|
||||||
| xargs -n 1 $(SED) -i "s#ReplicationV[A-Za-z0-9]\+()\.#ReplicationV$(API_VERSION)().#g"
|
| xargs -n 1 $(SED) -i "s#ReplicationV[A-Za-z0-9]\+()\.#ReplicationV$(API_VERSION)().#g"
|
||||||
|
|
|
@ -13,19 +13,61 @@ metadata:
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
release: {{ .Release.Name }}
|
release: {{ .Release.Name }}
|
||||||
rules:
|
rules:
|
||||||
|
# analytics.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "graphanalyticsengines.analytics.arangodb.com"
|
||||||
|
# apps.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangojobs.apps.arangodb.com"
|
||||||
|
# backup.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangobackuppolicies.backup.arangodb.com"
|
||||||
|
- "arangobackups.backup.arangodb.com"
|
||||||
|
# database.arangodb.com
|
||||||
- apiGroups: ["apiextensions.k8s.io"]
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
resources: ["customresourcedefinitions"]
|
resources: ["customresourcedefinitions"]
|
||||||
verbs: ["get", "list", "watch", "update", "delete"]
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
resourceNames:
|
resourceNames:
|
||||||
- "arangodeployments.database.arangodb.com"
|
|
||||||
- "arangoclustersynchronizations.database.arangodb.com"
|
- "arangoclustersynchronizations.database.arangodb.com"
|
||||||
|
- "arangodeployments.database.arangodb.com"
|
||||||
- "arangomembers.database.arangodb.com"
|
- "arangomembers.database.arangodb.com"
|
||||||
- "arangotasks.database.arangodb.com"
|
- "arangotasks.database.arangodb.com"
|
||||||
|
# ml.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangomlbatchjobs.ml.arangodb.com"
|
||||||
|
- "arangomlcronjobs.ml.arangodb.com"
|
||||||
|
- "arangomlextensions.ml.arangodb.com"
|
||||||
|
- "arangomlstorages.ml.arangodb.com"
|
||||||
|
# networking.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoroutes.networking.arangodb.com"
|
||||||
|
# replication.database.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
- "arangodeploymentreplications.replication.database.arangodb.com"
|
- "arangodeploymentreplications.replication.database.arangodb.com"
|
||||||
- "arangobackups.backup.arangodb.com"
|
# scheduler.arangodb.com
|
||||||
- "arangobackuppolicies.backup.arangodb.com"
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
- "arangojobs.apps.arangodb.com"
|
resources: ["customresourcedefinitions"]
|
||||||
- "arangolocalstorages.storage.arangodb.com"
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoprofiles.scheduler.arangodb.com"
|
||||||
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -13,19 +13,61 @@ metadata:
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
release: {{ .Release.Name }}
|
release: {{ .Release.Name }}
|
||||||
rules:
|
rules:
|
||||||
|
# analytics.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "graphanalyticsengines.analytics.arangodb.com"
|
||||||
|
# apps.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangojobs.apps.arangodb.com"
|
||||||
|
# backup.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangobackuppolicies.backup.arangodb.com"
|
||||||
|
- "arangobackups.backup.arangodb.com"
|
||||||
|
# database.arangodb.com
|
||||||
- apiGroups: ["apiextensions.k8s.io"]
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
resources: ["customresourcedefinitions"]
|
resources: ["customresourcedefinitions"]
|
||||||
verbs: ["get", "list", "watch", "update", "delete"]
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
resourceNames:
|
resourceNames:
|
||||||
- "arangodeployments.database.arangodb.com"
|
|
||||||
- "arangoclustersynchronizations.database.arangodb.com"
|
- "arangoclustersynchronizations.database.arangodb.com"
|
||||||
|
- "arangodeployments.database.arangodb.com"
|
||||||
- "arangomembers.database.arangodb.com"
|
- "arangomembers.database.arangodb.com"
|
||||||
- "arangotasks.database.arangodb.com"
|
- "arangotasks.database.arangodb.com"
|
||||||
|
# ml.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangomlbatchjobs.ml.arangodb.com"
|
||||||
|
- "arangomlcronjobs.ml.arangodb.com"
|
||||||
|
- "arangomlextensions.ml.arangodb.com"
|
||||||
|
- "arangomlstorages.ml.arangodb.com"
|
||||||
|
# networking.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoroutes.networking.arangodb.com"
|
||||||
|
# replication.database.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
- "arangodeploymentreplications.replication.database.arangodb.com"
|
- "arangodeploymentreplications.replication.database.arangodb.com"
|
||||||
- "arangobackups.backup.arangodb.com"
|
# scheduler.arangodb.com
|
||||||
- "arangobackuppolicies.backup.arangodb.com"
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
- "arangojobs.apps.arangodb.com"
|
resources: ["customresourcedefinitions"]
|
||||||
- "arangolocalstorages.storage.arangodb.com"
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoprofiles.scheduler.arangodb.com"
|
||||||
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -13,19 +13,61 @@ metadata:
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
release: {{ .Release.Name }}
|
release: {{ .Release.Name }}
|
||||||
rules:
|
rules:
|
||||||
|
# analytics.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "graphanalyticsengines.analytics.arangodb.com"
|
||||||
|
# apps.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangojobs.apps.arangodb.com"
|
||||||
|
# backup.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangobackuppolicies.backup.arangodb.com"
|
||||||
|
- "arangobackups.backup.arangodb.com"
|
||||||
|
# database.arangodb.com
|
||||||
- apiGroups: ["apiextensions.k8s.io"]
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
resources: ["customresourcedefinitions"]
|
resources: ["customresourcedefinitions"]
|
||||||
verbs: ["get", "list", "watch", "update", "delete"]
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
resourceNames:
|
resourceNames:
|
||||||
- "arangodeployments.database.arangodb.com"
|
|
||||||
- "arangoclustersynchronizations.database.arangodb.com"
|
- "arangoclustersynchronizations.database.arangodb.com"
|
||||||
|
- "arangodeployments.database.arangodb.com"
|
||||||
- "arangomembers.database.arangodb.com"
|
- "arangomembers.database.arangodb.com"
|
||||||
- "arangotasks.database.arangodb.com"
|
- "arangotasks.database.arangodb.com"
|
||||||
|
# ml.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangomlbatchjobs.ml.arangodb.com"
|
||||||
|
- "arangomlcronjobs.ml.arangodb.com"
|
||||||
|
- "arangomlextensions.ml.arangodb.com"
|
||||||
|
- "arangomlstorages.ml.arangodb.com"
|
||||||
|
# networking.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoroutes.networking.arangodb.com"
|
||||||
|
# replication.database.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
- "arangodeploymentreplications.replication.database.arangodb.com"
|
- "arangodeploymentreplications.replication.database.arangodb.com"
|
||||||
- "arangobackups.backup.arangodb.com"
|
# scheduler.arangodb.com
|
||||||
- "arangobackuppolicies.backup.arangodb.com"
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
- "arangojobs.apps.arangodb.com"
|
resources: ["customresourcedefinitions"]
|
||||||
- "arangolocalstorages.storage.arangodb.com"
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoprofiles.scheduler.arangodb.com"
|
||||||
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -13,19 +13,61 @@ metadata:
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
release: {{ .Release.Name }}
|
release: {{ .Release.Name }}
|
||||||
rules:
|
rules:
|
||||||
|
# analytics.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "graphanalyticsengines.analytics.arangodb.com"
|
||||||
|
# apps.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangojobs.apps.arangodb.com"
|
||||||
|
# backup.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangobackuppolicies.backup.arangodb.com"
|
||||||
|
- "arangobackups.backup.arangodb.com"
|
||||||
|
# database.arangodb.com
|
||||||
- apiGroups: ["apiextensions.k8s.io"]
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
resources: ["customresourcedefinitions"]
|
resources: ["customresourcedefinitions"]
|
||||||
verbs: ["get", "list", "watch", "update", "delete"]
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
resourceNames:
|
resourceNames:
|
||||||
- "arangodeployments.database.arangodb.com"
|
|
||||||
- "arangoclustersynchronizations.database.arangodb.com"
|
- "arangoclustersynchronizations.database.arangodb.com"
|
||||||
|
- "arangodeployments.database.arangodb.com"
|
||||||
- "arangomembers.database.arangodb.com"
|
- "arangomembers.database.arangodb.com"
|
||||||
- "arangotasks.database.arangodb.com"
|
- "arangotasks.database.arangodb.com"
|
||||||
|
# ml.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangomlbatchjobs.ml.arangodb.com"
|
||||||
|
- "arangomlcronjobs.ml.arangodb.com"
|
||||||
|
- "arangomlextensions.ml.arangodb.com"
|
||||||
|
- "arangomlstorages.ml.arangodb.com"
|
||||||
|
# networking.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoroutes.networking.arangodb.com"
|
||||||
|
# replication.database.arangodb.com
|
||||||
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
|
resources: ["customresourcedefinitions"]
|
||||||
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
- "arangodeploymentreplications.replication.database.arangodb.com"
|
- "arangodeploymentreplications.replication.database.arangodb.com"
|
||||||
- "arangobackups.backup.arangodb.com"
|
# scheduler.arangodb.com
|
||||||
- "arangobackuppolicies.backup.arangodb.com"
|
- apiGroups: ["apiextensions.k8s.io"]
|
||||||
- "arangojobs.apps.arangodb.com"
|
resources: ["customresourcedefinitions"]
|
||||||
- "arangolocalstorages.storage.arangodb.com"
|
verbs: ["get", "list", "watch", "update", "delete"]
|
||||||
|
resourceNames:
|
||||||
|
- "arangoprofiles.scheduler.arangodb.com"
|
||||||
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -3045,7 +3045,7 @@ Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.
|
||||||
|
|
||||||
### .spec.gateway.enabled
|
### .spec.gateway.enabled
|
||||||
|
|
||||||
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/deployment/v1/deployment_spec_gateway.go#L29)</sup>
|
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/deployment/v1/deployment_spec_gateway.go#L33)</sup>
|
||||||
|
|
||||||
Enabled setting enables/disables support for gateway in the cluster.
|
Enabled setting enables/disables support for gateway in the cluster.
|
||||||
When enabled, the cluster will contain a number of `gateway` servers.
|
When enabled, the cluster will contain a number of `gateway` servers.
|
||||||
|
@ -3056,13 +3056,205 @@ Default Value: `false`
|
||||||
|
|
||||||
### .spec.gateway.image
|
### .spec.gateway.image
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/deployment/v1/deployment_spec_gateway.go#L33)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/deployment/v1/deployment_spec_gateway.go#L37)</sup>
|
||||||
|
|
||||||
Image is the image to use for the gateway.
|
Image is the image to use for the gateway.
|
||||||
By default, the image is determined by the operator.
|
By default, the image is determined by the operator.
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.args
|
||||||
|
|
||||||
|
Type: `array` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/core.go#L50)</sup>
|
||||||
|
|
||||||
|
Arguments to the entrypoint.
|
||||||
|
The container image's CMD is used if this is not provided.
|
||||||
|
Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
|
||||||
|
cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
|
||||||
|
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
|
||||||
|
produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless
|
||||||
|
of whether the variable exists or not. Cannot be updated.
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes Docs](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.command
|
||||||
|
|
||||||
|
Type: `array` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/core.go#L40)</sup>
|
||||||
|
|
||||||
|
Entrypoint array. Not executed within a shell.
|
||||||
|
The container image's ENTRYPOINT is used if this is not provided.
|
||||||
|
Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
|
||||||
|
cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
|
||||||
|
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
|
||||||
|
produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless
|
||||||
|
of whether the variable exists or not. Cannot be updated.
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes Docs](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.controllerListenPort
|
||||||
|
|
||||||
|
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/integration.go#L36)</sup>
|
||||||
|
|
||||||
|
ControllerListenPort defines on which port the sidecar container will be listening for controller requests
|
||||||
|
|
||||||
|
Default Value: `9202`
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.env
|
||||||
|
|
||||||
|
Type: `core.EnvVar` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/environments.go#L36)</sup>
|
||||||
|
|
||||||
|
Env keeps the information about environment variables provided to the container
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes Docs](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#envvar-v1-core)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.envFrom
|
||||||
|
|
||||||
|
Type: `core.EnvFromSource` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/environments.go#L41)</sup>
|
||||||
|
|
||||||
|
EnvFrom keeps the information about environment variable sources provided to the container
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes Docs](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#envfromsource-v1-core)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.image
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/image.go#L35)</sup>
|
||||||
|
|
||||||
|
Image define image details
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.imagePullPolicy
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/image.go#L39)</sup>
|
||||||
|
|
||||||
|
ImagePullPolicy define Image pull policy
|
||||||
|
|
||||||
|
Default Value: `IfNotPresent`
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.lifecycle
|
||||||
|
|
||||||
|
Type: `core.Lifecycle` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/lifecycle.go#L35)</sup>
|
||||||
|
|
||||||
|
Lifecycle keeps actions that the management system should take in response to container lifecycle events.
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.listenPort
|
||||||
|
|
||||||
|
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/integration.go#L32)</sup>
|
||||||
|
|
||||||
|
ListenPort defines on which port the sidecar container will be listening for connections
|
||||||
|
|
||||||
|
Default Value: `9201`
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.livenessProbe
|
||||||
|
|
||||||
|
Type: `core.Probe` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/probes.go#L37)</sup>
|
||||||
|
|
||||||
|
LivenessProbe keeps configuration of periodic probe of container liveness.
|
||||||
|
Container will be restarted if the probe fails.
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.ports
|
||||||
|
|
||||||
|
Type: `[]core.ContainerPort` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/networking.go#L39)</sup>
|
||||||
|
|
||||||
|
Ports contains list of ports to expose from the container. Not specifying a port here
|
||||||
|
DOES NOT prevent that port from being exposed. Any port which is
|
||||||
|
listening on the default "0.0.0.0" address inside a container will be
|
||||||
|
accessible from the network.
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.readinessProbe
|
||||||
|
|
||||||
|
Type: `core.Probe` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/probes.go#L42)</sup>
|
||||||
|
|
||||||
|
ReadinessProbe keeps configuration of periodic probe of container service readiness.
|
||||||
|
Container will be removed from service endpoints if the probe fails.
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.resources
|
||||||
|
|
||||||
|
Type: `core.ResourceRequirements` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/resources.go#L37)</sup>
|
||||||
|
|
||||||
|
Resources holds resource requests & limits for container
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Documentation of core.ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#resourcerequirements-v1-core)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.securityContext
|
||||||
|
|
||||||
|
Type: `core.SecurityContext` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/security.go#L35)</sup>
|
||||||
|
|
||||||
|
SecurityContext holds container-level security attributes and common container settings.
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.startupProbe
|
||||||
|
|
||||||
|
Type: `core.Probe` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/probes.go#L50)</sup>
|
||||||
|
|
||||||
|
StartupProbe indicates that the Pod has successfully initialized.
|
||||||
|
If specified, no other probes are executed until this completes successfully.
|
||||||
|
If this probe fails, the Pod will be restarted, just as if the livenessProbe failed.
|
||||||
|
This can be used to provide different probe parameters at the beginning of a Pod's lifecycle,
|
||||||
|
when it might take a long time to load data or warm a cache, than during steady-state operation.
|
||||||
|
|
||||||
|
Links:
|
||||||
|
* [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes)
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.volumeMounts
|
||||||
|
|
||||||
|
Type: `[]core.VolumeMount` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/volume_mounts.go#L35)</sup>
|
||||||
|
|
||||||
|
VolumeMounts keeps list of pod volumes to mount into the container's filesystem.
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.gateway.sidecar.workingDir
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/scheduler/v1beta1/container/resources/core.go#L55)</sup>
|
||||||
|
|
||||||
|
Container's working directory.
|
||||||
|
If not specified, the container runtime's default will be used, which
|
||||||
|
might be configured in the container image.
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
### .spec.gateways.affinity
|
### .spec.gateways.affinity
|
||||||
|
|
||||||
Type: `core.PodAffinity` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/deployment/v1/server_group_spec.go#L156)</sup>
|
Type: `core.PodAffinity` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/deployment/v1/server_group_spec.go#L156)</sup>
|
||||||
|
|
|
@ -12,7 +12,15 @@ 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>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec.go#L27)</sup>
|
||||||
|
|
||||||
DeploymentName specifies the ArangoDeployment object name
|
Deployment specifies the ArangoDeployment object name
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .spec.destination.path
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec_destination.go#L36)</sup>
|
||||||
|
|
||||||
|
Path defines service path used for overrides
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
@ -123,15 +131,29 @@ UID keeps the information about object UID
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
### .status.targets\[int\].tls.insecure
|
### .status.target.destinations\[int\].host
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_destination.go#L38)</sup>
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.target.destinations\[int\].port
|
||||||
|
|
||||||
|
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_destination.go#L39)</sup>
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.target.path
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target.go#L37)</sup>
|
||||||
|
|
||||||
|
Path specifies request path override
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.target.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>
|
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
|
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>
|
|
||||||
|
|
||||||
|
|
28
examples/single-server-route.yaml
Normal file
28
examples/single-server-route.yaml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
apiVersion: "database.arangodb.com/v1"
|
||||||
|
kind: "ArangoDeployment"
|
||||||
|
metadata:
|
||||||
|
name: "example-simple-single"
|
||||||
|
spec:
|
||||||
|
mode: Single
|
||||||
|
image: 'arangodb/arangodb:3.12.2'
|
||||||
|
gateway:
|
||||||
|
enabled: true
|
||||||
|
gateways:
|
||||||
|
count: 1
|
||||||
|
---
|
||||||
|
apiVersion: "networking.arangodb.com/v1alpha1"
|
||||||
|
kind: "ArangoRoute"
|
||||||
|
metadata:
|
||||||
|
name: "example-simple-single-route"
|
||||||
|
spec:
|
||||||
|
deployment: example-simple-single
|
||||||
|
destination:
|
||||||
|
service:
|
||||||
|
name: example-simple-single
|
||||||
|
port: 8529
|
||||||
|
schema: https
|
||||||
|
tls:
|
||||||
|
insecure: true
|
||||||
|
path: "/_api/"
|
||||||
|
route:
|
||||||
|
path: "/secondary/"
|
|
@ -175,6 +175,14 @@ func Test_GenerateAPIDocs(t *testing.T) {
|
||||||
"Spec": deploymentApi.ArangoMember{}.Spec,
|
"Spec": deploymentApi.ArangoMember{}.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Shared: []string{
|
||||||
|
"shared/v1",
|
||||||
|
"scheduler/v1beta1",
|
||||||
|
"scheduler/v1beta1/container",
|
||||||
|
"scheduler/v1beta1/container/resources",
|
||||||
|
"scheduler/v1beta1/pod",
|
||||||
|
"scheduler/v1beta1/pod/resources",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"apps": map[string]inputPackage{
|
"apps": map[string]inputPackage{
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
|
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import "github.com/arangodb/kube-arangodb/pkg/util"
|
import (
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
type DeploymentSpecGateway struct {
|
type DeploymentSpecGateway struct {
|
||||||
// Enabled setting enables/disables support for gateway in the cluster.
|
// Enabled setting enables/disables support for gateway in the cluster.
|
||||||
|
@ -31,6 +35,9 @@ type DeploymentSpecGateway struct {
|
||||||
// Image is the image to use for the gateway.
|
// Image is the image to use for the gateway.
|
||||||
// By default, the image is determined by the operator.
|
// By default, the image is determined by the operator.
|
||||||
Image *string `json:"image"`
|
Image *string `json:"image"`
|
||||||
|
|
||||||
|
// Sidecar define the integration sidecar spec
|
||||||
|
Sidecar *schedulerApi.IntegrationSidecar `json:"sidecar,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEnabled returns whether the gateway is enabled.
|
// IsEnabled returns whether the gateway is enabled.
|
||||||
|
@ -42,9 +49,22 @@ func (d *DeploymentSpecGateway) IsEnabled() bool {
|
||||||
return *d.Enabled
|
return *d.Enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DeploymentSpecGateway) GetSidecar() *schedulerApi.IntegrationSidecar {
|
||||||
|
if d == nil || d.Sidecar == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.Sidecar
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the given spec
|
// Validate the given spec
|
||||||
func (d *DeploymentSpecGateway) Validate() error {
|
func (d *DeploymentSpecGateway) Validate() error {
|
||||||
return nil
|
if d == nil {
|
||||||
|
d = &DeploymentSpecGateway{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shared.WithErrors(
|
||||||
|
shared.PrefixResourceErrors("integrationSidecar", d.GetSidecar().Validate()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImage returns the image to use for the gateway.
|
// GetImage returns the image to use for the gateway.
|
||||||
|
|
|
@ -230,6 +230,8 @@ func (g ServerGroup) DefaultTerminationGracePeriod() time.Duration {
|
||||||
return time.Hour
|
return time.Hour
|
||||||
case ServerGroupCoordinators:
|
case ServerGroupCoordinators:
|
||||||
return time.Hour
|
return time.Hour
|
||||||
|
case ServerGroupGateways:
|
||||||
|
return 15 * time.Minute
|
||||||
default:
|
default:
|
||||||
return time.Second * 30
|
return time.Second * 30
|
||||||
}
|
}
|
||||||
|
|
6
pkg/apis/deployment/v1/zz_generated.deepcopy.go
generated
6
pkg/apis/deployment/v1/zz_generated.deepcopy.go
generated
|
@ -28,6 +28,7 @@ package v1
|
||||||
import (
|
import (
|
||||||
time "time"
|
time "time"
|
||||||
|
|
||||||
|
v1beta1 "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
sharedv1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
sharedv1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -1184,6 +1185,11 @@ func (in *DeploymentSpecGateway) DeepCopyInto(out *DeploymentSpecGateway) {
|
||||||
*out = new(string)
|
*out = new(string)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.Sidecar != nil {
|
||||||
|
in, out := &in.Sidecar, &out.Sidecar
|
||||||
|
*out = new(v1beta1.IntegrationSidecar)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
|
|
||||||
package v2alpha1
|
package v2alpha1
|
||||||
|
|
||||||
import "github.com/arangodb/kube-arangodb/pkg/util"
|
import (
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
type DeploymentSpecGateway struct {
|
type DeploymentSpecGateway struct {
|
||||||
// Enabled setting enables/disables support for gateway in the cluster.
|
// Enabled setting enables/disables support for gateway in the cluster.
|
||||||
|
@ -31,6 +35,9 @@ type DeploymentSpecGateway struct {
|
||||||
// Image is the image to use for the gateway.
|
// Image is the image to use for the gateway.
|
||||||
// By default, the image is determined by the operator.
|
// By default, the image is determined by the operator.
|
||||||
Image *string `json:"image"`
|
Image *string `json:"image"`
|
||||||
|
|
||||||
|
// Sidecar define the integration sidecar spec
|
||||||
|
Sidecar *schedulerApi.IntegrationSidecar `json:"sidecar,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEnabled returns whether the gateway is enabled.
|
// IsEnabled returns whether the gateway is enabled.
|
||||||
|
@ -42,9 +49,22 @@ func (d *DeploymentSpecGateway) IsEnabled() bool {
|
||||||
return *d.Enabled
|
return *d.Enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DeploymentSpecGateway) GetSidecar() *schedulerApi.IntegrationSidecar {
|
||||||
|
if d == nil || d.Sidecar == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.Sidecar
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the given spec
|
// Validate the given spec
|
||||||
func (d *DeploymentSpecGateway) Validate() error {
|
func (d *DeploymentSpecGateway) Validate() error {
|
||||||
return nil
|
if d == nil {
|
||||||
|
d = &DeploymentSpecGateway{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shared.WithErrors(
|
||||||
|
shared.PrefixResourceErrors("integrationSidecar", d.GetSidecar().Validate()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImage returns the image to use for the gateway.
|
// GetImage returns the image to use for the gateway.
|
||||||
|
|
|
@ -230,6 +230,8 @@ func (g ServerGroup) DefaultTerminationGracePeriod() time.Duration {
|
||||||
return time.Hour
|
return time.Hour
|
||||||
case ServerGroupCoordinators:
|
case ServerGroupCoordinators:
|
||||||
return time.Hour
|
return time.Hour
|
||||||
|
case ServerGroupGateways:
|
||||||
|
return 15 * time.Minute
|
||||||
default:
|
default:
|
||||||
return time.Second * 30
|
return time.Second * 30
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ package v2alpha1
|
||||||
import (
|
import (
|
||||||
time "time"
|
time "time"
|
||||||
|
|
||||||
|
v1beta1 "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
sharedv1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
sharedv1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -1184,6 +1185,11 @@ func (in *DeploymentSpecGateway) DeepCopyInto(out *DeploymentSpecGateway) {
|
||||||
*out = new(string)
|
*out = new(string)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.Sidecar != nil {
|
||||||
|
in, out := &in.Sidecar, &out.Sidecar
|
||||||
|
*out = new(v1beta1.IntegrationSidecar)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ package v1alpha1
|
||||||
import shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
import shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
|
||||||
type ArangoRouteSpec struct {
|
type ArangoRouteSpec struct {
|
||||||
// DeploymentName specifies the ArangoDeployment object name
|
// Deployment specifies the ArangoDeployment object name
|
||||||
DeploymentName *string `json:"deployment,omitempty"`
|
Deployment *string `json:"deployment,omitempty"`
|
||||||
|
|
||||||
// Destination defines the route destination
|
// Destination defines the route destination
|
||||||
Destination *ArangoRouteSpecDestination `json:"destination,omitempty"`
|
Destination *ArangoRouteSpecDestination `json:"destination,omitempty"`
|
||||||
|
@ -33,6 +33,14 @@ type ArangoRouteSpec struct {
|
||||||
Route *ArangoRouteSpecRoute `json:"route,omitempty"`
|
Route *ArangoRouteSpecRoute `json:"route,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ArangoRouteSpec) GetDeployment() string {
|
||||||
|
if s == nil || s.Destination == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return *s.Deployment
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ArangoRouteSpec) GetDestination() *ArangoRouteSpecDestination {
|
func (s *ArangoRouteSpec) GetDestination() *ArangoRouteSpecDestination {
|
||||||
if s == nil || s.Destination == nil {
|
if s == nil || s.Destination == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -54,7 +62,7 @@ func (s *ArangoRouteSpec) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := shared.WithErrors(shared.PrefixResourceErrors("spec",
|
if err := shared.WithErrors(shared.PrefixResourceErrors("spec",
|
||||||
shared.PrefixResourceErrors("deployment", shared.ValidateResourceNamePointer(s.DeploymentName)),
|
shared.PrefixResourceErrors("deployment", shared.ValidateResourceNamePointer(s.Deployment)),
|
||||||
shared.ValidateRequiredInterfacePath("destination", s.Destination),
|
shared.ValidateRequiredInterfacePath("destination", s.Destination),
|
||||||
shared.ValidateOptionalInterfacePath("route", s.Route),
|
shared.ValidateOptionalInterfacePath("route", s.Route),
|
||||||
)); err != nil {
|
)); err != nil {
|
||||||
|
|
|
@ -31,30 +31,41 @@ type ArangoRouteSpecDestination struct {
|
||||||
|
|
||||||
// TLS defines TLS Configuration
|
// TLS defines TLS Configuration
|
||||||
TLS *ArangoRouteSpecDestinationTLS `json:"tls,omitempty"`
|
TLS *ArangoRouteSpecDestinationTLS `json:"tls,omitempty"`
|
||||||
|
|
||||||
|
// Path defines service path used for overrides
|
||||||
|
Path *string `json:"path,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ArangoRouteSpecDestination) GetService() *ArangoRouteSpecDestinationService {
|
func (a *ArangoRouteSpecDestination) GetService() *ArangoRouteSpecDestinationService {
|
||||||
if s == nil || s.Service == nil {
|
if a == nil || a.Service == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Service
|
return a.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ArangoRouteSpecDestination) GetSchema() *ArangoRouteSpecDestinationSchema {
|
func (a *ArangoRouteSpecDestination) GetSchema() *ArangoRouteSpecDestinationSchema {
|
||||||
if s == nil || s.Schema == nil {
|
if a == nil || a.Schema == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Schema
|
return a.Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ArangoRouteSpecDestination) GetTLS() *ArangoRouteSpecDestinationTLS {
|
func (a *ArangoRouteSpecDestination) GetPath() string {
|
||||||
if s == nil || s.TLS == nil {
|
if a == nil || a.Path == nil {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return *a.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoRouteSpecDestination) GetTLS() *ArangoRouteSpecDestinationTLS {
|
||||||
|
if a == nil || a.TLS == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.TLS
|
return a.TLS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArangoRouteSpecDestination) Validate() error {
|
func (a *ArangoRouteSpecDestination) Validate() error {
|
||||||
|
@ -66,6 +77,7 @@ func (a *ArangoRouteSpecDestination) Validate() error {
|
||||||
shared.ValidateOptionalInterfacePath("service", a.Service),
|
shared.ValidateOptionalInterfacePath("service", a.Service),
|
||||||
shared.ValidateOptionalInterfacePath("schema", a.Schema),
|
shared.ValidateOptionalInterfacePath("schema", a.Schema),
|
||||||
shared.ValidateOptionalInterfacePath("tls", a.TLS),
|
shared.ValidateOptionalInterfacePath("tls", a.TLS),
|
||||||
|
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ type ArangoRouteSpecRoute struct {
|
||||||
|
|
||||||
func (a *ArangoRouteSpecRoute) GetPath() string {
|
func (a *ArangoRouteSpecRoute) GetPath() string {
|
||||||
if a == nil || a.Path == nil {
|
if a == nil || a.Path == nil {
|
||||||
return "/"
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return *a.Path
|
return *a.Path
|
||||||
|
@ -43,7 +43,7 @@ func (a *ArangoRouteSpecRoute) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := shared.WithErrors(
|
if err := shared.WithErrors(
|
||||||
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),
|
shared.ValidateRequiredPath("path", a.Path, shared.ValidateAPIPath),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,6 @@ type ArangoRouteStatus struct {
|
||||||
// Deployment keeps the ArangoDeployment reference
|
// Deployment keeps the ArangoDeployment reference
|
||||||
Deployment *sharedApi.Object `json:"deployment,omitempty"`
|
Deployment *sharedApi.Object `json:"deployment,omitempty"`
|
||||||
|
|
||||||
// Targets keeps the target details
|
// Target keeps the target details
|
||||||
Targets ArangoRouteStatusTargets `json:"targets,omitempty"`
|
Target *ArangoRouteStatusTarget `json:"target,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,25 +20,46 @@
|
||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import "github.com/arangodb/kube-arangodb/pkg/util"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
type ArangoRouteStatusTargets []ArangoRouteStatusTarget
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
)
|
||||||
func (a ArangoRouteStatusTargets) Hash() string {
|
|
||||||
return util.SHA256FromExtract(func(t ArangoRouteStatusTarget) string {
|
|
||||||
return t.Hash()
|
|
||||||
}, a...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArangoRouteStatusTarget struct {
|
type ArangoRouteStatusTarget struct {
|
||||||
Url string `json:"url,omitempty"`
|
// Destinations keeps target destinations
|
||||||
|
Destinations ArangoRouteStatusTargetDestinations `json:"destinations,omitempty"`
|
||||||
|
|
||||||
TLS ArangoRouteStatusTargetTLS `json:"tls,omitempty"`
|
// TLS Keeps target TLS Settings (if not nil, TLS is enabled)
|
||||||
|
TLS *ArangoRouteStatusTargetTLS `json:"TLS,omitempty"`
|
||||||
|
|
||||||
|
// Path specifies request path override
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoRouteStatusTarget) RenderURLs() []string {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var urls = make([]string, len(a.Destinations))
|
||||||
|
|
||||||
|
proto := "http"
|
||||||
|
|
||||||
|
if a.TLS != nil {
|
||||||
|
proto = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, dest := range a.Destinations {
|
||||||
|
urls[id] = fmt.Sprintf("%s://%s:%d%s", proto, dest.Host, dest.Port, a.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return urls
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArangoRouteStatusTarget) Hash() string {
|
func (a *ArangoRouteStatusTarget) Hash() string {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return util.SHA256FromStringArray(a.Url, a.TLS.Hash())
|
return util.SHA256FromStringArray(a.Destinations.Hash(), a.TLS.Hash(), a.Path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// 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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ArangoRouteStatusTargetDestinations []ArangoRouteStatusTargetDestination
|
||||||
|
|
||||||
|
func (a ArangoRouteStatusTargetDestinations) Hash() string {
|
||||||
|
return util.SHA256FromExtract(func(t ArangoRouteStatusTargetDestination) string {
|
||||||
|
return t.Hash()
|
||||||
|
}, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArangoRouteStatusTargetDestination struct {
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
Port int32 `json:"port,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoRouteStatusTargetDestination) Hash() string {
|
||||||
|
if a == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return util.SHA256FromStringArray(fmt.Sprintf("%s:%d", a.Host, a.Port))
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ import "github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
|
||||||
type ArangoRouteStatusTargetTLS struct {
|
type ArangoRouteStatusTargetTLS struct {
|
||||||
// Insecure allows Insecure traffic
|
// Insecure allows Insecure traffic
|
||||||
Insecure bool `json:"insecure"`
|
Insecure *bool `json:"insecure"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArangoRouteStatusTargetTLS) Hash() string {
|
func (a *ArangoRouteStatusTargetTLS) Hash() string {
|
||||||
|
@ -32,5 +32,13 @@ func (a *ArangoRouteStatusTargetTLS) Hash() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.SHA256FromStringArray(util.BoolSwitch(a.Insecure, "true", "false"))
|
return util.SHA256FromStringArray(util.BoolSwitch(a.IsInsecure(), "true", "false"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoRouteStatusTargetTLS) IsInsecure() bool {
|
||||||
|
if a == nil || a.Insecure == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return *a.Insecure
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
deploymentv1 "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
v2alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
v1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
v1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
||||||
|
@ -96,8 +96,8 @@ func (in *ArangoRouteList) DeepCopyObject() runtime.Object {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ArangoRouteSpec) DeepCopyInto(out *ArangoRouteSpec) {
|
func (in *ArangoRouteSpec) DeepCopyInto(out *ArangoRouteSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.DeploymentName != nil {
|
if in.Deployment != nil {
|
||||||
in, out := &in.DeploymentName, &out.DeploymentName
|
in, out := &in.Deployment, &out.Deployment
|
||||||
*out = new(string)
|
*out = new(string)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,11 @@ func (in *ArangoRouteSpecDestination) DeepCopyInto(out *ArangoRouteSpecDestinati
|
||||||
*out = new(ArangoRouteSpecDestinationTLS)
|
*out = new(ArangoRouteSpecDestinationTLS)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.Path != nil {
|
||||||
|
in, out := &in.Path, &out.Path
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +233,7 @@ func (in *ArangoRouteStatus) DeepCopyInto(out *ArangoRouteStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.Conditions != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.Conditions, &out.Conditions
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = make(deploymentv1.ConditionList, len(*in))
|
*out = make(v2alpha1.ConditionList, len(*in))
|
||||||
for i := range *in {
|
for i := range *in {
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
|
@ -238,10 +243,10 @@ func (in *ArangoRouteStatus) DeepCopyInto(out *ArangoRouteStatus) {
|
||||||
*out = new(v1.Object)
|
*out = new(v1.Object)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
if in.Targets != nil {
|
if in.Target != nil {
|
||||||
in, out := &in.Targets, &out.Targets
|
in, out := &in.Target, &out.Target
|
||||||
*out = make(ArangoRouteStatusTargets, len(*in))
|
*out = new(ArangoRouteStatusTarget)
|
||||||
copy(*out, *in)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -259,7 +264,16 @@ func (in *ArangoRouteStatus) DeepCopy() *ArangoRouteStatus {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ArangoRouteStatusTarget) DeepCopyInto(out *ArangoRouteStatusTarget) {
|
func (in *ArangoRouteStatusTarget) DeepCopyInto(out *ArangoRouteStatusTarget) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TLS = in.TLS
|
if in.Destinations != nil {
|
||||||
|
in, out := &in.Destinations, &out.Destinations
|
||||||
|
*out = make(ArangoRouteStatusTargetDestinations, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.TLS != nil {
|
||||||
|
in, out := &in.TLS, &out.TLS
|
||||||
|
*out = new(ArangoRouteStatusTargetTLS)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,9 +287,50 @@ func (in *ArangoRouteStatusTarget) DeepCopy() *ArangoRouteStatusTarget {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ArangoRouteStatusTargetDestination) DeepCopyInto(out *ArangoRouteStatusTargetDestination) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteStatusTargetDestination.
|
||||||
|
func (in *ArangoRouteStatusTargetDestination) DeepCopy() *ArangoRouteStatusTargetDestination {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ArangoRouteStatusTargetDestination)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in ArangoRouteStatusTargetDestinations) DeepCopyInto(out *ArangoRouteStatusTargetDestinations) {
|
||||||
|
{
|
||||||
|
in := &in
|
||||||
|
*out = make(ArangoRouteStatusTargetDestinations, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteStatusTargetDestinations.
|
||||||
|
func (in ArangoRouteStatusTargetDestinations) DeepCopy() ArangoRouteStatusTargetDestinations {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ArangoRouteStatusTargetDestinations)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return *out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ArangoRouteStatusTargetTLS) DeepCopyInto(out *ArangoRouteStatusTargetTLS) {
|
func (in *ArangoRouteStatusTargetTLS) DeepCopyInto(out *ArangoRouteStatusTargetTLS) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Insecure != nil {
|
||||||
|
in, out := &in.Insecure, &out.Insecure
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,23 +343,3 @@ func (in *ArangoRouteStatusTargetTLS) DeepCopy() *ArangoRouteStatusTargetTLS {
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return 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
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,9 +59,9 @@ func (m *Metadata) Apply(template *core.PodTemplateSpec) error {
|
||||||
|
|
||||||
z := m.DeepCopy()
|
z := m.DeepCopy()
|
||||||
|
|
||||||
template.Labels = z.Labels
|
template.Labels = util.MergeMaps(true, template.Labels, z.Labels)
|
||||||
template.Annotations = z.Annotations
|
template.Annotations = util.MergeMaps(true, template.Annotations, z.Annotations)
|
||||||
template.OwnerReferences = z.OwnerReferences
|
template.OwnerReferences = append(template.OwnerReferences, z.OwnerReferences...)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,49 @@ func Test_Metadata(t *testing.T) {
|
||||||
require.Contains(t, pod.Annotations, "B2")
|
require.Contains(t, pod.Annotations, "B2")
|
||||||
require.EqualValues(t, "4", pod.Annotations["B2"])
|
require.EqualValues(t, "4", pod.Annotations["B2"])
|
||||||
|
|
||||||
|
require.Len(t, pod.OwnerReferences, 2)
|
||||||
|
require.EqualValues(t, "test", pod.OwnerReferences[0].UID)
|
||||||
|
require.EqualValues(t, "test2", pod.OwnerReferences[1].UID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Update Templat", func(t *testing.T) {
|
||||||
|
applyMetadata(t, &core.PodTemplateSpec{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"A": "1",
|
||||||
|
},
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"B": "2",
|
||||||
|
},
|
||||||
|
OwnerReferences: []meta.OwnerReference{
|
||||||
|
{
|
||||||
|
UID: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, &Metadata{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"A": "3",
|
||||||
|
},
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"B2": "4",
|
||||||
|
},
|
||||||
|
OwnerReferences: []meta.OwnerReference{
|
||||||
|
{
|
||||||
|
UID: "test2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})(func(t *testing.T, pod *core.PodTemplateSpec) {
|
||||||
|
require.Len(t, pod.Labels, 1)
|
||||||
|
require.Contains(t, pod.Labels, "A")
|
||||||
|
require.EqualValues(t, "3", pod.Labels["A"])
|
||||||
|
|
||||||
|
require.Len(t, pod.Annotations, 2)
|
||||||
|
require.Contains(t, pod.Annotations, "B")
|
||||||
|
require.EqualValues(t, "2", pod.Annotations["B"])
|
||||||
|
require.Contains(t, pod.Annotations, "B2")
|
||||||
|
require.EqualValues(t, "4", pod.Annotations["B2"])
|
||||||
|
|
||||||
require.Len(t, pod.OwnerReferences, 2)
|
require.Len(t, pod.OwnerReferences, 2)
|
||||||
require.EqualValues(t, "test", pod.OwnerReferences[0].UID)
|
require.EqualValues(t, "test", pod.OwnerReferences[0].UID)
|
||||||
require.EqualValues(t, "test2", pod.OwnerReferences[1].UID)
|
require.EqualValues(t, "test2", pod.OwnerReferences[1].UID)
|
||||||
|
|
|
@ -59,9 +59,9 @@ func (m *Metadata) Apply(template *core.PodTemplateSpec) error {
|
||||||
|
|
||||||
z := m.DeepCopy()
|
z := m.DeepCopy()
|
||||||
|
|
||||||
template.Labels = z.Labels
|
template.Labels = util.MergeMaps(true, template.Labels, z.Labels)
|
||||||
template.Annotations = z.Annotations
|
template.Annotations = util.MergeMaps(true, template.Annotations, z.Annotations)
|
||||||
template.OwnerReferences = z.OwnerReferences
|
template.OwnerReferences = append(template.OwnerReferences, z.OwnerReferences...)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,49 @@ func Test_Metadata(t *testing.T) {
|
||||||
require.Contains(t, pod.Annotations, "B2")
|
require.Contains(t, pod.Annotations, "B2")
|
||||||
require.EqualValues(t, "4", pod.Annotations["B2"])
|
require.EqualValues(t, "4", pod.Annotations["B2"])
|
||||||
|
|
||||||
|
require.Len(t, pod.OwnerReferences, 2)
|
||||||
|
require.EqualValues(t, "test", pod.OwnerReferences[0].UID)
|
||||||
|
require.EqualValues(t, "test2", pod.OwnerReferences[1].UID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Update Template", func(t *testing.T) {
|
||||||
|
applyMetadata(t, &core.PodTemplateSpec{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"A": "1",
|
||||||
|
},
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"B": "2",
|
||||||
|
},
|
||||||
|
OwnerReferences: []meta.OwnerReference{
|
||||||
|
{
|
||||||
|
UID: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, &Metadata{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"A": "3",
|
||||||
|
},
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"B2": "4",
|
||||||
|
},
|
||||||
|
OwnerReferences: []meta.OwnerReference{
|
||||||
|
{
|
||||||
|
UID: "test2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})(func(t *testing.T, pod *core.PodTemplateSpec) {
|
||||||
|
require.Len(t, pod.Labels, 1)
|
||||||
|
require.Contains(t, pod.Labels, "A")
|
||||||
|
require.EqualValues(t, "3", pod.Labels["A"])
|
||||||
|
|
||||||
|
require.Len(t, pod.Annotations, 2)
|
||||||
|
require.Contains(t, pod.Annotations, "B")
|
||||||
|
require.EqualValues(t, "2", pod.Annotations["B"])
|
||||||
|
require.Contains(t, pod.Annotations, "B2")
|
||||||
|
require.EqualValues(t, "4", pod.Annotations["B2"])
|
||||||
|
|
||||||
require.Len(t, pod.OwnerReferences, 2)
|
require.Len(t, pod.OwnerReferences, 2)
|
||||||
require.EqualValues(t, "test", pod.OwnerReferences[0].UID)
|
require.EqualValues(t, "test", pod.OwnerReferences[0].UID)
|
||||||
require.EqualValues(t, "test2", pod.OwnerReferences[1].UID)
|
require.EqualValues(t, "test2", pod.OwnerReferences[1].UID)
|
||||||
|
|
|
@ -34,7 +34,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
resourceNameRE = regexp.MustCompile(`^([0-9\-\.a-z])+$`)
|
resourceNameRE = regexp.MustCompile(`^([0-9\-\.a-z])+$`)
|
||||||
apiPathRE = regexp.MustCompile(`^/([A-Za-z0-9\-]+/)*$`)
|
apiPathRE = regexp.MustCompile(`^/([_A-Za-z0-9\-]+/)*$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -190,6 +190,19 @@ func ValidateList[T any](in []T, validator func(T) error) error {
|
||||||
return WithErrors(errors...)
|
return WithErrors(errors...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateMap validates all elements on the list
|
||||||
|
func ValidateMap[T any](in map[string]T, validator func(string, T) error) error {
|
||||||
|
errors := make([]error, 0, len(in))
|
||||||
|
|
||||||
|
for id := range in {
|
||||||
|
if err := PrefixResourceError(fmt.Sprintf("`%s`", id), validator(id, in[id])); err != nil {
|
||||||
|
errors = append(errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WithErrors(errors...)
|
||||||
|
}
|
||||||
|
|
||||||
// ValidateImage Validates if provided image is valid
|
// ValidateImage Validates if provided image is valid
|
||||||
func ValidateImage(image string) error {
|
func ValidateImage(image string) error {
|
||||||
if image == "" {
|
if image == "" {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,14 @@ v1alpha1:
|
||||||
spec:
|
spec:
|
||||||
properties:
|
properties:
|
||||||
deployment:
|
deployment:
|
||||||
description: DeploymentName specifies the ArangoDeployment object name
|
description: Deployment specifies the ArangoDeployment object name
|
||||||
type: string
|
type: string
|
||||||
destination:
|
destination:
|
||||||
description: Destination defines the route destination
|
description: Destination defines the route destination
|
||||||
properties:
|
properties:
|
||||||
|
path:
|
||||||
|
description: Path defines service path used for overrides
|
||||||
|
type: string
|
||||||
schema:
|
schema:
|
||||||
description: Schema defines HTTP/S schema used for connection
|
description: Schema defines HTTP/S schema used for connection
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
|
||||||
|
@ -283,7 +284,7 @@ func (i *ImageUpdatePod) GetRole() string {
|
||||||
return "id"
|
return "id"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ImageUpdatePod) Init(_ context.Context, _ interfaces.Inspector, pod *core.Pod) error {
|
func (i *ImageUpdatePod) Init(_ context.Context, _ interfaces.Inspector, pod *core.PodTemplateSpec) error {
|
||||||
terminationGracePeriodSeconds := int64((time.Second * 30).Seconds())
|
terminationGracePeriodSeconds := int64((time.Second * 30).Seconds())
|
||||||
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
||||||
pod.Spec.PriorityClassName = i.spec.ID.Get().PriorityClassName
|
pod.Spec.PriorityClassName = i.spec.ID.Get().PriorityClassName
|
||||||
|
@ -311,7 +312,7 @@ func (i *ImageUpdatePod) GetVolumes() []core.Volume {
|
||||||
return getVolumes(i.AsInput()).Volumes()
|
return getVolumes(i.AsInput()).Volumes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ImageUpdatePod) GetSidecars(*core.Pod) error {
|
func (i *ImageUpdatePod) GetSidecars(spec *core.PodTemplateSpec) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,6 +504,10 @@ func (a *ImageUpdatePod) AsInput() pod.Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *ImageUpdatePod) Profiles() (schedulerApi.ProfileTemplates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetExecutor returns the fixed path to the ArangoSync binary in the container.
|
// GetExecutor returns the fixed path to the ArangoSync binary in the container.
|
||||||
func (a *ArangoSyncIdentity) GetExecutor() string {
|
func (a *ArangoSyncIdentity) GetExecutor() string {
|
||||||
return resources.ArangoSyncExecutor
|
return resources.ArangoSyncExecutor
|
||||||
|
|
|
@ -132,6 +132,8 @@ func (s *stateInspector) RefreshState(ctx context.Context, members api.Deploymen
|
||||||
if results[id].IsServing() {
|
if results[id].IsServing() {
|
||||||
client = results[id].client
|
client = results[id].client
|
||||||
}
|
}
|
||||||
|
case api.ServerGroupTypeGateway:
|
||||||
|
results[id] = s.fetchGatewayMemberState(ctxChild, members[id])
|
||||||
default:
|
default:
|
||||||
assertion.InvalidGroupKey.Assert(true, "Unable to fetch Health for an unknown group: %s", members[id].Group.AsRole())
|
assertion.InvalidGroupKey.Assert(true, "Unable to fetch Health for an unknown group: %s", members[id].Group.AsRole())
|
||||||
results[id] = State{
|
results[id] = State{
|
||||||
|
@ -178,6 +180,9 @@ func (s *stateInspector) RefreshState(ctx context.Context, members api.Deploymen
|
||||||
case api.ServerGroupTypeArangoSync:
|
case api.ServerGroupTypeArangoSync:
|
||||||
// ArangoSync is considered as healthy when it is possible to fetch version.
|
// ArangoSync is considered as healthy when it is possible to fetch version.
|
||||||
results[i].IsClusterHealthy = true
|
results[i].IsClusterHealthy = true
|
||||||
|
case api.ServerGroupTypeGateway:
|
||||||
|
// Gateway is considered as healthy when it is possible to fetch version.
|
||||||
|
results[i].IsClusterHealthy = true
|
||||||
default:
|
default:
|
||||||
assertion.InvalidGroupKey.Assert(true, "Unable to fetch Health for an unknown group: %s", members[i].Group.AsRole())
|
assertion.InvalidGroupKey.Assert(true, "Unable to fetch Health for an unknown group: %s", members[i].Group.AsRole())
|
||||||
results[i].IsClusterHealthy = false
|
results[i].IsClusterHealthy = false
|
||||||
|
@ -228,6 +233,26 @@ func (s *stateInspector) fetchArangosyncMemberState(ctx context.Context, m api.D
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stateInspector) fetchGatewayMemberState(ctx context.Context, m api.DeploymentStatusMemberElement) State {
|
||||||
|
// by default, it is not serving. It will be changed if it serves.
|
||||||
|
var state State
|
||||||
|
c, err := s.deployment.GetServerClient(ctx, m.Group, m.Member.ID)
|
||||||
|
if err != nil {
|
||||||
|
state.NotReachableErr = err
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := c.Version(ctx); err != nil {
|
||||||
|
state.NotReachableErr = err
|
||||||
|
return state
|
||||||
|
} else {
|
||||||
|
state.Version = v
|
||||||
|
state.client = c
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
func (s *stateInspector) fetchServerMemberState(ctx context.Context, m api.DeploymentStatusMemberElement,
|
func (s *stateInspector) fetchServerMemberState(ctx context.Context, m api.DeploymentStatusMemberElement,
|
||||||
servingGroup api.ServerGroup) State {
|
servingGroup api.ServerGroup) State {
|
||||||
// by default, it is not serving. It will be changed if it serves.
|
// by default, it is not serving. It will be changed if it serves.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// DISCLAIMER
|
// DISCLAIMER
|
||||||
//
|
//
|
||||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -81,4 +81,9 @@ var probeMap = map[api.ServerGroup]probes{
|
||||||
liveness: newProbe(true, true),
|
liveness: newProbe(true, true),
|
||||||
readiness: newProbe(false, false),
|
readiness: newProbe(false, false),
|
||||||
},
|
},
|
||||||
|
api.ServerGroupGateways: { // TODO: Enable Probes
|
||||||
|
startup: newProbe(false, false),
|
||||||
|
liveness: newProbe(false, false),
|
||||||
|
readiness: newProbe(false, false),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
|
|
||||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/resources"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/tolerations"
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/tolerations"
|
||||||
|
@ -78,7 +79,7 @@ func (a actionRuntimeContainerSyncTolerations) Start(ctx context.Context) (bool,
|
||||||
|
|
||||||
expectedTolerations := member.Spec.Template.PodSpec.Spec.Tolerations
|
expectedTolerations := member.Spec.Template.PodSpec.Spec.Tolerations
|
||||||
|
|
||||||
origTolerations := tolerations.CreatePodTolerations(a.actionCtx.GetMode(), a.action.Group)
|
origTolerations := resources.CreatePodTolerations(a.actionCtx.GetMode(), a.action.Group)
|
||||||
|
|
||||||
calculatedTolerations := tolerations.MergeTolerationsIfNotFound(currentTolerations, origTolerations, expectedTolerations)
|
calculatedTolerations := tolerations.MergeTolerationsIfNotFound(currentTolerations, origTolerations, expectedTolerations)
|
||||||
|
|
||||||
|
|
182
pkg/deployment/resources/config_map_gateway.go
Normal file
182
pkg/deployment/resources/config_map_gateway.go
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
//
|
||||||
|
// 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 resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/resources/gateway"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
|
||||||
|
configMapsV1 "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/configmap/v1"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/patcher"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *Resources) ensureGatewayConfig(ctx context.Context, cachedStatus inspectorInterface.Inspector, configMaps configMapsV1.ModInterface) error {
|
||||||
|
deploymentName := r.context.GetAPIObject().GetName()
|
||||||
|
configMapName := GetGatewayConfigMapName(deploymentName)
|
||||||
|
|
||||||
|
log := r.log.Str("section", "gateway-config").Str("name", configMapName)
|
||||||
|
|
||||||
|
cfg, err := r.renderGatewayConfig(cachedStatus)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(errors.Wrapf(err, "Failed to generate gateway config"))
|
||||||
|
}
|
||||||
|
|
||||||
|
gatewayCfgYaml, gatewayCfgChecksum, _, err := cfg.RenderYAML()
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(errors.Wrapf(err, "Failed to render gateway config"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cm, exists := cachedStatus.ConfigMap().V1().GetSimple(configMapName); !exists {
|
||||||
|
// Create
|
||||||
|
cm = &core.ConfigMap{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Name: configMapName,
|
||||||
|
},
|
||||||
|
Data: map[string]string{
|
||||||
|
GatewayConfigFileName: string(gatewayCfgYaml),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
owner := r.context.GetAPIObject().AsOwner()
|
||||||
|
|
||||||
|
err = globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(ctx, func(ctxChild context.Context) error {
|
||||||
|
return k8sutil.CreateConfigMap(ctxChild, configMaps, cm, &owner)
|
||||||
|
})
|
||||||
|
if kerrors.IsAlreadyExists(err) {
|
||||||
|
// CM added while we tried it also
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
// Failed to create
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Reconcile()
|
||||||
|
} else {
|
||||||
|
// CM Exists, checks checksum - if key is not in the map we return empty string
|
||||||
|
if existingSha := util.SHA256FromString(cm.Data[GatewayConfigFileName]); existingSha != gatewayCfgChecksum {
|
||||||
|
// We need to do the update
|
||||||
|
if _, changed, err := patcher.Patcher[*core.ConfigMap](ctx, cachedStatus.ConfigMapsModInterface().V1(), cm, meta.PatchOptions{},
|
||||||
|
patcher.PatchConfigMapData(map[string]string{
|
||||||
|
GatewayConfigFileName: string(gatewayCfgYaml),
|
||||||
|
})); err != nil {
|
||||||
|
log.Err(err).Debug("Failed to patch GatewayConfig ConfigMap")
|
||||||
|
return errors.WithStack(err)
|
||||||
|
} else if changed {
|
||||||
|
log.Str("service", cm.GetName()).Str("before", existingSha).Str("after", gatewayCfgChecksum).Info("Updated GatewayConfig")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resources) renderGatewayConfig(cachedStatus inspectorInterface.Inspector) (gateway.Config, error) {
|
||||||
|
deploymentName := r.context.GetAPIObject().GetName()
|
||||||
|
|
||||||
|
log := r.log.Str("section", "gateway-config-render")
|
||||||
|
|
||||||
|
spec := r.context.GetSpec()
|
||||||
|
svcServingName := fmt.Sprintf("%s-%s", deploymentName, spec.Mode.Get().ServingGroup().AsRole())
|
||||||
|
|
||||||
|
svc, svcExist := cachedStatus.Service().V1().GetSimple(svcServingName)
|
||||||
|
if !svcExist {
|
||||||
|
return gateway.Config{}, errors.Errorf("Service %s not found", svcServingName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg gateway.Config
|
||||||
|
|
||||||
|
cfg.DefaultDestination = gateway.ConfigDestination{
|
||||||
|
Targets: []gateway.ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: svc.Spec.ClusterIP,
|
||||||
|
Port: shared.ArangoPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if spec.TLS.IsSecure() {
|
||||||
|
// Enabled TLS, add config
|
||||||
|
keyPath := filepath.Join(shared.TLSKeyfileVolumeMountDir, constants.SecretTLSKeyfile)
|
||||||
|
cfg.DefaultTLS = &gateway.ConfigTLS{
|
||||||
|
CertificatePath: keyPath,
|
||||||
|
PrivateKeyPath: keyPath,
|
||||||
|
}
|
||||||
|
cfg.DefaultDestination.Type = util.NewType(gateway.ConfigDestinationTypeHTTPS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check ArangoRoutes
|
||||||
|
if c, err := cachedStatus.ArangoRoute().V1Alpha1(); err == nil {
|
||||||
|
cfg.Destinations = gateway.ConfigDestinations{}
|
||||||
|
if err := c.Iterate(func(at *networkingApi.ArangoRoute) error {
|
||||||
|
log := log.Str("ArangoRoute", at.GetName())
|
||||||
|
if !at.Status.Conditions.IsTrue(networkingApi.ReadyCondition) {
|
||||||
|
l := log
|
||||||
|
if c, ok := at.Status.Conditions.Get(networkingApi.ReadyCondition); ok {
|
||||||
|
l.Str("message", c.Message)
|
||||||
|
}
|
||||||
|
l.Warn("ArangoRoute is not ready")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if target := at.Status.Target; target != nil {
|
||||||
|
var dest gateway.ConfigDestination
|
||||||
|
if destinations := target.Destinations; len(destinations) > 0 {
|
||||||
|
for _, destination := range destinations {
|
||||||
|
var t gateway.ConfigDestinationTarget
|
||||||
|
|
||||||
|
t.Host = destination.Host
|
||||||
|
t.Port = destination.Port
|
||||||
|
|
||||||
|
dest.Targets = append(dest.Targets, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tls := target.TLS; tls != nil {
|
||||||
|
dest.Type = util.NewType(gateway.ConfigDestinationTypeHTTPS)
|
||||||
|
}
|
||||||
|
dest.Path = util.NewType(target.Path)
|
||||||
|
cfg.Destinations[at.Spec.GetRoute().GetPath()] = dest
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}, func(at *networkingApi.ArangoRoute) bool {
|
||||||
|
return at.Spec.GetDeployment() == deploymentName
|
||||||
|
}); err != nil {
|
||||||
|
return gateway.Config{}, errors.Wrapf(err, "Unable to iterate over ArangoRoutes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
|
@ -22,21 +22,13 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
core "k8s.io/api/core/v1"
|
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/metrics"
|
"github.com/arangodb/kube-arangodb/pkg/metrics"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
|
inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector"
|
||||||
configMapsV1 "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/configmap/v1"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -65,49 +57,3 @@ func (r *Resources) EnsureConfigMaps(ctx context.Context, cachedStatus inspector
|
||||||
}
|
}
|
||||||
return reconcileRequired.Reconcile(ctx)
|
return reconcileRequired.Reconcile(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resources) ensureGatewayConfig(ctx context.Context, cachedStatus inspectorInterface.Inspector, configMaps configMapsV1.ModInterface) error {
|
|
||||||
deploymentName := r.context.GetAPIObject().GetName()
|
|
||||||
configMapName := GetGatewayConfigMapName(deploymentName)
|
|
||||||
|
|
||||||
if _, exists := cachedStatus.ConfigMap().V1().GetSimple(configMapName); !exists {
|
|
||||||
// Find serving service (single/crdn)
|
|
||||||
spec := r.context.GetSpec()
|
|
||||||
svcServingName := fmt.Sprintf("%s-%s", deploymentName, spec.Mode.Get().ServingGroup().AsRole())
|
|
||||||
|
|
||||||
svc, svcExist := cachedStatus.Service().V1().GetSimple(svcServingName)
|
|
||||||
if !svcExist {
|
|
||||||
return errors.Errorf("Service %s not found", svcServingName)
|
|
||||||
}
|
|
||||||
|
|
||||||
gatewayCfgYaml, err := RenderGatewayConfigYAML(svc.Spec.ClusterIP)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(errors.Wrapf(err, "Failed to render gateway config"))
|
|
||||||
}
|
|
||||||
cm := &core.ConfigMap{
|
|
||||||
ObjectMeta: meta.ObjectMeta{
|
|
||||||
Name: configMapName,
|
|
||||||
},
|
|
||||||
Data: map[string]string{
|
|
||||||
GatewayConfigFileName: string(gatewayCfgYaml),
|
|
||||||
GatewayConfigChecksumName: util.SHA256(gatewayCfgYaml),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
owner := r.context.GetAPIObject().AsOwner()
|
|
||||||
|
|
||||||
err = globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(ctx, func(ctxChild context.Context) error {
|
|
||||||
return k8sutil.CreateConfigMap(ctxChild, configMaps, cm, &owner)
|
|
||||||
})
|
|
||||||
if kerrors.IsAlreadyExists(err) {
|
|
||||||
// CM added while we tried it also
|
|
||||||
return nil
|
|
||||||
} else if err != nil {
|
|
||||||
// Failed to create
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Reconcile()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
259
pkg/deployment/resources/gateway/gateway_config.go
Normal file
259
pkg/deployment/resources/gateway/gateway_config.go
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
//
|
||||||
|
// 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 gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
bootstrapAPI "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
|
||||||
|
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||||
|
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
|
listenerAPI "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||||
|
routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
|
routerAPI "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3"
|
||||||
|
httpConnectionManagerAPI "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
DefaultDestination ConfigDestination `json:"defaultDestination,omitempty"`
|
||||||
|
|
||||||
|
Destinations ConfigDestinations `json:"destinations,omitempty"`
|
||||||
|
|
||||||
|
DefaultTLS *ConfigTLS `json:"defaultTLS,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) Validate() error {
|
||||||
|
return errors.Errors(
|
||||||
|
shared.PrefixResourceErrors("defaultDestination", c.DefaultDestination.Validate()),
|
||||||
|
shared.PrefixResourceErrors("destinations", c.Destinations.Validate()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderYAML() ([]byte, string, *bootstrapAPI.Bootstrap, error) {
|
||||||
|
cfg, err := c.Render()
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := protojson.MarshalOptions{
|
||||||
|
UseProtoNames: true,
|
||||||
|
}.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err = yaml.JSONToYAML(data)
|
||||||
|
return data, util.SHA256(data), cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) Render() (*bootstrapAPI.Bootstrap, error) {
|
||||||
|
if err := c.Validate(); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Validation failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
clusters, err := c.RenderClusters()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render clusters")
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, err := c.RenderListener()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render listener")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bootstrapAPI.Bootstrap{
|
||||||
|
Admin: &bootstrapAPI.Admin{
|
||||||
|
Address: &coreAPI.Address{
|
||||||
|
Address: &coreAPI.Address_SocketAddress{
|
||||||
|
SocketAddress: &coreAPI.SocketAddress{
|
||||||
|
Address: "127.0.0.1",
|
||||||
|
PortSpecifier: &coreAPI.SocketAddress_PortValue{PortValue: 9901},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
StaticResources: &bootstrapAPI.Bootstrap_StaticResources{
|
||||||
|
Listeners: []*listenerAPI.Listener{
|
||||||
|
listener,
|
||||||
|
},
|
||||||
|
Clusters: clusters,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderClusters() ([]*clusterAPI.Cluster, error) {
|
||||||
|
def, err := c.DefaultDestination.RenderCluster("default")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clusters := []*clusterAPI.Cluster{
|
||||||
|
def,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range c.Destinations {
|
||||||
|
name := fmt.Sprintf("cluster_%s", util.SHA256FromString(k))
|
||||||
|
c, err := v.RenderCluster(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
clusters = append(clusters, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(clusters, func(i, j int) bool {
|
||||||
|
return clusters[i].Name < clusters[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
return clusters, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderRoutes() ([]*routeAPI.Route, error) {
|
||||||
|
def, err := c.DefaultDestination.RenderRoute("default", "/")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
routes := []*routeAPI.Route{
|
||||||
|
def,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range c.Destinations {
|
||||||
|
name := fmt.Sprintf("cluster_%s", util.SHA256FromString(k))
|
||||||
|
c, err := v.RenderRoute(name, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
routes = append(routes, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(routes, func(i, j int) bool {
|
||||||
|
return routes[i].GetMatch().GetPrefix() > routes[j].GetMatch().GetPrefix()
|
||||||
|
})
|
||||||
|
|
||||||
|
return routes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderFilters() ([]*listenerAPI.Filter, error) {
|
||||||
|
httpFilterConfigType, err := anypb.New(&routerAPI.Router{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render route config")
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err := c.RenderRoutes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render routes")
|
||||||
|
}
|
||||||
|
|
||||||
|
filterConfigType, err := anypb.New(&httpConnectionManagerAPI.HttpConnectionManager{
|
||||||
|
StatPrefix: "ingress_http",
|
||||||
|
CodecType: httpConnectionManagerAPI.HttpConnectionManager_AUTO,
|
||||||
|
RouteSpecifier: &httpConnectionManagerAPI.HttpConnectionManager_RouteConfig{
|
||||||
|
RouteConfig: &routeAPI.RouteConfiguration{
|
||||||
|
Name: "default",
|
||||||
|
VirtualHosts: []*routeAPI.VirtualHost{
|
||||||
|
{
|
||||||
|
Name: "default",
|
||||||
|
Domains: []string{"*"},
|
||||||
|
Routes: routes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
HttpFilters: []*httpConnectionManagerAPI.HttpFilter{
|
||||||
|
{
|
||||||
|
Name: "envoy.filters.http.routerAPI",
|
||||||
|
ConfigType: &httpConnectionManagerAPI.HttpFilter_TypedConfig{
|
||||||
|
TypedConfig: httpFilterConfigType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render http connection manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*listenerAPI.Filter{
|
||||||
|
{
|
||||||
|
Name: "envoy.filters.network.httpConnectionManagerAPI",
|
||||||
|
ConfigType: &listenerAPI.Filter_TypedConfig{
|
||||||
|
TypedConfig: filterConfigType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderDefaultFilterChain() (*listenerAPI.FilterChain, error) {
|
||||||
|
filters, err := c.RenderFilters()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render filters")
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := &listenerAPI.FilterChain{
|
||||||
|
Filters: filters,
|
||||||
|
}
|
||||||
|
|
||||||
|
if tls, err := c.DefaultTLS.RenderListenerTransportSocket(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
ret.TransportSocket = tls
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderSecondaryFilterChains() ([]*listenerAPI.FilterChain, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Config) RenderListener() (*listenerAPI.Listener, error) {
|
||||||
|
filterChains, err := c.RenderSecondaryFilterChains()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render secondary filter chains")
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultFilterChain, err := c.RenderDefaultFilterChain()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render default filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &listenerAPI.Listener{
|
||||||
|
Name: "default",
|
||||||
|
Address: &coreAPI.Address{
|
||||||
|
Address: &coreAPI.Address_SocketAddress{
|
||||||
|
SocketAddress: &coreAPI.SocketAddress{
|
||||||
|
Address: "0.0.0.0",
|
||||||
|
PortSpecifier: &coreAPI.SocketAddress_PortValue{PortValue: shared.ArangoPort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FilterChains: filterChains,
|
||||||
|
|
||||||
|
DefaultFilterChain: defaultFilterChain,
|
||||||
|
}, nil
|
||||||
|
}
|
122
pkg/deployment/resources/gateway/gateway_config_destination.go
Normal file
122
pkg/deployment/resources/gateway/gateway_config_destination.go
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
//
|
||||||
|
// 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 gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
||||||
|
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||||
|
routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigDestinations map[string]ConfigDestination
|
||||||
|
|
||||||
|
func (c ConfigDestinations) Validate() error {
|
||||||
|
if len(c) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return shared.WithErrors(
|
||||||
|
shared.ValidateMap(c, func(k string, destination ConfigDestination) error {
|
||||||
|
var errs []error
|
||||||
|
if k == "/" {
|
||||||
|
errs = append(errs, errors.Errorf("Route for `/` is reserved"))
|
||||||
|
}
|
||||||
|
if err := shared.ValidateAPIPath(k); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
if err := destination.Validate(); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
return shared.WithErrors(errs...)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigDestination struct {
|
||||||
|
Targets ConfigDestinationTargets `json:"targets,omitempty"`
|
||||||
|
|
||||||
|
Type *ConfigDestinationType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
Path *string `json:"path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestination) Validate() error {
|
||||||
|
return shared.WithErrors(
|
||||||
|
shared.PrefixResourceError("targets", c.Targets.Validate()),
|
||||||
|
shared.PrefixResourceError("type", c.Type.Validate()),
|
||||||
|
shared.PrefixResourceError("path", shared.ValidateAPIPath(c.GetPath())),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestination) GetPath() string {
|
||||||
|
if c.Path == nil {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return *c.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestination) RenderRoute(name, prefix string) (*routeAPI.Route, error) {
|
||||||
|
return &routeAPI.Route{
|
||||||
|
Match: &routeAPI.RouteMatch{
|
||||||
|
PathSpecifier: &routeAPI.RouteMatch_Prefix{
|
||||||
|
Prefix: prefix,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: &routeAPI.Route_Route{
|
||||||
|
Route: &routeAPI.RouteAction{
|
||||||
|
ClusterSpecifier: &routeAPI.RouteAction_Cluster{
|
||||||
|
Cluster: name,
|
||||||
|
},
|
||||||
|
PrefixRewrite: c.GetPath(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestination) RenderCluster(name string) (*clusterAPI.Cluster, error) {
|
||||||
|
cluster := &clusterAPI.Cluster{
|
||||||
|
Name: name,
|
||||||
|
ConnectTimeout: durationpb.New(time.Second),
|
||||||
|
LbPolicy: clusterAPI.Cluster_ROUND_ROBIN,
|
||||||
|
LoadAssignment: &endpointAPI.ClusterLoadAssignment{
|
||||||
|
ClusterName: name,
|
||||||
|
Endpoints: []*endpointAPI.LocalityLbEndpoints{
|
||||||
|
{
|
||||||
|
LbEndpoints: c.Targets.RenderEndpoints(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if t, err := c.Type.RenderUpstreamTransportSocket(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
cluster.TransportSocket = t
|
||||||
|
}
|
||||||
|
|
||||||
|
return cluster, nil
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
//
|
||||||
|
// 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 gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
|
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
||||||
|
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigDestinationTargets []ConfigDestinationTarget
|
||||||
|
|
||||||
|
func (c ConfigDestinationTargets) RenderEndpoints() []*endpointAPI.LbEndpoint {
|
||||||
|
var endpoints = make([]*endpointAPI.LbEndpoint, len(c))
|
||||||
|
|
||||||
|
for id := range c {
|
||||||
|
endpoints[id] = c[id].RenderEndpoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestinationTargets) Validate() error {
|
||||||
|
if len(c) == 0 {
|
||||||
|
return errors.Errorf("Empty Target not allowed")
|
||||||
|
}
|
||||||
|
return shared.ValidateList(c, func(target ConfigDestinationTarget) error {
|
||||||
|
return target.Validate()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigDestinationTarget struct {
|
||||||
|
Host string `json:"ip,omitempty"`
|
||||||
|
Port int32 `json:"port,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestinationTarget) Validate() error {
|
||||||
|
return shared.WithErrors(
|
||||||
|
shared.ValidateRequiredPath("ip", &c.Host, func(t string) error {
|
||||||
|
if t == "" {
|
||||||
|
return errors.Errorf("Empty string not allowed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
shared.ValidateRequiredPath("ip", &c.Port, func(t int32) error {
|
||||||
|
if t <= 0 {
|
||||||
|
return errors.Errorf("Port needs to be greater than 0")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ConfigDestinationTarget) RenderEndpoint() *endpointAPI.LbEndpoint {
|
||||||
|
return &endpointAPI.LbEndpoint{
|
||||||
|
HostIdentifier: &endpointAPI.LbEndpoint_Endpoint{
|
||||||
|
Endpoint: &endpointAPI.Endpoint{
|
||||||
|
Address: &coreAPI.Address{
|
||||||
|
Address: &coreAPI.Address_SocketAddress{
|
||||||
|
SocketAddress: &coreAPI.SocketAddress{
|
||||||
|
Protocol: coreAPI.SocketAddress_TCP,
|
||||||
|
Address: c.Host,
|
||||||
|
PortSpecifier: &coreAPI.SocketAddress_PortValue{
|
||||||
|
PortValue: uint32(c.Port),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
//
|
||||||
|
// 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 gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
|
tlsApi "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigDestinationType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConfigDestinationTypeHTTP ConfigDestinationType = iota
|
||||||
|
ConfigDestinationTypeHTTPS
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *ConfigDestinationType) Get() ConfigDestinationType {
|
||||||
|
if c == nil {
|
||||||
|
return ConfigDestinationTypeHTTP
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := *c; v {
|
||||||
|
case ConfigDestinationTypeHTTP, ConfigDestinationTypeHTTPS:
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return ConfigDestinationTypeHTTP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigDestinationType) RenderUpstreamTransportSocket() (*coreAPI.TransportSocket, error) {
|
||||||
|
if c.Get() == ConfigDestinationTypeHTTPS {
|
||||||
|
tlsConfig, err := anypb.New(&tlsApi.UpstreamTlsContext{
|
||||||
|
CommonTlsContext: &tlsApi.CommonTlsContext{
|
||||||
|
ValidationContextType: &tlsApi.CommonTlsContext_ValidationContext{},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &coreAPI.TransportSocket{
|
||||||
|
Name: "envoy.transport_sockets.tls",
|
||||||
|
ConfigType: &coreAPI.TransportSocket_TypedConfig{
|
||||||
|
TypedConfig: tlsConfig,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigDestinationType) Validate() error {
|
||||||
|
switch c.Get() {
|
||||||
|
case ConfigDestinationTypeHTTP, ConfigDestinationTypeHTTPS:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.Errorf("Invalid destination type")
|
||||||
|
}
|
||||||
|
}
|
150
pkg/deployment/resources/gateway/gateway_config_test.go
Normal file
150
pkg/deployment/resources/gateway/gateway_config_test.go
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
//
|
||||||
|
// 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 gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
bootstrapAPI "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func renderAndPrintGatewayConfig(t *testing.T, cfg Config) *bootstrapAPI.Bootstrap {
|
||||||
|
data, checksum, obj, err := cfg.RenderYAML()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Logf("Checksum: %s", checksum)
|
||||||
|
t.Log(string(data))
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_GatewayConfig(t *testing.T) {
|
||||||
|
t.Run("Default", func(t *testing.T) {
|
||||||
|
renderAndPrintGatewayConfig(t, Config{
|
||||||
|
DefaultDestination: ConfigDestination{
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Default", func(t *testing.T) {
|
||||||
|
renderAndPrintGatewayConfig(t, Config{
|
||||||
|
DefaultDestination: ConfigDestination{
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: util.NewType(ConfigDestinationTypeHTTPS),
|
||||||
|
},
|
||||||
|
DefaultTLS: &ConfigTLS{
|
||||||
|
CertificatePath: "/test",
|
||||||
|
PrivateKeyPath: "/test12",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Default", func(t *testing.T) {
|
||||||
|
renderAndPrintGatewayConfig(t, Config{
|
||||||
|
DefaultDestination: ConfigDestination{
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Path: util.NewType("/test/path/"),
|
||||||
|
Type: util.NewType(ConfigDestinationTypeHTTPS),
|
||||||
|
},
|
||||||
|
DefaultTLS: &ConfigTLS{
|
||||||
|
CertificatePath: "/test",
|
||||||
|
PrivateKeyPath: "/test12",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Default", func(t *testing.T) {
|
||||||
|
renderAndPrintGatewayConfig(t, Config{
|
||||||
|
DefaultDestination: ConfigDestination{
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Path: util.NewType("/test/path/"),
|
||||||
|
Type: util.NewType(ConfigDestinationTypeHTTPS),
|
||||||
|
},
|
||||||
|
DefaultTLS: &ConfigTLS{
|
||||||
|
CertificatePath: "/test",
|
||||||
|
PrivateKeyPath: "/test12",
|
||||||
|
},
|
||||||
|
Destinations: ConfigDestinations{
|
||||||
|
"/test/": {
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12346,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Path: util.NewType("/test/path/"),
|
||||||
|
Type: util.NewType(ConfigDestinationTypeHTTPS),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Default", func(t *testing.T) {
|
||||||
|
renderAndPrintGatewayConfig(t, Config{
|
||||||
|
DefaultDestination: ConfigDestination{
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12345,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Path: util.NewType("/test/path/"),
|
||||||
|
Type: util.NewType(ConfigDestinationTypeHTTPS),
|
||||||
|
},
|
||||||
|
DefaultTLS: &ConfigTLS{
|
||||||
|
CertificatePath: "/test",
|
||||||
|
PrivateKeyPath: "/test12",
|
||||||
|
},
|
||||||
|
Destinations: ConfigDestinations{
|
||||||
|
"/_test/": {
|
||||||
|
Targets: []ConfigDestinationTarget{
|
||||||
|
{
|
||||||
|
Host: "127.0.0.1",
|
||||||
|
Port: 12346,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Path: util.NewType("/test/path/"),
|
||||||
|
Type: util.NewType(ConfigDestinationTypeHTTP),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
69
pkg/deployment/resources/gateway/gateway_config_tls.go
Normal file
69
pkg/deployment/resources/gateway/gateway_config_tls.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
//
|
||||||
|
// 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 gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
|
tlsApi "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigTLS struct {
|
||||||
|
CertificatePath string `json:"certificatePath,omitempty"`
|
||||||
|
PrivateKeyPath string `json:"privateKeyPath,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfigTLS) RenderListenerTransportSocket() (*coreAPI.TransportSocket, error) {
|
||||||
|
if c == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsContext, err := anypb.New(&tlsApi.DownstreamTlsContext{
|
||||||
|
CommonTlsContext: &tlsApi.CommonTlsContext{
|
||||||
|
TlsCertificates: []*tlsApi.TlsCertificate{
|
||||||
|
{
|
||||||
|
CertificateChain: &coreAPI.DataSource{
|
||||||
|
Specifier: &coreAPI.DataSource_Filename{
|
||||||
|
Filename: c.CertificatePath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PrivateKey: &coreAPI.DataSource{
|
||||||
|
Specifier: &coreAPI.DataSource_Filename{
|
||||||
|
Filename: c.PrivateKeyPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Unable to render tls context")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &coreAPI.TransportSocket{
|
||||||
|
Name: "envoy.transport_sockets.tls",
|
||||||
|
ConfigType: &coreAPI.TransportSocket_TypedConfig{
|
||||||
|
TypedConfig: tlsContext,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -1,268 +0,0 @@
|
||||||
//
|
|
||||||
// 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 resources
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
bootstrapAPI "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
|
|
||||||
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
|
|
||||||
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
|
||||||
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
|
||||||
listenerAPI "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
|
||||||
routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
|
||||||
routerAPI "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3"
|
|
||||||
httpConnectionManagerAPI "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
|
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
|
||||||
"google.golang.org/protobuf/types/known/durationpb"
|
|
||||||
"sigs.k8s.io/yaml"
|
|
||||||
|
|
||||||
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Redirect util.KV[string, []string]
|
|
||||||
|
|
||||||
func WithRedirect(prefix string, target ...string) Redirect {
|
|
||||||
return Redirect{
|
|
||||||
K: prefix,
|
|
||||||
V: target,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderGatewayConfigYAML(dbServiceAddress string, redirects ...Redirect) ([]byte, error) {
|
|
||||||
cfg, err := RenderConfig(dbServiceAddress, redirects...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := protojson.MarshalOptions{
|
|
||||||
UseProtoNames: true,
|
|
||||||
}.Marshal(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err = yaml.JSONToYAML(data)
|
|
||||||
return data, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderConfig(dbServiceAddress string, redirects ...Redirect) (*bootstrapAPI.Bootstrap, error) {
|
|
||||||
clusters := []*clusterAPI.Cluster{
|
|
||||||
{
|
|
||||||
Name: "arangodb",
|
|
||||||
ConnectTimeout: durationpb.New(250 * time.Millisecond),
|
|
||||||
LbPolicy: clusterAPI.Cluster_ROUND_ROBIN,
|
|
||||||
LoadAssignment: &endpointAPI.ClusterLoadAssignment{
|
|
||||||
ClusterName: "arangodb",
|
|
||||||
Endpoints: []*endpointAPI.LocalityLbEndpoints{
|
|
||||||
{
|
|
||||||
LbEndpoints: []*endpointAPI.LbEndpoint{
|
|
||||||
{
|
|
||||||
HostIdentifier: &endpointAPI.LbEndpoint_Endpoint{
|
|
||||||
Endpoint: &endpointAPI.Endpoint{
|
|
||||||
Address: &coreAPI.Address{
|
|
||||||
Address: &coreAPI.Address_SocketAddress{
|
|
||||||
SocketAddress: &coreAPI.SocketAddress{
|
|
||||||
Address: dbServiceAddress,
|
|
||||||
PortSpecifier: &coreAPI.SocketAddress_PortValue{
|
|
||||||
PortValue: shared.ArangoPort,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
routes := []*routeAPI.Route{
|
|
||||||
{
|
|
||||||
Match: &routeAPI.RouteMatch{
|
|
||||||
PathSpecifier: &routeAPI.RouteMatch_Prefix{
|
|
||||||
Prefix: "/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: &routeAPI.Route_Route{
|
|
||||||
Route: &routeAPI.RouteAction{
|
|
||||||
ClusterSpecifier: &routeAPI.RouteAction_Cluster{
|
|
||||||
Cluster: "arangodb",
|
|
||||||
},
|
|
||||||
PrefixRewrite: "/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for id, redirect := range redirects {
|
|
||||||
var endpoints []*endpointAPI.LbEndpoint
|
|
||||||
|
|
||||||
for _, target := range redirect.V {
|
|
||||||
req, err := url.Parse(target)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
port, err := strconv.Atoi(req.Port())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoints = append(endpoints, &endpointAPI.LbEndpoint{
|
|
||||||
HostIdentifier: &endpointAPI.LbEndpoint_Endpoint{
|
|
||||||
Endpoint: &endpointAPI.Endpoint{
|
|
||||||
Address: &coreAPI.Address{
|
|
||||||
Address: &coreAPI.Address_SocketAddress{
|
|
||||||
SocketAddress: &coreAPI.SocketAddress{
|
|
||||||
Address: req.Hostname(),
|
|
||||||
PortSpecifier: &coreAPI.SocketAddress_PortValue{
|
|
||||||
PortValue: uint32(port),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
cluster := &clusterAPI.Cluster{
|
|
||||||
Name: fmt.Sprintf("cluster_%05d", id),
|
|
||||||
ConnectTimeout: durationpb.New(250 * time.Millisecond),
|
|
||||||
LbPolicy: clusterAPI.Cluster_ROUND_ROBIN,
|
|
||||||
LoadAssignment: &endpointAPI.ClusterLoadAssignment{
|
|
||||||
ClusterName: fmt.Sprintf("cluster_%05d", id),
|
|
||||||
Endpoints: []*endpointAPI.LocalityLbEndpoints{
|
|
||||||
{
|
|
||||||
LbEndpoints: endpoints,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
route := &routeAPI.Route{
|
|
||||||
Match: &routeAPI.RouteMatch{
|
|
||||||
PathSpecifier: &routeAPI.RouteMatch_Prefix{
|
|
||||||
Prefix: redirect.K,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: &routeAPI.Route_Route{
|
|
||||||
Route: &routeAPI.RouteAction{
|
|
||||||
ClusterSpecifier: &routeAPI.RouteAction_Cluster{
|
|
||||||
Cluster: fmt.Sprintf("cluster_%05d", id),
|
|
||||||
},
|
|
||||||
PrefixRewrite: "/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
clusters = append(clusters, cluster)
|
|
||||||
routes = append(routes, route)
|
|
||||||
}
|
|
||||||
|
|
||||||
routes = util.Sort(routes, func(i, j *routeAPI.Route) bool {
|
|
||||||
return i.Match.GetPrefix() > j.Match.GetPrefix()
|
|
||||||
})
|
|
||||||
|
|
||||||
httpFilterConfigType, err := anypb.New(&routerAPI.Router{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
filterConfigType, err := anypb.New(&httpConnectionManagerAPI.HttpConnectionManager{
|
|
||||||
StatPrefix: "ingress_http",
|
|
||||||
CodecType: httpConnectionManagerAPI.HttpConnectionManager_AUTO,
|
|
||||||
RouteSpecifier: &httpConnectionManagerAPI.HttpConnectionManager_RouteConfig{
|
|
||||||
RouteConfig: &routeAPI.RouteConfiguration{
|
|
||||||
Name: "local_route",
|
|
||||||
VirtualHosts: []*routeAPI.VirtualHost{
|
|
||||||
{
|
|
||||||
Name: "local_service",
|
|
||||||
Domains: []string{"*"},
|
|
||||||
Routes: routes,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
HttpFilters: []*httpConnectionManagerAPI.HttpFilter{
|
|
||||||
{
|
|
||||||
Name: "envoy.filters.http.routerAPI",
|
|
||||||
ConfigType: &httpConnectionManagerAPI.HttpFilter_TypedConfig{
|
|
||||||
TypedConfig: httpFilterConfigType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &bootstrapAPI.Bootstrap{
|
|
||||||
Admin: &bootstrapAPI.Admin{
|
|
||||||
Address: &coreAPI.Address{
|
|
||||||
Address: &coreAPI.Address_SocketAddress{
|
|
||||||
SocketAddress: &coreAPI.SocketAddress{
|
|
||||||
Address: "127.0.0.1",
|
|
||||||
PortSpecifier: &coreAPI.SocketAddress_PortValue{PortValue: 9901},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
StaticResources: &bootstrapAPI.Bootstrap_StaticResources{
|
|
||||||
Listeners: []*listenerAPI.Listener{
|
|
||||||
{
|
|
||||||
Name: "listener_0",
|
|
||||||
Address: &coreAPI.Address{
|
|
||||||
Address: &coreAPI.Address_SocketAddress{
|
|
||||||
SocketAddress: &coreAPI.SocketAddress{
|
|
||||||
Address: "0.0.0.0",
|
|
||||||
PortSpecifier: &coreAPI.SocketAddress_PortValue{PortValue: shared.ArangoPort},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
FilterChains: []*listenerAPI.FilterChain{
|
|
||||||
{
|
|
||||||
Filters: []*listenerAPI.Filter{
|
|
||||||
{
|
|
||||||
Name: "envoy.filters.network.httpConnectionManagerAPI",
|
|
||||||
ConfigType: &listenerAPI.Filter_TypedConfig{
|
|
||||||
TypedConfig: filterConfigType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Clusters: clusters,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
|
@ -286,10 +286,15 @@ func createArangoSyncArgs(apiObject meta.Object, spec api.DeploymentSpec, group
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
func createArangoGatewayArgs(groupSpec api.ServerGroupSpec) []string {
|
func createArangoGatewayArgs(input pod.Input, additionalOptions ...k8sutil.OptionPair) []string {
|
||||||
args := []string{"--config-path", GatewayConfigFilePath}
|
options := k8sutil.CreateOptionPairs(64)
|
||||||
if len(groupSpec.Args) > 0 {
|
options.Add("--config-path", GatewayConfigFilePath)
|
||||||
args = append(args, groupSpec.Args...)
|
|
||||||
|
options.Append(additionalOptions...)
|
||||||
|
|
||||||
|
args := options.Sort().AsSplittedArgs()
|
||||||
|
if len(input.GroupSpec.Args) > 0 {
|
||||||
|
args = append(args, input.GroupSpec.Args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
@ -297,7 +302,7 @@ func createArangoGatewayArgs(groupSpec api.ServerGroupSpec) []string {
|
||||||
|
|
||||||
// CreatePodTolerations creates a list of tolerations for a pod created for the given group.
|
// CreatePodTolerations creates a list of tolerations for a pod created for the given group.
|
||||||
func (r *Resources) CreatePodTolerations(group api.ServerGroup, groupSpec api.ServerGroupSpec) []core.Toleration {
|
func (r *Resources) CreatePodTolerations(group api.ServerGroup, groupSpec api.ServerGroupSpec) []core.Toleration {
|
||||||
return tolerations.MergeTolerationsIfNotFound(tolerations.CreatePodTolerations(r.context.GetMode(), group), groupSpec.GetTolerations())
|
return tolerations.MergeTolerationsIfNotFound(CreatePodTolerations(r.context.GetMode(), group), groupSpec.GetTolerations())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resources) RenderPodTemplateForMember(ctx context.Context, acs sutil.ACS, spec api.DeploymentSpec, status api.DeploymentStatus, memberID string, imageInfo api.ImageInfo) (*core.PodTemplateSpec, error) {
|
func (r *Resources) RenderPodTemplateForMember(ctx context.Context, acs sutil.ACS, spec api.DeploymentSpec, status api.DeploymentStatus, memberID string, imageInfo api.ImageInfo) (*core.PodTemplateSpec, error) {
|
||||||
|
@ -396,14 +401,15 @@ func (r *Resources) RenderPodForMember(ctx context.Context, acs sutil.ACS, spec
|
||||||
|
|
||||||
podCreator = &MemberGatewayPod{
|
podCreator = &MemberGatewayPod{
|
||||||
podName: podName,
|
podName: podName,
|
||||||
|
status: m,
|
||||||
groupSpec: groupSpec,
|
groupSpec: groupSpec,
|
||||||
spec: spec,
|
spec: spec,
|
||||||
group: group,
|
group: group,
|
||||||
resources: r,
|
resources: r,
|
||||||
imageInfo: imageInfo,
|
imageInfo: imageInfo,
|
||||||
|
context: r.context,
|
||||||
|
deploymentStatus: status,
|
||||||
arangoMember: *member,
|
arangoMember: *member,
|
||||||
apiObject: apiObject,
|
|
||||||
memberStatus: m,
|
|
||||||
cachedStatus: cache,
|
cachedStatus: cache,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -687,7 +693,18 @@ func RenderArangoPod(ctx context.Context, cachedStatus inspectorInterface.Inspec
|
||||||
PodAffinity: podCreator.GetPodAffinity(),
|
PodAffinity: podCreator.GetPodAffinity(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &p, nil
|
if profiles, err := podCreator.Profiles(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(profiles) > 0 {
|
||||||
|
if err := profiles.RenderOnTemplate(&p); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &core.Pod{
|
||||||
|
ObjectMeta: p.ObjectMeta,
|
||||||
|
Spec: p.Spec,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateArangoPod creates a new Pod with container provided by parameter 'containerCreator'
|
// CreateArangoPod creates a new Pod with container provided by parameter 'containerCreator'
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
|
@ -321,7 +322,7 @@ func (m *MemberArangoDPod) AsInput() pod.Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MemberArangoDPod) Init(_ context.Context, _ interfaces.Inspector, pod *core.Pod) error {
|
func (m *MemberArangoDPod) Init(_ context.Context, _ interfaces.Inspector, pod *core.PodTemplateSpec) error {
|
||||||
terminationGracePeriodSeconds := int64(math.Ceil(m.groupSpec.GetTerminationGracePeriod(m.group).Seconds()))
|
terminationGracePeriodSeconds := int64(math.Ceil(m.groupSpec.GetTerminationGracePeriod(m.group).Seconds()))
|
||||||
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
||||||
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
|
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
|
||||||
|
@ -409,7 +410,7 @@ func (m *MemberArangoDPod) GetServiceAccountName() string {
|
||||||
return m.groupSpec.GetServiceAccountName()
|
return m.groupSpec.GetServiceAccountName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MemberArangoDPod) GetSidecars(pod *core.Pod) error {
|
func (m *MemberArangoDPod) GetSidecars(pod *core.PodTemplateSpec) error {
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if m.spec.Metrics.IsEnabled() && m.spec.Metrics.Mode.Get() != api.MetricsModeInternal {
|
if m.spec.Metrics.IsEnabled() && m.spec.Metrics.Mode.Get() != api.MetricsModeInternal {
|
||||||
var c *core.Container
|
var c *core.Container
|
||||||
|
@ -595,6 +596,10 @@ func (m *MemberArangoDPod) Annotations() map[string]string {
|
||||||
return collection.MergeAnnotations(m.spec.Annotations, m.groupSpec.Annotations)
|
return collection.MergeAnnotations(m.spec.Annotations, m.groupSpec.Annotations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MemberArangoDPod) Profiles() (schedulerApi.ProfileTemplates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MemberArangoDPod) Labels() map[string]string {
|
func (m *MemberArangoDPod) Labels() map[string]string {
|
||||||
l := collection.ReservedLabels().Filter(collection.MergeAnnotations(m.spec.Labels, m.groupSpec.Labels))
|
l := collection.ReservedLabels().Filter(collection.MergeAnnotations(m.spec.Labels, m.groupSpec.Labels))
|
||||||
|
|
||||||
|
|
|
@ -21,21 +21,12 @@
|
||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
|
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
|
|
||||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
|
||||||
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/collection"
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/interfaces"
|
|
||||||
kresources "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -43,298 +34,22 @@ const (
|
||||||
GatewayVolumeMountDir = "/etc/gateway/"
|
GatewayVolumeMountDir = "/etc/gateway/"
|
||||||
GatewayVolumeName = "gateway"
|
GatewayVolumeName = "gateway"
|
||||||
GatewayConfigFileName = "gateway.yaml"
|
GatewayConfigFileName = "gateway.yaml"
|
||||||
GatewayConfigChecksumName = "gateway.yaml-checksum"
|
|
||||||
GatewayConfigFilePath = GatewayVolumeMountDir + GatewayConfigFileName
|
GatewayConfigFilePath = GatewayVolumeMountDir + GatewayConfigFileName
|
||||||
)
|
)
|
||||||
|
|
||||||
type ArangoGatewayContainer struct {
|
|
||||||
groupSpec api.ServerGroupSpec
|
|
||||||
spec api.DeploymentSpec
|
|
||||||
group api.ServerGroup
|
|
||||||
resources *Resources
|
|
||||||
imageInfo api.ImageInfo
|
|
||||||
apiObject meta.Object
|
|
||||||
memberStatus api.MemberStatus
|
|
||||||
arangoMember api.ArangoMember
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ interfaces.PodCreator = &MemberGatewayPod{}
|
|
||||||
var _ interfaces.ContainerCreator = &ArangoGatewayContainer{}
|
|
||||||
|
|
||||||
type MemberGatewayPod struct {
|
|
||||||
podName string
|
|
||||||
|
|
||||||
groupSpec api.ServerGroupSpec
|
|
||||||
spec api.DeploymentSpec
|
|
||||||
group api.ServerGroup
|
|
||||||
arangoMember api.ArangoMember
|
|
||||||
resources *Resources
|
|
||||||
imageInfo api.ImageInfo
|
|
||||||
apiObject meta.Object
|
|
||||||
memberStatus api.MemberStatus
|
|
||||||
cachedStatus interfaces.Inspector
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGatewayConfigMapName(name string) string {
|
func GetGatewayConfigMapName(name string) string {
|
||||||
return fmt.Sprintf("%s-gateway", name)
|
return fmt.Sprintf("%s-gateway", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetCommand() ([]string, error) {
|
func createGatewayVolumes(input pod.Input) pod.Volumes {
|
||||||
cmd := make([]string, 0, 128)
|
|
||||||
cmd = append(cmd, a.GetExecutor())
|
|
||||||
cmd = append(cmd, createArangoGatewayArgs(a.groupSpec)...)
|
|
||||||
return cmd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetName() string {
|
|
||||||
return shared.ServerContainerName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetPorts() []core.ContainerPort {
|
|
||||||
port := shared.ArangoPort
|
|
||||||
|
|
||||||
return []core.ContainerPort{
|
|
||||||
{
|
|
||||||
Name: shared.ServerContainerName,
|
|
||||||
ContainerPort: int32(port),
|
|
||||||
Protocol: core.ProtocolTCP,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetExecutor() string {
|
|
||||||
return a.groupSpec.GetEntrypoint(ArangoGatewayExecutor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetSecurityContext() *core.SecurityContext {
|
|
||||||
return k8sutil.CreateSecurityContext(a.groupSpec.SecurityContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetProbes() (*core.Probe, *core.Probe, *core.Probe, error) {
|
|
||||||
var liveness, readiness, startup *core.Probe
|
|
||||||
|
|
||||||
probeLivenessConfig, err := a.resources.getLivenessProbe(a.spec, a.group, a.imageInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
probeReadinessConfig, err := a.resources.getReadinessProbe(a.spec, a.group, a.imageInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
probeStartupConfig, err := a.resources.getReadinessProbe(a.spec, a.group, a.imageInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if probeLivenessConfig != nil {
|
|
||||||
liveness = probeLivenessConfig.Create()
|
|
||||||
}
|
|
||||||
|
|
||||||
if probeReadinessConfig != nil {
|
|
||||||
readiness = probeReadinessConfig.Create()
|
|
||||||
}
|
|
||||||
|
|
||||||
if probeStartupConfig != nil {
|
|
||||||
startup = probeStartupConfig.Create()
|
|
||||||
}
|
|
||||||
|
|
||||||
return liveness, readiness, startup, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetResourceRequirements() core.ResourceRequirements {
|
|
||||||
return kresources.ExtractPodAcceptedResourceRequirement(a.arangoMember.Spec.Overrides.GetResources(&a.groupSpec))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetLifecycle() (*core.Lifecycle, error) {
|
|
||||||
return k8sutil.NewLifecycleFinalizers()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetImagePullPolicy() core.PullPolicy {
|
|
||||||
return a.spec.GetImagePullPolicy()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetImage() string {
|
|
||||||
return a.imageInfo.Image
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetEnvs() ([]core.EnvVar, []core.EnvFromSource) {
|
|
||||||
envs := NewEnvBuilder()
|
|
||||||
|
|
||||||
envs.Add(true, k8sutil.GetLifecycleEnv()...)
|
|
||||||
|
|
||||||
if len(a.groupSpec.Envs) > 0 {
|
|
||||||
for _, env := range a.groupSpec.Envs {
|
|
||||||
// Do not override preset envs
|
|
||||||
envs.Add(false, core.EnvVar{
|
|
||||||
Name: env.Name,
|
|
||||||
Value: env.Value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return envs.GetEnvList(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArangoGatewayContainer) GetVolumeMounts() []core.VolumeMount {
|
|
||||||
return createGatewayVolumes(a.apiObject.GetName()).VolumeMounts()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetName() string {
|
|
||||||
return m.resources.context.GetAPIObject().GetName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetRole() string {
|
|
||||||
return m.group.AsRole()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetImagePullSecrets() []string {
|
|
||||||
return m.spec.ImagePullSecrets
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetPodAntiAffinity() *core.PodAntiAffinity {
|
|
||||||
a := &core.PodAntiAffinity{}
|
|
||||||
|
|
||||||
pod.AppendPodAntiAffinityDefault(m, a)
|
|
||||||
|
|
||||||
a = kresources.MergePodAntiAffinity(a, m.groupSpec.AntiAffinity)
|
|
||||||
|
|
||||||
return kresources.OptionalPodAntiAffinity(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetPodAffinity() *core.PodAffinity {
|
|
||||||
a := &core.PodAffinity{}
|
|
||||||
|
|
||||||
pod.AppendAffinityWithRole(m, a, api.ServerGroupDBServers.AsRole())
|
|
||||||
|
|
||||||
a = kresources.MergePodAffinity(a, m.groupSpec.Affinity)
|
|
||||||
|
|
||||||
return kresources.OptionalPodAffinity(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetNodeAffinity() *core.NodeAffinity {
|
|
||||||
a := &core.NodeAffinity{}
|
|
||||||
|
|
||||||
pod.AppendArchSelector(a, m.memberStatus.Architecture.Default(m.spec.Architecture.GetDefault()).AsNodeSelectorRequirement())
|
|
||||||
|
|
||||||
a = kresources.MergeNodeAffinity(a, m.groupSpec.NodeAffinity)
|
|
||||||
|
|
||||||
return kresources.OptionalNodeAffinity(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetNodeSelector() map[string]string {
|
|
||||||
return m.groupSpec.GetNodeSelector()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetServiceAccountName() string {
|
|
||||||
return m.groupSpec.GetServiceAccountName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetSidecars(pod *core.Pod) error {
|
|
||||||
// A sidecar provided by the user
|
|
||||||
sidecars := m.groupSpec.GetSidecars()
|
|
||||||
if len(sidecars) > 0 {
|
|
||||||
addLifecycleSidecar(m.groupSpec.SidecarCoreNames, sidecars)
|
|
||||||
pod.Spec.Containers = append(pod.Spec.Containers, sidecars...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetVolumes() []core.Volume {
|
|
||||||
return createGatewayVolumes(m.apiObject.GetName()).Volumes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) IsDeploymentMode() bool {
|
|
||||||
return m.spec.IsDevelopment()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error) {
|
|
||||||
var initContainers []core.Container
|
|
||||||
if c := m.groupSpec.InitContainers.GetContainers(); len(c) > 0 {
|
|
||||||
initContainers = append(initContainers, c...)
|
|
||||||
}
|
|
||||||
|
|
||||||
res := kresources.ExtractPodInitContainerAcceptedResourceRequirement(m.GetContainerCreator().GetResourceRequirements())
|
|
||||||
|
|
||||||
initContainers = applyInitContainersResourceResources(initContainers, res)
|
|
||||||
initContainers = upscaleInitContainersResourceResources(initContainers, res)
|
|
||||||
|
|
||||||
return initContainers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetFinalizers() []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetTolerations() []core.Toleration {
|
|
||||||
return m.resources.CreatePodTolerations(m.group, m.groupSpec)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetContainerCreator() interfaces.ContainerCreator {
|
|
||||||
return &ArangoGatewayContainer{
|
|
||||||
groupSpec: m.groupSpec,
|
|
||||||
spec: m.spec,
|
|
||||||
group: m.group,
|
|
||||||
resources: m.resources,
|
|
||||||
imageInfo: m.imageInfo,
|
|
||||||
apiObject: m.apiObject,
|
|
||||||
memberStatus: m.memberStatus,
|
|
||||||
arangoMember: m.arangoMember,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) GetRestartPolicy() core.RestartPolicy {
|
|
||||||
if features.RestartPolicyAlways().Enabled() {
|
|
||||||
return core.RestartPolicyAlways
|
|
||||||
}
|
|
||||||
return core.RestartPolicyNever
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) Init(ctx context.Context, cachedStatus interfaces.Inspector, pod *core.Pod) error {
|
|
||||||
terminationGracePeriodSeconds := int64(math.Ceil(m.groupSpec.GetTerminationGracePeriod(m.group).Seconds()))
|
|
||||||
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
|
||||||
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) Validate(_ interfaces.Inspector) error {
|
|
||||||
if err := validateSidecars(m.groupSpec.SidecarCoreNames, m.groupSpec.GetSidecars()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) ApplyPodSpec(spec *core.PodSpec) error {
|
|
||||||
if s := m.groupSpec.SchedulerName; s != nil {
|
|
||||||
spec.SchedulerName = *s
|
|
||||||
}
|
|
||||||
|
|
||||||
m.groupSpec.PodModes.Apply(spec)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) Annotations() map[string]string {
|
|
||||||
return collection.MergeAnnotations(m.spec.Annotations, m.groupSpec.Annotations)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MemberGatewayPod) Labels() map[string]string {
|
|
||||||
return collection.ReservedLabels().Filter(collection.MergeAnnotations(m.spec.Labels, m.groupSpec.Labels))
|
|
||||||
}
|
|
||||||
|
|
||||||
func createGatewayVolumes(memberName string) pod.Volumes {
|
|
||||||
volumes := pod.NewVolumes()
|
volumes := pod.NewVolumes()
|
||||||
|
|
||||||
volumes.AddVolume(k8sutil.LifecycleVolume())
|
volumes.AddVolume(k8sutil.CreateVolumeWithConfigMap(GatewayVolumeName, GetGatewayConfigMapName(input.ApiObject.GetName())))
|
||||||
volumes.AddVolumeMount(k8sutil.LifecycleVolumeMount())
|
|
||||||
|
|
||||||
volumes.AddVolume(k8sutil.CreateVolumeWithConfigMap(GatewayVolumeName, GetGatewayConfigMapName(memberName)))
|
|
||||||
volumes.AddVolumeMount(GatewayVolumeMount())
|
volumes.AddVolumeMount(GatewayVolumeMount())
|
||||||
|
|
||||||
|
// TLS
|
||||||
|
volumes.Append(pod.TLS(), input)
|
||||||
|
|
||||||
return volumes
|
return volumes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
149
pkg/deployment/resources/pod_creator_gateway_container.go
Normal file
149
pkg/deployment/resources/pod_creator_gateway_container.go
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
//
|
||||||
|
// 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 resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/interfaces"
|
||||||
|
kresources "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ interfaces.ContainerCreator = &ArangoGatewayContainer{}
|
||||||
|
|
||||||
|
type ArangoGatewayContainer struct {
|
||||||
|
member *MemberGatewayPod
|
||||||
|
resources *Resources
|
||||||
|
groupSpec api.ServerGroupSpec
|
||||||
|
spec api.DeploymentSpec
|
||||||
|
group api.ServerGroup
|
||||||
|
arangoMember api.ArangoMember
|
||||||
|
imageInfo api.ImageInfo
|
||||||
|
cachedStatus interfaces.Inspector
|
||||||
|
input pod.Input
|
||||||
|
status api.MemberStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetCommand() ([]string, error) {
|
||||||
|
cmd := make([]string, 0, 128)
|
||||||
|
cmd = append(cmd, a.GetExecutor())
|
||||||
|
cmd = append(cmd, createArangoGatewayArgs(a.input)...)
|
||||||
|
return cmd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetName() string {
|
||||||
|
return shared.ServerContainerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetPorts() []core.ContainerPort {
|
||||||
|
port := shared.ArangoPort
|
||||||
|
|
||||||
|
return []core.ContainerPort{
|
||||||
|
{
|
||||||
|
Name: shared.ServerContainerName,
|
||||||
|
ContainerPort: int32(port),
|
||||||
|
Protocol: core.ProtocolTCP,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetExecutor() string {
|
||||||
|
return a.groupSpec.GetEntrypoint(ArangoGatewayExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetSecurityContext() *core.SecurityContext {
|
||||||
|
return k8sutil.CreateSecurityContext(a.groupSpec.SecurityContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetProbes() (*core.Probe, *core.Probe, *core.Probe, error) {
|
||||||
|
var liveness, readiness, startup *core.Probe
|
||||||
|
|
||||||
|
probeLivenessConfig, err := a.resources.getLivenessProbe(a.spec, a.group, a.imageInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
probeReadinessConfig, err := a.resources.getReadinessProbe(a.spec, a.group, a.imageInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
probeStartupConfig, err := a.resources.getReadinessProbe(a.spec, a.group, a.imageInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if probeLivenessConfig != nil {
|
||||||
|
liveness = probeLivenessConfig.Create()
|
||||||
|
}
|
||||||
|
|
||||||
|
if probeReadinessConfig != nil {
|
||||||
|
readiness = probeReadinessConfig.Create()
|
||||||
|
}
|
||||||
|
|
||||||
|
if probeStartupConfig != nil {
|
||||||
|
startup = probeStartupConfig.Create()
|
||||||
|
}
|
||||||
|
|
||||||
|
return liveness, readiness, startup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetResourceRequirements() core.ResourceRequirements {
|
||||||
|
return kresources.ExtractPodAcceptedResourceRequirement(a.arangoMember.Spec.Overrides.GetResources(&a.groupSpec))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetLifecycle() (*core.Lifecycle, error) {
|
||||||
|
return k8sutil.NewLifecycleFinalizers()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetImagePullPolicy() core.PullPolicy {
|
||||||
|
return a.spec.GetImagePullPolicy()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetImage() string {
|
||||||
|
return a.imageInfo.Image
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetEnvs() ([]core.EnvVar, []core.EnvFromSource) {
|
||||||
|
envs := NewEnvBuilder()
|
||||||
|
|
||||||
|
envs.Add(true, k8sutil.GetLifecycleEnv()...)
|
||||||
|
|
||||||
|
if len(a.groupSpec.Envs) > 0 {
|
||||||
|
for _, env := range a.groupSpec.Envs {
|
||||||
|
// Do not override preset envs
|
||||||
|
envs.Add(false, core.EnvVar{
|
||||||
|
Name: env.Name,
|
||||||
|
Value: env.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return envs.GetEnvList(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ArangoGatewayContainer) GetVolumeMounts() []core.VolumeMount {
|
||||||
|
return createGatewayVolumes(a.input).VolumeMounts()
|
||||||
|
}
|
242
pkg/deployment/resources/pod_creator_gateway_pod.go
Normal file
242
pkg/deployment/resources/pod_creator_gateway_pod.go
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
//
|
||||||
|
// 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 resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
|
schedulerContainerResourcesApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/container/resources"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/integrations/sidecar"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/collection"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/interfaces"
|
||||||
|
kresources "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ interfaces.PodCreator = &MemberGatewayPod{}
|
||||||
|
|
||||||
|
type MemberGatewayPod struct {
|
||||||
|
podName string
|
||||||
|
status api.MemberStatus
|
||||||
|
groupSpec api.ServerGroupSpec
|
||||||
|
spec api.DeploymentSpec
|
||||||
|
deploymentStatus api.DeploymentStatus
|
||||||
|
group api.ServerGroup
|
||||||
|
arangoMember api.ArangoMember
|
||||||
|
context Context
|
||||||
|
resources *Resources
|
||||||
|
imageInfo api.ImageInfo
|
||||||
|
cachedStatus interfaces.Inspector
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetName() string {
|
||||||
|
return m.resources.context.GetAPIObject().GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetRole() string {
|
||||||
|
return m.group.AsRole()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetImagePullSecrets() []string {
|
||||||
|
return m.spec.ImagePullSecrets
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetPodAntiAffinity() *core.PodAntiAffinity {
|
||||||
|
a := &core.PodAntiAffinity{}
|
||||||
|
|
||||||
|
pod.AppendPodAntiAffinityDefault(m, a)
|
||||||
|
|
||||||
|
a = kresources.MergePodAntiAffinity(a, m.groupSpec.AntiAffinity)
|
||||||
|
|
||||||
|
return kresources.OptionalPodAntiAffinity(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) AsInput() pod.Input {
|
||||||
|
return pod.Input{
|
||||||
|
ApiObject: m.context.GetAPIObject(),
|
||||||
|
Deployment: m.spec,
|
||||||
|
Status: m.deploymentStatus,
|
||||||
|
Group: m.group,
|
||||||
|
GroupSpec: m.groupSpec,
|
||||||
|
Version: m.imageInfo.ArangoDBVersion,
|
||||||
|
Enterprise: m.imageInfo.Enterprise,
|
||||||
|
Member: m.status,
|
||||||
|
ArangoMember: m.arangoMember,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetPodAffinity() *core.PodAffinity {
|
||||||
|
a := &core.PodAffinity{}
|
||||||
|
|
||||||
|
pod.AppendAffinityWithRole(m, a, api.ServerGroupDBServers.AsRole())
|
||||||
|
|
||||||
|
a = kresources.MergePodAffinity(a, m.groupSpec.Affinity)
|
||||||
|
|
||||||
|
return kresources.OptionalPodAffinity(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetNodeAffinity() *core.NodeAffinity {
|
||||||
|
a := &core.NodeAffinity{}
|
||||||
|
|
||||||
|
pod.AppendArchSelector(a, m.status.Architecture.Default(m.spec.Architecture.GetDefault()).AsNodeSelectorRequirement())
|
||||||
|
|
||||||
|
a = kresources.MergeNodeAffinity(a, m.groupSpec.NodeAffinity)
|
||||||
|
|
||||||
|
return kresources.OptionalNodeAffinity(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetNodeSelector() map[string]string {
|
||||||
|
return m.groupSpec.GetNodeSelector()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetServiceAccountName() string {
|
||||||
|
return m.groupSpec.GetServiceAccountName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetSidecars(pod *core.PodTemplateSpec) error {
|
||||||
|
// A sidecar provided by the user
|
||||||
|
sidecars := m.groupSpec.GetSidecars()
|
||||||
|
if len(sidecars) > 0 {
|
||||||
|
addLifecycleSidecar(m.groupSpec.SidecarCoreNames, sidecars)
|
||||||
|
pod.Spec.Containers = append(pod.Spec.Containers, sidecars...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetVolumes() []core.Volume {
|
||||||
|
return createGatewayVolumes(m.AsInput()).Volumes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) IsDeploymentMode() bool {
|
||||||
|
return m.spec.IsDevelopment()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error) {
|
||||||
|
var initContainers []core.Container
|
||||||
|
if c := m.groupSpec.InitContainers.GetContainers(); len(c) > 0 {
|
||||||
|
initContainers = append(initContainers, c...)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := kresources.ExtractPodInitContainerAcceptedResourceRequirement(m.GetContainerCreator().GetResourceRequirements())
|
||||||
|
|
||||||
|
initContainers = applyInitContainersResourceResources(initContainers, res)
|
||||||
|
initContainers = upscaleInitContainersResourceResources(initContainers, res)
|
||||||
|
|
||||||
|
return initContainers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetFinalizers() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetTolerations() []core.Toleration {
|
||||||
|
return m.resources.CreatePodTolerations(m.group, m.groupSpec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetContainerCreator() interfaces.ContainerCreator {
|
||||||
|
return &ArangoGatewayContainer{
|
||||||
|
member: m,
|
||||||
|
spec: m.spec,
|
||||||
|
group: m.group,
|
||||||
|
resources: m.resources,
|
||||||
|
imageInfo: m.imageInfo,
|
||||||
|
groupSpec: m.groupSpec,
|
||||||
|
arangoMember: m.arangoMember,
|
||||||
|
cachedStatus: m.cachedStatus,
|
||||||
|
input: m.AsInput(),
|
||||||
|
status: m.status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) GetRestartPolicy() core.RestartPolicy {
|
||||||
|
if features.RestartPolicyAlways().Enabled() {
|
||||||
|
return core.RestartPolicyAlways
|
||||||
|
}
|
||||||
|
return core.RestartPolicyNever
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) Init(ctx context.Context, cachedStatus interfaces.Inspector, pod *core.PodTemplateSpec) error {
|
||||||
|
terminationGracePeriodSeconds := int64(math.Ceil(m.groupSpec.GetTerminationGracePeriod(m.group).Seconds()))
|
||||||
|
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
||||||
|
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) Validate(_ interfaces.Inspector) error {
|
||||||
|
if err := validateSidecars(m.groupSpec.SidecarCoreNames, m.groupSpec.GetSidecars()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) ApplyPodSpec(spec *core.PodSpec) error {
|
||||||
|
if s := m.groupSpec.SchedulerName; s != nil {
|
||||||
|
spec.SchedulerName = *s
|
||||||
|
}
|
||||||
|
|
||||||
|
m.groupSpec.PodModes.Apply(spec)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) Annotations() map[string]string {
|
||||||
|
return collection.MergeAnnotations(m.spec.Annotations, m.groupSpec.Annotations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) Labels() map[string]string {
|
||||||
|
l := collection.ReservedLabels().Filter(collection.MergeAnnotations(m.spec.Labels, m.groupSpec.Labels))
|
||||||
|
|
||||||
|
if m.status.Topology != nil && m.deploymentStatus.Topology.Enabled() && m.deploymentStatus.Topology.ID == m.status.Topology.ID {
|
||||||
|
if l == nil {
|
||||||
|
l = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
l[k8sutil.LabelKeyArangoZone] = fmt.Sprintf("%d", m.status.Topology.Zone)
|
||||||
|
l[k8sutil.LabelKeyArangoTopology] = string(m.status.Topology.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemberGatewayPod) Profiles() (schedulerApi.ProfileTemplates, error) {
|
||||||
|
integration, err := sidecar.NewIntegration(&schedulerContainerResourcesApi.Image{
|
||||||
|
Image: util.NewType(m.resources.context.GetOperatorImage()),
|
||||||
|
}, m.spec.Gateway.GetSidecar(), []string{shared.ServerContainerName})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*schedulerApi.ProfileTemplate{integration}, nil
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ import (
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
|
@ -266,7 +267,7 @@ func (m *MemberSyncPod) GetServiceAccountName() string {
|
||||||
return m.groupSpec.GetServiceAccountName()
|
return m.groupSpec.GetServiceAccountName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MemberSyncPod) GetSidecars(pod *core.Pod) error {
|
func (m *MemberSyncPod) GetSidecars(pod *core.PodTemplateSpec) error {
|
||||||
// A sidecar provided by the user
|
// A sidecar provided by the user
|
||||||
sidecars := m.groupSpec.GetSidecars()
|
sidecars := m.groupSpec.GetSidecars()
|
||||||
if len(sidecars) > 0 {
|
if len(sidecars) > 0 {
|
||||||
|
@ -350,7 +351,7 @@ func (m *MemberSyncPod) GetRestartPolicy() core.RestartPolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes the arangosync pod.
|
// Init initializes the arangosync pod.
|
||||||
func (m *MemberSyncPod) Init(ctx context.Context, cachedStatus interfaces.Inspector, pod *core.Pod) error {
|
func (m *MemberSyncPod) Init(ctx context.Context, cachedStatus interfaces.Inspector, pod *core.PodTemplateSpec) error {
|
||||||
terminationGracePeriodSeconds := int64(math.Ceil(m.groupSpec.GetTerminationGracePeriod(m.group).Seconds()))
|
terminationGracePeriodSeconds := int64(math.Ceil(m.groupSpec.GetTerminationGracePeriod(m.group).Seconds()))
|
||||||
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
|
||||||
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
|
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
|
||||||
|
@ -517,3 +518,7 @@ func (m *MemberSyncPod) syncHostAlias() *core.HostAlias {
|
||||||
|
|
||||||
return &alias
|
return &alias
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MemberSyncPod) Profiles() (schedulerApi.ProfileTemplates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
68
pkg/deployment/resources/pod_creator_tolerations.go
Normal file
68
pkg/deployment/resources/pod_creator_tolerations.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// 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 resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/tolerations"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreatePodTolerations creates a list of tolerations for a pod created for the given group.
|
||||||
|
func CreatePodTolerations(mode api.DeploymentMode, group api.ServerGroup) []core.Toleration {
|
||||||
|
notReadyDur := tolerations.TolerationDuration{Forever: false, TimeSpan: time.Minute}
|
||||||
|
unreachableDur := tolerations.TolerationDuration{Forever: false, TimeSpan: time.Minute}
|
||||||
|
switch group {
|
||||||
|
case api.ServerGroupAgents:
|
||||||
|
notReadyDur.Forever = true
|
||||||
|
unreachableDur.Forever = true
|
||||||
|
case api.ServerGroupCoordinators:
|
||||||
|
notReadyDur.TimeSpan = 15 * time.Second
|
||||||
|
unreachableDur.TimeSpan = 15 * time.Second
|
||||||
|
case api.ServerGroupDBServers:
|
||||||
|
notReadyDur.TimeSpan = 5 * time.Minute
|
||||||
|
unreachableDur.TimeSpan = 5 * time.Minute
|
||||||
|
case api.ServerGroupSingle:
|
||||||
|
if mode == api.DeploymentModeSingle {
|
||||||
|
notReadyDur.Forever = true
|
||||||
|
unreachableDur.Forever = true
|
||||||
|
} else {
|
||||||
|
notReadyDur.TimeSpan = 5 * time.Minute
|
||||||
|
unreachableDur.TimeSpan = 5 * time.Minute
|
||||||
|
}
|
||||||
|
case api.ServerGroupSyncMasters:
|
||||||
|
notReadyDur.TimeSpan = 15 * time.Second
|
||||||
|
unreachableDur.TimeSpan = 15 * time.Second
|
||||||
|
case api.ServerGroupSyncWorkers:
|
||||||
|
notReadyDur.TimeSpan = 1 * time.Minute
|
||||||
|
unreachableDur.TimeSpan = 1 * time.Minute
|
||||||
|
case api.ServerGroupGateways:
|
||||||
|
notReadyDur.TimeSpan = 15 * time.Second
|
||||||
|
unreachableDur.TimeSpan = 15 * time.Second
|
||||||
|
}
|
||||||
|
return []core.Toleration{tolerations.NewNoExecuteToleration(tolerations.TolerationKeyNodeNotReady, notReadyDur),
|
||||||
|
tolerations.NewNoExecuteToleration(tolerations.TolerationKeyNodeUnreachable, unreachableDur),
|
||||||
|
tolerations.NewNoExecuteToleration(tolerations.TolerationKeyNodeAlphaUnreachable, unreachableDur),
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,7 +125,7 @@ func (r *Resources) EnsureLeader(ctx context.Context, cachedStatus inspectorInte
|
||||||
selector := k8sutil.LabelsForLeaderMember(deploymentName, group.AsRole(), leaderID)
|
selector := k8sutil.LabelsForLeaderMember(deploymentName, group.AsRole(), leaderID)
|
||||||
|
|
||||||
if s, ok := cachedStatus.Service().V1().GetSimple(leaderAgentSvcName); ok {
|
if s, ok := cachedStatus.Service().V1().GetSimple(leaderAgentSvcName); ok {
|
||||||
if c, err := patcher.ServicePatcher(ctx, cachedStatus.ServicesModInterface().V1(), s, meta.PatchOptions{}, patcher.PatchServiceSelector(selector), patcher.PatchServicePorts(ports)); err != nil {
|
if _, c, err := patcher.Patcher[*core.Service](ctx, cachedStatus.ServicesModInterface().V1(), s, meta.PatchOptions{}, patcher.PatchServiceSelector(selector), patcher.PatchServicePorts(ports)); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
if !c {
|
if !c {
|
||||||
|
|
|
@ -131,7 +131,7 @@ func (r *Resources) EnsureSecrets(ctx context.Context, cachedStatus inspectorInt
|
||||||
|
|
||||||
if err := reconcileRequired.ParallelAll(len(members), func(id int) error {
|
if err := reconcileRequired.ParallelAll(len(members), func(id int) error {
|
||||||
switch members[id].Group.Type() {
|
switch members[id].Group.Type() {
|
||||||
case api.ServerGroupTypeArangoD:
|
case api.ServerGroupTypeArangoD, api.ServerGroupTypeGateway:
|
||||||
memberName := members[id].Member.ArangoMemberName(r.context.GetAPIObject().GetName(), members[id].Group)
|
memberName := members[id].Member.ArangoMemberName(r.context.GetAPIObject().GetName(), members[id].Group)
|
||||||
|
|
||||||
member, ok := cachedStatus.ArangoMember().V1().GetSimple(memberName)
|
member, ok := cachedStatus.ArangoMember().V1().GetSimple(memberName)
|
||||||
|
|
|
@ -120,7 +120,7 @@ func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorIn
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if changed, err := patcher.ServicePatcher(ctx, svcs, s, meta.PatchOptions{},
|
if _, changed, err := patcher.Patcher[*core.Service](ctx, svcs, s, meta.PatchOptions{},
|
||||||
patcher.PatchServicePorts(ports),
|
patcher.PatchServicePorts(ports),
|
||||||
patcher.PatchServiceSelector(selector),
|
patcher.PatchServiceSelector(selector),
|
||||||
patcher.PatchServicePublishNotReadyAddresses(true),
|
patcher.PatchServicePublishNotReadyAddresses(true),
|
||||||
|
@ -176,7 +176,7 @@ func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorIn
|
||||||
reconcileRequired.Required()
|
reconcileRequired.Required()
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
if changed, err := patcher.ServicePatcher(ctx, svcs, s, meta.PatchOptions{},
|
if _, changed, err := patcher.Patcher[*core.Service](ctx, svcs, s, meta.PatchOptions{},
|
||||||
patcher.PatchServicePorts(ports),
|
patcher.PatchServicePorts(ports),
|
||||||
patcher.PatchServiceSelector(selector),
|
patcher.PatchServiceSelector(selector),
|
||||||
patcher.PatchServicePublishNotReadyAddresses(false),
|
patcher.PatchServicePublishNotReadyAddresses(false),
|
||||||
|
@ -205,7 +205,7 @@ func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorIn
|
||||||
log.Str("service", svcName).Debug("Created headless service")
|
log.Str("service", svcName).Debug("Created headless service")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if changed, err := patcher.ServicePatcher(ctx, svcs, s, meta.PatchOptions{}, patcher.PatchServicePorts(headlessPorts), patcher.PatchServiceSelector(headlessSelector)); err != nil {
|
if _, changed, err := patcher.Patcher[*core.Service](ctx, svcs, s, meta.PatchOptions{}, patcher.PatchServicePorts(headlessPorts), patcher.PatchServiceSelector(headlessSelector)); err != nil {
|
||||||
log.Err(err).Debug("Failed to patch headless service")
|
log.Err(err).Debug("Failed to patch headless service")
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
} else if changed {
|
} else if changed {
|
||||||
|
@ -245,7 +245,7 @@ func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if changed, err := patcher.ServicePatcher(ctx, svcs, s, meta.PatchOptions{}, patcher.PatchServiceOnlyPorts(clientServicePorts...), patcher.PatchServiceSelector(clientServiceSelectors)); err != nil {
|
if _, changed, err := patcher.Patcher[*core.Service](ctx, svcs, s, meta.PatchOptions{}, patcher.PatchServiceOnlyPorts(clientServicePorts...), patcher.PatchServiceSelector(clientServiceSelectors)); err != nil {
|
||||||
log.Err(err).Debug("Failed to patch database client service")
|
log.Err(err).Debug("Failed to patch database client service")
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
} else if changed {
|
} else if changed {
|
||||||
|
@ -380,7 +380,7 @@ func (r *Resources) ensureExternalAccessServices(ctx context.Context, cachedStat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !createExternalAccessService && !deleteExternalAccessService {
|
if !createExternalAccessService && !deleteExternalAccessService {
|
||||||
if changed, err := patcher.ServicePatcher(ctx, svcs, existing, meta.PatchOptions{},
|
if _, changed, err := patcher.Patcher[*core.Service](ctx, svcs, existing, meta.PatchOptions{},
|
||||||
patcher.PatchServiceSelector(eaSelector),
|
patcher.PatchServiceSelector(eaSelector),
|
||||||
patcher.Optional(patcher.PatchServiceOnlyPorts(eaPorts...), owned)); err != nil {
|
patcher.Optional(patcher.PatchServiceOnlyPorts(eaPorts...), owned)); err != nil {
|
||||||
log.Err(err).Debug("Failed to patch database client service")
|
log.Err(err).Debug("Failed to patch database client service")
|
||||||
|
@ -434,8 +434,8 @@ func (r *Resources) ensureExternalAccessManagedServices(ctx context.Context, cac
|
||||||
log := r.log.Str("section", "service-ea").Str("service", eaServiceName)
|
log := r.log.Str("section", "service-ea").Str("service", eaServiceName)
|
||||||
managedServiceNames := spec.GetManagedServiceNames()
|
managedServiceNames := spec.GetManagedServiceNames()
|
||||||
|
|
||||||
apply := func(svc *core.Service) (bool, error) {
|
apply := func(svc *core.Service) (*core.Service, bool, error) {
|
||||||
return patcher.ServicePatcher(ctx, cachedStatus.ServicesModInterface().V1(), svc, meta.PatchOptions{},
|
return patcher.Patcher[*core.Service](ctx, cachedStatus.ServicesModInterface().V1(), svc, meta.PatchOptions{},
|
||||||
patcher.PatchServiceSelector(selectors))
|
patcher.PatchServiceSelector(selectors))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ func (r *Resources) ensureExternalAccessManagedServices(ctx context.Context, cac
|
||||||
log.Warn("the field \"spec.externalAccess.managedServiceNames\" should be provided for \"managed\" service type")
|
log.Warn("the field \"spec.externalAccess.managedServiceNames\" should be provided for \"managed\" service type")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else if changed, err := apply(svc); err != nil {
|
} else if _, changed, err := apply(svc); err != nil {
|
||||||
return errors.WithMessage(err, "failed to ensure service selector")
|
return errors.WithMessage(err, "failed to ensure service selector")
|
||||||
} else if changed {
|
} else if changed {
|
||||||
log.Info("selector applied to the managed service \"%s\"", svc.GetName())
|
log.Info("selector applied to the managed service \"%s\"", svc.GetName())
|
||||||
|
@ -464,7 +464,7 @@ func (r *Resources) ensureExternalAccessManagedServices(ctx context.Context, cac
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if changed, err := apply(svc); err != nil {
|
if _, changed, err := apply(svc); err != nil {
|
||||||
return errors.WithMessage(err, "failed to ensure service selector")
|
return errors.WithMessage(err, "failed to ensure service selector")
|
||||||
} else if changed {
|
} else if changed {
|
||||||
log.Info("selector applied to the managed service \"%s\"", svcName)
|
log.Info("selector applied to the managed service \"%s\"", svcName)
|
||||||
|
|
|
@ -35,7 +35,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) HandleArangoDeployment(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus) (bool, error) {
|
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)
|
var name = util.WithDefault(extension.Spec.Deployment)
|
||||||
|
|
||||||
if status.Deployment != nil {
|
if status.Deployment != nil {
|
||||||
name = status.Deployment.GetName()
|
name = status.Deployment.GetName()
|
||||||
|
|
|
@ -41,7 +41,7 @@ func Test_Handler_Deployment(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -73,7 +73,7 @@ func Test_Handler_MissingDeployment(t *testing.T) {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test", func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test", func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment-missing")
|
obj.Spec.Deployment = util.NewType("deployment-missing")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -105,7 +105,7 @@ func Test_Handler_Deployment_Changed(t *testing.T) {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test", func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test", func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
|
|
@ -35,7 +35,7 @@ import (
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util"
|
"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) {
|
func (h *handler) HandleArangoDestination(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus, deployment *api.ArangoDeployment) (*operator.Condition, bool, error) {
|
||||||
if dest := extension.Spec.GetDestination(); dest != nil {
|
if dest := extension.Spec.GetDestination(); dest != nil {
|
||||||
if svc := dest.GetService(); svc != nil {
|
if svc := dest.GetService(); svc != nil {
|
||||||
port := svc.Port
|
port := svc.Port
|
||||||
|
@ -117,30 +117,56 @@ func (h *handler) HandleArangoDestination(ctx context.Context, item operation.It
|
||||||
}, false, nil
|
}, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var targets = networkingApi.ArangoRouteStatusTargets{
|
var target networkingApi.ArangoRouteStatusTarget
|
||||||
networkingApi.ArangoRouteStatusTarget{
|
|
||||||
Url: fmt.Sprintf("%s://%s.%s.svc:%d%s", dest.GetSchema().String(), s.GetName(), s.GetNamespace(), destPort, extension.Spec.GetRoute().GetPath()),
|
target.Path = dest.GetPath()
|
||||||
TLS: networkingApi.ArangoRouteStatusTargetTLS{
|
|
||||||
Insecure: extension.Spec.Destination.GetTLS().GetInsecure(),
|
if dest.Schema.Get() == networkingApi.ArangoRouteSpecDestinationSchemaHTTPS {
|
||||||
},
|
target.TLS = &networkingApi.ArangoRouteStatusTargetTLS{
|
||||||
},
|
Insecure: util.NewType(extension.Spec.Destination.GetTLS().GetInsecure()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.Targets.Hash() == targets.Hash() {
|
if ip := s.Spec.ClusterIP; ip != "" {
|
||||||
|
target.Destinations = networkingApi.ArangoRouteStatusTargetDestinations{
|
||||||
|
networkingApi.ArangoRouteStatusTargetDestination{
|
||||||
|
Host: ip,
|
||||||
|
Port: destPort,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if domain := deployment.Spec.ClusterDomain; domain != nil {
|
||||||
|
target.Destinations = networkingApi.ArangoRouteStatusTargetDestinations{
|
||||||
|
networkingApi.ArangoRouteStatusTargetDestination{
|
||||||
|
Host: fmt.Sprintf("%s.%s.svc.%s", s.GetName(), s.GetNamespace(), *domain),
|
||||||
|
Port: destPort,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target.Destinations = networkingApi.ArangoRouteStatusTargetDestinations{
|
||||||
|
networkingApi.ArangoRouteStatusTargetDestination{
|
||||||
|
Host: fmt.Sprintf("%s.%s.svc", s.GetName(), s.GetNamespace()),
|
||||||
|
Port: destPort,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Target.Hash() == target.Hash() {
|
||||||
return &operator.Condition{
|
return &operator.Condition{
|
||||||
Status: true,
|
Status: true,
|
||||||
Reason: "Destination Found",
|
Reason: "Destination Found",
|
||||||
Message: "Destination Found",
|
Message: "Destination Found",
|
||||||
Hash: targets.Hash(),
|
Hash: target.Hash(),
|
||||||
}, false, nil
|
}, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
status.Targets = targets
|
status.Target = &target
|
||||||
return &operator.Condition{
|
return &operator.Condition{
|
||||||
Status: true,
|
Status: true,
|
||||||
Reason: "Destination Found",
|
Reason: "Destination Found",
|
||||||
Message: "Destination Found",
|
Message: "Destination Found",
|
||||||
Hash: targets.Hash(),
|
Hash: target.Hash(),
|
||||||
}, true, nil
|
}, true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,8 +180,8 @@ func (h *handler) HandleArangoDestination(ctx context.Context, item operation.It
|
||||||
|
|
||||||
func (h *handler) HandleArangoDestinationWithTargets(ctx context.Context, item operation.Item, extension *networkingApi.ArangoRoute, status *networkingApi.ArangoRouteStatus, depl *api.ArangoDeployment) (*operator.Condition, bool, error) {
|
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)
|
c, changed, err := h.HandleArangoDestination(ctx, item, extension, status, depl)
|
||||||
if c == nil && !c.Status && status.Targets != nil {
|
if c == nil && !c.Status && status.Target != nil {
|
||||||
status.Targets = nil
|
status.Target = nil
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ func Test_Handler_Destination_Service_Missing(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -81,7 +81,7 @@ func Test_Handler_Destination_Service_Valid(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -114,11 +114,117 @@ func Test_Handler_Destination_Service_Valid(t *testing.T) {
|
||||||
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
|
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
|
||||||
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
|
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
|
||||||
|
|
||||||
|
require.Len(t, extension.Status.Target.RenderURLs(), 1)
|
||||||
|
require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
|
||||||
|
|
||||||
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
|
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
|
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Handler_Destination_Service_Valid_WithIP(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.Deployment = 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
obj.Spec.ClusterIP = "127.0.0.2"
|
||||||
|
})
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
require.Len(t, extension.Status.Target.RenderURLs(), 1)
|
||||||
|
require.EqualValues(t, "http://127.0.0.2:10244/", extension.Status.Target.RenderURLs()[0])
|
||||||
|
|
||||||
|
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.Target.Hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Handler_Destination_Service_Valid_WithPath(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.Deployment = 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)),
|
||||||
|
},
|
||||||
|
Path: util.NewType("/test/path/"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
obj.Spec.ClusterIP = "127.0.0.2"
|
||||||
|
})
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
require.Len(t, extension.Status.Target.RenderURLs(), 1)
|
||||||
|
require.EqualValues(t, "http://127.0.0.2:10244/test/path/", extension.Status.Target.RenderURLs()[0])
|
||||||
|
|
||||||
|
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.Target.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Handler_Destination_Service_ValidName(t *testing.T) {
|
func Test_Handler_Destination_Service_ValidName(t *testing.T) {
|
||||||
|
@ -128,7 +234,7 @@ func Test_Handler_Destination_Service_ValidName(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -170,7 +276,7 @@ func Test_Handler_Destination_Service_ValidName(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
|
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Handler_Destination_Service_WrongPort(t *testing.T) {
|
func Test_Handler_Destination_Service_WrongPort(t *testing.T) {
|
||||||
|
@ -180,7 +286,7 @@ func Test_Handler_Destination_Service_WrongPort(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -226,7 +332,7 @@ func Test_Handler_Destination_Service_WrongPortName(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -272,7 +378,7 @@ func Test_Handler_Destination_Service_Insecure_Default(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -309,10 +415,9 @@ func Test_Handler_Destination_Service_Insecure_Default(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
|
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
|
||||||
|
|
||||||
require.Len(t, extension.Status.Targets, 1)
|
require.False(t, extension.Status.Target.TLS.IsInsecure())
|
||||||
require.False(t, extension.Status.Targets[0].TLS.Insecure)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Handler_Destination_Service_Insecure_Nil(t *testing.T) {
|
func Test_Handler_Destination_Service_Insecure_Nil(t *testing.T) {
|
||||||
|
@ -322,7 +427,7 @@ func Test_Handler_Destination_Service_Insecure_Nil(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -362,20 +467,19 @@ func Test_Handler_Destination_Service_Insecure_Nil(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
|
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
|
||||||
|
|
||||||
require.Len(t, extension.Status.Targets, 1)
|
require.False(t, extension.Status.Target.TLS.IsInsecure())
|
||||||
require.False(t, extension.Status.Targets[0].TLS.Insecure)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Handler_Destination_Service_Insecure_Override(t *testing.T) {
|
func Test_Handler_Destination_Service_Insecure_HTTPS_Override(t *testing.T) {
|
||||||
// Setup
|
// Setup
|
||||||
handler := newFakeHandler()
|
handler := newFakeHandler()
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.DeploymentName = util.NewType("deployment")
|
obj.Spec.Deployment = util.NewType("deployment")
|
||||||
},
|
},
|
||||||
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
func(t *testing.T, obj *networkingApi.ArangoRoute) {
|
||||||
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
|
||||||
|
@ -388,6 +492,7 @@ func Test_Handler_Destination_Service_Insecure_Override(t *testing.T) {
|
||||||
TLS: &networkingApi.ArangoRouteSpecDestinationTLS{
|
TLS: &networkingApi.ArangoRouteSpecDestinationTLS{
|
||||||
Insecure: util.NewType(true),
|
Insecure: util.NewType(true),
|
||||||
},
|
},
|
||||||
|
Schema: util.NewType(networkingApi.ArangoRouteSpecDestinationSchemaHTTPS),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
|
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
|
||||||
|
@ -415,8 +520,60 @@ func Test_Handler_Destination_Service_Insecure_Override(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Reason, "Destination Found")
|
require.EqualValues(t, c.Reason, "Destination Found")
|
||||||
require.EqualValues(t, c.Hash, extension.Status.Targets.Hash())
|
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
|
||||||
|
|
||||||
require.Len(t, extension.Status.Targets, 1)
|
require.True(t, extension.Status.Target.TLS.IsInsecure())
|
||||||
require.True(t, extension.Status.Targets[0].TLS.Insecure)
|
}
|
||||||
|
|
||||||
|
func Test_Handler_Destination_Service_Insecure_HTTP_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.Deployment = 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),
|
||||||
|
},
|
||||||
|
Schema: util.NewType(networkingApi.ArangoRouteSpecDestinationSchemaHTTP),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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.Target.Hash())
|
||||||
|
|
||||||
|
require.False(t, extension.Status.Target.TLS.IsInsecure())
|
||||||
}
|
}
|
||||||
|
|
59
pkg/integrations/sidecar/core.go
Normal file
59
pkg/integrations/sidecar/core.go
Normal 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 sidecar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Core struct {
|
||||||
|
Internal *bool
|
||||||
|
External *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) GetInternal() bool {
|
||||||
|
if c == nil || c.Internal == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return *c.Internal
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) GetExternal() bool {
|
||||||
|
if c == nil || c.External == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return *c.External
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) Args(int Integration) k8sutil.OptionPairs {
|
||||||
|
var options k8sutil.OptionPairs
|
||||||
|
name, ver := int.Name()
|
||||||
|
|
||||||
|
options.Add(fmt.Sprintf("--integration.%s.%s.internal", strings.ToLower(name), strings.ToLower(ver)), c.GetInternal())
|
||||||
|
options.Add(fmt.Sprintf("--integration.%s.%s.external", strings.ToLower(name), strings.ToLower(ver)), c.GetExternal())
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
85
pkg/integrations/sidecar/integration.authentication.v1.go
Normal file
85
pkg/integrations/sidecar/integration.authentication.v1.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
//
|
||||||
|
// 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 sidecar
|
||||||
|
|
||||||
|
import (
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ IntegrationVolumes = IntegrationAuthenticationV1{}
|
||||||
|
|
||||||
|
type IntegrationAuthenticationV1 struct {
|
||||||
|
Core *Core
|
||||||
|
Deployment *api.ArangoDeployment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthenticationV1) Name() (string, string) {
|
||||||
|
return "AUTHENTICATION", "V1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthenticationV1) Validate() error {
|
||||||
|
if i.Deployment == nil {
|
||||||
|
return errors.Errorf("Deployment is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthenticationV1) Args() (k8sutil.OptionPairs, error) {
|
||||||
|
options := k8sutil.CreateOptionPairs()
|
||||||
|
|
||||||
|
options.Add("--integration.authentication.v1", true)
|
||||||
|
options.Add("--integration.authentication.v1.enabled", i.Deployment.GetAcceptedSpec().IsAuthenticated())
|
||||||
|
options.Add("--integration.authentication.v1.path", shared.ClusterJWTSecretVolumeMountDir)
|
||||||
|
|
||||||
|
options.Merge(i.Core.Args(i))
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthenticationV1) Volumes() ([]core.Volume, []core.VolumeMount, error) {
|
||||||
|
if i.Deployment.GetAcceptedSpec().IsAuthenticated() {
|
||||||
|
return []core.Volume{
|
||||||
|
{
|
||||||
|
Name: shared.ClusterJWTSecretVolumeName,
|
||||||
|
VolumeSource: core.VolumeSource{
|
||||||
|
Secret: &core.SecretVolumeSource{
|
||||||
|
SecretName: pod.JWTSecretFolder(i.Deployment.GetName()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, []core.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: shared.ClusterJWTSecretVolumeName,
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: shared.ClusterJWTSecretVolumeMountDir,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
47
pkg/integrations/sidecar/integration.authorization.v1.go
Normal file
47
pkg/integrations/sidecar/integration.authorization.v1.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// 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 sidecar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IntegrationAuthorizationV0 struct {
|
||||||
|
Core *Core
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthorizationV0) Name() (string, string) {
|
||||||
|
return "AUTHORIZATION", "V0"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthorizationV0) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationAuthorizationV0) Args() (k8sutil.OptionPairs, error) {
|
||||||
|
options := k8sutil.CreateOptionPairs()
|
||||||
|
|
||||||
|
options.Add("--integration.authorization.v0", true)
|
||||||
|
|
||||||
|
options.Merge(i.Core.Args(i))
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
57
pkg/integrations/sidecar/integration.envoy.v3.go
Normal file
57
pkg/integrations/sidecar/integration.envoy.v3.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
//
|
||||||
|
// 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 sidecar
|
||||||
|
|
||||||
|
import (
|
||||||
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IntegrationEnvoyV3 struct {
|
||||||
|
Core *Core
|
||||||
|
Deployment *api.ArangoDeployment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationEnvoyV3) Name() (string, string) {
|
||||||
|
return "ENVOY", "V3"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationEnvoyV3) Validate() error {
|
||||||
|
if i.Deployment == nil {
|
||||||
|
return errors.Errorf("Deployment is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationEnvoyV3) Args() (k8sutil.OptionPairs, error) {
|
||||||
|
options := k8sutil.CreateOptionPairs()
|
||||||
|
|
||||||
|
options.Add("--integration.authentication.v1", true)
|
||||||
|
options.Add("--integration.authentication.v1.enabled", i.Deployment.GetAcceptedSpec().IsAuthenticated())
|
||||||
|
options.Add("--integration.authentication.v1.path", shared.ClusterJWTSecretVolumeMountDir)
|
||||||
|
|
||||||
|
options.Merge(i.Core.Args(i))
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
211
pkg/integrations/sidecar/integration.go
Normal file
211
pkg/integrations/sidecar/integration.go
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
//
|
||||||
|
// DISCLAIMER
|
||||||
|
//
|
||||||
|
// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany
|
||||||
|
|
||||||
|
package sidecar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
|
schedulerContainerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/container"
|
||||||
|
schedulerContainerResourcesApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/container/resources"
|
||||||
|
schedulerPodApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/pod"
|
||||||
|
schedulerPodResourcesApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/pod/resources"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ContainerName = "integration"
|
||||||
|
ListenPortName = "integration"
|
||||||
|
ListenPortHealthName = "health"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithIntegrationEnvs(in Integration) ([]core.EnvVar, error) {
|
||||||
|
if v, ok := in.(IntegrationEnvs); ok {
|
||||||
|
return v.Envs()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntegrationEnvs interface {
|
||||||
|
Integration
|
||||||
|
Envs() ([]core.EnvVar, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithIntegrationVolumes(in Integration) ([]core.Volume, []core.VolumeMount, error) {
|
||||||
|
if v, ok := in.(IntegrationVolumes); ok {
|
||||||
|
return v.Volumes()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntegrationVolumes interface {
|
||||||
|
Integration
|
||||||
|
Volumes() ([]core.Volume, []core.VolumeMount, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Integration interface {
|
||||||
|
Name() (string, string)
|
||||||
|
Args() (k8sutil.OptionPairs, error)
|
||||||
|
Validate() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIntegration(image *schedulerContainerResourcesApi.Image, integration *schedulerApi.IntegrationSidecar, coreContainers []string, integrations ...Integration) (*schedulerApi.ProfileTemplate, error) {
|
||||||
|
for _, integration := range integrations {
|
||||||
|
if err := integration.Validate(); err != nil {
|
||||||
|
name, version := integration.Name()
|
||||||
|
|
||||||
|
return nil, errors.Wrapf(err, "Failure in %s/%s", name, version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arguments
|
||||||
|
|
||||||
|
exePath := k8sutil.BinaryPath()
|
||||||
|
lifecycle, err := k8sutil.NewLifecycleFinalizersWithBinary(exePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "NewLifecycleFinalizers failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
options := k8sutil.CreateOptionPairs(64)
|
||||||
|
|
||||||
|
options.Addf("--services.address", "127.0.0.1:%d", integration.GetListenPort())
|
||||||
|
options.Addf("--health.address", "0.0.0.0:%d", integration.GetControllerListenPort())
|
||||||
|
|
||||||
|
// Volumes
|
||||||
|
var volumes []core.Volume
|
||||||
|
var volumeMounts []core.VolumeMount
|
||||||
|
|
||||||
|
// Envs
|
||||||
|
|
||||||
|
var envs = []core.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "INTEGRATION_API_ADDRESS",
|
||||||
|
Value: fmt.Sprintf("127.0.0.1:%d", integration.GetListenPort()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "INTEGRATION_SERVICE_ADDRESS",
|
||||||
|
Value: fmt.Sprintf("127.0.0.1:%d", integration.GetListenPort()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range integrations {
|
||||||
|
name, version := i.Name()
|
||||||
|
|
||||||
|
if err := i.Validate(); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failure in %s/%s", name, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if args, err := i.Args(); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failure in arguments %s/%s", name, version)
|
||||||
|
} else if len(args) > 0 {
|
||||||
|
options.Merge(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lvolumes, lvolumeMounts, err := WithIntegrationVolumes(i); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failure in volumes %s/%s", name, version)
|
||||||
|
} else if len(lvolumes) > 0 || len(lvolumeMounts) > 0 {
|
||||||
|
volumes = append(volumes, lvolumes...)
|
||||||
|
volumeMounts = append(volumeMounts, lvolumeMounts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lenvs, err := WithIntegrationEnvs(i); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failure in envs %s/%s", name, version)
|
||||||
|
} else if len(lenvs) > 0 {
|
||||||
|
envs = append(envs, lenvs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
envs = append(envs, core.EnvVar{
|
||||||
|
Name: fmt.Sprintf("INTEGRATION_SERVICE_%s_%s", strings.ToUpper(name), strings.ToUpper(version)),
|
||||||
|
Value: fmt.Sprintf("127.0.0.1:%d", integration.GetListenPort()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c := schedulerContainerApi.Container{
|
||||||
|
Core: &schedulerContainerResourcesApi.Core{
|
||||||
|
Command: append([]string{exePath, "integration"}, options.Sort().AsArgs()...),
|
||||||
|
},
|
||||||
|
Environments: &schedulerContainerResourcesApi.Environments{
|
||||||
|
Env: k8sutil.GetLifecycleEnv(),
|
||||||
|
},
|
||||||
|
Networking: &schedulerContainerResourcesApi.Networking{
|
||||||
|
Ports: []core.ContainerPort{
|
||||||
|
{
|
||||||
|
Name: ListenPortName,
|
||||||
|
ContainerPort: int32(integration.GetListenPort()),
|
||||||
|
Protocol: core.ProtocolTCP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: ListenPortHealthName,
|
||||||
|
ContainerPort: int32(integration.GetControllerListenPort()),
|
||||||
|
Protocol: core.ProtocolTCP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Image: image,
|
||||||
|
|
||||||
|
Lifecycle: &schedulerContainerResourcesApi.Lifecycle{
|
||||||
|
Lifecycle: lifecycle,
|
||||||
|
},
|
||||||
|
|
||||||
|
Probes: &schedulerContainerResourcesApi.Probes{
|
||||||
|
ReadinessProbe: &core.Probe{
|
||||||
|
ProbeHandler: core.ProbeHandler{
|
||||||
|
GRPC: &core.GRPCAction{
|
||||||
|
Port: int32(integration.GetControllerListenPort()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InitialDelaySeconds: 1, // Wait 1s before first probe
|
||||||
|
TimeoutSeconds: 2, // Timeout of each probe is 2s
|
||||||
|
PeriodSeconds: 30, // Interval between probes is 30s
|
||||||
|
SuccessThreshold: 1, // Single probe is enough to indicate success
|
||||||
|
FailureThreshold: 2, // Need 2 failed probes to consider a failed state
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
VolumeMounts: &schedulerContainerResourcesApi.VolumeMounts{
|
||||||
|
VolumeMounts: volumeMounts,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pt := schedulerApi.ProfileTemplate{
|
||||||
|
Container: &schedulerApi.ProfileContainerTemplate{
|
||||||
|
Containers: map[string]schedulerContainerApi.Container{
|
||||||
|
ContainerName: util.TypeOrDefault(k8sutil.CreateDefaultContainerTemplate(image).With(&c).With(integration.GetContainer())),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Pod: &schedulerPodApi.Pod{
|
||||||
|
Metadata: &schedulerPodResourcesApi.Metadata{
|
||||||
|
Annotations: map[string]string{},
|
||||||
|
},
|
||||||
|
Volumes: &schedulerPodResourcesApi.Volumes{
|
||||||
|
Volumes: volumes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, container := range coreContainers {
|
||||||
|
pt.Pod.Metadata.Annotations[fmt.Sprintf("%s/%s", constants.AnnotationShutdownCoreContainer, container)] = constants.AnnotationShutdownCoreContainerModeWait
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.Pod.Metadata.Annotations[fmt.Sprintf("%s/%s", constants.AnnotationShutdownContainer, ContainerName)] = ListenPortHealthName
|
||||||
|
pt.Pod.Metadata.Annotations[constants.AnnotationShutdownManagedContainer] = "true"
|
||||||
|
|
||||||
|
pt.Container.Containers.ExtendContainers(&schedulerContainerApi.Container{
|
||||||
|
Environments: &schedulerContainerResourcesApi.Environments{
|
||||||
|
Env: envs,
|
||||||
|
},
|
||||||
|
}, coreContainers...)
|
||||||
|
|
||||||
|
return &pt, nil
|
||||||
|
}
|
47
pkg/integrations/sidecar/integration.shutdown.v1.go
Normal file
47
pkg/integrations/sidecar/integration.shutdown.v1.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//
|
||||||
|
// 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 sidecar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IntegrationShutdownV1 struct {
|
||||||
|
Core *Core
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationShutdownV1) Name() (string, string) {
|
||||||
|
return "SHUTDOWN", "V1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationShutdownV1) Validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IntegrationShutdownV1) Args() (k8sutil.OptionPairs, error) {
|
||||||
|
options := k8sutil.CreateOptionPairs()
|
||||||
|
|
||||||
|
options.Add("--integration.shutdown.v1", true)
|
||||||
|
|
||||||
|
options.Merge(i.Core.Args(i))
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
50
pkg/util/dict_test.go
Normal file
50
pkg/util/dict_test.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
//
|
||||||
|
// 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 util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testDictDefaultValue[T any](t *testing.T, expected T) {
|
||||||
|
t.Run(reflect.TypeOf(expected).String(), func(t *testing.T) {
|
||||||
|
m := map[string]T{}
|
||||||
|
|
||||||
|
ev, ok := m["missing"]
|
||||||
|
require.False(t, ok)
|
||||||
|
|
||||||
|
require.Equal(t, expected, ev)
|
||||||
|
|
||||||
|
evs := m["missing"]
|
||||||
|
|
||||||
|
require.Equal(t, expected, evs)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Dict_Types(t *testing.T) {
|
||||||
|
testDictDefaultValue[string](t, "")
|
||||||
|
testDictDefaultValue[int](t, 0)
|
||||||
|
testDictDefaultValue[*string](t, nil)
|
||||||
|
testDictDefaultValue[*int](t, nil)
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// DISCLAIMER
|
// DISCLAIMER
|
||||||
//
|
//
|
||||||
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
|
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/secret"
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/secret"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service"
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service"
|
||||||
)
|
)
|
||||||
|
@ -39,11 +40,11 @@ type PodModifier interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PodCreator interface {
|
type PodCreator interface {
|
||||||
Init(context.Context, Inspector, *core.Pod) error
|
Init(context.Context, Inspector, *core.PodTemplateSpec) error
|
||||||
GetName() string
|
GetName() string
|
||||||
GetRole() string
|
GetRole() string
|
||||||
GetVolumes() []core.Volume
|
GetVolumes() []core.Volume
|
||||||
GetSidecars(*core.Pod) error
|
GetSidecars(*core.PodTemplateSpec) error
|
||||||
GetInitContainers(cachedStatus Inspector) ([]core.Container, error)
|
GetInitContainers(cachedStatus Inspector) ([]core.Container, error)
|
||||||
GetFinalizers() []string
|
GetFinalizers() []string
|
||||||
GetTolerations() []core.Toleration
|
GetTolerations() []core.Toleration
|
||||||
|
@ -61,6 +62,8 @@ type PodCreator interface {
|
||||||
Annotations() map[string]string
|
Annotations() map[string]string
|
||||||
Labels() map[string]string
|
Labels() map[string]string
|
||||||
|
|
||||||
|
Profiles() (schedulerApi.ProfileTemplates, error)
|
||||||
|
|
||||||
PodModifier
|
PodModifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// DISCLAIMER
|
// DISCLAIMER
|
||||||
//
|
//
|
||||||
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
|
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -148,6 +148,17 @@ func (o OptionPairs) AsArgs() []string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o OptionPairs) AsSplittedArgs() []string {
|
||||||
|
s := make([]string, len(o)*2)
|
||||||
|
|
||||||
|
for id, pair := range o {
|
||||||
|
s[id*2] = pair.Key
|
||||||
|
s[id*2+1] = pair.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// OptionPair key value pair builder
|
// OptionPair key value pair builder
|
||||||
type OptionPair struct {
|
type OptionPair struct {
|
||||||
Key string
|
Key string
|
||||||
|
|
40
pkg/util/k8sutil/patcher/config_map.go
Normal file
40
pkg/util/k8sutil/patcher/config_map.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// 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 patcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PatchConfigMapData(data map[string]string) Patch[*core.ConfigMap] {
|
||||||
|
return func(in *core.ConfigMap) []patch.Item {
|
||||||
|
if len(data) == len(in.Data) && equality.Semantic.DeepDerivative(data, in.Data) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []patch.Item{
|
||||||
|
patch.ItemReplace(patch.NewPath("data"), data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
pkg/util/k8sutil/patcher/config_map_test.go
Normal file
105
pkg/util/k8sutil/patcher/config_map_test.go
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
//
|
||||||
|
// 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 patcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/tests"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ConfigMap(t *testing.T) {
|
||||||
|
c := tests.NewEmptyInspector(t)
|
||||||
|
|
||||||
|
t.Run("Create", func(t *testing.T) {
|
||||||
|
require.NoError(t, c.Refresh(context.Background()))
|
||||||
|
|
||||||
|
_, err := c.ConfigMapsModInterface().V1().Create(context.Background(), &core.ConfigMap{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
Name: "test",
|
||||||
|
Namespace: c.Namespace(),
|
||||||
|
},
|
||||||
|
}, meta.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, c.Refresh(context.Background()))
|
||||||
|
|
||||||
|
t.Run("Check", func(t *testing.T) {
|
||||||
|
cm, ok := c.ConfigMap().V1().GetSimple("test")
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Len(t, cm.Data, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, c.Refresh(context.Background()))
|
||||||
|
|
||||||
|
t.Run("Update", func(t *testing.T) {
|
||||||
|
cm, ok := c.ConfigMap().V1().GetSimple("test")
|
||||||
|
require.True(t, ok)
|
||||||
|
uCm, ok, err := Patcher[*core.ConfigMap](context.Background(), c.ConfigMapsModInterface().V1(), cm, meta.PatchOptions{}, PatchConfigMapData(map[string]string{
|
||||||
|
"A": "B",
|
||||||
|
}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
require.NoError(t, c.Refresh(context.Background()))
|
||||||
|
|
||||||
|
cm, ok = c.ConfigMap().V1().GetSimple("test")
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
require.Equal(t, map[string]string{
|
||||||
|
"A": "B",
|
||||||
|
}, uCm.Data)
|
||||||
|
|
||||||
|
require.Equal(t, map[string]string{
|
||||||
|
"A": "B",
|
||||||
|
}, cm.Data)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Reupdate", func(t *testing.T) {
|
||||||
|
cm, ok := c.ConfigMap().V1().GetSimple("test")
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
uCm, ok, err := Patcher[*core.ConfigMap](context.Background(), c.ConfigMapsModInterface().V1(), cm, meta.PatchOptions{}, PatchConfigMapData(map[string]string{
|
||||||
|
"A": "B",
|
||||||
|
}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, ok)
|
||||||
|
|
||||||
|
require.NoError(t, c.Refresh(context.Background()))
|
||||||
|
|
||||||
|
cm, ok = c.ConfigMap().V1().GetSimple("test")
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
require.Equal(t, map[string]string{
|
||||||
|
"A": "B",
|
||||||
|
}, uCm.Data)
|
||||||
|
|
||||||
|
require.Equal(t, map[string]string{
|
||||||
|
"A": "B",
|
||||||
|
}, cm.Data)
|
||||||
|
})
|
||||||
|
}
|
89
pkg/util/k8sutil/patcher/patcher.go
Normal file
89
pkg/util/k8sutil/patcher/patcher.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
//
|
||||||
|
// 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 patcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Patch[T meta.Object] func(in T) []patch.Item
|
||||||
|
|
||||||
|
type Client[T meta.Object] interface {
|
||||||
|
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts meta.PatchOptions, subresources ...string) (result T, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Patcher[T meta.Object](ctx context.Context, client Client[T], in T, opts meta.PatchOptions, functions ...Patch[T]) (T, bool, error) {
|
||||||
|
if v := reflect.ValueOf(in); !v.IsValid() || v.IsZero() {
|
||||||
|
return util.Default[T](), false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.GetName() == "" {
|
||||||
|
return util.Default[T](), false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []patch.Item
|
||||||
|
|
||||||
|
for id := range functions {
|
||||||
|
if f := functions[id]; f != nil {
|
||||||
|
items = append(items, f(in)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(items) == 0 {
|
||||||
|
return in, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := patch.NewPatch(items...).Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return util.Default[T](), false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nctx, c := globals.GetGlobals().Timeouts().Kubernetes().WithTimeout(ctx)
|
||||||
|
defer c()
|
||||||
|
|
||||||
|
if obj, err := client.Patch(nctx, in.GetName(), types.JSONPatchType, data, opts); err != nil {
|
||||||
|
return util.Default[T](), false, err
|
||||||
|
} else {
|
||||||
|
return obj, true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Optional[T meta.Object](p Patch[T], enabled bool) Patch[T] {
|
||||||
|
return func(in T) []patch.Item {
|
||||||
|
if !enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != nil {
|
||||||
|
return p(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// DISCLAIMER
|
// DISCLAIMER
|
||||||
//
|
//
|
||||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -21,57 +21,13 @@
|
||||||
package patcher
|
package patcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/equality"
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
|
||||||
v1 "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServicePatch func(in *core.Service) []patch.Item
|
func PatchServicePorts(ports []core.ServicePort) Patch[*core.Service] {
|
||||||
|
|
||||||
func ServicePatcher(ctx context.Context, client v1.ModInterface, in *core.Service, opts meta.PatchOptions, functions ...ServicePatch) (bool, error) {
|
|
||||||
if in == nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.GetName() == "" {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var items []patch.Item
|
|
||||||
|
|
||||||
for id := range functions {
|
|
||||||
if f := functions[id]; f != nil {
|
|
||||||
items = append(items, f(in)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(items) == 0 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := patch.NewPatch(items...).Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nctx, c := globals.GetGlobals().Timeouts().Kubernetes().WithTimeout(ctx)
|
|
||||||
defer c()
|
|
||||||
|
|
||||||
if _, err := client.Patch(nctx, in.GetName(), types.JSONPatchType, data, opts); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PatchServicePorts(ports []core.ServicePort) ServicePatch {
|
|
||||||
return func(in *core.Service) []patch.Item {
|
return func(in *core.Service) []patch.Item {
|
||||||
if len(ports) == len(in.Spec.Ports) && equality.Semantic.DeepDerivative(ports, in.Spec.Ports) {
|
if len(ports) == len(in.Spec.Ports) && equality.Semantic.DeepDerivative(ports, in.Spec.Ports) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -83,21 +39,7 @@ func PatchServicePorts(ports []core.ServicePort) ServicePatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Optional(p ServicePatch, enabled bool) ServicePatch {
|
func PatchServiceOnlyPorts(ports ...core.ServicePort) Patch[*core.Service] {
|
||||||
return func(in *core.Service) []patch.Item {
|
|
||||||
if !enabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if p != nil {
|
|
||||||
return p(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PatchServiceOnlyPorts(ports ...core.ServicePort) ServicePatch {
|
|
||||||
return func(in *core.Service) []patch.Item {
|
return func(in *core.Service) []patch.Item {
|
||||||
psvc := in.Spec.DeepCopy()
|
psvc := in.Spec.DeepCopy()
|
||||||
cp := psvc.Ports
|
cp := psvc.Ports
|
||||||
|
@ -149,7 +91,7 @@ func PatchServiceOnlyPorts(ports ...core.ServicePort) ServicePatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PatchServiceSelector(selector map[string]string) ServicePatch {
|
func PatchServiceSelector(selector map[string]string) Patch[*core.Service] {
|
||||||
return func(in *core.Service) []patch.Item {
|
return func(in *core.Service) []patch.Item {
|
||||||
if in.Spec.Selector != nil && equality.Semantic.DeepEqual(in.Spec.Selector, selector) {
|
if in.Spec.Selector != nil && equality.Semantic.DeepEqual(in.Spec.Selector, selector) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -161,7 +103,7 @@ func PatchServiceSelector(selector map[string]string) ServicePatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PatchServiceType(t core.ServiceType) ServicePatch {
|
func PatchServiceType(t core.ServiceType) Patch[*core.Service] {
|
||||||
return func(in *core.Service) []patch.Item {
|
return func(in *core.Service) []patch.Item {
|
||||||
if in.Spec.Type == t {
|
if in.Spec.Type == t {
|
||||||
return nil
|
return nil
|
||||||
|
@ -173,7 +115,7 @@ func PatchServiceType(t core.ServiceType) ServicePatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PatchServicePublishNotReadyAddresses(publishNotReadyAddresses bool) ServicePatch {
|
func PatchServicePublishNotReadyAddresses(publishNotReadyAddresses bool) Patch[*core.Service] {
|
||||||
return func(in *core.Service) []patch.Item {
|
return func(in *core.Service) []patch.Item {
|
||||||
if in.Spec.PublishNotReadyAddresses == publishNotReadyAddresses {
|
if in.Spec.PublishNotReadyAddresses == publishNotReadyAddresses {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// DISCLAIMER
|
// DISCLAIMER
|
||||||
//
|
//
|
||||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -53,7 +53,7 @@ func Test_Service(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.False(t, svc.Spec.PublishNotReadyAddresses)
|
require.False(t, svc.Spec.PublishNotReadyAddresses)
|
||||||
|
|
||||||
changed, err := ServicePatcher(context.Background(), c.ServicesModInterface().V1(), svc, meta.PatchOptions{}, PatchServicePublishNotReadyAddresses(true))
|
_, changed, err := Patcher[*core.Service](context.Background(), c.ServicesModInterface().V1(), svc, meta.PatchOptions{}, PatchServicePublishNotReadyAddresses(true))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, changed)
|
require.True(t, changed)
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func Test_Service(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.True(t, svc.Spec.PublishNotReadyAddresses)
|
require.True(t, svc.Spec.PublishNotReadyAddresses)
|
||||||
|
|
||||||
changed, err := ServicePatcher(context.Background(), c.ServicesModInterface().V1(), svc, meta.PatchOptions{}, PatchServicePublishNotReadyAddresses(true))
|
_, changed, err := Patcher[*core.Service](context.Background(), c.ServicesModInterface().V1(), svc, meta.PatchOptions{}, PatchServicePublishNotReadyAddresses(true))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.False(t, changed)
|
require.False(t, changed)
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ func Test_Service(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.True(t, svc.Spec.PublishNotReadyAddresses)
|
require.True(t, svc.Spec.PublishNotReadyAddresses)
|
||||||
|
|
||||||
changed, err := ServicePatcher(context.Background(), c.ServicesModInterface().V1(), svc, meta.PatchOptions{}, PatchServicePublishNotReadyAddresses(false))
|
_, changed, err := Patcher[*core.Service](context.Background(), c.ServicesModInterface().V1(), svc, meta.PatchOptions{}, PatchServicePublishNotReadyAddresses(false))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, changed)
|
require.True(t, changed)
|
||||||
|
|
||||||
|
|
|
@ -560,10 +560,10 @@ func NewContainer(containerCreator interfaces.ContainerCreator) (core.Container,
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPod creates a basic Pod for given settings.
|
// NewPod creates a basic Pod for given settings.
|
||||||
func NewPod(deploymentName, role, id, podName string, podCreator interfaces.PodCreator) core.Pod {
|
func NewPod(deploymentName, role, id, podName string, podCreator interfaces.PodCreator) core.PodTemplateSpec {
|
||||||
|
|
||||||
hostname := shared.CreatePodHostName(deploymentName, role, id)
|
hostname := shared.CreatePodHostName(deploymentName, role, id)
|
||||||
p := core.Pod{
|
p := core.PodTemplateSpec{
|
||||||
ObjectMeta: meta.ObjectMeta{
|
ObjectMeta: meta.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
Labels: LabelsForMember(deploymentName, role, id),
|
Labels: LabelsForMember(deploymentName, role, id),
|
||||||
|
|
|
@ -82,7 +82,7 @@ func CreateExporterService(ctx context.Context, cachedStatus inspector.Inspector
|
||||||
svcName := CreateExporterClientServiceName(deploymentName)
|
svcName := CreateExporterClientServiceName(deploymentName)
|
||||||
|
|
||||||
if svc, exists := cachedStatus.Service().V1().GetSimple(svcName); exists {
|
if svc, exists := cachedStatus.Service().V1().GetSimple(svcName); exists {
|
||||||
if changed, err := patcher.ServicePatcher(ctx, cachedStatus.ServicesModInterface().V1(), svc, meta.PatchOptions{}, patcher.PatchServiceSelector(selectors), patcher.PatchServicePorts(ports)); err != nil {
|
if _, changed, err := patcher.Patcher[*core.Service](ctx, cachedStatus.ServicesModInterface().V1(), svc, meta.PatchOptions{}, patcher.PatchServiceSelector(selectors), patcher.PatchServicePorts(ports)); err != nil {
|
||||||
return "", false, err
|
return "", false, err
|
||||||
} else {
|
} else {
|
||||||
return svcName, changed, nil
|
return svcName, changed, nil
|
||||||
|
|
|
@ -24,8 +24,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -105,41 +103,3 @@ func AddTolerationIfNotFound(source []core.Toleration, toAdd core.Toleration) []
|
||||||
|
|
||||||
return append(source, toAdd)
|
return append(source, toAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePodTolerations creates a list of tolerations for a pod created for the given group.
|
|
||||||
func CreatePodTolerations(mode api.DeploymentMode, group api.ServerGroup) []core.Toleration {
|
|
||||||
notReadyDur := TolerationDuration{Forever: false, TimeSpan: time.Minute}
|
|
||||||
unreachableDur := TolerationDuration{Forever: false, TimeSpan: time.Minute}
|
|
||||||
switch group {
|
|
||||||
case api.ServerGroupAgents:
|
|
||||||
notReadyDur.Forever = true
|
|
||||||
unreachableDur.Forever = true
|
|
||||||
case api.ServerGroupCoordinators:
|
|
||||||
notReadyDur.TimeSpan = 15 * time.Second
|
|
||||||
unreachableDur.TimeSpan = 15 * time.Second
|
|
||||||
case api.ServerGroupDBServers:
|
|
||||||
notReadyDur.TimeSpan = 5 * time.Minute
|
|
||||||
unreachableDur.TimeSpan = 5 * time.Minute
|
|
||||||
case api.ServerGroupSingle:
|
|
||||||
if mode == api.DeploymentModeSingle {
|
|
||||||
notReadyDur.Forever = true
|
|
||||||
unreachableDur.Forever = true
|
|
||||||
} else {
|
|
||||||
notReadyDur.TimeSpan = 5 * time.Minute
|
|
||||||
unreachableDur.TimeSpan = 5 * time.Minute
|
|
||||||
}
|
|
||||||
case api.ServerGroupSyncMasters:
|
|
||||||
notReadyDur.TimeSpan = 15 * time.Second
|
|
||||||
unreachableDur.TimeSpan = 15 * time.Second
|
|
||||||
case api.ServerGroupSyncWorkers:
|
|
||||||
notReadyDur.TimeSpan = 1 * time.Minute
|
|
||||||
unreachableDur.TimeSpan = 1 * time.Minute
|
|
||||||
case api.ServerGroupGateways:
|
|
||||||
notReadyDur.TimeSpan = 15 * time.Second
|
|
||||||
unreachableDur.TimeSpan = 15 * time.Second
|
|
||||||
}
|
|
||||||
return []core.Toleration{NewNoExecuteToleration(TolerationKeyNodeNotReady, notReadyDur),
|
|
||||||
NewNoExecuteToleration(TolerationKeyNodeUnreachable, unreachableDur),
|
|
||||||
NewNoExecuteToleration(TolerationKeyNodeAlphaUnreachable, unreachableDur),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue