diff --git a/compass/api/api.py b/compass/api/api.py index c8fff11b..a5619b40 100644 --- a/compass/api/api.py +++ b/compass/api/api.py @@ -18,6 +18,7 @@ import datetime import functools import logging import netaddr +import requests import simplejson as json from flask import flash @@ -48,6 +49,7 @@ from compass.db.api import user as user_api from compass.db.api import user_log as user_log_api from compass.utils import flags from compass.utils import logsetting +from compass.utils import setting_wrapper as setting from compass.utils import util @@ -2016,14 +2018,15 @@ def add_host_network(host_id): ) -@app.route("/hosts/networks", methods=['POST']) +@app.route("/hosts/networks", methods=['PUT']) @log_user_action @login_required -def add_host_networks(): +def update_host_networks(): """add host networks.""" data = _get_request_data_as_list() return utils.make_json_response( - 200, host_api.add_host_networks(current_user, data) + 200, host_api.add_host_networks( + current_user, data) ) @@ -2175,6 +2178,121 @@ def take_host_action(host_id): ) +def _get_headers(*keys): + headers = {} + for key in keys: + if key in request.headers: + headers[key] = request.headers[key] + return headers + + +def _get_response_json(response): + try: + return response.json() + except ValueError: + return response.text + + +@app.route("/proxy/", methods=['GET']) +@log_user_action +@login_required +def proxy_get(url): + """proxy url.""" + headers = _get_headers( + 'Content-Type', 'Accept-Encoding', + 'Content-Encoding', 'Accept', 'User-Agent', + 'Content-MD5', 'Transfer-Encoding', app.config['AUTH_HEADER_NAME'], + 'Cookie' + ) + response = requests.get( + '%s/%s' % (setting.PROXY_URL_PREFIX, url), + params=_get_request_args(), + headers=headers, + stream=True + ) + logging.debug( + 'proxy %s response: %s', + url, response.text + ) + return utils.make_json_response( + response.status_code, _get_response_json(response) + ) + + +@app.route("/proxy/", methods=['POST']) +@log_user_action +@login_required +def proxy_post(url): + """proxy url.""" + headers = _get_headers( + 'Content-Type', 'Accept-Encoding', + 'Content-Encoding', 'Accept', 'User-Agent', + 'Content-MD5', 'Transfer-Encoding', + 'Cookie' + ) + response = requests.post( + '%s/%s' % (setting.PROXY_URL_PREFIX, url), + data=request.data, + headers=headers + ) + logging.debug( + 'proxy %s response: %s', + url, response.text + ) + return utils.make_json_response( + response.status_code, _get_response_json(response) + ) + + +@app.route("/proxy/", methods=['PUT']) +@log_user_action +@login_required +def proxy_put(url): + """proxy url.""" + headers = _get_headers( + 'Content-Type', 'Accept-Encoding', + 'Content-Encoding', 'Accept', 'User-Agent', + 'Content-MD5', 'Transfer-Encoding', + 'Cookie' + ) + response = requests.put( + '%s/%s' % (setting.PROXY_URL_PREFIX, url), + data=request.data, + headers=headers + ) + logging.debug( + 'proxy %s response: %s', + url, response.text + ) + return utils.make_json_response( + response.status_code, _get_response_json(response) + ) + + +@app.route("/proxy/", methods=['DELETE']) +@log_user_action +@login_required +def proxy_delete(url): + """proxy url.""" + headers = _get_headers( + 'Content-Type', 'Accept-Encoding', + 'Content-Encoding', 'Accept', 'User-Agent', + 'Content-MD5', 'Transfer-Encoding', + 'Cookie' + ) + response = requests.delete( + '%s/%s' % (setting.PROXY_URL_PREFIX, url), + headers=headers + ) + logging.debug( + 'proxy %s response: %s', + url, response.text + ) + return utils.make_json_response( + response.status_code, _get_response_json(response) + ) + + def init(): logging.info('init flask') database.init() diff --git a/compass/api/exception_handler.py b/compass/api/exception_handler.py index 5bb4c080..a9001394 100644 --- a/compass/api/exception_handler.py +++ b/compass/api/exception_handler.py @@ -27,6 +27,9 @@ class HTTPException(Exception): self.traceback = traceback.format_exc() self.status_code = status_code + def to_dict(self): + return {'message': str(self)} + class ItemNotFound(HTTPException): """Define the exception for referring non-existing object.""" @@ -78,8 +81,11 @@ class ConflictObject(HTTPException): @app.errorhandler(Exception) def handle_exception(error): - response = {'message': str(error)} - if hasattr(error, 'traceback'): + if hasattr(error, 'to_dict'): + response = error.to_dict() + else: + response = {'message': str(error)} + if app.debug and hasattr(error, 'traceback'): response['traceback'] = error.traceback status_code = 400 diff --git a/compass/db/api/host.py b/compass/db/api/host.py index 016d37ea..ff4bafb4 100644 --- a/compass/db/api/host.py +++ b/compass/db/api/host.py @@ -539,22 +539,36 @@ def add_host_network( ) def add_host_networks( session, creator, - exception_when_existing=True, + exception_when_existing=False, data=[] ): """Create host networks.""" hosts = [] + failed_hosts = [] for host_data in data: host_id = host_data['host_id'] networks = host_data['networks'] host_networks = [] - hosts.append({'host_id': host_id, 'networks': host_networks}) + failed_host_networks = [] for network in networks: - host_networks.append(_add_host_network( - session, creator, host_id, exception_when_existing, - **network - )) - return hosts + try: + host_networks.append(_add_host_network( + session, creator, host_id, exception_when_existing, + **network + )) + except exception.DatabaseException as error: + logging.exception(error) + failed_host_networks.append(network) + if host_networks: + hosts.append({'host_id': host_id, 'networks': host_networks}) + if failed_host_networks: + failed_hosts.append({ + 'host_id': host_id, 'networks': failed_host_networks + }) + return { + 'hosts': hosts, + 'failed_hosts': failed_hosts + } @utils.supported_filters( diff --git a/compass/db/exception.py b/compass/db/exception.py index 263a7b18..b9595a26 100644 --- a/compass/db/exception.py +++ b/compass/db/exception.py @@ -22,6 +22,9 @@ class DatabaseException(Exception): self.traceback = traceback.format_exc() self.status_code = 400 + def to_dict(self): + return {'message': str(self)} + class RecordNotExists(DatabaseException): """Define the exception for referring non-existing object in DB.""" @@ -82,3 +85,26 @@ class InvalidResponse(DatabaseException): def __init__(self, message): super(InvalidResponse, self).__init__(message) self.status_code = 400 + + +class MultiDatabaseException(DatabaseException): + """Define the exception composites with multi exceptions.""" + def __init__(self, exceptions): + super(MultiDatabaseException, self).__init__('multi exceptions') + self.exceptions = exceptions + self.status_code = 400 + + @property + def traceback(self): + tracebacks = [] + for exception in self.exceptions: + tracebacks.append(exception.trackback) + + def to_dict(self): + dict_info = super(MultiDatabaseException, self).to_dict() + dict_info.update({ + 'exceptions': [ + exception.to_dict() for exception in self.exceptions + ] + }) + return dict_info diff --git a/compass/utils/setting_wrapper.py b/compass/utils/setting_wrapper.py index c9b2e933..a1db6a32 100644 --- a/compass/utils/setting_wrapper.py +++ b/compass/utils/setting_wrapper.py @@ -99,6 +99,8 @@ VALIDATOR_DIR = lazypy.delay( TMPL_DIR = lazypy.delay( lambda: os.path.join(CONFIG_DIR, 'templates') ) +PROXY_URL_PREFIX = 'http://10.145.81.205:5000' + if ( 'COMPASS_IGNORE_SETTING' in os.environ and os.environ['COMPASS_IGNORE_SETTING']