Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #38 from tengu-team/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
sebastienpattyn93 authored Apr 27, 2018
2 parents 992278a + dfa3919 commit 04b08f6
Show file tree
Hide file tree
Showing 46 changed files with 4,816 additions and 1,896 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.ropeproject
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ Since it is still in beta, any suggestions and bugs are welcome on [Github](http
The required charms can be found in the qrama-charms repo. In order to install these using the following commands, one must be in the topdir of the cloned qrama-charms repo.
```
juju deploy ./sojobo-api
juju deploy ./redis redis-server --series xenial
juju add-relation sojobo-api redis
juju deploy ./arangodb
juju add-relation sojobo-api arangodb
```
Each cloud environment has its own subordinate charm, containing some cloud-specific workflows.
```
Expand All @@ -25,7 +25,7 @@ When installation is completed, you can see the status of the installed sojobo-a
}
```
**Warning**
We are waiting on a bugfix in libjuju. In order to circumvent the problem for now, one must manually edit the model.py file of the juju package (`/usr/local/lib/python3.6/dist-packages/juju`).
We are waiting on a bugfix in libjuju. In order to circumvent the problem for now, one must manually edit the model.py file of the juju package (`/usr/local/lib/python3.5/dist-packages/juju`).
L1293:
```python
await self.revoke(username)
Expand Down Expand Up @@ -84,11 +84,11 @@ def get_supported_series():
* A `get_supported_series()` function which returns a list of Ubuntu-versions this controller can deploy.

# Documentation
Documentation of the api can be found under [docs](docs).
Documentation of the api can be found under the Wiki Tab of this repository.

# Bugs
Report bugs on [Github](https://github.com/Qrama/Sojobo-api/issues)
Report bugs on [Github](https://github.com/tengu-team/layer-sojobo/issues)

# Authors
- Mathijs Moerman <[email protected]>
- Sébastien Pattyn <[email protected]>
- Michiel Ghyselinck <[email protected]>
21 changes: 21 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,24 @@ options:
type: int
default: 80
description: listen port.
cloud-type:
type: string
default: ""
description: |
Type of cloud that will be used to setup the Login Server, Make sure that
the required subordinate charm is available. Options are [google, aws,
azure, LXD, Manual]
cloud-credential:
type: string
default: ""
description: |
Credential used to setup the Login server for the sojobo-api. This setting
is required and has to be a valid cloud credential for the provided
login-cloud option.
cloud-region:
type: string
default: ""
description: |
Region used to setup the Login server for the sojobo-api in the specified
region. This setting is required and has to be a valid cloud region for
the provided cloud-type option.
165 changes: 111 additions & 54 deletions files/sojobo_api/api/api_bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,71 +16,128 @@
from functools import wraps
import requests
import yaml
import logging
import sys
import traceback
from werkzeug.exceptions import HTTPException
from sojobo_api.api.w_juju import execute_task
from flask import request, Blueprint, abort
from sojobo_api.api.w_juju import create_response
from sojobo_api.api import w_errors as errors, w_juju as juju, w_datastore as datastore, w_permissions, w_bundles as bundles
from sojobo_api import settings


BUNDLES = Blueprint('bundles', __name__)

REPO = settings.REPO_NAME
def get():
return BUNDLES
LOGGER = logging.getLogger('api_bundles')
LOGGER.setLevel(logging.DEBUG)

@BUNDLES.before_app_first_request
def initialize():
hdlr = logging.FileHandler('/opt/sojobo_api/log/api_bundles.log')
hdlr.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
LOGGER.addHandler(hdlr)

def authenticate(func):
@wraps(func)
def function(*args, **kwargs):
try:
if request.headers['api-key'] != settings.API_KEY:
abort(403, 'You do not have permission to use the API')
else:
return func(*args, **kwargs)
except KeyError:
abort(400, 'The request does not have all the required data or the data is not in the right format.')
return function
def get():
return BUNDLES

@BUNDLES.route('/types', methods=['GET'])
def get_all_bundles():
try:
LOGGER.info('/BUNDLES/types [GET] => receiving call')
auth_data = juju.get_connection_info(request.authorization)
execute_task(juju.authenticate, request.headers['api-key'], request.authorization, auth_data)
LOGGER.info('/BUNDLES/types [GET] => Authenticated!')
if auth_data['company']:
company = auth_data['company']['name']
else:
company = None
LOGGER.info('/BUNDLES/types [GET] => Always authorized!')
types = bundles.get_all_bundles(company)
LOGGER.info('/BUNDLES/types [GET] => Succesfully retrieved all bundles!')
return juju.create_response(200, types)
except KeyError:
code, response = errors.invalid_data()
error_log()
return juju.create_response(code, response)
except HTTPException:
raise
except Exception:
ers = error_log()
code, response = errors.cmd_error(ers)
return juju.create_response(code, response)

@BUNDLES.route('', methods=['GET'])
@authenticate
def get_bundles():
i = 1
res = requests.get('https://api.github.com/orgs/{}/repos'.format(REPO))
data = []
while res.json() != [] and res.status_code == 200:
for b in res.json():
if 'bundle' in b['name']:
data.append({
'name': b['name'],
'description': b['description'],
'json': get_json(b['name']),
'logo': None
})
i += 1
res = requests.get('https://api.github.com/orgs/{}/repos?page={}'.format(REPO, i))
return create_response(200, data)

@BUNDLES.route('/types', methods=['POST'])
def determine_closest_type():
try:
LOGGER.info('/BUNDLES/typess [POST] => receiving call')
data = request.json
auth_data = juju.get_connection_info(request.authorization)
execute_task(juju.authenticate, request.headers['api-key'], request.authorization, auth_data)
LOGGER.info('/BUNDLES/types [POST] => Authenticated!')
LOGGER.info('/BUNDLES/types [POST] => Always authorized!')
if 'applications' in data:
b_type = bundles.determine_closest_type(data['applications'])
if b_type:
LOGGER.info('/BUNDLES/types [POST] => determined type: %s', b_type['name'])
return juju.create_response(200, b_type)
else:
LOGGER.info('/BUNDLES/types [POST] => no matching type found')
return juju.create_response(404, 'Could not find a matching type.')
else:
return juju.create_response(400, 'The Body should contain an applications property.')
except KeyError:
error_log()
return juju.create_response(errors.invalid_data()[0], errors.invalid_data()[1])
except HTTPException:
raise
except Exception:
ers = error_log()
return juju.create_response(errors.cmd_error(ers)[0], errors.cmd_error(ers)[1])

@BUNDLES.route('/<bundle>', methods=['GET'])
@authenticate
def get_bundle(bundle):
res = requests.get('https://api.github.com/repos/{}/{}'.format(REPO, bundle))
if res.status_code == 200:
data = {
'name': res.json()['name'],
'description': res.json()['description'],
'json': get_json(res.json()['name']),
'logo': None
}
return create_response(200, data)
else:
abort(404, 'The bundle {}:{} could not be found'.format(REPO, bundle))
@BUNDLES.route('/types', methods=['PUT'])
def upload_types():
#TODO: at the moment only Tengu admin can perform this task. Will be changed
# in the future to allow company_admins to upload company specific bundles as well
try:
LOGGER.info('/BUNDLES/types [PUT] => receiving call')
data = request.json
auth_data = juju.get_connection_info(request.authorization)
execute_task(juju.authenticate, request.headers['api-key'], request.authorization, auth_data)
LOGGER.info('/BUNDLES/types [PUT] => Authenticated!')
if auth_data['company']:
company = auth_data['company']['name']
else:
company = None
if juju.check_if_admin(request.authorization): #, company):
if 'repositories' in data:
LOGGER.info('/BUNDLES/types [PUT] => Start uploading repositories')
types = bundles.upload_types(data['repositories'], company)
LOGGER.info('/BUNDLES/types [PUT] => Succesfully uploaded %s repositories', len(types))
return juju.create_response(200, types)
else:
return juju.create_response(400, 'The Body should contain a repositories property.')
else:
code, response = errors.no_permission()
LOGGER.info('/BUNDLES/types [PUT] => No Permission to perform this action!')
return juju.create_response(code, response)
except KeyError:
code, response = errors.invalid_data()
error_log()
return juju.create_response(code, response)
except HTTPException:
raise
except Exception:
ers = error_log()
code, response = errors.cmd_error(ers)
return juju.create_response(code, response)


def get_json(bundle):
res = requests.get('https://raw.githubusercontent.com/{}/{}/master/bundle.yaml'.format(REPO, bundle))
if res.status_code == 200:
res_dict = yaml.load(res.text)
return res_dict
else:
abort(404, 'The bundle {}:{} could not be found'.format(REPO, bundle))
def error_log():
exc_type, exc_value, exc_traceback = sys.exc_info()
lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
for l in lines:
LOGGER.error(l)
return lines
Loading

0 comments on commit 04b08f6

Please sign in to comment.