def test_set_info(self): service_uuid = str(uuid.uuid4()) task_id = self.task_manager.create_task(service_uuid, None, 'test.service', 'op', False) info_val = self.task_manager.get_info(task_id) info = TypeConverter.convert_to_python(info_val, Info.get_binding_type()) info.description = self.description progress = Progress() progress.total = 100 progress.completed = 10 progress.message = self.progress_msg info.progress = progress info.start_time = datetime.utcnow() info.status = Status.RUNNING info.cancelable = True self.task_manager.set_info(task_id, TypeConverter.convert_to_vapi(info, Info.get_binding_type())) result = self.task_manager.get_info(task_id) self.assertEqual(result.get_field('progress'), OptionalValue(TypeConverter.convert_to_vapi(progress, Progress.get_binding_type()))) self.assertEqual(result.get_field('cancelable'), BooleanValue(info.cancelable)) self.assertEqual(result.get_field('status'), StringValue('RUNNING'))
def _override_api_info(self, published_info): """ Override service and operation task info fields """ self.info.service = TypeConverter.convert_to_python( published_info.get_field('service'), StringType()) self.info.operation = TypeConverter.convert_to_python( published_info.get_field('operation'), StringType())
def _convert(self, dt, dt_str): dt_str = StringValue(dt_str) self.assertEqual( TypeConverter.convert_to_vapi( dt, self.typ, rest_converter_mode=RestConverter.SWAGGER_REST), dt_str) self.assertEqual( TypeConverter.convert_to_python( dt_str, self.typ, rest_converter_mode=RestConverter.SWAGGER_REST), dt)
def _initialize_common_info(self): """ Initialize common task info fields """ published_info = self.task_manager.get_info(self.task_id) self._override_api_info(published_info) self.info.cancelable = TypeConverter.convert_to_python( published_info.get_field('cancelable'), BooleanType()) desc = published_info.get_field('description') if desc is not None: self.info.description = TypeConverter.convert_to_python( desc, LocalizableMessage.get_binding_type()) self.info.status = TypeConverter.convert_to_python( published_info.get_field('status'), StringType())
def test_publish(self): info = self.task_handle.get_info() progress = Progress() progress.total = 100 progress.completed = 42 progress.message = self.progress_msg desc2 = LocalizableMessage(id='msg2', default_message='task1', args=[]) info.description = desc2 info.cancelable = False info.status = 'RUNNING' info.start_time = datetime.utcnow() info.progress = progress self.task_handle.publish() result = self.task_manager.get_info(self.task_id) self.assertEqual(result.get_field('status'), StringValue('RUNNING')) progress_val = StructValue('com.vmware.cis.task.progress') progress_val.set_field('total', IntegerValue(100)) progress_val.set_field('completed', IntegerValue(42)) progress_val.set_field( 'message', TypeConverter.convert_to_vapi( self.progress_msg, LocalizableMessage.get_binding_type())) self.assertEqual(result.get_field('progress'), OptionalValue(progress_val)) self.assertEqual(result.get_field('cancelable'), BooleanValue(False))
def get_published_info(self): """ Returns the current published task Info """ info = self.task_manager.get_info(self.task_id) converted_info = TypeConverter.convert_to_python( info, self.info_type.get_binding_type()) return converted_info
def test_basic(self): dt = datetime.datetime.utcnow() string_val = TypeConverter.convert_to_vapi(dt, self.typ) self.assertTrue(isinstance(string_val, StringValue)) dt_new = TypeConverter.convert_to_python(string_val, self.typ) self.assertTrue(isinstance(dt_new, datetime.datetime)) self.assertEqual(dt.year, dt_new.year) self.assertEqual(dt.month, dt_new.month) self.assertEqual(dt.day, dt_new.day) self.assertEqual(dt.hour, dt_new.hour) self.assertEqual(dt.minute, dt_new.minute) self.assertEqual(dt.second, dt_new.second) string_val_new = TypeConverter.convert_to_vapi(dt_new, self.typ) self.assertEqual(string_val, string_val_new)
def get_result(self): """ Returns task result :rtype: :class:`com.vmware.cis.tasks_client.Info` :return: Task Result """ return TypeConverter.convert_to_python(self.get_info().result, self.result_type)
def create_task(self, description, service_id, operation_id, cancelable, error_types, id_=None): """ Creates a task in task manager. :type description: :class:`com.vmware.vapi.std.LocalizableMessage` :param description: Task description. :type service_id: :class:`str` :param service_id: Service Id. :type operation_id: :class:`str` :param operation_id: Operation Id. :type cancelable: :class:`bool` :param cancelable: Is the task cancelable. :type error_types: :class:`list` of :class:`vmware.vapi.bindings.type.ReferenceType` :param error_types: Error definitions describing the errors this operation can report :type id_: :class:`str` :param id_: Base task id """ task_info = StructValue() if description is not None: task_info.set_field( 'description', TypeConverter.convert_to_vapi( description, LocalizableMessage.get_binding_type())) else: desc_value = StructValue() desc_value.set_field('id', StringValue()) desc_value.set_field('default_message', StringValue()) desc_value.set_field('args', ListValue()) task_info.set_field('description', desc_value) user = self._get_user_from_sec_ctx() if user is not None: task_info.set_field('user', StringValue(user)) task_info.set_field('service', StringValue(service_id)) task_info.set_field('operation', StringValue(operation_id)) task_info.set_field('cancelable', BooleanValue(True if cancelable else False)) task_info.set_field('status', PENDING_STRING_VALUE) base_id = id_ if id_ is not None else str(uuid.uuid4()) task_id = self._create_task_id(base_id, service_id) task_summary = TaskSummary(task_info, error_types) with self.lock: self.task_map.setdefault(task_id, task_summary) self._remove_expired_task() return task_id
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 """ 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 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: result = TypeConverter.convert_to_vapi( self.info.result, self.result_type) self.info.result = result info = TypeConverter.convert_to_vapi(self.info, self.info_type.get_binding_type()) 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 if (self.info.description is None or (not self.info.description.id and not self.info.description.default_message)): msg = message_factory.get_message( 'vapi.data.structure.field.missing', self.info_type, 'description') logger.debug(msg) raise CoreException(msg)
def get_result(self): """ Returns task result :rtype: :class:`com.vmware.cis.tasks_client.Info` :return: Task Result """ info = self.get_info() if hasattr(info, 'result'): return TypeConverter.convert_to_python(info.result, self.result_type) else: return None
def _initialize_common_info(self): """ Initialize common task info fields """ summary = self.task_manager.get_summary(self.task_id) published_info = summary.info self.error_types = summary.errors self._override_api_info(published_info) self.info.cancelable = TypeConverter.convert_to_python( published_info.get_field('cancelable'), BooleanType()) desc = published_info.get_field('description') if desc is not None: self.info.description = TypeConverter.convert_to_python( desc, LocalizableMessage.get_binding_type()) self.info.status = TypeConverter.convert_to_python( published_info.get_field('status'), StringType()) try: user = published_info.get_field('user') self.info.user = TypeConverter.convert_to_python( user, StringType()) except: # pylint: disable=W0702 pass
def create_task(self, provider_id, description, service_id, operation_id, cancelable, id_=None): """ Creates a task in task manager. :type provider_id: :class:`str` :param provider_id: Service UUID :type description: :class:`com.vmware.vapi.std.LocalizableMessage` :param description: Task description. :type service_id: :class:`str` :param service_id: Service Id. :type operation_id: :class:`str` :param operation_id: Operation Id. :type cancelable: :class:`bool` :param cancelable: Is the task cancelable. :type id_: :class:`str` :param id_: Base task id """ task_info = StructValue() if description is not None: task_info.set_field( 'description', TypeConverter.convert_to_vapi( description, LocalizableMessage.get_binding_type())) else: desc_value = StructValue() desc_value.set_field('id', StringValue()) desc_value.set_field('default_message', StringValue()) desc_value.set_field('args', ListValue()) task_info.set_field('description', desc_value) task_info.set_field('service', StringValue(service_id)) task_info.set_field('operation', StringValue(operation_id)) task_info.set_field('cancelable', BooleanValue(True if cancelable else False)) task_info.set_field('status', StringValue('PENDING')) base_id = id_ if id_ is not None else str(uuid.uuid4()) task_id = self._create_task_id(base_id, provider_id) with self.lock: self.task_map.setdefault(task_id, task_info) self._remove_expired_task() return task_id
def test_create_task(self): service_uuid = str(uuid.uuid4()) task_id = self.task_manager.create_task(service_uuid, self.description, 'test.service1', 'op', False) info = self.task_manager.get_info(task_id) self.assertIn(service_uuid, task_id) self.assertEqual(info.get_field('description'), TypeConverter.convert_to_vapi(self.description, LocalizableMessage.get_binding_type())) self.assertEqual(info.get_field('service'), StringValue('test.service1')) self.assertEqual(info.get_field('operation'), StringValue('op')) self.assertEqual(info.get_field('cancelable'), BooleanValue(False)) self.assertEqual(info.get_field('status'), StringValue('PENDING'))
def get_struct_value(self): """ Returns the corresponding StructValue for the VapiStruct class :rtype: :class:`vmware.vapi.data.value.StructValue` :return: StructValue for this VapiStruct """ # For dynamic structures if self._struct_value: return self._struct_value else: # For static structures import TypeConverter here since # otherwise it causes circular imports from vmware.vapi.bindings.converter import TypeConverter struct_value = TypeConverter.convert_to_vapi( py_val=self, binding_type=self._binding_type) return struct_value
def convert_to(self, cls): """ Convert the underlying StructValue to an instance of the provided class if possible. Conversion will be possible if the StructValue contains all the fields expected by the provided class and the type of the value in each fields matches the type of the field expected by the provided class. :type cls: :class:`vmware.vapi.data.value.StructValue` :param cls: The type to convert to :rtype: :class:'vmware.vapi.bindings.struct.VapiStruct' :return: The converted value """ # Import TypeConverter here since otherwise it causes circular imports from vmware.vapi.bindings.converter import TypeConverter return TypeConverter.convert_to_python( vapi_val=self.get_struct_value(), binding_type=cls.get_binding_type(), rest_converter_mode=self._rest_converter_mode)
def _convert(self, dt, dt_str): dt_str = StringValue(dt_str) self.assertEqual(TypeConverter.convert_to_vapi(dt, self.typ), dt_str) self.assertEqual(TypeConverter.convert_to_python(dt_str, self.typ), dt)
def test_utc_time_conversion(self): dt1 = datetime.datetime(2006, 11, 21, 16, 30, tzinfo=GMT1()) utc_dt = convert_to_utc(dt1) self.assertEqual(TypeConverter.convert_to_vapi(utc_dt, self.typ), StringValue('2006-11-21T15:30:00.000Z'))
def _convert(self, uri_string): self.assertEqual(TypeConverter.convert_to_vapi(uri_string, self.typ), StringValue(uri_string)) self.assertEqual( TypeConverter.convert_to_python(StringValue(uri_string), self.typ), uri_string)
def native_invoke(self, ctx, method_name, kwargs): """ Invokes the method corresponding to the given method name with the kwargs. In this method, python native values are converted to vAPI runtime values, operation is invoked and the result are converted back to python native values :type ctx: :class:`vmware.vapi.core.ExecutionContext` :param ctx: Execution context for this method :type method_name: :class:`str` :param method_name: Method name :type kwargs: :class:`dict` :param kwargs: arguments to be passed to the method :rtype: :class:`object` :return: Method result """ op_info = self._operations.get(method_name) if op_info is None: raise Exception('Could not find %s method in %s interface' % (method_name, str(self._iface_id))) # Convert input input_type = op_info['input_type'] data_val = TypeConverter.convert_to_vapi(kwargs, input_type, self._rest_converter_mode) # Validate input validators = op_info['input_value_validator_list'] for validator in validators: msg_list = validator.validate(data_val, input_type) raise_core_exception(msg_list) if OPID in ctx.application_context: logger.debug( 'opId: %s invoke: interface_id: %s, operation_name: %s', ctx.application_context[OPID], self._iface_id.get_name(), method_name) else: logger.debug('invoke: interface_id: %s, operation_name: %s', self._iface_id, method_name) # Invoke method_id = MethodIdentifier(self._iface_id, method_name) if self._use_rest: operation_rest_metadata = None if self._rest_metadata: operation_rest_metadata = self._rest_metadata.get(method_name) if operation_rest_metadata is None: msg = message_factory.get_message( 'vapi.bindings.stub.rest_metadata.unavailable') logger.debug(msg) raise CoreException(msg) else: if self._is_vapi_rest is not None and not self._is_vapi_rest: # If the rest format is not vapi, then the server # (OpenAPI based) will not be supporting json-rpc. msg = message_factory.get_message( 'vapi.bindings.stub.jsonrpc.unsupported') logger.debug(msg) raise CoreException(msg) method_result = self.invoke(ctx, method_id, data_val) # Validate output if method_result.success(): validators = op_info['output_validator_list'] output_type = op_info['output_type'] for validator in validators: msg_list = validator.validate(method_result.output, output_type) raise_core_exception(msg_list) # Convert output return TypeConverter.convert_to_python(method_result.output, output_type, self._config.resolver, self._rest_converter_mode) else: # Convert error errors = op_info['errors'] error_type = errors.get(method_result.error.name) if error_type is None: error_type = self._config.resolver.resolve( method_result.error.name) if error_type is None: logger.warning('Unable to convert unexpected vAPI error %s ' + 'to native Python exception', method_result.error.name) vapi_error = UnresolvedError(method_result.error) raise vapi_error raise TypeConverter.convert_to_python(method_result.error, # pylint: disable=E0702 error_type, self._config.resolver, self._rest_converter_mode)
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 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)