Ejemplo n.º 1
0
    def test_error_value_as_data_value(self):
        ev = make_error_value_from_msgs(self.error_def, *self.multiple_messages)
        self.assertTrue(isinstance(ev, StructValue))
        self.assertEqual(self.error_name, ev.name)
        self.assertFalse(ev.get_field_names() is None)
        self.assertEqual(2, len(ev.get_field_names()))
        self.assertTrue('messages' in ev.get_field_names())

        msg_struct1 = StructValue('localizable_message')
        msg_struct1.set_field('id', StringValue(self.message1.id))
        msg_struct1.set_field('default_message',
                              StringValue(self.message1.def_msg))
        args_list = ListValue()
        args_list.add_all((StringValue(s) for s in self.message1.args))
        msg_struct1.set_field('args', args_list)
        msg_struct2 = StructValue('localizable_message')
        msg_struct2.set_field('id', StringValue(self.message2.id))
        msg_struct2.set_field('default_message',
                              StringValue(self.message2.def_msg))
        msg_struct2.set_field('args', ListValue())
        msg_struct3 = StructValue('localizable_message')
        msg_struct3.set_field('id', StringValue(self.message3.id))
        msg_struct3.set_field('default_message',
                              StringValue(self.message3.def_msg))
        msg_struct3.set_field('args', ListValue())
        messages = ListValue()
        messages.add_all([msg_struct1, msg_struct2, msg_struct3])
        expected_data_value = ev = make_error_value_from_msgs(self.error_def)
        expected_data_value.set_field('messages', messages)
        self.assertEqual(expected_data_value, ev)
Ejemplo n.º 2
0
    def _invoke_int(self, service_id, operation_id, input_value, ctx):
        """
        Internal implementation of invoke method

        :type  service_id: :class:`str`
        :param service_id: Service identifier
        :type  operation_id: :class:`str`
        :param operation_id: Operation identifier
        :type  input_value: :class:`vmware.vapi.data.value.StructValue`
        :param input_value: Method input parameters
        :type  ctx: :class:`vmware.vapi.core.ExecutionContext`
        :param ctx: Execution context for this method

        :rtype: :class:`vmware.vapi.core.MethodResult`
        :return: Result of the method invocation
        """
        # Check if the provider exists
        provider = self._service_id_map.get(service_id)
        if not provider:
            msg = message_factory.get_message(
                'vapi.method.input.invalid.interface', service_id)
            logger.error(msg)
            error_value = make_error_value_from_msgs(
                self._operation_not_found_def, msg)
            return MethodResult(error=error_value)

        # Continue the authentication chain only if the target service
        # is not in the local provider of this process. i.e. for only
        # remote calls
        if service_id not in self._local_service_ids:
            for processor in self._authn_chain_processors:
                ctx.security_context = processor.next_context(
                    ctx.security_context)

        # Actual method execution
        try:
            method_result = provider.invoke(service_id, operation_id,
                                            input_value, ctx)
            return method_result
        except Exception as e:
            stack_trace = traceback.format_exc()
            logger.error(
                'Service: %s, Operation: %s, input_value %s: exception: %s',
                service_id, operation_id, input_value, stack_trace)
            msg = message_factory.get_message('vapi.method.invoke.exception',
                                              str(e))
            error_value = make_error_value_from_msgs(
                self._internal_server_error_def, msg)
            method_result = MethodResult(error=error_value)
            return method_result
Ejemplo n.º 3
0
 def test_report_undeclared_error(self):
     msg = message_factory.get_message(
         'vapi.method.status.errors.invalid', not_found_error.name,
         str(method_id_dict[report_undeclared_error].get_name()))
     expected_error = make_error_value_from_msgs(internal_server_error_def,
                                                 *([msg, _msg]))
     self._test_method_failure(report_undeclared_error, expected_error)
