Merge branch 'better-error' of https://bitbucket.org/yackob03/quay into better-error
Conflicts: util/http.py
This commit is contained in:
commit
9650c1867b
4 changed files with 53 additions and 38 deletions
|
@ -72,10 +72,10 @@ def endpoint_invalid_request(e):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def request_error(exception = None, **kwargs):
|
def request_error(exception=None, **kwargs):
|
||||||
data = kwargs.copy()
|
data = kwargs.copy()
|
||||||
if exception:
|
if exception:
|
||||||
data['message'] = ex.message
|
data['message'] = exception.message
|
||||||
|
|
||||||
return make_response(jsonify(data), 400)
|
return make_response(jsonify(data), 400)
|
||||||
|
|
||||||
|
@ -254,12 +254,14 @@ def convert_user_to_organization():
|
||||||
# Ensure that the new admin user is the not user being converted.
|
# Ensure that the new admin user is the not user being converted.
|
||||||
admin_username = convert_data['adminUser']
|
admin_username = convert_data['adminUser']
|
||||||
if admin_username == user.username:
|
if admin_username == user.username:
|
||||||
return request_error(reason = 'invaliduser', message = 'The admin user is not valid')
|
return request_error(reason='invaliduser',
|
||||||
|
message='The admin user is not valid')
|
||||||
|
|
||||||
# Ensure that the sign in credentials work.
|
# Ensure that the sign in credentials work.
|
||||||
admin_password = convert_data['adminPassword']
|
admin_password = convert_data['adminPassword']
|
||||||
if not model.verify_user(admin_username, admin_password):
|
if not model.verify_user(admin_username, admin_password):
|
||||||
return request_error(reason = 'invaliduser', message = 'The admin user credentials are not valid')
|
return request_error(reason='invaliduser',
|
||||||
|
message='The admin user credentials are not valid')
|
||||||
|
|
||||||
# Subscribe the organization to the new plan.
|
# Subscribe the organization to the new plan.
|
||||||
plan = convert_data['plan']
|
plan = convert_data['plan']
|
||||||
|
@ -295,14 +297,15 @@ def change_user_details():
|
||||||
new_email = user_data['email']
|
new_email = user_data['email']
|
||||||
if model.find_user_by_email(new_email):
|
if model.find_user_by_email(new_email):
|
||||||
# Email already used.
|
# Email already used.
|
||||||
return request_error(message = 'E-mail address already used')
|
return request_error(message='E-mail address already used')
|
||||||
|
|
||||||
logger.debug('Sending email to change email address for user: %s', user.username)
|
logger.debug('Sending email to change email address for user: %s',
|
||||||
|
user.username)
|
||||||
code = model.create_confirm_email_code(user, new_email=new_email)
|
code = model.create_confirm_email_code(user, new_email=new_email)
|
||||||
send_change_email(user.username, user_data['email'], code.code)
|
send_change_email(user.username, user_data['email'], code.code)
|
||||||
|
|
||||||
except model.InvalidPasswordException, ex:
|
except model.InvalidPasswordException, ex:
|
||||||
return request_error(exception = ex)
|
return request_error(exception=ex)
|
||||||
|
|
||||||
return jsonify(user_view(user))
|
return jsonify(user_view(user))
|
||||||
|
|
||||||
|
@ -314,7 +317,7 @@ def create_new_user():
|
||||||
|
|
||||||
existing_user = model.get_user(user_data['username'])
|
existing_user = model.get_user(user_data['username'])
|
||||||
if existing_user:
|
if existing_user:
|
||||||
return request_error(message = 'The username already exists')
|
return request_error(message='The username already exists')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_user = model.create_user(user_data['username'], user_data['password'],
|
new_user = model.create_user(user_data['username'], user_data['password'],
|
||||||
|
@ -323,7 +326,7 @@ def create_new_user():
|
||||||
send_confirmation_email(new_user.username, new_user.email, code.code)
|
send_confirmation_email(new_user.username, new_user.email, code.code)
|
||||||
return make_response('Created', 201)
|
return make_response('Created', 201)
|
||||||
except model.DataModelException as ex:
|
except model.DataModelException as ex:
|
||||||
return request_error(exception = ex)
|
return request_error(exception=ex)
|
||||||
|
|
||||||
|
|
||||||
@api.route('/signin', methods=['POST'])
|
@api.route('/signin', methods=['POST'])
|
||||||
|
@ -467,14 +470,15 @@ def create_organization():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
return request_error(message = 'A user or organization with this name already exists')
|
msg = 'A user or organization with this name already exists'
|
||||||
|
return request_error(message=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
model.create_organization(org_data['name'], org_data['email'],
|
model.create_organization(org_data['name'], org_data['email'],
|
||||||
current_user.db_user())
|
current_user.db_user())
|
||||||
return make_response('Created', 201)
|
return make_response('Created', 201)
|
||||||
except model.DataModelException as ex:
|
except model.DataModelException as ex:
|
||||||
return request_error(exception = ex)
|
return request_error(exception=ex)
|
||||||
|
|
||||||
|
|
||||||
def org_view(o, teams):
|
def org_view(o, teams):
|
||||||
|
@ -529,7 +533,7 @@ def change_organization_details(orgname):
|
||||||
if 'email' in org_data and org_data['email'] != org.email:
|
if 'email' in org_data and org_data['email'] != org.email:
|
||||||
new_email = org_data['email']
|
new_email = org_data['email']
|
||||||
if model.find_user_by_email(new_email):
|
if model.find_user_by_email(new_email):
|
||||||
return request_error(message = 'E-mail address already used')
|
return request_error(message='E-mail address already used')
|
||||||
|
|
||||||
logger.debug('Changing email address for organization: %s', org.username)
|
logger.debug('Changing email address for organization: %s', org.username)
|
||||||
model.update_email(org, new_email)
|
model.update_email(org, new_email)
|
||||||
|
@ -614,7 +618,8 @@ def create_organization_prototype_permission(orgname):
|
||||||
details = request.get_json()
|
details = request.get_json()
|
||||||
activating_username = None
|
activating_username = None
|
||||||
|
|
||||||
if 'activating_user' in details and details['activating_user'] and 'name' in details['activating_user']:
|
if ('activating_user' in details and details['activating_user'] and
|
||||||
|
'name' in details['activating_user']):
|
||||||
activating_username = details['activating_user']['name']
|
activating_username = details['activating_user']['name']
|
||||||
|
|
||||||
delegate = details['delegate']
|
delegate = details['delegate']
|
||||||
|
@ -632,10 +637,10 @@ def create_organization_prototype_permission(orgname):
|
||||||
if delegate_teamname else None)
|
if delegate_teamname else None)
|
||||||
|
|
||||||
if activating_username and not activating_user:
|
if activating_username and not activating_user:
|
||||||
return request_error(message = 'Unknown activating user')
|
return request_error(message='Unknown activating user')
|
||||||
|
|
||||||
if not delegate_user and not delegate_team:
|
if not delegate_user and not delegate_team:
|
||||||
return request_error(message = 'Missing delagate user or team')
|
return request_error(message='Missing delagate user or team')
|
||||||
|
|
||||||
role_name = details['role']
|
role_name = details['role']
|
||||||
|
|
||||||
|
@ -893,7 +898,7 @@ def update_organization_team_member(orgname, teamname, membername):
|
||||||
# Find the user.
|
# Find the user.
|
||||||
user = model.get_user(membername)
|
user = model.get_user(membername)
|
||||||
if not user:
|
if not user:
|
||||||
return request_error(message = 'Unknown user')
|
return request_error(message='Unknown user')
|
||||||
|
|
||||||
# Add the user to the team.
|
# Add the user to the team.
|
||||||
model.add_user_to_team(user, team)
|
model.add_user_to_team(user, team)
|
||||||
|
@ -934,7 +939,7 @@ def create_repo():
|
||||||
|
|
||||||
existing = model.get_repository(namespace_name, repository_name)
|
existing = model.get_repository(namespace_name, repository_name)
|
||||||
if existing:
|
if existing:
|
||||||
return request_error(message = 'Repository already exists')
|
return request_error(message='Repository already exists')
|
||||||
|
|
||||||
visibility = req['visibility']
|
visibility = req['visibility']
|
||||||
|
|
||||||
|
@ -1007,7 +1012,7 @@ def list_repos():
|
||||||
if page:
|
if page:
|
||||||
try:
|
try:
|
||||||
page = int(page)
|
page = int(page)
|
||||||
except:
|
except Exception:
|
||||||
page = None
|
page = None
|
||||||
|
|
||||||
username = None
|
username = None
|
||||||
|
@ -1537,7 +1542,7 @@ def change_user_permissions(namespace, repository, username):
|
||||||
# This repository is not part of an organization
|
# This repository is not part of an organization
|
||||||
pass
|
pass
|
||||||
except model.DataModelException as ex:
|
except model.DataModelException as ex:
|
||||||
return request_error(exception = ex)
|
return request_error(exception=ex)
|
||||||
|
|
||||||
log_action('change_repo_permission', namespace,
|
log_action('change_repo_permission', namespace,
|
||||||
{'username': username, 'repo': repository,
|
{'username': username, 'repo': repository,
|
||||||
|
@ -1590,7 +1595,7 @@ def delete_user_permissions(namespace, repository, username):
|
||||||
try:
|
try:
|
||||||
model.delete_user_permission(username, namespace, repository)
|
model.delete_user_permission(username, namespace, repository)
|
||||||
except model.DataModelException as ex:
|
except model.DataModelException as ex:
|
||||||
return request_error(exception = ex)
|
return request_error(exception=ex)
|
||||||
|
|
||||||
log_action('delete_repo_permission', namespace,
|
log_action('delete_repo_permission', namespace,
|
||||||
{'username': username, 'repo': repository},
|
{'username': username, 'repo': repository},
|
||||||
|
@ -1846,7 +1851,7 @@ def subscribe(user, plan, token, require_business_plan):
|
||||||
plan_found['price'] == 0):
|
plan_found['price'] == 0):
|
||||||
logger.warning('Business attempting to subscribe to personal plan: %s',
|
logger.warning('Business attempting to subscribe to personal plan: %s',
|
||||||
user.username)
|
user.username)
|
||||||
return request_error(message = 'No matching plan found')
|
return request_error(message='No matching plan found')
|
||||||
|
|
||||||
private_repos = model.get_private_repo_count(user.username)
|
private_repos = model.get_private_repo_count(user.username)
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
from flask import request, make_response, jsonify, abort as flask_abort, session, Blueprint
|
from flask import request, make_response, jsonify, session, Blueprint
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
from data.queue import webhook_queue
|
from data.queue import webhook_queue
|
||||||
from app import app, mixpanel
|
from app import mixpanel
|
||||||
from auth.auth import (process_auth, get_authenticated_user,
|
from auth.auth import (process_auth, get_authenticated_user,
|
||||||
get_validated_token)
|
get_validated_token)
|
||||||
from util.names import parse_repository_name
|
from util.names import parse_repository_name
|
||||||
|
@ -15,9 +15,9 @@ from util.email import send_confirmation_email
|
||||||
from auth.permissions import (ModifyRepositoryPermission, UserPermission,
|
from auth.permissions import (ModifyRepositoryPermission, UserPermission,
|
||||||
ReadRepositoryPermission,
|
ReadRepositoryPermission,
|
||||||
CreateRepositoryPermission)
|
CreateRepositoryPermission)
|
||||||
|
|
||||||
from util.http import abort
|
from util.http import abort
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
index = Blueprint('index', __name__)
|
index = Blueprint('index', __name__)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from flask import (make_response, request, session, Response, abort as flask_abort,
|
from flask import (make_response, request, session, Response, redirect,
|
||||||
redirect, Blueprint)
|
Blueprint)
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from time import time
|
from time import time
|
||||||
|
@ -59,7 +59,8 @@ def require_completion(f):
|
||||||
def wrapper(namespace, repository, *args, **kwargs):
|
def wrapper(namespace, repository, *args, **kwargs):
|
||||||
if store.exists(store.image_mark_path(namespace, repository,
|
if store.exists(store.image_mark_path(namespace, repository,
|
||||||
kwargs['image_id'])):
|
kwargs['image_id'])):
|
||||||
abort(400, 'Image %(image_id)s is being uploaded, retry later', image_id=kwargs['image_id'])
|
abort(400, 'Image %(image_id)s is being uploaded, retry later',
|
||||||
|
image_id=kwargs['image_id'])
|
||||||
|
|
||||||
return f(namespace, repository, *args, **kwargs)
|
return f(namespace, repository, *args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
@ -194,7 +195,8 @@ def put_image_checksum(namespace, repository, image_id):
|
||||||
abort(400, "Missing checksum for image %(image_id)s", image_id=image_id)
|
abort(400, "Missing checksum for image %(image_id)s", image_id=image_id)
|
||||||
|
|
||||||
if not session.get('checksum'):
|
if not session.get('checksum'):
|
||||||
abort(400, 'Checksum not found in Cookie for image %(imaage_id)s', image_id=image_id)
|
abort(400, 'Checksum not found in Cookie for image %(imaage_id)s',
|
||||||
|
image_id=image_id)
|
||||||
|
|
||||||
if not store.exists(store.image_json_path(namespace, repository, image_id)):
|
if not store.exists(store.image_json_path(namespace, repository, image_id)):
|
||||||
abort(404, 'Image not found: %(image_id)s', image_id=image_id)
|
abort(404, 'Image not found: %(image_id)s', image_id=image_id)
|
||||||
|
@ -321,10 +323,12 @@ def put_image_json(namespace, repository, image_id):
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
pass
|
pass
|
||||||
if not data or not isinstance(data, dict):
|
if not data or not isinstance(data, dict):
|
||||||
abort(400, 'Invalid JSON for image: %(image_id)s\nJSON: %(json)s', image_id=image_id, json=request.data)
|
abort(400, 'Invalid JSON for image: %(image_id)s\nJSON: %(json)s',
|
||||||
|
image_id=image_id, json=request.data)
|
||||||
|
|
||||||
if 'id' not in data:
|
if 'id' not in data:
|
||||||
abort(400, 'Missing key `id` in JSON for image: %(image_id)s', image_id=image_id)
|
abort(400, 'Missing key `id` in JSON for image: %(image_id)s',
|
||||||
|
image_id=image_id)
|
||||||
|
|
||||||
# Read the checksum
|
# Read the checksum
|
||||||
checksum = request.headers.get('X-Docker-Checksum')
|
checksum = request.headers.get('X-Docker-Checksum')
|
||||||
|
@ -338,10 +342,12 @@ def put_image_json(namespace, repository, image_id):
|
||||||
# We cleanup any old checksum in case it's a retry after a fail
|
# We cleanup any old checksum in case it's a retry after a fail
|
||||||
store.remove(store.image_checksum_path(namespace, repository, image_id))
|
store.remove(store.image_checksum_path(namespace, repository, image_id))
|
||||||
if image_id != data['id']:
|
if image_id != data['id']:
|
||||||
abort(400, 'JSON data contains invalid id for image: %(image_id)s', image_id=image_id)
|
abort(400, 'JSON data contains invalid id for image: %(image_id)s',
|
||||||
|
image_id=image_id)
|
||||||
|
|
||||||
parent_id = data.get('parent')
|
parent_id = data.get('parent')
|
||||||
if parent_id and not store.exists(store.image_json_path(namespace, repository, parent_id)):
|
if (parent_id and not
|
||||||
|
store.exists(store.image_json_path(namespace, repository, parent_id))):
|
||||||
abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s',
|
abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s',
|
||||||
image_id=image_id, parent_id=parent_id)
|
image_id=image_id, parent_id=parent_id)
|
||||||
|
|
||||||
|
|
16
util/http.py
16
util/http.py
|
@ -1,11 +1,12 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from app import mixpanel
|
from app import mixpanel
|
||||||
from flask import request, abort as flask_abort, make_response
|
from flask import request, abort as flask_abort, jsonify
|
||||||
from auth.auth import process_auth, extract_namespace_repo_from_session, get_authenticated_user, get_validated_token
|
from auth.auth import get_authenticated_user, get_validated_token
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_MESSAGE = {}
|
DEFAULT_MESSAGE = {}
|
||||||
DEFAULT_MESSAGE[400] = 'Invalid Request'
|
DEFAULT_MESSAGE[400] = 'Invalid Request'
|
||||||
DEFAULT_MESSAGE[401] = 'Unauthorized'
|
DEFAULT_MESSAGE[401] = 'Unauthorized'
|
||||||
|
@ -14,7 +15,8 @@ DEFAULT_MESSAGE[404] = 'Not Found'
|
||||||
DEFAULT_MESSAGE[409] = 'Conflict'
|
DEFAULT_MESSAGE[409] = 'Conflict'
|
||||||
|
|
||||||
def abort(status_code, message=None, **kwargs):
|
def abort(status_code, message=None, **kwargs):
|
||||||
message = str(message) % kwargs if message else DEFAULT_MESSAGE.get(status_code, '')
|
message = (str(message) % kwargs if message else
|
||||||
|
DEFAULT_MESSAGE.get(status_code, ''))
|
||||||
|
|
||||||
params = dict(request.view_args)
|
params = dict(request.view_args)
|
||||||
params.copy(kwargs)
|
params.copy(kwargs)
|
||||||
|
@ -27,11 +29,13 @@ def abort(status_code, message=None, **kwargs):
|
||||||
message = '%s (user: %s)' % (message, auth_user.username)
|
message = '%s (user: %s)' % (message, auth_user.username)
|
||||||
elif auth_token:
|
elif auth_token:
|
||||||
mixpanel.track(auth_token.core, 'http_error', params)
|
mixpanel.track(auth_token.core, 'http_error', params)
|
||||||
message = '%s (token: %s)' % (message, auth_token.friendly_name or auth_token.code)
|
message = '%s (token: %s)' % (message,
|
||||||
|
auth_token.friendly_name or auth_token.code)
|
||||||
|
|
||||||
# Log the abort.
|
# Log the abort.
|
||||||
logger.error('Error %s: %s. Arguments: %s' % (status_code, message, params))
|
logger.error('Error %s: %s. Arguments: %s' % (status_code, message, params))
|
||||||
|
resp = jsonify({'error': message})
|
||||||
|
resp.status_code = status_code
|
||||||
|
|
||||||
# Report the abort to the user.
|
# Report the abort to the user.
|
||||||
flask_abort(make_response(message, status_code, {}))
|
flask_abort(resp)
|
||||||
|
|
||||||
|
|
Reference in a new issue