-
Notifications
You must be signed in to change notification settings - Fork 444
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #177 from hightall/issue176
feat: add basic framework for k8s rest agent
- Loading branch information
Showing
44 changed files
with
1,335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
FROM python:3.8 | ||
|
||
COPY src/agent/k8s-rest-agent/requirements.txt / | ||
COPY src/agent/k8s-rest-agent/pip /root/.pip | ||
|
||
RUN pip install -r /requirements.txt | ||
|
||
COPY src/agent/k8s-rest-agent/src /var/www/server | ||
COPY src/agent/k8s-rest-agent/entrypoint.sh / | ||
COPY src/agent/k8s-rest-agent/uwsgi/server.ini /etc/uwsgi/apps-enabled/ | ||
RUN mkdir /var/log/supervisor | ||
|
||
ENV WEBROOT / | ||
ENV WEB_CONCURRENCY 10 | ||
ENV DEBUG False | ||
ENV UWSGI_WORKERS 1 | ||
ENV UWSGI_PROCESSES 1 | ||
ENV UWSGI_OFFLOAD_THREADS 10 | ||
ENV UWSGI_MODULE server.wsgi:application | ||
|
||
WORKDIR /var/www/server | ||
RUN python manage.py collectstatic --noinput | ||
|
||
CMD bash /entrypoint.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
FROM python:3.8 | ||
|
||
COPY requirements.txt / | ||
COPY pip /root/.pip | ||
|
||
RUN pip install -r /requirements.txt | ||
|
||
COPY src /var/www/server | ||
COPY entrypoint.sh / | ||
COPY uwsgi/server.ini /etc/uwsgi/apps-enabled/ | ||
RUN mkdir /var/log/supervisor | ||
|
||
ENV WEBROOT / | ||
ENV WEB_CONCURRENCY 10 | ||
ENV DEBUG False | ||
ENV UWSGI_WORKERS 1 | ||
ENV UWSGI_PROCESSES 1 | ||
ENV UWSGI_OFFLOAD_THREADS 10 | ||
ENV UWSGI_MODULE server.wsgi:application | ||
|
||
WORKDIR /var/www/server | ||
RUN python manage.py collectstatic --noinput | ||
|
||
CMD bash /entrypoint.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#!/usr/bin/env bash | ||
|
||
if [[ "$RUN_TYPE" == "SERVER" ]]; then | ||
uwsgi --ini /etc/uwsgi/apps-enabled/server.ini; | ||
else | ||
if [[ "$RUN_TYPE" == "TASK" ]]; then | ||
celery -A server worker --autoscale=20,6 -l info | ||
elif [[ "$RUN_TYPE" == "BEAT_TASK" ]]; then | ||
celery -A server beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler --pidfile=/opt/celeryd.pid | ||
fi | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[global] | ||
index-url=http://mirrors.cloud.aliyuncs.com/pypi/simple/ | ||
|
||
[install] | ||
trusted-host=mirrors.cloud.aliyuncs.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Django>=3.0 | ||
uwsgi | ||
enum34 | ||
djangorestframework | ||
holdup>1.5.0,<=1.6.0 | ||
drf-yasg<=1.17.0 | ||
swagger_spec_validator<=2.4.1 | ||
psycopg2-binary | ||
celery<5.0,>=4.4 | ||
redis | ||
requests | ||
supervisor | ||
django-celery-beat | ||
django-celery-results | ||
django-3-jet | ||
djangorestframework-jwt<=1.11.0 | ||
python-jwt # 需要安装,否则会出现token解码失败错误 | ||
shortuuid |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class ApiConfig(AppConfig): | ||
name = "api" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import base64 | ||
import json | ||
import logging | ||
|
||
from django.contrib.auth import get_user_model | ||
from django.utils.translation import ugettext as _ | ||
from rest_framework import authentication | ||
from rest_framework import exceptions | ||
from rest_framework_jwt.authentication import ( | ||
JSONWebTokenAuthentication as CoreJSONWebTokenAuthentication, | ||
) | ||
from rest_framework_jwt.settings import api_settings | ||
|
||
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER | ||
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER | ||
User = get_user_model() | ||
|
||
LOG = logging.getLogger(__name__) | ||
|
||
|
||
class JSONWebTokenAuthentication(CoreJSONWebTokenAuthentication): | ||
@staticmethod | ||
def _get_or_create_user(user_id, payload=None): | ||
if payload is None: | ||
payload = {} | ||
|
||
user, _ = User.objects.get_or_create( | ||
id=user_id, username=user_id, defaults={"password": user_id} | ||
) | ||
|
||
return user | ||
|
||
def authenticate_credentials(self, payload): | ||
""" | ||
Returns an active user that matches the payload's user id and email. | ||
""" | ||
username = jwt_get_username_from_payload(payload) | ||
|
||
if not username: | ||
msg = _("Invalid payload.") | ||
raise exceptions.AuthenticationFailed(msg) | ||
|
||
user = self._get_or_create_user(username, payload) | ||
|
||
if not user.is_active: | ||
msg = _("User account is disabled.") | ||
raise exceptions.AuthenticationFailed(msg) | ||
|
||
return user | ||
|
||
|
||
class IstioJWTAuthentication(authentication.BaseAuthentication): | ||
def authenticate(self, request): | ||
token = request.META.get("HTTP_TOKEN", None) | ||
if token is None: | ||
return None | ||
|
||
token += "=" * (-len(token) % 4) | ||
token = base64.b64decode(token) | ||
token = json.loads(token) | ||
user_id = token.get("sub", None) | ||
if user_id is None: | ||
return None | ||
user, _ = User.objects.get_or_create( | ||
id=user_id, username=user_id, defaults={"password": user_id} | ||
) | ||
return user, None |
Empty file.
Empty file.
14 changes: 14 additions & 0 deletions
14
src/agent/k8s-rest-agent/src/api/management/commands/test_task.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from django.core.management import BaseCommand | ||
from api.tasks import example_task | ||
from django_celery_beat.models import IntervalSchedule, PeriodicTask | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Test Task" | ||
|
||
def handle(self, *args, **options): | ||
interval = IntervalSchedule.objects.first() | ||
PeriodicTask.objects.create( | ||
interval=interval, name="example", task="server.tasks.example_task" | ||
) | ||
# example_task.delay() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .user import User, Profile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from django.contrib.auth.models import AbstractUser | ||
from django.db import models | ||
from django.db.models.signals import post_save | ||
from api.utils.db_functions import make_uuid | ||
|
||
|
||
class User(AbstractUser): | ||
roles = [] | ||
|
||
id = models.UUIDField( | ||
primary_key=True, | ||
help_text="ID of user", | ||
default=make_uuid, | ||
editable=True, | ||
) | ||
username = models.CharField(default="", max_length=128, unique=True) | ||
|
||
def __str__(self): | ||
return self.username | ||
|
||
|
||
class Profile(models.Model): | ||
user = models.OneToOneField( | ||
User, related_name="profile", on_delete=models.CASCADE | ||
) | ||
created_at = models.DateTimeField(auto_now_add=True) | ||
|
||
def __str__(self): | ||
return "%s's profile" % self.user | ||
|
||
class Meta: | ||
ordering = ("-created_at",) | ||
|
||
|
||
def create_user_profile(sender, instance, created, **kwargs): | ||
if created: | ||
Profile.objects.create(user=instance) | ||
|
||
|
||
post_save.connect(create_user_profile, sender=User) | ||
|
||
# Create your models here. |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import logging | ||
import os | ||
|
||
from rest_framework import viewsets, status | ||
from drf_yasg.utils import swagger_auto_schema | ||
from rest_framework.decorators import action, permission_classes | ||
from rest_framework.permissions import IsAuthenticated | ||
from rest_framework.response import Response | ||
|
||
from api.auth import JSONWebTokenAuthentication, IstioJWTAuthentication | ||
from api.utils.mixins import PermissionsPerMethodMixin | ||
|
||
LOG = logging.getLogger(__name__) | ||
APP_VERSION = os.getenv("APP_VERSION", "v1") | ||
|
||
|
||
class HelloViewSet(PermissionsPerMethodMixin, viewsets.ViewSet): | ||
authentication_classes = (IstioJWTAuthentication,) | ||
|
||
@swagger_auto_schema( | ||
operation_summary="Hello world", operation_description="Hello world" | ||
) | ||
def list(self, request): | ||
return Response( | ||
{"hello": "world %s" % APP_VERSION}, status=status.HTTP_200_OK | ||
) | ||
|
||
@swagger_auto_schema(operation_summary="hello world need auth") | ||
@action( | ||
methods=["get"], | ||
url_path="need-auth", | ||
url_name="need-auth", | ||
detail=False, | ||
) | ||
# @permission_classes((IsAuthenticated,)) | ||
def need_auth(self, request): | ||
LOG.info("request user %s", request.user) | ||
return Response( | ||
{"hello": "auth world %s" % APP_VERSION}, status=status.HTTP_200_OK | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from api.tasks.task.example import example_task |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import logging | ||
|
||
from server.celery import app | ||
|
||
|
||
LOG = logging.getLogger(__name__) | ||
|
||
|
||
@app.task(name="example_task") | ||
def example_task(): | ||
LOG.info("example task") | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.test import TestCase | ||
|
||
# Create your tests here. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .swagger import with_common_response | ||
from .db import paginate_list |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from django.core.paginator import Paginator | ||
from django.db.models import Func | ||
|
||
|
||
class Round(Func): | ||
function = "ROUND" | ||
arity = 2 | ||
|
||
|
||
def paginate_list(data=None, page=1, per_page=10, limit=None): | ||
if not data: | ||
data = [] | ||
|
||
total = len(data) | ||
|
||
if per_page != -1: | ||
p = Paginator(data, per_page) | ||
last_page = p.page_range[-1] | ||
page = page if page <= last_page else last_page | ||
data = p.page(page) | ||
total = p.count | ||
else: | ||
if limit: | ||
data = data[:limit] | ||
|
||
return data, total |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
from drf_yasg import openapi | ||
from rest_framework import serializers | ||
from rest_framework import status | ||
|
||
from api.utils.serializers import BadResponseSerializer | ||
|
||
basic_type_info = [ | ||
(serializers.CharField, openapi.TYPE_STRING), | ||
(serializers.BooleanField, openapi.TYPE_BOOLEAN), | ||
(serializers.IntegerField, openapi.TYPE_INTEGER), | ||
(serializers.FloatField, openapi.TYPE_NUMBER), | ||
(serializers.FileField, openapi.TYPE_FILE), | ||
(serializers.ImageField, openapi.TYPE_FILE), | ||
] | ||
|
||
|
||
def to_form_paras(self): | ||
custom_paras = [] | ||
for field_name, field in self.fields.items(): | ||
type_str = openapi.TYPE_STRING | ||
for field_class, type_format in basic_type_info: | ||
if isinstance(field, field_class): | ||
type_str = type_format | ||
help_text = getattr(field, "help_text") | ||
default = getattr(field, "default", None) | ||
required = getattr(field, "required") | ||
if callable(default): | ||
custom_paras.append( | ||
openapi.Parameter( | ||
field_name, | ||
openapi.IN_FORM, | ||
help_text, | ||
type=type_str, | ||
required=required, | ||
) | ||
) | ||
else: | ||
custom_paras.append( | ||
openapi.Parameter( | ||
field_name, | ||
openapi.IN_FORM, | ||
help_text, | ||
type=type_str, | ||
required=required, | ||
default=default, | ||
) | ||
) | ||
return custom_paras | ||
|
||
|
||
def with_common_response(responses=None): | ||
if responses is None: | ||
responses = {} | ||
|
||
responses.update( | ||
{ | ||
status.HTTP_400_BAD_REQUEST: BadResponseSerializer, | ||
status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal Error", | ||
} | ||
) | ||
|
||
return responses |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import uuid | ||
import shortuuid | ||
|
||
|
||
def make_uuid(): | ||
return str(uuid.uuid4()) | ||
|
||
|
||
def make_uuid_hex(): | ||
return uuid.uuid4().hex | ||
|
||
|
||
def make_short_uuid(): | ||
return shortuuid.ShortUUID().random(length=16) |
Oops, something went wrong.