Ejemplo n.º 4
0
 def invoke(self, service_id, operation_id, input, ctx):
     if operation_id == report_vapi_error:
         error_value = make_error_value_from_msgs(not_found_def, self.msg)
         return MethodResult(error=error_value)
     elif operation_id == report_vapi_success:
         return MethodResult(output=BooleanValue(True))
     elif operation_id == 'echo':
         msg = input.get_field('message')
         return MethodResult(output=msg)
     elif operation_id == 'echo_long_running':
         msg = input.get_field('message')
         return MethodResult(output=msg)
     elif operation_id == 'echo_long_running$task':
         return MethodResult(output=StringValue(str(uuid.uuid4())))
     else:
         error_value = make_error_value_from_msgs(operation_not_found_def,
                                                  self.msg)
         return MethodResult(error=error_value)
Ejemplo n.º 5
0
    def test_single_message_list_construction(self):
        ev = make_error_value_from_msgs(self.error_def, *self.single_message)

        self.assertEqual(self.error_name, ev.name)
        messages = ev.get_field('messages')
        self.assertEqual(len(self.single_message), len(messages))
        it = iter(messages)
        self.assertEqual(_make_struct_value_from_message(self.message1),
                         six.advance_iterator(it))
        self.assertRaises(StopIteration, lambda it: six.advance_iterator(it), it)
Ejemplo n.º 6
0
 def invoke(self, ctx, method_id, input_):
     name = method_id.get_name()
     self.counters[name] = self.counters.get(name, 0) + 1
     if name == veto_method_name:
         method_input = input_.get_field('operation_input')
         raise_error = method_input.get_field('raise')
         if raise_error.value:
             msg = Message('mockup.message.id', 'mockup error message')
             return MethodResult(
                 error=make_error_value_from_msgs(not_found_error_def, msg))
     return MethodResult(output=VoidValue())
Ejemplo n.º 7
0
    def _test_operation_not_found(self, interface_name, method_name, error,
                                  message_id, *args):
        ctx = ExecutionContext()
        expected_msg = message_factory.get_message(message_id, *args)
        expected_error_value = make_error_value_from_msgs(error, expected_msg)

        method_result = self.local_provider.invoke(interface_name, method_name,
                                                   StructValue(), ctx)

        self.assertEquals(None, method_result.output)
        self.assertEquals(expected_error_value, method_result.error)
Ejemplo n.º 8
0
    def check_for_unknown_fields(cls, value_type, value):
        """
        Check if the StructValues inside the input DataValue has any
        unknown fields

        :type  value_type: :class:`vmware.vapi.bindings.type.BindingType`
        :param value_type: Binding Type
        :type  value: :class:`vmware.vapi.data.value.DataValue`
        :param value: DataValue
        :rtype: :class:`vmware.vapi.data.value.ErrorValue` or ``None``
        :return: ErrorValue describing the unknown fields or None if no
                 unknown fields were found
        """
        if isinstance(value_type, ReferenceType):
            value_type = value_type.resolved_type

        if isinstance(value_type, DynamicStructType):
            pass
        elif isinstance(value_type, StructType):
            expected_field_names = value_type.get_field_names()
            unexpected_fields = set([  # pylint: disable=consider-using-set-comprehension
                field for field in value.get_field_names()
                if field not in expected_field_names
                and cls.is_set_optional_field(value.get_field(field))
            ])
            if unexpected_fields:
                msg = message_factory.get_message(
                    'vapi.data.structure.field.unexpected',
                    repr(unexpected_fields), value.name)
                logger.debug(msg)
                return make_error_value_from_msgs(cls._unexpected_input_def,
                                                  msg)
            for field in expected_field_names:
                field_value = value.get_field(field)
                field_type = value_type.get_field(field)
                error = ApiInterfaceSkeleton.check_for_unknown_fields(
                    field_type, field_value)
                if error:
                    return error
        elif isinstance(value_type, ListType):
            element_type = value_type.element_type
            if isinstance(element_type, (
                    ListType, OptionalType, StructType, ReferenceType)):
                for element in value:
                    error = ApiInterfaceSkeleton.check_for_unknown_fields(
                        element_type, element)
                    if error:
                        return error
        elif isinstance(value_type, OptionalType):
            if value.is_set():
                return ApiInterfaceSkeleton.check_for_unknown_fields(
                    value_type.element_type, value.value)
        return None
