To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit a14bf1c5 authored by Luzian Bieri's avatar Luzian Bieri

first version

parents
Pipeline #75517 failed with stages
in 2 minutes and 7 seconds
# Docker
Dockerfile
local.py
README.md
.gitlab-ci.yml
.gitignore
data/
venv/
config.yaml
config.example.yaml
**/__pycache__/
__pycache__/
\ No newline at end of file
venv/
config.yaml
**/__pycache__/**
data/*
.vscode
\ No newline at end of file
stages:
- build
- deploy
build_master:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE" ./
- docker push "$CI_REGISTRY_IMAGE"
only:
- master
build:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE:dev" ./
- docker push "$CI_REGISTRY_IMAGE:dev"
except:
- master
deploy_cluster:
stage: deploy
image: amiveth/service-update-helper
script:
- /update.py
only:
- master
FROM python:3.8-alpine
# Create user with home directory and no password and change workdir
RUN adduser -Dh /cdn cdn
WORKDIR /cdn
# API will run on port 80
EXPOSE 8080
# Install bjoern and dependencies for install (we need to keep libev)
RUN apk add --no-cache --virtual .deps \
musl-dev python3-dev gcc git && \
apk add --no-cache libev-dev && \
pip install bjoern
# Copy files to /announce directory, install requirements
COPY ./ /announce
RUN pip install -r /announce/requirements.txt
# Cleanup dependencies
RUN apk del .deps
# Switch user
USER announce
# Start bjoern
CMD ["python3", "-d", "server.py"]
# AMIV Webhook service
## How to run this Flask app
### Development
To start the app locally for development, do the following:
1. Clone this repo
2. Create a python3 virtual environment: `virtualenv venv` (you might specify your python3 binary with `--pytho=/usr/bin/python3`)
3. Activate the virtual environment: `source venv/bin/activate`
4. Install the requirements inside the venv: `pip install -r requirements.txt`
5. Set the following environment variables: `export FLASK_APP="local.py"` and `export FLASK_DEBUG=1`
6. Create the configuration file with all the juicy secrets inside in `config.yaml`. You might copy the file `config.example.yaml`.
7. Run the flask app: `flask run`
### Production (w/o docker)
To start the app in a production environment, do the following:
1. clone this repo
2. Install the requirements: `pip install -r requirements.txt`
3. Set the following environment variable: `export FLASK_APP="run.py"`
4. Create the configuration file with all the juicy secrets inside in `config.yaml`. You might copy the file `config.example.yaml`.
5. Run the flask app: `python3 server.py`
### Production (w/ docker)
Create an Announce-Tool Backend service and give it access to the config using a docker secret:
```bash
# Create new Announce-Tool Backend service with secret
# Map port 80 (host) to 8080 (container)
docker service create \
--name webhook-service -p 80:8080 --network backend \
-v data:\data -v -v config.yaml:config.yaml\
amiveth/webhook-service
```
## Which endpoints are available
### /"hook_name"
Returns the File saved under the given path
### /upload
This is the endpoint which is used to send mails with this backend.
It expects three variables via POST:
1. "token" - The AMIV API token to be used for authentication
## Environment variables
```
CONFIG -> name of config file (default: config.yaml)
```
\ No newline at end of file
from flask_restplus import Api, Resource
from flask import send_file, current_app
from .hook import api as hook
from werkzeug.exceptions import BadRequest
import os.path
api = Api(
title='AMIV CDN',
version='0.1',
description='CDN where data can be uploaded using the AMIV groups',
)
api.add_namespace(hook)
@api.route('/<path:directory>')
class HardwareBenchmarkFilesEndpoint(Resource):
def get(self, directory):
fn = os.path.join(current_app.config['BASE_DIR'], directory)
if os.path.exists(fn):
return send_file(fn)
else:
raise BadRequest('File not found')
import requests
from json import loads, dumps
from flask import current_app
from werkzeug.exceptions import BadRequest
def check_auth(token, groups):
group_met = False
try:
# get user id
user_id_api = requests.get(
current_app.config['API_URL'] + '/sessions?where={"token":"%s"}' % token, headers={'Authorization': token})
user_id = loads(user_id_api.text)['_items'][0]['user']
where = {
'$and':[
{'user': user_id},
{'$or': [{'group': g} for g in groups]}
]
}
# request all groupmemberships of user of given groups
api = requests.get(
current_app.config['API_URL'] + '/groupmemberships?where=%s' % dumps(where), headers={'Authorization': token})
except:
raise BadRequest('AMIV-API address misconfigured or unreachable')
try:
string = api.text
obj = loads(string)
content = obj['_items']
# if one or more memberships are fullfilled token is verified
group_met = len(content) > 0
except KeyError:
if str(obj["_status"]) == "ERR":
if obj["_error"]["code"] == 401:
raise BadRequest('Invalid or expired token.')
else:
raise BadRequest('AMIV-API returned unknown response.')
except:
raise BadRequest('AMIV-API returned unknown response. Or Group membership could not be checked.')
return group_met
from flask import Flask, current_app
from flask_restplus import Namespace, Resource
from werkzeug.exceptions import BadRequest
import requests
from .auth.check_token import check_auth
import os.path
api = Namespace(
'hook',
description='Triggers hooks authenticated via AMIV groups')
upload_parser = api.parser()
upload_parser.add_argument('token', required=True)
@api.route('/<hook>')
class HardwareBenchmarkFilesEndpoint(Resource):
@api.expect(upload_parser)
def post(self, hook):
# Validate arguments
args = upload_parser.parse_args()
if not args.get('token'):
BadRequest('No token submitted')
token = args['token']
# check requested hook
c = list(filter(lambda x: x['path'] == hook, current_app.config['HOOKS']))
if len(c) != 1:
raise BadRequest('Requested hook is not configured')
c = c[0]
groups = c['group'] if type(c['group']) == list else [c['group']]
# check authorization for requested directory
if not check_auth(token, groups):
raise BadRequest('Not authorized to trigger this hook')
# trigger hook
res = requests.post(c['url'])
return res.json(), res.status_code
from flask import Flask, request, jsonify, send_file, abort
from flask_cors import CORS
from api import api
from yaml import safe_load
from os import getenv, makedirs
import os.path
with open(getenv('CONFIG', 'config.yaml')) as cfg:
config = safe_load(cfg)
app = Flask(__name__)
app.config.update(
API_URL=config.get('api_url', 'localhost'),
HOOKS=config.get('hooks', [])
)
CORS(app)
api.init_app(app)
api_url: https://api.amiv.ethz.ch
hooks:
- path: hook1
group: 5ac9246b4db3bd0001e9f2a8
url: webhook
- path: hook2
group:
- 5ac9246b4db3bd0001e9f2a8
- 5ac9246b4db3bd0001e9f2a8
url: webhook
\ No newline at end of file
from app import app
if __name__ == '__main__':
app.run(host= '0.0.0.0')
flask-restplus
flask_cors
flask
flask_marshmallow
webargs
requests
# until falsk_resplus is fixed
werkzeug==0.16.1
\ No newline at end of file
# wsgi server (used in docker container)
# [bjoern](https://github.com/jonashaag/bjoern) required.
from app import app
import bjoern
if __name__ == '__main__':
print('Starting bjoern on port 8080...', flush=True)
bjoern.run(app, '0.0.0.0', 8080)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment