Added support for webhooks in Helm charts (#5118)

* added webhook support

* added webhook tests

* update_version supports helm values

* fix

* debug

* fix

* fix remote file test

* increase minikube resources

* fix syntax

* Update helm.yml

* fixed comment

* Update .github/workflows/helm.yml

Co-authored-by: Kirill Sizov <kirill.sizov@cvat.ai>

Co-authored-by: Kirill Sizov <kirill.sizov@cvat.ai>
main
Andrey Zhavoronkov 3 years ago committed by GitHub
parent 1fdec2cf73
commit 469217cc55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -36,17 +36,19 @@ jobs:
- uses: actions/checkout@v3
- name: Start minikube
uses: medyagh/setup-minikube@latest
uses: medyagh/setup-minikube@master
with:
cpus: max
memory: max
- name: Try the cluster!
run: kubectl get pods -A
- name: Pull images
- name: Build images
run: |
export SHELL=/bin/bash
eval $(minikube -p minikube docker-env)
docker pull cvat/server
docker pull cvat/ui
docker compose -f docker-compose.yml -f docker-compose.dev.yml build
echo -n "verifying images:"
docker images
@ -56,12 +58,12 @@ jobs:
- name: Deploy to minikube
run: |
printf "traefik:\n service:\n externalIPs:\n - $(minikube ip)\n" > helm-chart/values.override.yaml
printf "traefik:\n service:\n externalIPs:\n - $(minikube ip)\n" >> tests/values.test.yaml
find cvat/apps/iam/rules -name "*.rego" -and ! -name '*test*' -exec basename {} \; | tar -czf helm-chart/rules.tar.gz -C cvat/apps/iam/rules/ -T -
cd helm-chart
helm dependency update
cd ..
helm upgrade -n default cvat -i --create-namespace helm-chart -f helm-chart/values.yaml -f helm-chart/values.override.yaml
helm upgrade -n default cvat -i --create-namespace helm-chart -f helm-chart/values.yaml -f tests/values.test.yaml
- name: Update test config
run: |
@ -71,10 +73,13 @@ jobs:
- name: Wait for CVAT to be ready
run: |
max_tries=30
max_tries=60
while [[ $(kubectl get pods -l component=server -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" && max_tries -gt 0 ]]; do echo "waiting for CVAT pod" && (( max_tries-- )) && sleep 5; done
while [[ $(kubectl get pods -l app.kubernetes.io/name=postgresql -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" && max_tries -gt 0 ]]; do echo "waiting for DB pod" && (( max_tries-- )) && sleep 5; done
while [[ $(curl -s -o /tmp/server_response -w "%{http_code}" cvat.local/api/server/about) != "200" && max_tries -gt 0 ]]; do echo "waiting for CVAT" && (( max_tries-- )) && sleep 5; done
kubectl get pods
kubectl logs $(kubectl get pods -l component=server -o jsonpath='{.items[0].metadata.name}')
- name: Generate schema
run: |
@ -94,9 +99,11 @@ jobs:
- name: REST API and SDK tests
run: |
kubectl cp tests/mounted_file_share/images $(kubectl get pods -l component=server -o jsonpath='{.items[0].metadata.name}'):/home/django/share
pytest --platform=kube \
--ignore=tests/python/rest_api/test_cloud_storages.py \
--ignore=tests/python/rest_api/test_analytics.py \
--ignore=tests/python/rest_api/test_resource_import_export.py \
--ignore=tests/python/rest_api/test_webhooks_sender.py \
-k 'not create_task_with_cloud_storage_files' \
tests/python

@ -15,7 +15,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.3.1
version: 0.4.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to

@ -0,0 +1,117 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-backend-worker-webhooks
namespace: {{ .Release.Namespace }}
labels:
app: cvat-app
tier: backend
component: worker-webhooks
{{- include "cvat.labels" . | nindent 4 }}
{{- with .Values.cvat.backend.worker.webhooks.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.cvat.backend.worker.webhooks.replicas }}
strategy:
type: Recreate
selector:
matchLabels:
{{- include "cvat.labels" . | nindent 6 }}
{{- with .Values.cvat.backend.worker.webhooks.labels }}
{{- toYaml . | nindent 6 }}
{{- end }}
app: cvat-app-worker-webhooks
tier: backend
component: worker-webhooks
template:
metadata:
labels:
app: cvat-app-worker-webhooks
tier: backend
component: worker-webhooks
{{- include "cvat.labels" . | nindent 8 }}
{{- with .Values.cvat.backend.worker.webhooks.labels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.annotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
containers:
- name: cvat-app-backend-worker-webhooks-container
image: {{ .Values.cvat.backend.image }}:{{ .Values.cvat.backend.tag }}
{{- with .Values.cvat.backend.worker.webhooks.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
args: ["-c", "supervisord/worker.webhooks.conf"]
env:
{{- if .Values.redis.enabled }}
- name: CVAT_REDIS_HOST
value: "{{ .Release.Name }}-redis-master"
{{- else }}
- name: CVAT_REDIS_HOST
value: "{{ .Values.redis.external.host }}"
{{- end }}
{{- if .Values.postgresql.enabled }}
- name: CVAT_POSTGRES_HOST
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-{{ .Values.postgresql.secret.name }}"
key: postgresql-hostname
- name: CVAT_POSTGRES_USER
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-{{ .Values.postgresql.secret.name }}"
key: postgresql-username
- name: CVAT_POSTGRES_DBNAME
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-{{ .Values.postgresql.secret.name }}"
key: postgresql-database
- name: CVAT_POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: "{{ .Release.Name }}-{{ .Values.postgresql.secret.name }}"
key: postgresql-password
{{- else }}
- name: CVAT_POSTGRES_HOST
value: "{{ .Values.postgresql.external.host }}"
- name: CVAT_POSTGRES_USER
value: "{{ .Values.postgresql.external.user }}"
- name: CVAT_POSTGRES_DBNAME
value: "{{ .Values.postgresql.external.dbname }}"
- name: CVAT_POSTGRES_PASSWORD
value: "{{ .Values.postgresql.external.password }}"
- name: CVAT_POSTGRES_PORT
value: "{{ .Values.postgresql.external.port }}"
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.additionalEnv }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.additionalVolumeMounts }}
volumeMounts:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.cvat.backend.worker.webhooks.additionalVolumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}

@ -43,6 +43,16 @@ cvat:
additionalEnv: []
additionalVolumes: []
additionalVolumeMounts: []
webhooks:
replicas: 1
labels: {}
annotations: {}
resources: {}
affinity: {}
tolerations: []
additionalEnv: []
additionalVolumes: []
additionalVolumeMounts: []
utils:
replicas: 1
labels: {}
@ -55,7 +65,7 @@ cvat:
additionalVolumeMounts: []
replicas: 1
image: cvat/server
tag: latest
tag: dev
permissionFix:
enabled: true
service:
@ -74,7 +84,7 @@ cvat:
frontend:
replicas: 1
image: cvat/ui
tag: latest
tag: dev
labels: {}
# test: test
annotations: {}

@ -17,20 +17,8 @@ loglevel=debug ; info, debug, warn, trace
pidfile=/tmp/supervisord/supervisord.pid ; pidfile location
childlogdir=%(ENV_HOME)s/logs/ ; where child log files will live
[program:ssh-agent]
command=bash -c "rm /tmp/ssh-agent.sock -f && /usr/bin/ssh-agent -d -a /tmp/ssh-agent.sock"
priority=1
autorestart=true
[program:rqworker_webhooks]
command=%(ENV_HOME)s/wait-for-it.sh %(ENV_CVAT_REDIS_HOST)s:6379 -t 0 -- bash -ic \
"exec python3 %(ENV_HOME)s/manage.py rqworker -v 3 webhooks"
environment=SSH_AUTH_SOCK="/tmp/ssh-agent.sock"
numprocs=%(ENV_NUMPROCS)s
[program:clamav_update]
command=bash -c "if [ \"${CLAM_AV}\" = 'yes' ]; then /usr/bin/freshclam -d \
-l %(ENV_HOME)s/logs/freshclam.log --foreground=true; fi"
numprocs=1
environment=SSH_AUTH_SOCK="/tmp/ssh-agent.sock"

@ -0,0 +1,17 @@
cvat:
backend:
server:
additionalVolumeMounts:
- mountPath: /home/django/share
name: cvat-backend-data
subPath: share
worker:
default:
additionalVolumeMounts:
- mountPath: /home/django/share
name: cvat-backend-data
subPath: share
traefik:
service:
externalIPs:
- 192.168.49.2

@ -4,8 +4,12 @@ from pathlib import Path
import re
SUCCESS_CHAR = '\u2714'
FAIL_CHAR = '\u2716'
CVAT_VERSION_PATTERN = r'VERSION\s*=\s*\((\d+),\s*(\d*),\s*(\d+),\s*[\',\"](\w+)[\',\"],\s*(\d+)\)'
COMPOSE_VERSION_PATTERN = r'(\$\{CVAT_VERSION:-)([\w.]+)(\})'
HELM_VERSION_PATTERN = r'(^ image: cvat/(?:ui|server)\n tag: )([\w.]+)'
@dataclass()
class Version:
@ -90,10 +94,10 @@ def update_compose_config(new_version: Version) -> None:
with open(compose_file, 'w') as fp:
fp.write(compose_text)
print(f'\u2714 {compose_file} was updated. {match[2]} -> {new_version_repr}\n')
print(f'{SUCCESS_CHAR} {compose_file} was updated. {match[2]} -> {new_version_repr}\n')
else:
print(f'\u2714 {compose_file} no need to update.')
print(f'{SUCCESS_CHAR} {compose_file} no need to update.')
def update_cvat_version(old_version: str, new_version: Version) -> None:
version_file = get_cvat_version_filename()
@ -106,7 +110,32 @@ def update_cvat_version(old_version: str, new_version: Version) -> None:
with open(version_file, 'w') as fp:
fp.write(version_text)
print(f'\u2714 {version_file} was updated. {old_version} -> {new_version_str}\n')
print(f'{SUCCESS_CHAR} {version_file} was updated. {old_version} -> {new_version_str}\n')
def update_helm_version(new_version: Version) -> None:
helm_values_file = get_helm_version_filename()
with open(helm_values_file, 'r') as fp:
helm_values_text = fp.read()
if new_version.prerelease == 'final':
new_version_repr = new_version.compose_repr()
else:
new_version_repr = 'dev'
match = re.search(HELM_VERSION_PATTERN, helm_values_text, re.M)
if not match:
raise RuntimeError('Cannot match version pattern')
if match[2] != new_version_repr:
helm_values_text = re.sub(HELM_VERSION_PATTERN, f'\\g<1>{new_version_repr}', helm_values_text, 2, re.M)
with open(helm_values_file, 'w') as fp:
fp.write(helm_values_text)
print(f'{SUCCESS_CHAR} {helm_values_file} was updated. {match[2]} -> {new_version_repr}\n')
else:
print(f'{SUCCESS_CHAR} {helm_values_file} no need to update.')
def verify_input(version_types: dict, args: dict) -> None:
versions_to_bump = [args[v_type] for v_type in version_types]
@ -122,7 +151,10 @@ def get_cvat_version_filename() -> Path:
def get_compose_filename() -> Path:
return Path(__file__).resolve().parents[2] / 'docker-compose.yml'
def get_current_version() -> tuple[str, Version]:
def get_helm_version_filename() -> Path:
return Path(__file__).resolve().parents[2] / 'helm-chart' / 'values.yaml'
def get_current_version() -> 'tuple[str, Version]':
version_file = get_cvat_version_filename()
with open(version_file, 'r') as fp:
@ -180,7 +212,7 @@ def main() -> None:
try:
verify_input(version_types, vars(args))
except ValueError as e:
print(f'\u2716 ERROR: {e}\n')
print(f'{FAIL_CHAR} ERROR: {e}\n')
parser.print_help()
return
@ -202,10 +234,11 @@ def main() -> None:
elif args.major:
version.increment_major()
print(f'\u2714 Bump version to {version}\n')
print(f'{SUCCESS_CHAR} Bump version to {version}\n')
update_cvat_version(version_str, version)
update_compose_config(version)
update_helm_version(version)
if __name__ == '__main__':
main()

Loading…
Cancel
Save