Initial commit
This commit is contained in:
commit
e7041b2ccd
25
.drone.yml
Normal file
25
.drone.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: code-analysis
|
||||||
|
image: aosapps/drone-sonar-plugin
|
||||||
|
settings:
|
||||||
|
sonar_host:
|
||||||
|
from_secret: SONAR_HOST
|
||||||
|
sonar_token:
|
||||||
|
from_secret: SONAR_CODE
|
||||||
|
|
||||||
|
- name: kaniko
|
||||||
|
image: banzaicloud/drone-kaniko
|
||||||
|
settings:
|
||||||
|
registry: registry.kmlabz.com
|
||||||
|
repo: universalrobots/${DRONE_REPO_NAME}
|
||||||
|
username:
|
||||||
|
from_secret: DOCKER_USERNAME
|
||||||
|
password:
|
||||||
|
from_secret: DOCKER_PASSWORD
|
||||||
|
tags:
|
||||||
|
- latest
|
||||||
|
- ${DRONE_BUILD_NUMBER}
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*.swp
|
||||||
|
venv
|
||||||
|
*.pyc
|
||||||
|
__pycache__/*
|
||||||
|
__pycache__
|
||||||
|
*.wpr
|
||||||
|
*.log
|
||||||
|
.idea
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM python:3.9
|
||||||
|
|
||||||
|
ADD job_orchestrator_service requirements.txt /job_orchestrator_service/
|
||||||
|
WORKDIR /job_orchestrator_service/
|
||||||
|
|
||||||
|
RUN pip3 install -r requirements.txt && pip3 install gunicorn
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:app"]
|
||||||
|
|
34
job_orchestrator_service/app.py
Normal file
34
job_orchestrator_service/app.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from config import Config
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.flask import FlaskIntegration
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
from utils import register_all_error_handlers
|
||||||
|
|
||||||
|
# import views
|
||||||
|
from views import JobView
|
||||||
|
|
||||||
|
# Setup sentry
|
||||||
|
|
||||||
|
if Config.SENTRY_DSN:
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn=Config.SENTRY_DSN,
|
||||||
|
integrations=[FlaskIntegration()],
|
||||||
|
send_default_pii=True,
|
||||||
|
release=Config.RELEASE_ID,
|
||||||
|
environment=Config.RELEASEMODE
|
||||||
|
)
|
||||||
|
|
||||||
|
# create flask app
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(Config)
|
||||||
|
register_all_error_handlers(app)
|
||||||
|
|
||||||
|
# register views
|
||||||
|
for view in [JobView]:
|
||||||
|
view.register(app, trailing_slash=False)
|
||||||
|
|
||||||
|
# start debuggig if needed
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=True)
|
15
job_orchestrator_service/config.py
Normal file
15
job_orchestrator_service/config.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
|
||||||
|
"""
|
||||||
|
Configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
SECRET_KEY = os.environ.get("SECRET_KEY", os.urandom(12))
|
||||||
|
CORS_ORIGINS = os.environ.get("ALLOWED_ORIGINS", "*")
|
||||||
|
|
||||||
|
SENTRY_DSN = os.environ.get("SENTRY_DSN")
|
||||||
|
RELEASE_ID = os.environ.get("RELEASE_ID", "test")
|
||||||
|
RELEASEMODE = os.environ.get("RELEASEMODE", "dev")
|
2
job_orchestrator_service/schemas/__init__.py
Normal file
2
job_orchestrator_service/schemas/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from .job_schema import JobSchema
|
22
job_orchestrator_service/schemas/job_schema.py
Normal file
22
job_orchestrator_service/schemas/job_schema.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from marshmallow import Schema, fields
|
||||||
|
from marshmallow.validate import Length
|
||||||
|
from marshmallow import RAISE
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class ControlConfigurationSchema(Schema):
|
||||||
|
pod_id = fields.UUID(required=False, missing=uuid.uuid4)
|
||||||
|
robot_address = fields.Str(required=True)
|
||||||
|
program_url = fields.Str(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class JobSchema(Schema):
|
||||||
|
id = fields.UUID(required=False, missing=uuid.uuid4)
|
||||||
|
created_at = fields.DateTime(required=False, missing=datetime.now)
|
||||||
|
|
||||||
|
controllers = fields.Nested(ControlConfigurationSchema, many=True, required=True, validate=Length(min=1))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unknown = RAISE
|
3
job_orchestrator_service/utils/__init__.py
Normal file
3
job_orchestrator_service/utils/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from .require_decorators import json_required
|
||||||
|
from .error_handlers import register_all_error_handlers
|
18
job_orchestrator_service/utils/error_handlers.py
Normal file
18
job_orchestrator_service/utils/error_handlers.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
|
def get_standard_error_handler(code: int):
|
||||||
|
def error_handler(err):
|
||||||
|
return {"msg": str(err)}, code
|
||||||
|
|
||||||
|
return error_handler
|
||||||
|
|
||||||
|
|
||||||
|
# function to register all handlers
|
||||||
|
|
||||||
|
|
||||||
|
def register_all_error_handlers(app):
|
||||||
|
error_codes_to_override = [404, 403, 401, 405, 400, 409, 422]
|
||||||
|
|
||||||
|
for code in error_codes_to_override:
|
||||||
|
app.register_error_handler(code, get_standard_error_handler(code))
|
16
job_orchestrator_service/utils/require_decorators.py
Normal file
16
job_orchestrator_service/utils/require_decorators.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from flask import request, current_app, abort
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
def json_required(f):
|
||||||
|
@wraps(f)
|
||||||
|
def call(*args, **kwargs):
|
||||||
|
|
||||||
|
if request.is_json:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
abort(400, "JSON required")
|
||||||
|
|
||||||
|
return call
|
3
job_orchestrator_service/views/__init__.py
Normal file
3
job_orchestrator_service/views/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from .job_view import JobView
|
||||||
|
|
31
job_orchestrator_service/views/job_view.py
Normal file
31
job_orchestrator_service/views/job_view.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from flask import request, jsonify, current_app, abort, Response
|
||||||
|
from flask_classful import FlaskView, route
|
||||||
|
|
||||||
|
from utils import json_required
|
||||||
|
|
||||||
|
from marshmallow.exceptions import ValidationError
|
||||||
|
|
||||||
|
from schemas import JobSchema
|
||||||
|
|
||||||
|
|
||||||
|
class JobView(FlaskView):
|
||||||
|
job_schema = JobSchema(many=False)
|
||||||
|
jobs_schema = JobSchema(many=True, exclude=['controllers'])
|
||||||
|
|
||||||
|
def index(self):
|
||||||
|
# List all jobs
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get(self, _id: str):
|
||||||
|
# Get info about a job
|
||||||
|
pass
|
||||||
|
|
||||||
|
@json_required
|
||||||
|
def post(self):
|
||||||
|
# Start (schedule) a job
|
||||||
|
pass
|
||||||
|
|
||||||
|
def delete(self, _id: str):
|
||||||
|
# stop a job
|
||||||
|
pass
|
7
requirements.txt
Normal file
7
requirements.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
pyyaml
|
||||||
|
|
||||||
|
blinker
|
||||||
|
Flask
|
||||||
|
marshmallow
|
||||||
|
Flask-Classful
|
||||||
|
sentry-sdk
|
Loading…
Reference in New Issue
Block a user