Skip to content

Commit e97fb0c

Browse files
ykadowakkpangokmrmt
authoredFeb 27, 2024··
Add index-operator template implementation (#2375)
* improve Backport Pull Request Title & Description Quality (#2373) Signed-off-by: kpango <kpango@vdaas.org> Co-authored-by: Kosuke Morimoto <ksk@vdaas.org> * [bugfix] fix backport github value bypass failure (#2378) Signed-off-by: kpango <kpango@vdaas.org> * [bugfix] fix backport github value bypass failure (#2381) Signed-off-by: kpango <kpango@vdaas.org> * Add index operator boilerplate * Add k8s controller * Add pod and job controllers * Add annotations in the pod reconciler * Update auto indexing service configurations * Update WithOnReconcileFunc signature to include context * Refactor debugging log * Refactor reconcile funcs * add nolint * remove unused parameters * lint * Add dockerfile and build ci * remove params * Add index-operator image build command to Makefile * Add index operator k8s templates * Update helm schema * Update readme * Add internal/k8s as a trigger for images that depends on controller-runtime * remove comment * Update pkg/index/operator/service/operator.go Co-authored-by: Yusuke Kato <kpango@vdaas.org> Signed-off-by: Yusuke Kadowaki <yusuke.kadowaki.1231@gmail.com> * Update pkg/index/operator/service/operator.go Co-authored-by: Yusuke Kato <kpango@vdaas.org> Signed-off-by: Yusuke Kadowaki <yusuke.kadowaki.1231@gmail.com> * Refactor * Add build commands * Refactor Co-authored-by: Yusuke Kato <kpango@vdaas.org> --------- Signed-off-by: kpango <kpango@vdaas.org> Signed-off-by: Yusuke Kadowaki <yusuke.kadowaki.1231@gmail.com> Co-authored-by: Yusuke Kato <kpango@vdaas.org> Co-authored-by: Kosuke Morimoto <ksk@vdaas.org>
1 parent 1d4efd8 commit e97fb0c

File tree

26 files changed

+4171
-951
lines changed

26 files changed

+4171
-951
lines changed
 

‎.github/workflows/dockers-agent-ngt-image.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ on:
3434
- "internal/**"
3535
- "!internal/**/*_test.go"
3636
- "!internal/db/**"
37-
- "!internal/k8s/**"
37+
- "internal/k8s/**"
3838
- "apis/grpc/**"
3939
- "pkg/agent/core/ngt/**"
4040
- "cmd/agent/core/ngt/**"
@@ -51,7 +51,7 @@ on:
5151
- "internal/**"
5252
- "!internal/**/*_test.go"
5353
- "!internal/db/**"
54-
- "!internal/k8s/**"
54+
- "internal/k8s/**"
5555
- "apis/grpc/**"
5656
- "pkg/agent/core/ngt/**"
5757
- "cmd/agent/core/ngt/**"
@@ -68,7 +68,7 @@ on:
6868
- "internal/**"
6969
- "!internal/**/*_test.go"
7070
- "!internal/db/**"
71-
- "!internal/k8s/**"
71+
- "internal/k8s/**"
7272
- "apis/grpc/**"
7373
- "pkg/agent/core/ngt/**"
7474
- "cmd/agent/core/ngt/**"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#
2+
# Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# You may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
name: "Build docker image: index-operator"
17+
on:
18+
push:
19+
branches:
20+
- main
21+
tags:
22+
- "*.*.*"
23+
- "v*.*.*"
24+
- "*.*.*-*"
25+
- "v*.*.*-*"
26+
paths:
27+
- ".github/actions/docker-build/actions.yaml"
28+
- ".github/workflows/dockers-index-operator.yml"
29+
- "go.mod"
30+
- "go.sum"
31+
- "internal/**"
32+
- "!internal/**/*_test.go"
33+
- "!internal/db/**"
34+
- "internal/k8s/**"
35+
- "apis/grpc/**"
36+
- "pkg/index/operator/**"
37+
- "cmd/index/operator/**"
38+
- "dockers/index/operator/Dockerfile"
39+
- "versions/GO_VERSION"
40+
pull_request:
41+
paths:
42+
- ".github/actions/docker-build/actions.yaml"
43+
- ".github/workflows/_docker-image.yaml"
44+
- ".github/workflows/dockers-index-operator.yml"
45+
- "go.mod"
46+
- "go.sum"
47+
- "internal/**"
48+
- "!internal/**/*_test.go"
49+
- "!internal/db/**"
50+
- "internal/k8s/**"
51+
- "apis/grpc/**"
52+
- "pkg/index/operator/**"
53+
- "cmd/index/operator/**"
54+
- "dockers/index/operator/Dockerfile"
55+
- "versions/GO_VERSION"
56+
pull_request_target:
57+
paths:
58+
- ".github/actions/docker-build/actions.yaml"
59+
- ".github/workflows/_docker-image.yaml"
60+
- ".github/workflows/dockers-index-operator.yml"
61+
- "go.mod"
62+
- "go.sum"
63+
- "internal/**"
64+
- "!internal/**/*_test.go"
65+
- "!internal/db/**"
66+
- "internal/k8s/**"
67+
- "apis/grpc/**"
68+
- "pkg/index/operator/**"
69+
- "cmd/index/operator/**"
70+
- "dockers/index/operator/Dockerfile"
71+
- "versions/GO_VERSION"
72+
jobs:
73+
build:
74+
uses: ./.github/workflows/_docker-image.yaml
75+
with:
76+
target: index-operator
77+
secrets: inherit

‎.github/workflows/dockers-readreplica-rotate.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ on:
3131
- "internal/**"
3232
- "!internal/**/*_test.go"
3333
- "!internal/db/**"
34-
- "!internal/k8s/**"
34+
- "internal/k8s/**"
3535
- "apis/grpc/**"
3636
- "pkg/index/job/readreplica/rotate/**"
3737
- "cmd/index/job/readreplica/rotate/**"
@@ -47,7 +47,7 @@ on:
4747
- "internal/**"
4848
- "!internal/**/*_test.go"
4949
- "!internal/db/**"
50-
- "!internal/k8s/**"
50+
- "internal/k8s/**"
5151
- "apis/grpc/**"
5252
- "pkg/index/job/readreplica/rotate/**"
5353
- "cmd/index/job/readreplica/rotate/**"
@@ -63,7 +63,7 @@ on:
6363
- "internal/**"
6464
- "!internal/**/*_test.go"
6565
- "!internal/db/**"
66-
- "!internal/k8s/**"
66+
- "internal/k8s/**"
6767
- "apis/grpc/**"
6868
- "pkg/index/job/readreplica/rotate/**"
6969
- "cmd/index/job/readreplica/rotate/**"

‎Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ LOADTEST_IMAGE = $(NAME)-loadtest
3535
INDEX_CORRECTION_IMAGE = $(NAME)-index-correction
3636
INDEX_CREATION_IMAGE = $(NAME)-index-creation
3737
INDEX_SAVE_IMAGE = $(NAME)-index-save
38+
INDEX_OPERATOR_IMAGE = $(NAME)-index-operator
3839
READREPLICA_ROTATE_IMAGE = $(NAME)-readreplica-rotate
3940
MANAGER_INDEX_IMAGE = $(NAME)-manager-index
4041
BENCHMARK_JOB_IMAGE = $(NAME)-benchmark-job

‎Makefile.d/build.mk

+12-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ binary/build: \
3030
cmd/index/job/save/index-save \
3131
cmd/manager/index/index \
3232
cmd/tools/benchmark/job/job \
33-
cmd/tools/benchmark/operator/operator
33+
cmd/tools/benchmark/operator/operator \
34+
cmd/index/operator/index-operator
3435

3536

3637
cmd/agent/core/ngt/ngt: \
@@ -83,6 +84,10 @@ cmd/index/job/readreplica/rotate/readreplica-rotate:
8384
$(eval CGO_ENABLED = 0)
8485
$(call go-build,index/job/readreplica/rotate,,-static,,,$@)
8586

87+
cmd/index/operator/index-operator:
88+
$(eval CGO_ENABLED = 0)
89+
$(call go-build,index/operator,,-static,,,$@)
90+
8691
cmd/tools/benchmark/job/job:
8792
$(call go-build,tools/benchmark/job,-linkmode 'external',-static -fPIC -pthread -fopenmp -std=gnu++20 -lhdf5 -lhdf5_hl -lm -ldl, cgo,$(HDF5_VERSION),$@)
8893

@@ -104,7 +109,8 @@ binary/build/zip: \
104109
artifacts/vald-lb-gateway-$(GOOS)-$(GOARCH).zip \
105110
artifacts/vald-manager-index-$(GOOS)-$(GOARCH).zip \
106111
artifacts/vald-mirror-gateway-$(GOOS)-$(GOARCH).zip \
107-
artifacts/vald-readreplica-rotate-$(GOOS)-$(GOARCH).zip
112+
artifacts/vald-readreplica-rotate-$(GOOS)-$(GOARCH).zip \
113+
artifacts/vald-index-operator-$(GOOS)-$(GOARCH).zip
108114

109115
artifacts/vald-agent-ngt-$(GOOS)-$(GOARCH).zip: cmd/agent/core/ngt/ngt
110116
$(call mkdir, $(dir $@))
@@ -161,3 +167,7 @@ artifacts/vald-index-save-$(GOOS)-$(GOARCH).zip: cmd/index/job/save/index-save
161167
artifacts/vald-readreplica-rotate-$(GOOS)-$(GOARCH).zip: cmd/index/job/readreplica/rotate/readreplica-rotate
162168
$(call mkdir, $(dir $@))
163169
zip --junk-paths $@ $<
170+
171+
artifacts/vald-index-operator-$(GOOS)-$(GOARCH).zip: cmd/index/operator/index-operator
172+
$(call mkdir, $(dir $@))
173+
zip --junk-paths $@ $<

‎Makefile.d/docker.mk

+11
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,17 @@ docker/build/index-save:
242242
IMAGE=$(INDEX_SAVE_IMAGE) \
243243
docker/build/image
244244

245+
.PHONY: docker/name/index-operator
246+
docker/name/index-operator:
247+
@echo "$(ORG)/$(INDEX_OPERATOR_IMAGE)"
248+
249+
.PHONY: docker/build/index-operator
250+
## build index-operator image
251+
docker/build/index-operator:
252+
@make DOCKERFILE="$(ROOTDIR)/dockers/index/operator/Dockerfile" \
253+
IMAGE=$(INDEX_OPERATOR_IMAGE) \
254+
docker/build/image
255+
245256
.PHONY: docker/name/readreplica-rotate
246257
docker/name/readreplica-rotate:
247258
@echo "$(ORG)/$(READREPLICA_ROTATE_IMAGE)"

‎Makefile.d/k8s.mk

+18-13
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ k8s/manifest/update: \
4747
mv $(TEMP_DIR)/vald/templates/discoverer k8s/discoverer
4848
mv $(TEMP_DIR)/vald/templates/gateway k8s/gateway
4949
mv $(TEMP_DIR)/vald/templates/manager/index k8s/manager/index
50+
mv $(TEMP_DIR)/vald/templates/index/operator k8s/index/operator
5051
mv $(TEMP_DIR)/vald/templates/index/job/correction k8s/index/job/correction
5152
mv $(TEMP_DIR)/vald/templates/index/job/creation k8s/index/job/creation
5253
mv $(TEMP_DIR)/vald/templates/index/job/save k8s/index/job/save
@@ -120,6 +121,7 @@ k8s/vald/deploy:
120121
--set manager.index.image.repository=$(CRORG)/$(MANAGER_INDEX_IMAGE) \
121122
--set manager.index.creator.image.repository=$(CRORG)/$(INDEX_CREATION_IMAGE) \
122123
--set manager.index.saver.image.repository=$(CRORG)/$(INDEX_SAVE_IMAGE) \
124+
--set manager.index.operator.image.repository=$(CRORG)/$(INDEX_OPERATOR_IMAGE) \
123125
$(HELM_EXTRA_OPTIONS) \
124126
--include-crds \
125127
--output-dir $(TEMP_DIR) \
@@ -138,6 +140,7 @@ k8s/vald/deploy:
138140
kubectl apply -f $(TEMP_DIR)/vald/templates/index/job/creation || true
139141
kubectl apply -f $(TEMP_DIR)/vald/templates/index/job/save || true
140142
kubectl apply -f $(TEMP_DIR)/vald/templates/index/job/readreplica/rotate || true
143+
kubectl apply -f $(TEMP_DIR)/vald/templates/index/operator || true
141144
rm -rf $(TEMP_DIR)
142145
kubectl get pods -o jsonpath="{.items[*].spec.containers[*].image}" | tr " " "\n"
143146

@@ -154,24 +157,26 @@ k8s/vald/delete:
154157
--set gateway.lb.image.repository=$(CRORG)/$(LB_GATEWAY_IMAGE) \
155158
--set gateway.mirror.image.repository=$(CRORG)/$(MIRROR_GATEWAY_IMAGE) \
156159
--set manager.index.image.repository=$(CRORG)/$(MANAGER_INDEX_IMAGE) \
160+
--set manager.index.operator.image.repository=$(CRORG)/$(INDEX_OPERATOR_IMAGE) \
157161
--include-crds \
158162
--output-dir $(TEMP_DIR) \
159163
charts/vald
160-
kubectl delete -f $(TEMP_DIR)/vald/templates/gateway/mirror
161-
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/readreplica/rotate
162-
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/save
163-
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/creation
164-
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/correction
165-
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/creation
166-
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/save
167-
kubectl delete -f $(TEMP_DIR)/vald/templates/gateway
168-
kubectl delete -f $(TEMP_DIR)/vald/templates/gateway/lb
169-
kubectl delete -f $(TEMP_DIR)/vald/templates/manager/index
170-
kubectl delete -f $(TEMP_DIR)/vald/templates/discoverer
164+
kubectl delete -f $(TEMP_DIR)/vald/templates/gateway/mirror || true
165+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/operator || true
166+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/readreplica/rotate || true
167+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/save || true
168+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/creation || true
169+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/correction || true
170+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/creation || true
171+
kubectl delete -f $(TEMP_DIR)/vald/templates/index/job/save || true
172+
kubectl delete -f $(TEMP_DIR)/vald/templates/gateway || true
173+
kubectl delete -f $(TEMP_DIR)/vald/templates/gateway/lb || true
174+
kubectl delete -f $(TEMP_DIR)/vald/templates/manager/index || true
175+
kubectl delete -f $(TEMP_DIR)/vald/templates/discoverer || true
171176
kubectl delete -f $(TEMP_DIR)/vald/templates/agent/readreplica || true
172177
kubectl delete -f $(TEMP_DIR)/vald/templates/agent/ngt || true
173-
kubectl delete -f $(TEMP_DIR)/vald/templates/agent
174-
kubectl delete -f $(TEMP_DIR)/vald/crds
178+
kubectl delete -f $(TEMP_DIR)/vald/templates/agent || true
179+
kubectl delete -f $(TEMP_DIR)/vald/crds || true
175180
rm -rf $(TEMP_DIR)
176181

177182
.PHONY: k8s/multi/vald/deploy

‎charts/vald-helm-operator/crds/valdrelease.yaml

+745
Large diffs are not rendered by default.

‎charts/vald/README.md

+950-910
Large diffs are not rendered by default.

‎charts/vald/templates/discoverer/clusterrole.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,12 @@ rules:
5959
verbs:
6060
- get
6161
- list
62+
- apiGroups:
63+
- batch
64+
resources:
65+
- jobs
66+
verbs:
67+
- get
68+
- list
69+
- watch
6270
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#
2+
# Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# You may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
{{- $operator := .Values.manager.index.operator -}}
17+
{{- $agent := .Values.agent -}}
18+
{{- if $operator.enabled }}
19+
apiVersion: v1
20+
kind: ConfigMap
21+
metadata:
22+
name: {{ $operator.name }}-config
23+
labels:
24+
app.kubernetes.io/name: {{ include "vald.name" . }}
25+
helm.sh/chart: {{ include "vald.chart" . }}
26+
app.kubernetes.io/managed-by: {{ .Release.Service }}
27+
app.kubernetes.io/instance: {{ .Release.Name }}
28+
app.kubernetes.io/version: {{ .Chart.Version }}
29+
app.kubernetes.io/component: index-operator
30+
data:
31+
config.yaml: |
32+
---
33+
version: {{ $operator.version }}
34+
time_zone: {{ default .Values.defaults.time_zone $operator.time_zone }}
35+
logging:
36+
{{- $logging := dict "Values" $operator.logging "default" .Values.defaults.logging }}
37+
{{- include "vald.logging" $logging | nindent 6 }}
38+
server_config:
39+
{{- $servers := dict "Values" $operator.server_config "default" .Values.defaults.server_config }}
40+
{{- include "vald.servers" $servers | nindent 6 }}
41+
observability:
42+
{{- $observability := dict "Values" $operator.observability "default" .Values.defaults.observability }}
43+
{{- include "vald.observability" $observability | nindent 6 }}
44+
operator:
45+
agent_name: {{ $agent.name }}
46+
agent_namespace: {{ $agent.namespace }}
47+
concurrency: 1
48+
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#
2+
# Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# You may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
{{- $operator := .Values.manager.index.operator -}}
17+
{{- $valdServiceAccount := .Values.discoverer.serviceAccount -}}
18+
{{- if and $operator.enabled (eq $operator.kind "Deployment") }}
19+
apiVersion: apps/v1
20+
kind: Deployment
21+
metadata:
22+
name: {{ $operator.name }}
23+
labels:
24+
app: {{ $operator.name }}
25+
app.kubernetes.io/name: {{ include "vald.name" . }}
26+
helm.sh/chart: {{ include "vald.chart" . }}
27+
app.kubernetes.io/managed-by: {{ .Release.Service }}
28+
app.kubernetes.io/instance: {{ .Release.Name }}
29+
app.kubernetes.io/version: {{ .Chart.Version }}
30+
app.kubernetes.io/component: index-operator
31+
{{- if $operator.annotations }}
32+
annotations:
33+
{{- toYaml $operator.annotations | nindent 4 }}
34+
{{- end }}
35+
spec:
36+
progressDeadlineSeconds: {{ $operator.progressDeadlineSeconds }}
37+
replicas: {{ $operator.replicas }}
38+
revisionHistoryLimit: {{ $operator.revisionHistoryLimit }}
39+
selector:
40+
matchLabels:
41+
app: {{ $operator.name }}
42+
strategy:
43+
type: RollingUpdate
44+
rollingUpdate:
45+
maxSurge: {{ $operator.rollingUpdate.maxSurge }}
46+
maxUnavailable: {{ $operator.rollingUpdate.maxUnavailable }}
47+
template:
48+
metadata:
49+
creationTimestamp: null
50+
labels:
51+
app: {{ $operator.name }}
52+
app.kubernetes.io/name: {{ include "vald.name" . }}
53+
app.kubernetes.io/instance: {{ .Release.Name }}
54+
app.kubernetes.io/component: operator
55+
annotations:
56+
checksum/configmap: {{ include (print $.Template.BasePath "/index/operator/configmap.yaml") . | sha256sum }}
57+
{{- if $operator.podAnnotations }}
58+
{{- toYaml $operator.podAnnotations | nindent 8 }}
59+
{{- end }}
60+
{{- $pprof := default .Values.defaults.server_config.metrics.pprof $operator.server_config.metrics.pprof }}
61+
{{- if $pprof.enabled }}
62+
pyroscope.io/scrape: "true"
63+
pyroscope.io/application-name: {{ $operator.name }}
64+
pyroscope.io/profile-cpu-enabled: "true"
65+
pyroscope.io/profile-mem-enabled: "true"
66+
pyroscope.io/port: "{{ $pprof.port }}"
67+
{{- end }}
68+
spec:
69+
{{- if $operator.initContainers }}
70+
initContainers:
71+
{{- $initContainers := dict "initContainers" $operator.initContainers "Values" .Values "namespace" .Release.Namespace -}}
72+
{{- include "vald.initContainers" $initContainers | trim | nindent 8 }}
73+
{{- end }}
74+
affinity:
75+
{{- include "vald.affinity" $operator.affinity | nindent 8 }}
76+
{{- if $operator.topologySpreadConstraints }}
77+
topologySpreadConstraints:
78+
{{- toYaml $operator.topologySpreadConstraints | nindent 8 }}
79+
{{- end }}
80+
containers:
81+
- name: {{ $operator.name }}
82+
image: "{{ $operator.image.repository }}:{{ default .Values.defaults.image.tag $operator.image.tag }}"
83+
imagePullPolicy: {{ $operator.image.pullPolicy }}
84+
{{- $servers := dict "Values" $operator.server_config "default" .Values.defaults.server_config -}}
85+
{{- include "vald.containerPorts" $servers | trim | nindent 10 }}
86+
resources:
87+
{{- toYaml $operator.resources | nindent 12 }}
88+
terminationMessagePath: /dev/termination-log
89+
terminationMessagePolicy: File
90+
{{- if $operator.securityContext }}
91+
securityContext:
92+
{{- toYaml $operator.securityContext | nindent 12 }}
93+
{{- end }}
94+
{{- if $operator.env }}
95+
env:
96+
{{- toYaml $operator.env | nindent 12 }}
97+
{{- end }}
98+
volumeMounts:
99+
- name: {{ $operator.name }}-config
100+
mountPath: /etc/server/
101+
{{- if $operator.volumeMounts }}
102+
{{- toYaml $operator.volumeMounts | nindent 12 }}
103+
{{- end }}
104+
dnsPolicy: ClusterFirst
105+
restartPolicy: Always
106+
schedulerName: default-scheduler
107+
serviceAccountName: {{ $valdServiceAccount.name }}
108+
{{- if $operator.podSecurityContext }}
109+
securityContext:
110+
{{- toYaml $operator.podSecurityContext | nindent 8 }}
111+
{{- end }}
112+
terminationGracePeriodSeconds: {{ $operator.terminationGracePeriodSeconds }}
113+
volumes:
114+
- name: {{ $operator.name }}-config
115+
configMap:
116+
defaultMode: 420
117+
name: {{ $operator.name }}-config
118+
{{- if $operator.volumes }}
119+
{{- toYaml $operator.volumes | nindent 8 }}
120+
{{- end }}
121+
{{- if $operator.nodeName }}
122+
nodeName: {{ $operator.nodeName }}
123+
{{- end }}
124+
{{- if $operator.nodeSelector }}
125+
nodeSelector:
126+
{{- toYaml $operator.nodeSelector | nindent 8 }}
127+
{{- end }}
128+
{{- if $operator.tolerations }}
129+
tolerations:
130+
{{- toYaml $operator.tolerations | nindent 8 }}
131+
{{- end }}
132+
{{- if $operator.podPriority }}
133+
{{- if $operator.podPriority.enabled }}
134+
priorityClassName: {{ .Release.Namespace }}-{{ $operator.name }}-priority
135+
{{- end }}
136+
{{- end }}
137+
status:
138+
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#
2+
# Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# You may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
{{- $operator := .Values.manager.index.operator -}}
17+
{{- if and $operator.enabled $operator.podPriority.enabled }}
18+
apiVersion: scheduling.k8s.io/v1
19+
kind: PriorityClass
20+
metadata:
21+
name: {{ .Release.Namespace }}-{{ $operator.name }}-priority
22+
labels:
23+
app.kubernetes.io/name: {{ include "vald.name" . }}
24+
helm.sh/chart: {{ include "vald.chart" . }}
25+
app.kubernetes.io/managed-by: {{ .Release.Service }}
26+
app.kubernetes.io/instance: {{ .Release.Name }}
27+
app.kubernetes.io/version: {{ .Chart.Version }}
28+
app.kubernetes.io/component: index-operator
29+
value: {{ $operator.podPriority.value }}
30+
preemptionPolicy: Never
31+
globalDefault: false
32+
description: "A priority class for Vald index operator."
33+
{{- end }}

‎charts/vald/values.schema.json

+1,238
Large diffs are not rendered by default.

‎charts/vald/values.yaml

+172
Original file line numberDiff line numberDiff line change
@@ -3502,3 +3502,175 @@ manager:
35023502
# @schema {"name": "manager.index.readreplica.rotator.clusterRoleBinding.name", "type": "string"}
35033503
# manager.index.readreplica.rotator.clusterRoleBinding.name -- name of clusterRoleBinding
35043504
name: vald-readreplica-rotate
3505+
# @schema {"name": "manager.index.operator", "type": "object"}
3506+
# manager.index.operator -- [THIS FEATURE IS WIP] operator that manages vald index
3507+
operator:
3508+
# @schema {"name": "manager.index.operator.enabled", "type": "boolean"}
3509+
# manager.index.operator.enabled -- index operator enabled
3510+
enabled: false
3511+
# @schema {"name": "manager.index.operator.version", "alias": "version"}
3512+
# manager.index.operator.version -- version of index operator config
3513+
version: v0.0.0
3514+
# @schema {"name": "manager.index.operator.time_zone", "type": "string"}
3515+
# manager.index.operator.time_zone -- Time zone
3516+
time_zone: ""
3517+
# @schema {"name": "manager.index.operator.logging", "alias": "logging"}
3518+
# manager.index.operator.logging -- logging config (overrides defaults.logging)
3519+
logging: {}
3520+
# @schema {"name": "manager.index.operator.name", "type": "string"}
3521+
# manager.index.operator.name -- name of manager.index.operator deployment
3522+
name: vald-index-operator
3523+
# @schema {"name": "manager.index.operator.kind", "type": "string", "enum": ["Deployment", "DaemonSet"]}
3524+
# manager.index.operator.kind -- deployment kind: Deployment or DaemonSet
3525+
kind: Deployment
3526+
# @schema {"name": "manager.index.operator.progressDeadlineSeconds", "type": "integer"}
3527+
# manager.index.operator.progressDeadlineSeconds -- progress deadline seconds
3528+
progressDeadlineSeconds: 600
3529+
# @schema {"name": "manager.index.operator.replicas", "type": "integer", "minimum": 0}
3530+
# manager.index.operator.replicas -- number of replicas.
3531+
replicas: 1
3532+
# @schema {"name": "manager.index.operator.revisionHistoryLimit", "type": "integer", "minimum": 0}
3533+
# manager.index.operator.revisionHistoryLimit -- number of old history to retain to allow rollback
3534+
revisionHistoryLimit: 2
3535+
# @schema {"name": "manager.index.operator.terminationGracePeriodSeconds", "type": "integer", "minimum": 0}
3536+
# manager.index.operator.terminationGracePeriodSeconds -- duration in seconds pod needs to terminate gracefully
3537+
terminationGracePeriodSeconds: 30
3538+
# @schema {"name": "manager.index.operator.podSecurityContext", "type": "object"}
3539+
# manager.index.operator.podSecurityContext -- security context for pod
3540+
podSecurityContext:
3541+
runAsUser: 65532
3542+
runAsNonRoot: true
3543+
runAsGroup: 65532
3544+
fsGroup: 65532
3545+
fsGroupChangePolicy: "OnRootMismatch"
3546+
# @schema {"name": "manager.index.operator.securityContext", "type": "object"}
3547+
# manager.index.operator.securityContext -- security context for container
3548+
securityContext:
3549+
runAsUser: 65532
3550+
runAsNonRoot: true
3551+
runAsGroup: 65532
3552+
privileged: false
3553+
allowPrivilegeEscalation: false
3554+
readOnlyRootFilesystem: true
3555+
capabilities:
3556+
drop:
3557+
- ALL
3558+
# @schema {"name": "manager.index.operator.podPriority", "alias": "podPriority"}
3559+
podPriority:
3560+
# manager.index.operator.podPriority.enabled -- manager.index.operator pod PriorityClass enabled
3561+
enabled: true
3562+
# manager.index.operator.podPriority.value -- manager.index.operator pod PriorityClass value
3563+
value: 1000000
3564+
# @schema {"name": "manager.index.operator.annotations", "type": "object"}
3565+
# manager.index.operator.annotations -- deployment annotations
3566+
annotations: {}
3567+
# @schema {"name": "manager.index.operator.podAnnotations", "type": "object"}
3568+
# manager.index.operator.podAnnotations -- pod annotations
3569+
podAnnotations: {}
3570+
# @schema {"name": "manager.index.operator.image", "alias": "image"}
3571+
image:
3572+
# manager.index.operator.image.repository -- image repository
3573+
repository: vdaas/vald-index-operator
3574+
# manager.index.operator.image.tag -- image tag (overrides defaults.image.tag)
3575+
tag: ""
3576+
# manager.index.operator.image.pullPolicy -- image pull policy
3577+
pullPolicy: Always
3578+
# @schema {"name": "manager.index.operator.rollingUpdate", "alias": "rollingUpdate"}
3579+
rollingUpdate:
3580+
# manager.index.operator.rollingUpdate.maxSurge -- max surge of rolling update
3581+
maxSurge: 25%
3582+
# manager.index.operator.rollingUpdate.maxUnavailable -- max unavailable of rolling update
3583+
maxUnavailable: 25%
3584+
# @schema {"name": "manager.index.operator.initContainers", "alias": "initContainers"}
3585+
# manager.index.operator.initContainers -- init containers
3586+
initContainers: []
3587+
# @schema {"name": "manager.index.operator.env", "alias": "env"}
3588+
# manager.index.operator.env -- environment variables
3589+
env:
3590+
- name: MY_NODE_NAME
3591+
valueFrom:
3592+
fieldRef:
3593+
fieldPath: spec.nodeName
3594+
- name: MY_POD_NAME
3595+
valueFrom:
3596+
fieldRef:
3597+
fieldPath: metadata.name
3598+
- name: MY_POD_NAMESPACE
3599+
valueFrom:
3600+
fieldRef:
3601+
fieldPath: metadata.namespace
3602+
# @schema {"name": "manager.index.operator.volumeMounts", "alias": "volumeMounts"}
3603+
# manager.index.operator.volumeMounts -- volume mounts
3604+
volumeMounts: []
3605+
# @schema {"name": "manager.index.operator.volumes", "alias": "volumes"}
3606+
# manager.index.operator.volumes -- volumes
3607+
volumes: []
3608+
# @schema {"name": "manager.index.operator.nodeName", "type": "string"}
3609+
# manager.index.operator.nodeName -- node name
3610+
nodeName: ""
3611+
# @schema {"name": "manager.index.operator.nodeSelector", "alias": "nodeSelector"}
3612+
# manager.index.operator.nodeSelector -- node selector
3613+
nodeSelector: {}
3614+
# @schema {"name": "manager.index.operator.tolerations", "alias": "tolerations"}
3615+
# manager.index.operator.tolerations -- tolerations
3616+
tolerations: []
3617+
# @schema {"name": "manager.index.operator.affinity", "alias": "affinity"}
3618+
affinity:
3619+
nodeAffinity:
3620+
# manager.index.operator.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution -- node affinity preferred scheduling terms
3621+
preferredDuringSchedulingIgnoredDuringExecution: []
3622+
requiredDuringSchedulingIgnoredDuringExecution:
3623+
# manager.index.operator.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms -- node affinity required node selectors
3624+
nodeSelectorTerms: []
3625+
podAffinity:
3626+
# manager.index.operator.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution -- pod affinity preferred scheduling terms
3627+
preferredDuringSchedulingIgnoredDuringExecution: []
3628+
# manager.index.operator.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution -- pod affinity required scheduling terms
3629+
requiredDuringSchedulingIgnoredDuringExecution: []
3630+
podAntiAffinity:
3631+
# manager.index.operator.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution -- pod anti-affinity preferred scheduling terms
3632+
preferredDuringSchedulingIgnoredDuringExecution:
3633+
- weight: 100
3634+
podAffinityTerm:
3635+
topologyKey: kubernetes.io/hostname
3636+
labelSelector:
3637+
matchExpressions:
3638+
- key: app
3639+
operator: In
3640+
values:
3641+
- vald-index-operator
3642+
# manager.index.operator.affinity.podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution -- pod anti-affinity required scheduling terms
3643+
requiredDuringSchedulingIgnoredDuringExecution: []
3644+
# @schema {"name": "manager.index.operator.topologySpreadConstraints", "alias": "topologySpreadConstraints"}
3645+
# manager.index.operator.topologySpreadConstraints -- topology spread constraints of manager.index.operator pods
3646+
topologySpreadConstraints: []
3647+
# @schema {"name": "manager.index.operator.server_config", "alias": "server_config"}
3648+
# manager.index.operator.server_config -- server config (overrides defaults.server_config)
3649+
server_config:
3650+
servers:
3651+
rest: {}
3652+
grpc: {}
3653+
healths:
3654+
liveness: {}
3655+
readiness: {}
3656+
startup: {}
3657+
metrics:
3658+
pprof: {}
3659+
# @schema {"name": "manager.index.operator.observability", "alias": "observability"}
3660+
# manager.index.operator.observability -- observability config (overrides defaults.observability)
3661+
observability:
3662+
otlp:
3663+
attribute:
3664+
service_name: vald-index-operator
3665+
# @schema {"name": "manager.index.operator.resources", "alias": "resources"}
3666+
# manager.index.operator.resources -- compute resources
3667+
resources:
3668+
requests:
3669+
cpu: 200m
3670+
memory: 65Mi
3671+
limits:
3672+
cpu: 600m
3673+
memory: 200Mi
3674+
# @schema {"name": "manager.index.operator.namespace", "type": "string"}
3675+
# manager.index.operator.namespace -- namespace to discovery
3676+
namespace: _MY_POD_NAMESPACE_

‎cmd/index/operator/main.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package main
15+
16+
import (
17+
"context"
18+
19+
"github.com/vdaas/vald/internal/errors"
20+
"github.com/vdaas/vald/internal/info"
21+
"github.com/vdaas/vald/internal/log"
22+
"github.com/vdaas/vald/internal/runner"
23+
"github.com/vdaas/vald/internal/safety"
24+
"github.com/vdaas/vald/pkg/index/operator/config"
25+
"github.com/vdaas/vald/pkg/index/operator/usecase"
26+
)
27+
28+
const (
29+
maxVersion = "v0.0.10"
30+
minVersion = "v0.0.0"
31+
name = "index operator"
32+
)
33+
34+
func main() {
35+
if err := safety.RecoverFunc(func() error {
36+
return runner.Do(
37+
context.Background(),
38+
runner.WithName(name),
39+
runner.WithVersion(info.Version, maxVersion, minVersion),
40+
runner.WithConfigLoader(func(path string) (interface{}, *config.GlobalConfig, error) {
41+
cfg, err := config.NewConfig(path)
42+
if err != nil {
43+
return nil, nil, errors.Wrap(err, "failed to load "+name+"'s configuration")
44+
}
45+
return cfg, &cfg.GlobalConfig, nil
46+
}),
47+
runner.WithDaemonInitializer(func(cfg interface{}) (runner.Runner, error) {
48+
c, ok := cfg.(*config.Data)
49+
if !ok {
50+
return nil, errors.ErrInvalidConfig
51+
}
52+
return usecase.New(c)
53+
}),
54+
)
55+
})(); err != nil {
56+
log.Fatal(err, info.Get())
57+
return
58+
}
59+
}

‎cmd/index/operator/sample.yaml

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#
2+
# Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# You may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
version: v0.0.0
17+
time_zone: JST
18+
logging:
19+
format: raw
20+
level: debug
21+
logger: glg
22+
server_config:
23+
servers:
24+
- name: grpc
25+
host: 0.0.0.0
26+
port: 8081
27+
grpc:
28+
bidirectional_stream_concurrency: 20
29+
connection_timeout: ""
30+
header_table_size: 0
31+
initial_conn_window_size: 0
32+
initial_window_size: 0
33+
interceptors: []
34+
keepalive:
35+
max_conn_age: ""
36+
max_conn_age_grace: ""
37+
max_conn_idle: ""
38+
time: ""
39+
timeout: ""
40+
max_header_list_size: 0
41+
max_receive_message_size: 0
42+
max_send_message_size: 0
43+
read_buffer_size: 0
44+
write_buffer_size: 0
45+
mode: GRPC
46+
probe_wait_time: 3s
47+
restart: true
48+
health_check_servers:
49+
- name: readiness
50+
host: 0.0.0.0
51+
port: 3001
52+
http:
53+
handler_timeout: ""
54+
idle_timeout: ""
55+
read_header_timeout: ""
56+
read_timeout: ""
57+
shutdown_duration: 0s
58+
write_timeout: ""
59+
mode: ""
60+
probe_wait_time: 3s
61+
metrics_servers:
62+
startup_strategy:
63+
- grpc
64+
- readiness
65+
full_shutdown_duration: 600s
66+
tls:
67+
ca: /path/to/ca
68+
cert: /path/to/cert
69+
enabled: false
70+
key: /path/to/key
71+
operator:
72+
agent_name: "vald-agent"
73+
agent_namespace: "default"
74+
concurrency: 1
75+
observability:
76+
enabled: false
77+
otlp:
78+
collector_endpoint: "otel-collector.monitoring.svc.cluster.local:4317"
79+
trace_batch_timeout: "1s"
80+
trace_export_timeout: "1m"
81+
trace_max_export_batch_size: 1024
82+
trace_max_queue_size: 256
83+
metrics_export_interval: "1s"
84+
metrics_export_timeout: "1m"
85+
attribute:
86+
namespace: "_MY_POD_NAMESPACE_"
87+
pod_name: "_MY_POD_NAME_"
88+
node_name: "_MY_NODE_NAME_"
89+
service_name: "vald-index-creation"
90+
metrics:
91+
enable_cgo: true
92+
enable_goroutine: true
93+
enable_memory: true
94+
enable_version_info: true
95+
version_info_labels:
96+
- vald_version
97+
- server_name
98+
- git_commit
99+
- build_time
100+
- go_version
101+
- go_os
102+
- go_arch
103+
- algorithm_info
104+
trace:
105+
enabled: true

‎dockers/index/operator/Dockerfile

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# syntax = docker/dockerfile:latest
2+
#
3+
# Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# You may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
ARG DISTROLESS_IMAGE=gcr.io/distroless/static
19+
ARG DISTROLESS_IMAGE_TAG=nonroot
20+
ARG MAINTAINER="vdaas.org vald team <vald@vdaas.org>"
21+
22+
FROM --platform=${TARGETPLATFORM} ubuntu:devel AS builder
23+
24+
ARG GO_VERSION
25+
ARG TARGETARCH
26+
ARG TARGETOS
27+
28+
ENV GO111MODULE on
29+
ENV DEBIAN_FRONTEND noninteractive
30+
ENV INITRD No
31+
ENV LANG en_US.UTF-8
32+
ENV GOROOT /opt/go
33+
ENV GOPATH /go
34+
ENV PATH ${PATH}:${GOROOT}/bin:${GOPATH}/bin
35+
ENV ORG vdaas
36+
ENV REPO vald
37+
ENV PKG index/operator
38+
ENV APP_NAME index-operator
39+
40+
41+
# skipcq: DOK-DL3008
42+
RUN apt-get update && apt-get install -y --no-install-recommends \
43+
ca-certificates \
44+
build-essential \
45+
curl \
46+
upx \
47+
git \
48+
&& apt-get clean \
49+
&& rm -rf /var/lib/apt/lists/*
50+
51+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/Makefile.d
52+
COPY Makefile.d .
53+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}
54+
COPY Makefile .
55+
COPY .git .
56+
COPY go.mod .
57+
COPY go.sum .
58+
59+
RUN --mount=type=cache,target="${GOPATH}/pkg",id="go-build-${TARGETARCH}" \
60+
--mount=type=cache,target="${HOME}/.cache/go-build",id="go-build-${TARGETARCH}" \
61+
make GO_VERSION=${GO_VERSION} go/install \
62+
&& make go/download
63+
64+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/internal
65+
COPY internal .
66+
67+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/apis/grpc
68+
COPY apis/grpc .
69+
70+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/pkg/${PKG}
71+
COPY pkg/${PKG} .
72+
73+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/cmd/${PKG}
74+
COPY cmd/${PKG} .
75+
76+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/versions
77+
COPY versions .
78+
79+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}
80+
RUN --mount=type=cache,target="${GOPATH}/pkg",id="go-build-${TARGETARCH}" \
81+
--mount=type=cache,target="${HOME}/.cache/go-build",id="go-build-${TARGETARCH}" \
82+
make GOARCH=${TARGETARCH} GOOS=${TARGETOS} REPO=${ORG} NAME=${REPO} cmd/${PKG}/${APP_NAME} \
83+
&& mv "cmd/${PKG}/${APP_NAME}" "/usr/bin/${APP_NAME}"
84+
85+
WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/cmd/${PKG}
86+
RUN cp sample.yaml /tmp/config.yaml
87+
88+
FROM --platform=${TARGETPLATFORM} ${DISTROLESS_IMAGE}:${DISTROLESS_IMAGE_TAG}
89+
LABEL maintainer="${MAINTAINER}"
90+
91+
ENV APP_NAME index-operator
92+
93+
COPY --from=builder /usr/bin/${APP_NAME} /go/bin/${APP_NAME}
94+
COPY --from=builder /tmp/config.yaml /etc/server/config.yaml
95+
96+
USER nonroot:nonroot
97+
98+
ENTRYPOINT ["/go/bin/index-operator"]

‎internal/config/index_operator.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package config
15+
16+
// IndexCreation represents the configurations for index creation.
17+
type IndexOperator struct {
18+
// AgentName represent agents meta_name for service discovery
19+
AgentName string `json:"agent_name" yaml:"agent_name"`
20+
21+
// AgentNamespace represent agent namespace location
22+
AgentNamespace string `json:"agent_namespace" yaml:"agent_namespace"`
23+
24+
// Concurrency represents indexing concurrency.
25+
Concurrency int `json:"concurrency" yaml:"concurrency"`
26+
}
27+
28+
func (ic *IndexOperator) Bind() *IndexOperator {
29+
ic.AgentName = GetActualValue(ic.AgentName)
30+
ic.AgentNamespace = GetActualValue(ic.AgentNamespace)
31+
return ic
32+
}

‎internal/k8s/pod/option.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
package pod
1919

2020
import (
21+
"context"
22+
2123
"sigs.k8s.io/controller-runtime/pkg/client"
2224
"sigs.k8s.io/controller-runtime/pkg/manager"
2325
)
@@ -47,7 +49,7 @@ func WithOnErrorFunc(f func(err error)) Option {
4749
}
4850
}
4951

50-
func WithOnReconcileFunc(f func(podList map[string][]Pod)) Option {
52+
func WithOnReconcileFunc(f func(ctx context.Context, podList map[string][]Pod)) Option {
5153
return func(r *reconciler) error {
5254
r.onReconcile = f
5355
return nil

‎internal/k8s/pod/pod.go

+20-18
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,20 @@ type reconciler struct {
4040
name string
4141
namespace string
4242
onError func(err error)
43-
onReconcile func(podList map[string][]Pod)
43+
onReconcile func(ctx context.Context, podList map[string][]Pod)
4444
lopts []client.ListOption
4545
}
4646

4747
type Pod struct {
48-
Name string
49-
NodeName string
50-
Namespace string
51-
IP string
52-
CPULimit float64
53-
CPURequest float64
54-
MemLimit float64
55-
MemRequest float64
48+
Name string
49+
NodeName string
50+
Namespace string
51+
IP string
52+
CPULimit float64
53+
CPURequest float64
54+
MemLimit float64
55+
MemRequest float64
56+
Annotations map[string]string
5657
}
5758

5859
func New(opts ...Option) PodWatcher {
@@ -142,19 +143,20 @@ func (r *reconciler) Reconcile(ctx context.Context, _ reconcile.Request) (res re
142143
}
143144

144145
pods[podName] = append(pods[podName], Pod{
145-
Name: pod.GetName(),
146-
NodeName: pod.Spec.NodeName,
147-
Namespace: pod.GetNamespace(),
148-
IP: pod.Status.PodIP,
149-
CPULimit: cpuLimit,
150-
CPURequest: cpuRequest,
151-
MemLimit: memLimit,
152-
MemRequest: memRequest,
146+
Name: pod.GetName(),
147+
NodeName: pod.Spec.NodeName,
148+
Namespace: pod.GetNamespace(),
149+
IP: pod.Status.PodIP,
150+
CPULimit: cpuLimit,
151+
CPURequest: cpuRequest,
152+
MemLimit: memLimit,
153+
MemRequest: memRequest,
154+
Annotations: pod.GetAnnotations(),
153155
})
154156
}
155157

156158
if r.onReconcile != nil {
157-
r.onReconcile(pods)
159+
r.onReconcile(ctx, pods)
158160
}
159161
return
160162
}

‎pkg/discoverer/k8s/service/discover.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func New(selector *config.Selectors, opts ...Option) (dsc Discoverer, err error)
137137
pod.WithOnErrorFunc(func(err error) {
138138
log.Error("failed to reconcile:", err)
139139
}),
140-
pod.WithOnReconcileFunc(func(podList map[string][]pod.Pod) {
140+
pod.WithOnReconcileFunc(func(_ context.Context, podList map[string][]pod.Pod) {
141141
log.Debugf("pod resource reconciled\t%#v", podList)
142142
for name, pods := range podList {
143143
if len(pods) > d.maxPods {

‎pkg/index/operator/config/config.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package config
15+
16+
import (
17+
"github.com/vdaas/vald/internal/config"
18+
"github.com/vdaas/vald/internal/errors"
19+
)
20+
21+
// GlobalConfig is a type alias of config.GlobalConfig representing application base configurations.
22+
type GlobalConfig = config.GlobalConfig
23+
24+
// Data represents the application configurations.
25+
type Data struct {
26+
// GlobalConfig represents application base configurations.
27+
config.GlobalConfig `json:",inline" yaml:",inline"`
28+
29+
// Server represent all server configurations
30+
Server *config.Servers `json:"server_config" yaml:"server_config"`
31+
32+
// Observability represents observability configurations.
33+
Observability *config.Observability `json:"observability" yaml:"observability"`
34+
35+
// Operator represents auto indexing service configurations.
36+
Operator *config.IndexOperator `json:"operator" yaml:"operator"`
37+
}
38+
39+
// NewConfig load configurations from file path.
40+
func NewConfig(path string) (cfg *Data, err error) {
41+
cfg = new(Data)
42+
43+
if err = config.Read(path, &cfg); err != nil {
44+
return nil, err
45+
}
46+
47+
if cfg != nil {
48+
_ = cfg.GlobalConfig.Bind()
49+
} else {
50+
return nil, errors.ErrInvalidConfig
51+
}
52+
53+
if cfg.Server != nil {
54+
_ = cfg.Server.Bind()
55+
} else {
56+
return nil, errors.ErrInvalidConfig
57+
}
58+
59+
if cfg.Observability != nil {
60+
_ = cfg.Observability.Bind()
61+
} else {
62+
cfg.Observability = new(config.Observability).Bind()
63+
}
64+
65+
if cfg.Operator != nil {
66+
_ = cfg.Operator.Bind()
67+
} else {
68+
return nil, errors.ErrInvalidConfig
69+
}
70+
return cfg, nil
71+
}
+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package service
15+
16+
import (
17+
"context"
18+
"reflect"
19+
20+
"github.com/vdaas/vald/internal/errors"
21+
"github.com/vdaas/vald/internal/k8s"
22+
"github.com/vdaas/vald/internal/k8s/job"
23+
"github.com/vdaas/vald/internal/k8s/pod"
24+
"github.com/vdaas/vald/internal/log"
25+
"github.com/vdaas/vald/internal/observability/trace"
26+
"github.com/vdaas/vald/internal/safety"
27+
"github.com/vdaas/vald/internal/sync/errgroup"
28+
)
29+
30+
const (
31+
apiName = "vald/index/operator"
32+
)
33+
34+
// Operator represents an interface for indexing.
35+
type Operator interface {
36+
Start(ctx context.Context) (<-chan error, error)
37+
}
38+
39+
type operator struct {
40+
ctrl k8s.Controller
41+
eg errgroup.Group
42+
namespace string
43+
}
44+
45+
// New returns Indexer object if no error occurs.
46+
func New(agentName string, opts ...Option) (o Operator, err error) {
47+
operator := new(operator)
48+
for _, opt := range append(defaultOpts, opts...) {
49+
if err := opt(operator); err != nil {
50+
oerr := errors.ErrOptionFailed(err, reflect.ValueOf(opt))
51+
e := &errors.ErrCriticalOption{}
52+
if errors.As(oerr, &e) {
53+
log.Error(err)
54+
return nil, oerr
55+
}
56+
log.Warn(oerr)
57+
}
58+
}
59+
60+
podController := pod.New(
61+
pod.WithControllerName("pod reconciler for index operator"),
62+
pod.WithOnErrorFunc(func(err error) {
63+
log.Error("failed to reconcile:", err)
64+
}),
65+
pod.WithNamespace(operator.namespace),
66+
pod.WithOnReconcileFunc(operator.podOnReconcile),
67+
pod.WithLabels(map[string]string{
68+
"app": agentName,
69+
}),
70+
)
71+
72+
jobController, err := job.New(
73+
job.WithControllerName("job reconciler for index operator"),
74+
job.WithNamespaces(operator.namespace),
75+
job.WithOnErrorFunc(func(err error) {
76+
log.Errorf("failed to reconcile job resource:", err)
77+
}),
78+
job.WithOnReconcileFunc(operator.jobOnReconcile),
79+
)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
operator.ctrl, err = k8s.New(
85+
k8s.WithResourceController(podController),
86+
k8s.WithResourceController(jobController),
87+
)
88+
if err != nil {
89+
return nil, err
90+
}
91+
return operator, nil
92+
}
93+
94+
// Start starts indexing process.
95+
func (o *operator) Start(ctx context.Context) (<-chan error, error) {
96+
ctx, span := trace.StartSpan(ctx, apiName+"/service/operator.Start")
97+
defer func() {
98+
if span != nil {
99+
span.End()
100+
}
101+
}()
102+
103+
dech, err := o.ctrl.Start(ctx)
104+
if err != nil {
105+
return nil, err
106+
}
107+
ech := make(chan error, 2)
108+
o.eg.Go(safety.RecoverFunc(func() (err error) {
109+
defer close(ech)
110+
for {
111+
select {
112+
case <-ctx.Done():
113+
return ctx.Err()
114+
case err := <-dech:
115+
if err != nil {
116+
ech <- err
117+
}
118+
}
119+
}
120+
}))
121+
122+
return ech, nil
123+
}
124+
125+
// TODO: implement agent pod reconcile logic to detect conditions to start indexing and saving.
126+
func (o *operator) podOnReconcile(ctx context.Context, podList map[string][]pod.Pod) {
127+
for k, v := range podList {
128+
for _, pod := range v {
129+
log.Debug("key", k, "name:", pod.Name, "annotations:", pod.Annotations)
130+
}
131+
}
132+
}
133+
134+
// TODO: implement job reconcile logic to detect save job completion and to start rotation.
135+
func (o *operator) jobOnReconcile(ctx context.Context, jobList map[string][]job.Job) {
136+
for k, v := range jobList {
137+
for _, job := range v {
138+
log.Debug("key", k, "name:", job.Name, "status:", job.Status)
139+
}
140+
}
141+
}

‎pkg/index/operator/service/options.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package service
15+
16+
import "github.com/vdaas/vald/internal/sync/errgroup"
17+
18+
// Option represents the functional option for index.
19+
type Option func(_ *operator) error
20+
21+
var defaultOpts = []Option{
22+
WithErrGroup(errgroup.Get()),
23+
}
24+
25+
func WithErrGroup(eg errgroup.Group) Option {
26+
return func(o *operator) error {
27+
if eg != nil {
28+
o.eg = eg
29+
}
30+
return nil
31+
}
32+
}
+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright (C) 2019-2024 vdaas.org vald team <vald@vdaas.org>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// You may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package usecase
15+
16+
import (
17+
"context"
18+
19+
iconfig "github.com/vdaas/vald/internal/config"
20+
"github.com/vdaas/vald/internal/errors"
21+
"github.com/vdaas/vald/internal/net/grpc"
22+
"github.com/vdaas/vald/internal/net/grpc/interceptor/server/recover"
23+
"github.com/vdaas/vald/internal/observability"
24+
"github.com/vdaas/vald/internal/runner"
25+
"github.com/vdaas/vald/internal/safety"
26+
"github.com/vdaas/vald/internal/servers/server"
27+
"github.com/vdaas/vald/internal/servers/starter"
28+
"github.com/vdaas/vald/internal/sync/errgroup"
29+
"github.com/vdaas/vald/pkg/index/operator/config"
30+
"github.com/vdaas/vald/pkg/index/operator/service"
31+
)
32+
33+
type run struct {
34+
eg errgroup.Group
35+
cfg *config.Data
36+
observability observability.Observability
37+
server starter.Server
38+
operator service.Operator
39+
}
40+
41+
// New returns Runner instance.
42+
func New(cfg *config.Data) (_ runner.Runner, err error) {
43+
eg := errgroup.Get()
44+
operator, err := service.New(cfg.Operator.AgentName)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
srv, err := starter.New(
50+
starter.WithConfig(cfg.Server),
51+
starter.WithGRPC(func(cfg *iconfig.Server) []server.Option {
52+
return []server.Option{
53+
server.WithGRPCOption(
54+
grpc.ChainUnaryInterceptor(recover.RecoverInterceptor()),
55+
grpc.ChainStreamInterceptor(recover.RecoverStreamInterceptor()),
56+
),
57+
}
58+
}),
59+
)
60+
if err != nil {
61+
return nil, err
62+
}
63+
64+
var obs observability.Observability
65+
if cfg.Observability.Enabled {
66+
obs, err = observability.NewWithConfig(
67+
cfg.Observability,
68+
)
69+
if err != nil {
70+
return nil, err
71+
}
72+
}
73+
74+
return &run{
75+
eg: eg,
76+
cfg: cfg,
77+
observability: obs,
78+
server: srv,
79+
operator: operator,
80+
}, nil
81+
}
82+
83+
// PreStart is a method called before execution of Start, and it invokes the PreStart method of observability.
84+
func (r *run) PreStart(ctx context.Context) error {
85+
if r.observability != nil {
86+
return r.observability.PreStart(ctx)
87+
}
88+
return nil
89+
}
90+
91+
// Start is a method used to initiate an operation in the run, and it returns a channel for receiving errors
92+
// during the operation and an error representing any initialization errors.
93+
func (r *run) Start(ctx context.Context) (<-chan error, error) {
94+
ech := make(chan error, 3) //nolint: gomnd
95+
var oech, dech, sech <-chan error
96+
r.eg.Go(safety.RecoverFunc(func() (err error) {
97+
defer close(ech)
98+
if r.observability != nil {
99+
oech = r.observability.Start(ctx)
100+
}
101+
dech, err = r.operator.Start(ctx)
102+
if err != nil {
103+
ech <- err
104+
return err
105+
}
106+
107+
sech = r.server.ListenAndServe(ctx)
108+
109+
for {
110+
select {
111+
case <-ctx.Done():
112+
return ctx.Err()
113+
case err = <-oech:
114+
case err = <-dech:
115+
case err = <-sech:
116+
}
117+
if err != nil {
118+
select {
119+
case <-ctx.Done():
120+
return ctx.Err()
121+
case ech <- err:
122+
}
123+
}
124+
}
125+
}))
126+
return ech, nil
127+
}
128+
129+
// PreStop is a method called before execution of Stop.
130+
func (*run) PreStop(_ context.Context) error {
131+
return nil
132+
}
133+
134+
// Stop is a method used to stop an operation in the run.
135+
func (r *run) Stop(ctx context.Context) (errs error) {
136+
if r.observability != nil {
137+
if err := r.observability.Stop(ctx); err != nil {
138+
errs = errors.Join(errs, err)
139+
}
140+
}
141+
if r.server != nil {
142+
if err := r.server.Shutdown(ctx); err != nil {
143+
errs = errors.Join(errs, err)
144+
}
145+
}
146+
return errs
147+
}
148+
149+
// PtopStop is a method called after execution of Stop.
150+
func (*run) PostStop(_ context.Context) error {
151+
return nil
152+
}

0 commit comments

Comments
 (0)
Please sign in to comment.