Skip to content

Commit

Permalink
IAM OPA bundle for dev environment (#5190)
Browse files Browse the repository at this point in the history
  • Loading branch information
azhavoro committed Nov 2, 2022
1 parent 05598e0 commit 49bdef0
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
/db.sqlite3
/keys
**/node_modules

/static
4 changes: 2 additions & 2 deletions .github/workflows/full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ jobs:
HOST_COVERAGE_DATA_DIR: ${{ github.workspace }}
CONTAINER_COVERAGE_DATA_DIR: "/coverage_data"
run: |
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa cvat_server
max_tries=12
while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done
while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health?bundles) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done
docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \
-c 'python manage.py test cvat/apps -v 2'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ jobs:
HOST_COVERAGE_DATA_DIR: ${{ github.workspace }}
CONTAINER_COVERAGE_DATA_DIR: "/coverage_data"
run: |
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa cvat_server
max_tries=12
while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done
while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health?bundles) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done
docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \
-c 'python manage.py test cvat/apps -v 2'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/schedule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ jobs:
HOST_COVERAGE_DATA_DIR: ${{ github.workspace }}
CONTAINER_COVERAGE_DATA_DIR: "/coverage_data"
run: |
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa cvat_server
max_tries=12
while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done
while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health?bundles) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done
docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \
-c 'coverage run -a manage.py test cvat/apps && mv .coverage ${CONTAINER_COVERAGE_DATA_DIR}'
Expand Down
5 changes: 4 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@
"python": "${command:python.interpreterPath}",
"program": "${workspaceRoot}/manage.py",
"env": {
"CVAT_SERVERLESS": "1"
"CVAT_SERVERLESS": "1",
"ALLOWED_HOSTS": "*",
"IAM_OPA_BUNDLE": "1"

},
"args": [
"runserver",
Expand Down
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,7 @@ COPY --chown=${USER} cvat/ ${HOME}/cvat
USER ${USER}
WORKDIR ${HOME}

RUN mkdir -p data share keys logs /tmp/supervisord static/opa
RUN find cvat/apps/iam/rules -name "*.rego" -and ! -name '*test*' -exec basename {} \; | \
tar -czf static/opa/bundle.tar.gz --transform 's,^,rules/,' -C cvat/apps/iam/rules/ -T -
RUN mkdir -p data share keys logs /tmp/supervisord static

EXPOSE 8080
ENTRYPOINT ["/usr/bin/supervisord"]
Expand Down
7 changes: 7 additions & 0 deletions cvat/apps/iam/apps.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from distutils.util import strtobool
import os
from django.apps import AppConfig

from .utils import create_opa_bundle

class IAMConfig(AppConfig):
name = 'cvat.apps.iam'

def ready(self):
from .signals import register_signals
register_signals(self)

if strtobool(os.environ.get("IAM_OPA_BUNDLE", '0')):
create_opa_bundle()
14 changes: 14 additions & 0 deletions cvat/apps/iam/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from pathlib import Path
import tarfile

from django.conf import settings

def create_opa_bundle():
bundle_path = Path(settings.IAM_OPA_BUNDLE_PATH)
if bundle_path.is_file():
bundle_path.unlink()

rules_path = Path(settings.BASE_DIR) / 'cvat/apps/iam/rules'
with tarfile.open(bundle_path, 'w:gz') as tar:
for f in rules_path.glob('*[!.gen].rego'):
tar.add(name=f, arcname=f.relative_to(rules_path.parent))
50 changes: 37 additions & 13 deletions cvat/apps/iam/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
#
# SPDX-License-Identifier: MIT

import functools
import hashlib
import os.path as osp
from django_sendfile import sendfile

from django.core.exceptions import BadRequest
from django.utils.functional import SimpleLazyObject
from rest_framework import views, serializers
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import AllowAny
from django.conf import settings
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.http import etag
from django.http import HttpResponse
from django.views.decorators.http import etag as django_etag
from rest_framework.response import Response
from dj_rest_auth.registration.views import RegisterView
from allauth.account import app_settings as allauth_settings
Expand Down Expand Up @@ -74,6 +73,7 @@ def get_context(request):
}

return context

class ContextMiddleware:
def __init__(self, get_response):
self.get_response = get_response
Expand Down Expand Up @@ -111,7 +111,6 @@ def post(self, request):
url = furl(url).add({Signer.QUERY_PARAM: sign}).url
return Response(url)


class RegisterViewEx(RegisterView):
def get_response_data(self, user):
data = self.get_serializer(user).data
Expand All @@ -123,19 +122,44 @@ def get_response_data(self, user):
data['key'] = user.auth_token.key
return data