Ejemplo n.º 9
0
 def get_operations(self, service_id):
     service_info = self._service_data.get(service_id)
     if service_info:
         method_ids = service_info.get_definition().get_method_identifiers()
         return MethodResult(output=ListValue(values=[
             StringValue(method_id.get_name()) for method_id in method_ids
         ]))
     else:
         msg = message_factory.get_message(
             'vapi.introspection.operation.service.not_found', service_id)
         error_value = make_error_value_from_msgs(not_found_def, msg)
         return MethodResult(error=error_value)
Ejemplo n.º 10
0
 def get_service_info(self, service_id):
     provider = self._get_provider(service_id)
     if provider:
         ctx = ExecutionContext()
         struct_value = StructValue(name=OPERATION_INPUT,
                                    values={'id': StringValue(service_id)})
         return provider.invoke(Introspection.SERVICE_SVC, 'get',
                                struct_value, ctx)
     else:
         msg = message_factory.get_message(
             'vapi.introspection.operation.service.not_found', service_id)
         error_value = make_error_value_from_msgs(not_found_def, msg)
         return MethodResult(error=error_value)
Ejemplo n.º 11
0
    def test_invalid_input(self):
        ctx = ExecutionContext()
        expected_msg = message_factory.get_message('vapi.method.input.invalid')
        expected_error_value = make_error_value_from_msgs(
            invalid_argument_def, expected_msg)

        method_result = self.local_provider.invoke(
            service_id=raise_python_exception_id.get_interface_identifier(
            ).get_name(),
            operation_id=raise_python_exception_id.get_name(),
            input_value=IntegerValue(),
            ctx=ctx)

        self.assertEquals(None, method_result.output)
        self.assertEquals(expected_error_value, method_result.error)
Ejemplo n.º 12
0
 def get_operation_info(self, service_id, operation_id):
     service_info = self._service_data.get(service_id)
     if service_info:
         method_ids = service_info.get_definition().get_method_identifiers()
         operation_names = [
             method_id.get_name() for method_id in method_ids
         ]
         if operation_id in operation_names:
             method_def = service_info.get_method_definition(
                 MethodIdentifier(InterfaceIdentifier(service_id),
                                  operation_id))
             output = self._convert_method_def_to_data_value(method_def)
             return MethodResult(output=output)
         else:
             msg = message_factory.get_message(
                 'vapi.introspection.operation.not_found', operation_id,
                 service_id)
             error_value = make_error_value_from_msgs(not_found_def, msg)
             return MethodResult(error=error_value)
     else:
         msg = message_factory.get_message(
             'vapi.introspection.operation.service.not_found', service_id)
         error_value = make_error_value_from_msgs(not_found_def, msg)
         return MethodResult(error=error_value)
Ejemplo n.º 13
0
    def test_input_validation_failure(self):
        ctx = ExecutionContext()
        expected_msg0 = message_factory.get_message(
            'vapi.data.structure.field.invalid', 'param', OPERATION_INPUT)
        expected_msg1 = message_factory.get_message(
            'vapi.data.validate.mismatch', 'Integer', 'Structure')
        expected_error_value = make_error_value_from_msgs(
            invalid_argument_def, expected_msg0, expected_msg1)

        service_id = raise_python_exception_id.get_interface_identifier(
        ).get_name()
        operation_id = raise_python_exception_id.get_name()
        method_def = self.introspection.get_method(service_id, operation_id)
        input_value = method_def.get_input_definition().new_value()
        input_value.set_field(param_name, StructValue())
        method_result = self.local_provider.invoke(service_id=service_id,
                                                   operation_id=operation_id,
                                                   input_value=input_value,
                                                   ctx=ctx)

        self.assertEquals(None, method_result.output)
        self.assertEquals(expected_error_value, method_result.error)
Ejemplo n.º 14
0
    def _test_method_failure(self,
                             operation_id,
                             error,
                             message_id=None,
                             *args):
        ctx = ExecutionContext()
        method_id = method_id_dict[operation_id]
        service_id = method_id.get_interface_identifier().get_name()

        if isinstance(error, ErrorValue):
            expected_error_value = error
        else:
            msg = message_factory.get_message(message_id, *args)
            expected_error_value = make_error_value_from_msgs(error, msg)

        provider = self.local_provider
        method_def = self.introspection.get_method(service_id, operation_id)
        input_value = method_def.get_input_definition().new_value()
        input_value.set_field(param_name, IntegerValue(0))
        method_result = provider.invoke(service_id, operation_id, input_value,
                                        ctx)

        self.assertEquals(None, method_result.output)
        self.assertEquals(expected_error_value, method_result.error)
