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)
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
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)
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)
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)
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())
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)
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
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)
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)
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)
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)
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)
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)
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)
'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,
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
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
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