コード例 #1
0
def _get_v35_plus_ovdc_url_data(method: str, tokens: list):
    """Parse tokens from url and http method to get v35 ovdc specific data.

    Returns a dictionary with operation and url data.

    :param shared_constants.RequestMethod method: http verb
    :param str[] tokens: http url

    :rtype: dict
    """
    num_tokens = len(tokens)
    if num_tokens == 5:
        if method == shared_constants.RequestMethod.GET:
            return {_OPERATION_KEY: CseOperation.V35_OVDC_LIST}
        raise cse_exception.MethodNotAllowedRequestError()
    if num_tokens == 6:
        if method == shared_constants.RequestMethod.PUT:
            return {
                _OPERATION_KEY: CseOperation.V35_OVDC_UPDATE,
                shared_constants.RequestKey.OVDC_ID: tokens[5]
            }
        if method == shared_constants.RequestMethod.GET:
            return {
                _OPERATION_KEY: CseOperation.V35_OVDC_INFO,
                shared_constants.RequestKey.OVDC_ID: tokens[5]
            }
        raise cse_exception.MethodNotAllowedRequestError()
コード例 #2
0
def _get_v35_plus_native_cluster_url_data(method: str, tokens: list):
    """Parse tokens from url and http method to get v35 native cluster data.

    Returns a dictionary with operation and url data.

    :param RequestMethod method: http verb
    :param str[] tokens: http url

    :rtype: dict
    """
    num_tokens = len(tokens)
    if num_tokens == 5:
        if method == shared_constants.RequestMethod.GET:
            return {_OPERATION_KEY: CseOperation.V35_NATIVE_CLUSTER_LIST}
        raise cse_exception.MethodNotAllowedRequestError()
コード例 #3
0
def process_request(message):
    """
    Determine the correct api handler to invoke and invoke it.

    The request URI, api version and HTTP verb are used to determine the
    request operation and the corresponding handler.

    Additionally support for payload verification, query param verification
    will be added in a later point of time.

    URL template matching is also performed to compute values of url template
    parameters. These computed values, request body and query params are all
    sent to handlers in form of a dictionary.

    :param dict message: message received over AMQP/MQTT bus representing the
        incoming REST request.

    :returns: response computed by the handler after processing the request
    """
    LOGGER.debug(f"Incoming request message: {json.dumps(message)}")

    api_version_header = _parse_accept_header(
        accept_header=message['headers'].get('Accept'))
    api_version = _get_api_version_from_accept_header(
        api_version_header=api_version_header)

    # Convert to upper case for matching the ENUM values
    method = RequestMethod(message['method'].upper())

    url = message['requestUri']
    url_tokens = url.split("/")
    # ignore the vcd host and /api in the url
    if len(url_tokens) > 2:
        url_tokens = url_tokens[2:]

    query_params = None
    if message['queryString']:
        query_params = dict(parse_qsl(message['queryString']))

    request_body = None
    # Should we do a content-type check? and allow only application/json content?  # noqa: E501
    # Process request body only for requests with HTTP verbs that allow body
    if method in [RequestMethod.POST,
                  RequestMethod.PUT,
                  RequestMethod.DELETE] and \
            len(message['body']) > 0:
        raw_body = base64.b64decode(message['body']).decode(
            sys.getfilesystemencoding())  # noqa: E501
        request_body = json.loads(raw_body)

    import container_service_extension.server.service as cse_service
    server_config = cse_service.Service().get_service_config()

    found = False
    operation = None
    handler_method = None
    url_data = {}
    for entry in CSE_REQUEST_DISPATCHER_LIST:
        if found:
            break
        if len(entry['url_tokens']) != len(url_tokens):
            continue

        url_matched = True
        for i in range(0, len(url_tokens)):
            token = entry['url_tokens'][i]
            if token.startswith("$"):
                url_data[token[1:]] = url_tokens[i]
            elif token.lower() != url_tokens[i].lower():
                url_matched = False
                url_data.clear()
                break

        if not url_matched:
            continue

        if method not in entry.keys():
            raise cse_exception.MethodNotAllowedRequestError()

        handlers = entry[method]
        matched_handler = None
        supported_api_versions = []
        for versions in handlers.keys():
            supported_api_versions.extend(list(versions))
            if api_version in versions or '*' in versions:
                matched_handler = handlers[versions]
                break

        if not matched_handler:
            raise cse_exception.NotAcceptableRequestError(
                error_message="Invalid api version specified. Expected "
                f"api version '{supported_api_versions}'.")

        required_feature_flags = matched_handler.get('feature_flags', {})
        feature_flags_satisfied = True
        for feature_flag in required_feature_flags:
            value = server_config['feature_flags'].get(feature_flag, False)
            if not value:
                LOGGER.debug("Url matched but failed to satisfy feature "
                             f"flag {feature_flag}")
                feature_flags_satisfied = False
                break

        if feature_flags_satisfied:
            operation = matched_handler['operation']
            handler_method = matched_handler['handler']

            # ToDo: Extra validation based on allowed query params, content type etc.  # noqa: E501
            found = True
        else:
            break

    if not found:
        raise cse_exception.NotFoundRequestError()

    # /system operations are excluded from these checks
    if operation not in (CseOperation.SYSTEM_INFO, CseOperation.SYSTEM_UPDATE):
        if not cse_service.Service().is_running():
            raise cse_exception.BadRequestError(
                error_message='CSE service is disabled. '
                'Contact the System Administrator.')

    # create request data dict from incoming message data
    request_data = {}

    # update request data dict with query params data
    if query_params:
        request_data[RequestKey.QUERY_PARAMS] = query_params
        LOGGER.debug(f"query parameters: {query_params}")

    # update request_data with request_body
    if request_body:
        request_data[RequestKey.INPUT_SPEC] = request_body
        LOGGER.debug(f"request body: {request_body}")

    # update request_data with url template param key-values
    request_data.update(url_data)
    request_data['url'] = url

    # extract out the authorization token
    tenant_auth_token = message['headers'].get('x-vcloud-authorization')
    is_jwt_token = False
    auth_header = message['headers'].get('Authorization')
    if auth_header:
        tokens = auth_header.split(" ")
        if len(tokens) == 2 and tokens[0].lower() == 'bearer':
            tenant_auth_token = tokens[1]
            is_jwt_token = True

    # create operation context
    operation_ctx = ctx.OperationContext(tenant_auth_token,
                                         is_jwt=is_jwt_token,
                                         request_id=message['id'])

    try:
        body_content = handler_method(request_data, operation_ctx)
    finally:
        if not operation_ctx.is_async:
            operation_ctx.end()

    if not isinstance(body_content, (list, dict)):
        body_content = {RESPONSE_MESSAGE_KEY: str(body_content)}
    response = {
        'status_code': operation.ideal_response_code,
        'body': body_content,
    }
    LOGGER.debug(f"Outgoing response: {str(response)}")
    return response
コード例 #4
0
def _get_legacy_url_data(method: str, url: str, api_version: str):
    tokens = url.split('/')
    num_tokens = len(tokens)

    operation_type = tokens[3].lower()
    if operation_type.endswith('s'):
        operation_type = operation_type[:-1]

    if operation_type == OperationType.NATIVE_CLUSTER:
        if api_version not in (VcdApiVersion.VERSION_33.value,
                               VcdApiVersion.VERSION_35.value):
            raise cse_exception.NotFoundRequestError()
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.NATIVE_CLUSTER_LIST}
            raise cse_exception.MethodNotAllowedRequestError()

    if operation_type == OperationType.CLUSTER:
        if api_version not in (VcdApiVersion.VERSION_33.value,
                               VcdApiVersion.VERSION_34.value):
            raise cse_exception.NotFoundRequestError()

        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.CLUSTER_LIST}
            if method == shared_constants.RequestMethod.POST:
                return {_OPERATION_KEY: CseOperation.CLUSTER_CREATE}
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 5:
            if method == shared_constants.RequestMethod.GET:
                return {
                    _OPERATION_KEY: CseOperation.CLUSTER_INFO,
                    shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                }
            if method == shared_constants.RequestMethod.PUT:
                return {
                    _OPERATION_KEY: CseOperation.CLUSTER_RESIZE,
                    shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                }
            if method == shared_constants.RequestMethod.DELETE:
                return {
                    _OPERATION_KEY: CseOperation.CLUSTER_DELETE,
                    shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                }
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 6:
            if method == shared_constants.RequestMethod.GET:
                if tokens[5] == 'config':
                    return {
                        _OPERATION_KEY: CseOperation.CLUSTER_CONFIG,
                        shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                    }
                if tokens[5] == 'upgrade-plan':
                    return {
                        _OPERATION_KEY: CseOperation.CLUSTER_UPGRADE_PLAN,
                        shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                    }
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 7:
            if method == shared_constants.RequestMethod.POST:
                if tokens[5] == 'action' and tokens[6] == 'upgrade':
                    return {
                        _OPERATION_KEY: CseOperation.CLUSTER_UPGRADE,
                        shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                    }
            raise cse_exception.MethodNotAllowedRequestError()
    elif operation_type == OperationType.NODE:
        if api_version not in (VcdApiVersion.VERSION_33.value,
                               VcdApiVersion.VERSION_34.value):
            raise cse_exception.NotFoundRequestError()

        if num_tokens == 4:
            if method == shared_constants.RequestMethod.POST:
                return {_OPERATION_KEY: CseOperation.NODE_CREATE}
            if method == shared_constants.RequestMethod.DELETE:
                return {_OPERATION_KEY: CseOperation.NODE_DELETE}
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 5:
            if method == shared_constants.RequestMethod.GET:
                return {
                    _OPERATION_KEY: CseOperation.NODE_INFO,
                    shared_constants.RequestKey.NODE_NAME: tokens[4]
                }
            raise cse_exception.MethodNotAllowedRequestError()
    elif operation_type == OperationType.OVDC:
        if api_version not in (VcdApiVersion.VERSION_33.value,
                               VcdApiVersion.VERSION_34.value):
            raise cse_exception.NotFoundRequestError()

        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.OVDC_LIST}
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 5:
            if method == shared_constants.RequestMethod.GET:
                return {
                    _OPERATION_KEY: CseOperation.OVDC_INFO,
                    shared_constants.RequestKey.OVDC_ID: tokens[4]
                }
            if method == shared_constants.RequestMethod.PUT:
                return {
                    _OPERATION_KEY: CseOperation.OVDC_UPDATE,
                    shared_constants.RequestKey.OVDC_ID: tokens[4]
                }
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 6 and tokens[5] == 'compute-policies':
            if method == shared_constants.RequestMethod.GET:
                return {
                    _OPERATION_KEY: CseOperation.OVDC_COMPUTE_POLICY_LIST,
                    shared_constants.RequestKey.OVDC_ID: tokens[4]
                }
            if method == shared_constants.RequestMethod.PUT:
                return {
                    _OPERATION_KEY: CseOperation.OVDC_COMPUTE_POLICY_UPDATE,
                    shared_constants.RequestKey.OVDC_ID: tokens[4]
                }
            raise cse_exception.MethodNotAllowedRequestError()
    elif operation_type == OperationType.ORG_VDCS:
        if api_version not in (VcdApiVersion.VERSION_33.value,
                               VcdApiVersion.VERSION_34.value):
            raise cse_exception.NotFoundRequestError()
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.ORG_VDC_LIST}
            raise cse_exception.NotFoundRequestError()
    elif operation_type == OperationType.SYSTEM:
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.SYSTEM_INFO}
            if method == shared_constants.RequestMethod.PUT:
                return {_OPERATION_KEY: CseOperation.SYSTEM_UPDATE}
            raise cse_exception.MethodNotAllowedRequestError()
    elif operation_type == OperationType.TEMPLATE:
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.TEMPLATE_LIST}
            raise cse_exception.MethodNotAllowedRequestError()

    raise cse_exception.NotFoundRequestError()
コード例 #5
0
def _get_v35_plus_cluster_url_data(method: str, tokens: list,
                                   api_version: str) -> dict:  # noqa: E501
    """Parse tokens from url and http method to get v35 cluster specific data.

    Returns a dictionary with operation and url data.

    :param RequestMethod method: http verb
    :param str[] tokens: http url
    :param str api_version: API version of the request

    :rtype: dict
    """
    num_tokens = len(tokens)
    if num_tokens == 5:
        if method == shared_constants.RequestMethod.GET:
            return {_OPERATION_KEY: CseOperation.V35_CLUSTER_LIST}
        if method == shared_constants.RequestMethod.POST:
            return {_OPERATION_KEY: CseOperation.V35_CLUSTER_CREATE}
        raise cse_exception.MethodNotAllowedRequestError()
    if num_tokens == 6:
        if method == shared_constants.RequestMethod.GET:
            return {
                _OPERATION_KEY: CseOperation.V35_CLUSTER_INFO,
                shared_constants.RequestKey.CLUSTER_ID: tokens[5]
            }
        if method == shared_constants.RequestMethod.PUT:
            url_data = {shared_constants.RequestKey.CLUSTER_ID: tokens[5]}
            if api_version == VcdApiVersion.VERSION_35.value:
                url_data[_OPERATION_KEY] = CseOperation.V35_CLUSTER_RESIZE
            else:
                url_data[_OPERATION_KEY] = CseOperation.V36_CLUSTER_UPDATE
            return url_data
        if method == shared_constants.RequestMethod.DELETE:
            return {
                _OPERATION_KEY: CseOperation.V35_CLUSTER_DELETE,
                shared_constants.RequestKey.CLUSTER_ID: tokens[5]
            }
        raise cse_exception.MethodNotAllowedRequestError()
    if num_tokens == 7:
        if method == shared_constants.RequestMethod.GET:
            if tokens[6] == 'config':
                return {
                    _OPERATION_KEY: CseOperation.V35_CLUSTER_CONFIG,
                    shared_constants.RequestKey.CLUSTER_ID: tokens[5]
                }
            if tokens[6] == 'upgrade-plan':
                return {
                    _OPERATION_KEY:
                    CseOperation.V35_CLUSTER_UPGRADE_PLAN,  # noqa: E501
                    shared_constants.RequestKey.CLUSTER_ID: tokens[5]
                }
            if tokens[6] == 'acl':
                return {
                    _OPERATION_KEY: CseOperation.V35_CLUSTER_ACL_LIST,
                    shared_constants.RequestKey.CLUSTER_ID: tokens[5]
                }
        if method == shared_constants.RequestMethod.PUT:
            if tokens[6] == 'acl':
                return {
                    _OPERATION_KEY: CseOperation.V35_CLUSTER_ACL_UPDATE,
                    shared_constants.RequestKey.CLUSTER_ID: tokens[5]
                }
        raise cse_exception.MethodNotAllowedRequestError()
    if num_tokens == 8:
        if method == shared_constants.RequestMethod.POST:
            if tokens[6] == 'action' and tokens[7] == 'upgrade':
                # TODO create a constant in pyvcloud.
                if api_version == '36.0':
                    raise cse_exception.MethodNotAllowedRequestError()
                return {
                    _OPERATION_KEY: CseOperation.V35_CLUSTER_UPGRADE,
                    shared_constants.RequestKey.CLUSTER_ID: tokens[5]
                }
        if method == shared_constants.RequestMethod.DELETE:
            if tokens[6] == 'nfs':
                return {
                    _OPERATION_KEY: CseOperation.V35_NODE_DELETE,
                    shared_constants.RequestKey.CLUSTER_ID: tokens[5],
                    shared_constants.RequestKey.NODE_NAME: tokens[7]
                }
        raise cse_exception.MethodNotAllowedRequestError()
コード例 #6
0
def _get_pks_url_data(method: str, url: str):
    """Parse url and http method to get desired PKS operation and url data.

    Returns a data dictionary with 'operation' key and also any relevant url
    data.

    :param shared_constants.RequestMethod method:
    :param str url:

    :rtype: dict
    """
    tokens = url.split('/')
    num_tokens = len(tokens)

    operation_type = tokens[3].lower()
    if operation_type.endswith('s'):
        operation_type = operation_type[:-1]

    if operation_type == OperationType.CLUSTER:
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.PKS_CLUSTER_LIST}
            if method == shared_constants.RequestMethod.POST:
                return {_OPERATION_KEY: CseOperation.PKS_CLUSTER_CREATE}
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 5:
            if method == shared_constants.RequestMethod.GET:
                return {
                    _OPERATION_KEY: CseOperation.PKS_CLUSTER_INFO,
                    shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                }
            if method == shared_constants.RequestMethod.PUT:
                return {
                    _OPERATION_KEY: CseOperation.PKS_CLUSTER_RESIZE,
                    shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                }
            if method == shared_constants.RequestMethod.DELETE:
                return {
                    _OPERATION_KEY: CseOperation.PKS_CLUSTER_DELETE,
                    shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                }
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 6:
            if method == shared_constants.RequestMethod.GET:
                if tokens[5] == 'config':
                    return {
                        _OPERATION_KEY: CseOperation.PKS_CLUSTER_CONFIG,
                        shared_constants.RequestKey.CLUSTER_NAME: tokens[4]
                    }
            raise cse_exception.MethodNotAllowedRequestError()
    elif operation_type == OperationType.OVDC:
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.PKS_OVDC_LIST}
            raise cse_exception.MethodNotAllowedRequestError()
        if num_tokens == 5:
            if method == shared_constants.RequestMethod.GET:
                return {
                    _OPERATION_KEY: CseOperation.PKS_OVDC_INFO,
                    shared_constants.RequestKey.OVDC_ID: tokens[4]
                }
            if method == shared_constants.RequestMethod.PUT:
                return {
                    _OPERATION_KEY: CseOperation.PKS_OVDC_UPDATE,
                    shared_constants.RequestKey.OVDC_ID: tokens[4]
                }
            raise cse_exception.MethodNotAllowedRequestError()
    elif operation_type == OperationType.ORG_VDCS:
        if num_tokens == 4:
            if method == shared_constants.RequestMethod.GET:
                return {_OPERATION_KEY: CseOperation.PKS_ORG_VDC_LIST}
            raise cse_exception.MethodNotAllowedRequestError()
    raise cse_exception.NotFoundRequestError()