Ejemplo n.º 15
0
    def publish(self, accept=False):
        """
        Publish the temporary task info into task manager

        :type  accept: :class:`bool`
        :param accept: Accept task and return task id to client
        """
        msg_list = None
        published_info = self.task_manager.get_info(self.task_id)

        # Override the common info fields which can't be modified by providers
        self._override_api_info(published_info)

        if hasattr(self.info, 'error') and self.info.error is not None:
            err_type = self.info.error.get_binding_type()
            # Verify if the error set by provider is amongst the ones
            # defined in VMODL2, if not throw InternalServerError
            if (err_type not in self.error_types):
                msg_list = [
                    message_factory.get_message('vapi.task.invalid.error',
                                                err_type.name,
                                                self.info.operation)
                ]

        if hasattr(self.info, 'result') and self.info.result is not None:
            # Check if result type is Opaque or actual type
            res_type = self.info_type.get_binding_type().get_field('result')
            if isinstance(res_type.element_type.definition, OpaqueDefinition):
                result = None
                try:
                    result = TypeConverter.convert_to_vapi(
                        self.info.result, self.result_type.get_binding_type())
                except AttributeError:
                    try:
                        result = TypeConverter.convert_to_vapi(
                            self.info.result, self.result_type)
                    except CoreException:
                        msg_list = [
                            message_factory.get_message(
                                'vapi.task.invalid.result', self.info.result,
                                self.info.operation)
                        ]
                        self.info.result = None

                if msg_list is None:
                    self.info.result = result

        info = TypeConverter.convert_to_vapi(self.info,
                                             self.info_type.get_binding_type())

        if msg_list is not None:
            info.set_field('status', FAILED_STRING_VALUE)
            logger.error(msg_list[0])
            error = make_error_value_from_msgs(self._internal_server_error_def,
                                               *msg_list)
            info.set_field('error', OptionalValue(error))

        self.task_manager.set_info(self.task_id, info)

        if accept:
            event = get_event()
            event.set()
            clear_event()
            # Validate that description is set while accepting the task
            desc = self.info.description
            if desc is None or (not desc.id and not desc.default_message):
                msg = message_factory.get_message(
                    'vapi.data.structure.field.missing', self.info_type,
                    'description')
                logger.debug(msg)
                raise CoreException(msg)
Ejemplo n.º 16
0
    'com.vmware.vapi.std.errors.internal_server_error')
invalid_argument_def = make_std_error_def(
    'com.vmware.vapi.std.errors.invalid_argument')
not_found_error_def = make_std_error_def(
    'com.vmware.vapi.std.errors.not_found')
operation_not_found_def = make_std_error_def(
    'com.vmware.vapi.std.errors.operation_not_found')

error_values = ListValue([
    convert_data_def_to_data_value(internal_server_error_def),
    convert_data_def_to_data_value(invalid_argument_def),
    convert_data_def_to_data_value(operation_not_found_def)
])

_msg = Message('mockup.message.id', 'mockup error message')
not_found_error = make_error_value_from_msgs(not_found_error_def, _msg)

param_name = 'param'


class MockupApiInterface(ApiInterface):
    def __init__(self):
        pass

    def get_identifier(self):
        return interface_id

    def get_definition(self):
        return InterfaceDefinition(interface_id, [
            missing_input_definition_id, invalid_input_definition_id,
            missing_output_definition_id, invalid_output_definition_id,
Ejemplo n.º 17
0
    def __call__(self, request):
        """
        The implementation of WsgiApplication

        :type  request: :class:`werkzeug.wrappers.Request`
        :param request: Request object
        :rtype: :class:`werkzeug.wrappers.Response`
        :return: Response object
        """
        try:
            urls = self.rule_map.bind_to_environ(request.environ)
            endpoint, args = urls.match()
            if provider_wire_logger.isEnabledFor(logging.DEBUG):
                provider_wire_logger.debug('HTTP %s %s ', request.method,
                                           request.url)
                provider_wire_logger.debug('REQUEST HEADERS: %s',
                                           request.headers)
                provider_wire_logger.debug('REQUEST BODY: %s',
                                           request.get_data())
            if endpoint == JSONRPC:
                result, headers = self._handle_jsonrpc_call(request)
                response = Response(result)
                if headers:
                    response.headers = headers
            else:
                status, result, cookies, headers = self._handle_rest_call(
                    request, endpoint, args)
                response = Response(result)
                response.status_code = status
                if headers:
                    response.headers = headers
                if cookies:
                    path = self._rest_prefix
                    for k, v in six.iteritems(cookies):
                        response.set_cookie(k, v, path=path)
            response.content_type = JSON_CONTENT_TYPE
            if provider_wire_logger.isEnabledFor(logging.DEBUG):
                provider_wire_logger.debug('RESPONSE STATUS: %s',
                                           response.status_code)
                provider_wire_logger.debug('RESPONSE HEADERS: %s',
                                           response.headers)
                provider_wire_logger.debug('RESPONSE BODY: %s',
                                           response.response)
            return response
        except HTTPException as e:
            try:
                internal_server_error_def = make_std_error_def(
                    'com.vmware.vapi.std.errors.invalid_request')
                msg = message_factory.get_message(
                    'vapi.method.invoke.exception',  # pylint: disable=line-too-long
                    e.description)
                error_value = make_error_value_from_msgs(
                    internal_server_error_def, msg)
                json_output = DataValueConverter.convert_to_json(error_value)
                response = e.get_response()
                response.set_data(json_output)
                response.headers['Content-Type'] = 'application/json'
                return response
            except Exception:
                # if there is error in serialize the error,
                # just return the original raw exception
                return e
Ejemplo n.º 18
0
    def invoke(self, ctx, method_id, input_value):
        """
        Invokes the specified method using the execution context and
        the input provided

        :type  ctx: :class:`vmware.vapi.core.ExecutionContext`
        :param ctx: Execution context for this method
        :type  input_value: :class:`vmware.vapi.data.value.StructValue`
        :param input_value: Method input parameters

        :rtype: :class:`vmware.vapi.core.MethodResult`
        :return: Result of the method invocation
        """
        op_info = self._operations.get(method_id.get_name())

        # Set execution context
        set_context(ctx)

        try:
            # input validators
            validators = op_info['input_value_validator_list']
            input_type = op_info['input_type']
            for validator in validators:
                msg_list = validator.validate(input_value, input_type)
                if msg_list:
                    error_value = make_error_value_from_msgs(
                        self._invalid_argument_def, *msg_list)
                    return MethodResult(error=error_value)
            error_value = ApiInterfaceSkeleton.check_for_unknown_fields(
                input_type, input_value)
            if error_value:
                return MethodResult(error=error_value)

            try:
                meth_args = TypeConverter.convert_to_python(
                    input_value, binding_type=input_type,
                    resolver=self._resolver)
            except CoreException as e:
                error_value = make_error_value_from_msgs(
                    self._invalid_argument_def, *e.messages)
                return MethodResult(error=error_value)

            method_name = Converter.canonical_to_pep(
                            get_non_task_operation_name(method_id.get_name()))
            method = getattr(self._impl, method_name)

            # If it's a task method then create a new thread to run provider
            # impl and return task id or result depending upon type of
            # invocation.
            if op_info['task_type'] != TaskType.NONE:
                meth_output, task_accepted = self._invoke_task_operation(
                    ctx, method_id, method, meth_args)

                if isinstance(meth_output, VapiError):
                    raise meth_output  # pylint: disable=raising-bad-type

                # In case of provider not accepting task throw an error.
                if task_accepted is False:
                    msg_list = [message_factory.get_message(
                                'vapi.bindings.skeleton.task.invalidstate')]
                    error_value = make_error_value_from_msgs(
                        self._internal_server_error_def,
                        *msg_list)
                    return MethodResult(error=error_value)
            else:
                meth_output = method(**meth_args)

            output_type = op_info['output_type']
            # output validators
            validators = op_info['output_validator_list']

            output = TypeConverter.convert_to_vapi(meth_output,
                                                   output_type)

            for validator in validators:
                msg_list = validator.validate(output, output_type)
                if msg_list:
                    error_value = make_error_value_from_msgs(
                        self._internal_server_error_def, *msg_list)
                    return MethodResult(error=error_value)
            result = MethodResult(output=output)
        except CoreException as e:
            logger.exception("Error in invoking %s - %s",
                             str(method_id), e)
            error_value = make_error_value_from_msgs(
                self._internal_server_error_def,
                *e.messages)
            result = MethodResult(error=error_value)
        except VapiError as e:
            exc_info = sys.exc_info()
            error_type = e.__class__.get_binding_type()
            try:
                error = TypeConverter.convert_to_vapi(e, error_type)
            except CoreException as ce:
                logger.error('Failed to convert %s to error type %s because %s',
                             e, error_type.name,
                             ' because '.join((e.def_msg for e in ce.messages)),
                             exc_info=exc_info)
                raise
            result = MethodResult(error=error)
        finally:
            # Reset the execution context after the operation
            clear_context()

        return result
Ejemplo n.º 19
0
    def _invoke_int(self, service_id, operation_id, input_value, ctx):  # pylint: disable=R0911
        """
        Internal implementation of InvokeMethod

        :type  service_id: :class:`str`
        :param service_id: Service identifier
        :type  operation_id: :class:`str`
        :param operation_id: Operation identifier
        :type  ctx: :class:`vmware.vapi.core.ExecutionContext`
        :param ctx: Execution context for this method
        :type  input_value: :class:`vmware.vapi.data.value.StructValue`
        :param input_value: Method input parameters

        :rtype: :class:`vmware.vapi.core.MethodResult`
        :return: Result of the method invocation
        """
        # Step 0: Verify input types
        if (input_value and not (input_value.type == Type.STRUCTURE)):
            logger.error("Invalid inputs")
            error_value = make_error_value_from_msg_id(
                self._invalid_argument_def, 'vapi.method.input.invalid')
            return MethodResult(error=error_value)

        iface_id = InterfaceIdentifier(service_id)
        method_id = MethodIdentifier(iface_id, operation_id)

        # Step 1: Get method definition
        iface = self._service_map.get(service_id)
        if not iface:
            logger.error('Could not find service: %s', service_id)
            error_value = make_error_value_from_msg_id(
                self._operation_not_found_def,
                'vapi.method.input.invalid.interface', service_id)
            return MethodResult(error=error_value)

        method_def = iface.get_method_definition(method_id)
        if not method_def:
            logger.error("Could not find method %s", method_id.get_name())
            error_value = make_error_value_from_msg_id(
                self._operation_not_found_def,
                'vapi.method.input.invalid.method', method_id.get_name())
            return MethodResult(error=error_value)

        input_def = method_def.get_input_definition()
        if not isinstance(input_def, StructDefinition):
            error_value = make_error_value_from_msg_id(
                self._internal_server_error_def,
                'vapi.method.input.invalid.definition')
            return MethodResult(error=error_value)

        output_def = method_def.get_output_definition()
        if not isinstance(output_def, DataDefinition):
            error_value = make_error_value_from_msg_id(
                self._internal_server_error_def,
                'vapi.method.output.invalid.definition')
            return MethodResult(error=error_value)

        # Step 2: Validate input with input def
        input_def.complete_value(input_value)
        messages = input_def.validate(input_value)
        if messages:
            logger.error("Input validation failed for method %s",
                         method_id.get_name())
            error_value = make_error_value_from_msgs(
                self._invalid_argument_def, *messages)
            return MethodResult(error=error_value)

        # Step 3: Execute method
        method_result = iface.invoke(ctx, method_id, input_value)

        # Step 4: Validate output with output def or error against errors set
        if method_result.success():
            messages = output_def.validate(method_result.output)
            if messages:
                logger.error("Output validation failed for method %s",
                             method_id.get_name())
                error_value = make_error_value_from_msgs(
                    self._internal_server_error_def, *messages)
                return MethodResult(error=error_value)
        else:
            error_value = method_result.error
            messages = self._validate_error(error_value, method_def)
            if messages:
                new_error_value = make_error_value_from_error_value_and_msgs(
                    self._internal_server_error_def, error_value, *messages)
                return MethodResult(error=new_error_value)

        return method_result