# Django Generic View is used here instead of DRF APIView due to native support of etag
# that doesn't supported by DRF without extra dependencies
class RulesView(View):
def _etag(etag_func):
"""
Decorator to support conditional retrieval (or change)
for a Django Rest Framework's ViewSet.
It calls Django's original decorator but pass correct request object to it.
Django's original decorator doesn't work with DRF request object.
"""
def decorator(func):
@functools.wraps(func)
def wrapper(obj_self, request, *args, **kwargs):
drf_request = request
wsgi_request = request._request

@django_etag(etag_func=etag_func)
def patched_viewset_method(*_args, **_kwargs):
"""Call original viewset method with correct type of request"""
return func(obj_self, drf_request, *args, **kwargs)

return patched_viewset_method(wsgi_request, *args, **kwargs)
return wrapper
return decorator

class RulesView(views.APIView):
serializer_class = None
permission_classes = [AllowAny]
authentication_classes = []
iam_organization_field = None

@staticmethod
def _get_bundle_path():
return osp.join(settings.STATIC_ROOT, 'opa', 'bundle.tar.gz')
return settings.IAM_OPA_BUNDLE_PATH

@staticmethod
def _etag_func(file_path):
with open(file_path, 'rb') as f:
return hashlib.blake2b(f.read()).hexdigest()

@method_decorator(etag(lambda _: RulesView._etag_func(RulesView._get_bundle_path())))
@_etag(lambda _: RulesView._etag_func(RulesView._get_bundle_path()))
def get(self, request):
file_path = self._get_bundle_path()
return sendfile(request, file_path)
file_obj = open(self._get_bundle_path() ,"rb")
return HttpResponse(file_obj, content_type='application/x-tar')
3 changes: 3 additions & 0 deletions cvat/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ def add_ssh_keys():
TMP_FILES_ROOT = os.path.join(DATA_ROOT, 'tmp')
os.makedirs(TMP_FILES_ROOT, exist_ok=True)

IAM_OPA_BUNDLE_PATH = os.path.join(STATIC_ROOT, 'opa', 'bundle.tar.gz')
os.makedirs(Path(IAM_OPA_BUNDLE_PATH).parent, exist_ok=True)

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
Expand Down
3 changes: 0 additions & 3 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,5 @@ services:
dockerfile: Dockerfile.ui

cvat_opa:
volumes:
- ./cvat/apps/iam/rules:/rules
ports:
- '8181:8181'
command: run --server --set=decision_logs.console=true /rules
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ services:
CVAT_REDIS_HOST: 'cvat_redis'
CVAT_POSTGRES_HOST: 'cvat_db'
ADAPTIVE_AUTO_ANNOTATION: 'false'
IAM_OPA_BUNDLE: '1'
no_proxy: elasticsearch,kibana,logstash,nuclio,opa,${no_proxy}
NUMPROCS: 1
command: -c supervisord/server.conf
Expand Down
2 changes: 1 addition & 1 deletion helm-chart/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.4.2
version: 0.4.3

# 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
Expand Down
2 changes: 2 additions & 0 deletions helm-chart/templates/cvat_backend/server/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ spec:
value: {{ .Values.cvat.backend.server.envs.ALLOWED_HOSTS | squote}}
- name: DJANGO_MODWSGI_EXTRA_ARGS
value: {{ .Values.cvat.backend.server.envs.DJANGO_MODWSGI_EXTRA_ARGS}}
- name: IAM_OPA_BUNDLE
value: "1"
{{- if .Values.redis.enabled }}
- name: CVAT_REDIS_HOST
value: "{{ .Release.Name }}-redis-master"
Expand Down
6 changes: 4 additions & 2 deletions site/content/en/docs/contributing/development-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,12 @@ description: 'Installing a development environment for different operating syste
- Install [Docker Engine](https://docs.docker.com/engine/install/ubuntu/) and [Docker-Compose](https://docs.docker.com/compose/install/)
- Pull and run OpenPolicyAgent Docker image (run from CVAT root dir):
- Pull and run OpenPolicyAgent Docker image:
```bash
sudo docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa
docker run -d --rm --name cvat_opa_debug openpolicyagent/opa:0.34.2-rootless \
run --server --set=decision_logs.console=true --set=services.cvat.url=http://host.docker.internal:7000 \
--set=bundles.cvat.service=cvat --set=bundles.cvat.resource=/api/auth/rules
```
### Run CVAT
Expand Down

0 comments on commit 49bdef0

Please sign in to comment.