def visit_struct(self, typ): """ Visit StructValue :type typ: :class:`vmware.vapi.bindings.type.StructType` :param typ: Binding type of the value """ in_value = self._in_value out_value = {} typ_field_names = typ.get_field_names() value_field_names = in_value.get_field_names() for field_name in typ_field_names: if typ.binding_class: pep_name = typ.binding_class._get_pep_name(field_name) # pylint: disable=W0212 else: pep_name = Converter.canonical_to_pep(field_name) field_type = typ.get_field(field_name) # When the request is converted from DataValue to Native value # on the server side: # - if the client - server version matches: we wont hit this case # - if new client talks to old server, runtime would have # raised InvalidArgument error if there are unexpected optional # fields # - if old client talks to new server, runtime adds the missing # optional fields, so we wont hit this case # # When the response is converted from DataValue to Native value # on the client side: # - if the client - server version matches: we wont hit this case # - if new client talks to old server, client bindings should # tolerate the absence of expected optional properties. So, # we have to set it to None! # - if old client talks to new server, we will visit all the known # fields here and the unexpected fields are added to the # VapiStruct object if ((isinstance(field_type, OptionalType) or self._allow_skip_struct_fields) and not in_value.has_field(field_name)): out_value[pep_name] = None else: out_value[pep_name] = self._visit_struct_field( in_value.get_field(field_name), field_type) self._in_value = in_value struct_class = typ.binding_class if struct_class is not None: struct_class.validate_struct_value(self._in_value) self._out_value = struct_class(**out_value) # Fields present in struct value but not in struct binding type. extra_field_names = set(value_field_names) - set(typ_field_names) if extra_field_names: extra_fields = {} for field_name in extra_field_names: extra_fields[field_name] = in_value.get_field(field_name) self._out_value._set_extra_fields(extra_fields) # pylint: disable=E1103,W0212 else: self._out_value = out_value
def _get_pep_name(cls, canonical_name): """ Return the pep name for the provided canonical name :rtype: :class:`str` :return: Pep name used in the binding """ if (cls._canonical_to_pep_names and canonical_name in cls._canonical_to_pep_names): return cls._canonical_to_pep_names[canonical_name] else: return Converter.canonical_to_pep(canonical_name)
def _pepify_args(meth_args): """ Converts all the keys of given keyword arguments into PEP8 standard names :type meth_args: :class:`dict` :param meth_args: The keyword arguments to be converted :rtype: :class:`dict` :return: The converted keyword arguments """ new_args = {} for k, v in six.iteritems(meth_args): new_args[Converter.canonical_to_pep(k)] = v return new_args
def _visit_python_dict(self, typ): """ Visit an instance of Python native dictionary :type typ: :class:`vmware.vapi.bindings.type.StructType` :param typ: Binding type of the value :rtype: :class:`vmware.vapi.data.value.DataValue` :return: vAPI Data value """ in_value = self._in_value out_value = typ.definition.new_value() field_names = typ.get_field_names() for field_name in field_names: field_type = typ.get_field(field_name) try: if typ.binding_class: # pylint: disable=W0212 pep_name = typ.binding_class._get_pep_name(field_name) else: pep_name = Converter.canonical_to_pep(field_name) self._in_value = in_value[pep_name] except KeyError: if isinstance(field_type, OptionalType): # If the field is optional, then tolerate # the absence of it in the dictionary self._in_value = None else: msg = message_factory.get_message( 'vapi.bindings.typeconverter.dict.missing.key', pep_name) logger.debug(msg) raise CoreException(msg) self.visit(field_type) out_value.set_field(field_name, self._out_value) self._in_value = in_value self._out_value = out_value
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