def _invoke(self, service_id, operation_id, input_value, ctx, rest_metadata, # pylint: disable=W0613 is_vapi_rest): """ Invokes the specified method using the input value, execution context and rest metadata provided :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.DataValue` :param input_value: method input parameters :type ctx: :class:`vmware.vapi.core.ExecutionContext` :param ctx: execution context object :type rest_metadata: :class:`vmware.vapi.lib.rest.OperationRestMetadata` :param rest_metadata: Rest metadata for the operation :type is_vapi_rest: :class:`bool` :param is_vapi_rest: Whether the Rest json message format is VAPI Rest or not :rtype: :class:`vmware.vapi.core.MethodResult` :return: method result object """ http_method = rest_metadata.http_method (url_path, auth_headers, request_body_str, cookies) = \ RestSerializer.serialize_request(input_value, ctx, rest_metadata, is_vapi_rest) # Add headers # Accept header is needed because any operation can report an error and # hence could have a body. headers = { 'Accept': 'application/json', } if http_method not in [HTTPMethod.GET, HTTPMethod.HEAD]: # TODO Maybe add this as part of REST metadata headers['Content-Type'] = 'application/json' if auth_headers is not None: headers.update(auth_headers) request_logger.debug('_invoke: request url: %s', url_path) request_logger.debug('_invoke: request http method: %s', http_method) request_logger.debug('_invoke: request headers: %s', headers) request_logger.debug('_invoke: request body: %s', request_body_str) http_request = HTTPRequest(method=http_method, url_path=url_path, headers=headers, body=request_body_str, cookies=cookies) # TODO Add post processors #for processor in self.post_processors: # request_msg = processor.process(request_msg) http_response = self._http_provider.do_request(http_request) request_logger.debug( '_invoke: response status: %s', http_response.status) request_logger.debug('_invoke: response body: %s', http_response.body) method_result = RestSerializer.deserialize_response( http_response.status, http_response.body, is_vapi_rest) return method_result
def test_all_annotations(self): input_val = StructValue(name='operation-input', values={ 'spec_val': StructValue(name='spec', values={ 'string_val': StringValue('string1'), }), 'string_val_url': StringValue('string2'), 'action_val': StringValue('stop'), }) rest_metadata = OperationRestMetadata( http_method='POST', url_template='/foo/{stringValUrl}', request_body_parameter='spec_val', path_variables={'string_val_url': 'stringValUrl'}, query_parameters={'action_val': 'action'}) url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo/string2?action=stop' expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_query_params_optionals(self): input_val = StructValue(name='operation-input', values={ 'string_val': StringValue('string1'), 'action1_val': OptionalValue(value=StringValue('start')), 'action2_val': OptionalValue() }) rest_metadata = OperationRestMetadata(http_method='POST', url_template='/foo/bar', query_parameters={ 'action1_val': 'action1', 'action2_val': 'action2' }) url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo/bar?action1=start' expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_string_value(self): input_status = 200 input_response = '"vm-100"' expected_result = MethodResult(output=StringValue('vm-100')) actual_result = RestSerializer.deserialize_response( status=input_status, response_str=input_response, is_vapi_rest=False) self.assertEqual(expected_result.output, actual_result.output) self.assertEqual(expected_result.error, actual_result.error)
def test_successful_status_202(self): input_status = 202 input_response = '{"value":"vm-100"}' expected_result = MethodResult(output=StringValue('vm-100')) actual_result = RestSerializer.deserialize_response( status=input_status, response_str=input_response, is_vapi_rest=True) self.assertEqual(expected_result.output, actual_result.output) self.assertEqual(expected_result.error, actual_result.error)
def test_void_value(self): input_status = 200 input_response = '' expected_result = MethodResult(output=VoidValue()) actual_result = RestSerializer.deserialize_response( status=input_status, response_str=input_response, is_vapi_rest=True) self.assertEqual(expected_result.output, actual_result.output) self.assertEqual(expected_result.error, actual_result.error)
def test_empty_input_no_metadata(self): input_val = StructValue(name='operation-input', values={}) url_path, headers, actual_body, cookies = \ RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=None, is_vapi_rest=True) expected_body = '{}' expected_headers = {} self.assertIsNone(url_path) self.assertEqual(expected_headers, headers) self.assertIsNone(cookies) self.assertEqual(expected_body, actual_body)
def test_session_security_context(self): input_val = StructValue(name='operation-input', values={}) session_id = 'some-session-id' sec_ctx = create_session_security_context(session_id) _, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=ExecutionContext(security_context=sec_ctx), rest_metadata=None, is_vapi_rest=True) expected_body = '{}' expected_headers = {REST_SESSION_ID_KEY: session_id} self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_string_input(self): input_val = StructValue(name='operation-input', values={ 'string_val': StringValue('string1'), }) _, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=None, is_vapi_rest=True) expected_body = '{"string_val":"string1"}' expected_headers = {} self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_struct_value(self): input_status = 200 input_response = '{"id":"vm-100", "name":"Linux VM"}' expected_result = MethodResult(output=StructValue( values={ 'id': StringValue('vm-100'), 'name': StringValue('Linux VM') })) actual_result = RestSerializer.deserialize_response( status=input_status, response_str=input_response, is_vapi_rest=False) self.assertEqual(expected_result.output, actual_result.output) self.assertEqual(expected_result.error, actual_result.error)
def test_url_path_without_path_variable(self): input_val = StructValue(name='operation-input', values={ 'string_val': StringValue('string1'), }) rest_metadata = OperationRestMetadata(http_method='GET', url_template='/foo/bar', path_variables={}) url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo/bar' expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_username_security_context(self): input_val = StructValue(name='operation-input', values={}) user, password = '******', 'pwd' sec_ctx = create_user_password_security_context(user, password) _, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=ExecutionContext(security_context=sec_ctx), rest_metadata=None, is_vapi_rest=True) expected_body = '{}' if six.PY2: b64_credentials = base64.b64encode('%s:%s' % (user, password)) authorization_val = 'Basic %s' % b64_credentials else: b64_credentials = base64.b64encode( bytes('%s:%s' % (user, password), 'utf-8')) authorization_val = b'Basic ' + b64_credentials expected_headers = {'Authorization': authorization_val} self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_request_body_annotation(self): spec_val = StructValue(name='spec', values={ 'string_val': StringValue('string1'), }) input_val = StructValue(name='operation-input', values={'spec_val': spec_val}) rest_metadata = OperationRestMetadata( http_method='POST', url_template='/foo', request_body_parameter='spec_val') url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo' expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_not_found_error_value(self): input_status = 404 input_response = '{"type":"com.vmware.vapi.std.errors.not_found","value":{"messages":[{"args":["datacenter-21"],"default_message":"Datacenter with identifier \'datacenter-21\' does not exist.","id":"com.vmware.api.vcenter.datacenter.not_found"}]}}' msg_val = StructValue( values={ 'id': StringValue('com.vmware.api.vcenter.datacenter.not_found'), 'default_message': StringValue( 'Datacenter with identifier \'datacenter-21\' does not exist.' ), 'args': ListValue([StringValue('datacenter-21')]) }) error_val = ErrorValue('com.vmware.vapi.std.errors.not_found', {'messages': ListValue([msg_val])}) expected_result = MethodResult(error=error_val) logging.debug(expected_result) actual_result = RestSerializer.deserialize_response( status=input_status, response_str=input_response, is_vapi_rest=True) self.assertEqual(expected_result.output, actual_result.output) self.assertEqual(expected_result.error, actual_result.error)
def test_url_path_with_query_param_and_other_query_params(self): input_val = StructValue(name='operation-input', values={ 'string_val': StringValue('string1'), 'action2_val': StringValue('stop'), }) rest_metadata = OperationRestMetadata( http_method='POST', url_template='/foo/bar?action1=start', query_parameters={'action2_val': 'action2'}) url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_paths = [ '/foo/bar?action1=start&action2=stop', '/foo/bar?action2=stop&action1=start' ] expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertTrue(url_path in expected_url_paths) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def _invoke( self, service_id, operation_id, input_value, ctx, rest_metadata, # pylint: disable=W0613 is_vapi_rest): """ Invokes the specified method using the input value, execution context and rest metadata provided :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.DataValue` :param input_value: method input parameters :type ctx: :class:`vmware.vapi.core.ExecutionContext` :param ctx: execution context object :type rest_metadata: :class:`vmware.vapi.lib.rest.OperationRestMetadata` :param rest_metadata: Rest metadata for the operation :type is_vapi_rest: :class:`bool` :param is_vapi_rest: Whether the Rest json message format is VAPI Rest or not :rtype: :class:`vmware.vapi.core.MethodResult` :return: method result object """ http_method = rest_metadata.http_method (url_path, input_headers, request_body_str, cookies) = \ RestSerializer.serialize_request(input_value, ctx, rest_metadata, is_vapi_rest) # Add headers # Accept header is needed because any operation can report an error and # hence could have a body. headers = { HTTP_ACCEPT_HEADER: JSON_CONTENT_TYPE, HTTP_USER_AGENT_HEADER: get_user_agent(), } if input_headers is not None: headers.update(input_headers) if rest_metadata.content_type is not None: headers[HTTP_CONTENT_TYPE_HEADER] = rest_metadata.content_type elif http_method not in [HTTPMethod.GET, HTTPMethod.HEAD]: # TODO Maybe add this as part of REST metadata headers[HTTP_CONTENT_TYPE_HEADER] = JSON_CONTENT_TYPE request_logger.debug('_invoke: request url: %s', url_path) request_logger.debug('_invoke: request http method: %s', http_method) request_logger.debug('_invoke: request headers: %s', headers) request_logger.debug('_invoke: request body: %s', request_body_str) http_request = HTTPRequest(method=http_method, url_path=url_path, headers=headers, body=request_body_str, cookies=cookies) # TODO Add post processors #for processor in self.post_processors: # request_msg = processor.process(request_msg) http_response = self._http_provider.do_request(http_request) request_logger.debug('_invoke: response status: %s', http_response.status) request_logger.debug('_invoke: response body: %s', http_response.body) if ctx.runtime_data is not None and 'response_extractor' in ctx.runtime_data: # pylint: disable=line-too-long ctx.runtime_data.get('response_extractor').set_http_status(http_response.status) # pylint: disable=line-too-long ctx.runtime_data.get('response_extractor').set_http_headers(http_response.headers) # pylint: disable=line-too-long ctx.runtime_data.get('response_extractor').set_http_body(http_response.body) # pylint: disable=line-too-long ctx.runtime_data.get('response_extractor').set_http_method(http_method) # pylint: disable=line-too-long url = self._http_provider._base_url + url_path # pylint: disable=protected-access ctx.runtime_data.get('response_extractor').set_http_url(url) # pylint: disable=line-too-long method_result = RestSerializer.deserialize_response( http_response.status, http_response.body, is_vapi_rest) return method_result