Beispiel #1
0
 def __set_obj_attribute(self, obj, property_path, param_value, param_name):
     """
     Recursively set object properties
     :param obj: The object on which to set a property value.
     :param property_path: A list of property names in the form of strings.
     :param param_value: The value to set.
     :return: The original object.
     """
     while len(property_path) > 0:
         raw_prop_name = property_path.pop(0)
         prop_name = PYTHON_KEYWORD_MAPPING.get(raw_prop_name,
                                                raw_prop_name)
         prop_kind = obj.swagger_types[prop_name]
         if prop_kind in PRIMITIVES:
             try:
                 setattr(obj, prop_name, param_value)
             except ValueError as exc:
                 msg = str(exc)
                 if param_value is None and 'None' in msg:
                     pass
                 else:
                     raise KubernetesException(
                         "Error setting {0} to {1}: {2}".format(
                             prop_name, param_value, msg))
         elif prop_kind.startswith('dict('):
             if not getattr(obj, prop_name):
                 setattr(obj, prop_name, param_value)
             else:
                 self.__compare_dict(getattr(obj, prop_name), param_value,
                                     param_name)
         elif prop_kind.startswith('list['):
             if getattr(obj, prop_name) is None:
                 setattr(obj, prop_name, [])
             obj_type = prop_kind.replace('list[', '').replace(']', '')
             if obj_type not in PRIMITIVES and obj_type not in ('list',
                                                                'dict'):
                 self.__compare_obj_list(getattr(obj, prop_name),
                                         param_value, obj_type, param_name)
             else:
                 self.__compare_list(getattr(obj, prop_name), param_value,
                                     param_name)
         else:
             # prop_kind is an object class
             sub_obj = getattr(obj, prop_name)
             if not sub_obj:
                 sub_obj = self.model_class_from_name(prop_kind)()
             setattr(
                 obj, prop_name,
                 self.__set_obj_attribute(sub_obj, property_path,
                                          param_value, param_name))
     return obj
Beispiel #2
0
    def __compare_list(self, src_values, request_values, param_name):
        """
        Compare src_values list with request_values list, and append any missing
        request_values to src_values.
        """
        if not request_values:
            return

        if not src_values:
            src_values += request_values

        if type(src_values[0]).__name__ in PRIMITIVES:
            if set(src_values) >= set(request_values):
                # src_value list includes request_value list
                return
            # append the missing elements from request value
            src_values += list(set(request_values) - set(src_values))
        elif type(src_values[0]).__name__ == 'dict':
            missing = []
            for request_dict in request_values:
                match = False
                for src_dict in src_values:
                    if '__cmp__' in dir(src_dict):
                        # python < 3
                        if src_dict >= request_dict:
                            match = True
                            break
                    elif iteritems(src_dict) == iteritems(request_dict):
                        # python >= 3
                        match = True
                        break
                if not match:
                    missing.append(request_dict)
            src_values += missing
        elif type(src_values[0]).__name__ == 'list':
            missing = []
            for request_list in request_values:
                match = False
                for src_list in src_values:
                    if set(request_list) >= set(src_list):
                        match = True
                        break
                if not match:
                    missing.append(request_list)
            src_values += missing
        else:
            raise KubernetesException(
                "Evaluating {0}: encountered unimplemented type {1} in "
                "__compare_list()".format(param_name,
                                          type(src_values[0]).__name__))
Beispiel #3
0
    def test_stream_creation(self, mock_watch):
        _name = 'test-vmirs'
        # Desired state:
        args = dict(name=_name, namespace='vms', replicas=2, wait=True)
        set_module_args(args)

        # Mock pre-change state:
        resource_args = dict( kind='VirtualMachineInstanceReplicaSet', **RESOURCE_DEFAULT_ARGS )
        K8sAnsibleMixin.find_resource.return_value = Resource(**resource_args)
        res_inst = ResourceInstance('', dict(metadata = {'name': _name}, spec = {'replicas': 3}))
        Resource.get.return_value = res_inst

        # Actual test:
        mock_watch.side_effect = KubernetesException("Test", value=42)
        with pytest.raises(AnsibleFailJson) as result:
            mymodule.KubeVirtScaleVMIRS().execute_module()
Beispiel #4
0
 def find_arg_spec(self, module_param_name):
     """For testing, allow the param_name value to be an alias"""
     if module_param_name in self.argspec:
         return self.argspec[module_param_name]
     result = None
     for key, value in iteritems(self.argspec):
         if value.get('aliases'):
             for alias in value['aliases']:
                 if alias == module_param_name:
                     result = self.argspec[key]
                     break
             if result:
                 break
     if not result:
         raise KubernetesException(
             "Error: received unrecognized module parameter {0}".format(
                 module_param_name))
     return result
Beispiel #5
0
 def __compare_dict(self, src_value, request_value, param_name):
     """
     Compare src_value dict with request_value dict, and update src_value with any differences.
     Does not remove items from src_value dict.
     """
     if not request_value:
         return
     for item, value in iteritems(request_value):
         if type(value).__name__ in ('str', 'int', 'bool'):
             src_value[item] = value
         elif type(value).__name__ == 'list':
             self.__compare_list(src_value[item], value, param_name)
         elif type(value).__name__ == 'dict':
             self.__compare_dict(src_value[item], value, param_name)
         else:
             raise KubernetesException(
                 "Evaluating {0}: encountered unimplemented type {1} in "
                 "__compare_dict()".format(param_name,
                                           type(value).__name__))
Beispiel #6
0
    def test_stream_creation(self, mock_watch):
        _kind = 'PersistentVolumeClaim'
        # Desired state:
        args = dict(state='present',
                    kind=_kind,
                    wait=True,
                    name='testvmi',
                    namespace='vms',
                    api_version='v1')
        set_module_args(args)

        # Mock pre-change state:
        Resource.get.return_value = None  # Resource does NOT initially exist in cluster
        resource_args = dict(kind=_kind, **RESOURCE_DEFAULT_ARGS)
        K8sAnsibleMixin.find_resource.return_value = Resource(**resource_args)

        # Actual test:
        mock_watch.side_effect = KubernetesException("Test", value=42)
        with pytest.raises(AnsibleFailJson) as result:
            mymodule.KubeVirtVM().execute_module()
Beispiel #7
0
    def __update_object_properties(self, obj, item):
        """ Recursively update an object's properties. Returns a pointer to the object. """

        for key, value in iteritems(item):
            snake_key = self.attribute_to_snake(key)
            try:
                kind = obj.swagger_types[snake_key]
            except (AttributeError, KeyError):
                possible_matches = ', '.join(list(obj.swagger_types.keys()))
                class_snake_name = self.get_base_model_name_snake(
                    type(obj).__name__)
                raise KubernetesException(
                    "Unable to find '{0}' in {1}. Valid property names include: {2}"
                    .format(snake_key, class_snake_name, possible_matches))
            if kind in PRIMITIVES or kind.startswith(
                    'list[') or kind.startswith('dict('):
                self.__set_obj_attribute(obj, [snake_key], value, snake_key)
            else:
                # kind is an object, hopefully
                if not getattr(obj, snake_key):
                    setattr(obj, snake_key, self.model_class_from_name(kind)())
                self.__update_object_properties(getattr(obj, snake_key), value)

        return obj
Beispiel #8
0
    def __compare_obj_list(self, src_value, request_value, obj_class,
                           param_name):
        """
        Compare a src_value (list of ojects) with a request_value (list of dicts), and update
        src_value with differences. Assumes each object and each dict has a 'name' attributes,
        which can be used for matching. Elements are not removed from the src_value list.
        """
        if not request_value:
            return

        sample_obj = self.model_class_from_name(obj_class)()

        # Try to determine the unique key for the array
        key_names = ['name', 'type']
        key_name = None
        for key in key_names:
            if hasattr(sample_obj, key):
                key_name = key
                break

        if key_name:
            # If the key doesn't exist in the request values, then ignore it, rather than throwing an error
            for item in request_value:
                if not item.get(key_name):
                    key_name = None
                    break

        if key_name:
            # compare by key field
            for item in request_value:
                if not item.get(key_name):
                    # Prevent user from creating something that will be impossible to patch or update later
                    raise KubernetesException(
                        "Evaluating {0} - expecting parameter {1} to contain a `{2}` attribute "
                        "in __compare_obj_list().".format(
                            param_name,
                            self.get_base_model_name_snake(obj_class),
                            key_name))
                found = False
                for obj in src_value:
                    if not obj:
                        continue
                    if getattr(obj, key_name) == item[key_name]:
                        # Assuming both the src_value and the request value include a name property
                        found = True
                        for key, value in iteritems(item):
                            snake_key = self.attribute_to_snake(key)
                            item_kind = sample_obj.swagger_types.get(snake_key)
                            if item_kind and item_kind in PRIMITIVES or type(
                                    value).__name__ in PRIMITIVES:
                                setattr(obj, snake_key, value)
                            elif item_kind and item_kind.startswith('list['):
                                obj_type = item_kind.replace('list[',
                                                             '').replace(
                                                                 ']', '')
                                if getattr(obj, snake_key) is None:
                                    setattr(obj, snake_key, [])
                                if obj_type not in ('str', 'int', 'bool'):
                                    self.__compare_obj_list(
                                        getattr(obj, snake_key), value,
                                        obj_type, param_name)
                                else:
                                    # Straight list comparison
                                    self.__compare_list(
                                        getattr(obj, snake_key), value,
                                        param_name)
                            elif item_kind and item_kind.startswith('dict('):
                                self.__compare_dict(getattr(obj, snake_key),
                                                    value, param_name)
                            elif item_kind and type(value).__name__ == 'dict':
                                # object
                                param_obj = getattr(obj, snake_key)
                                if not param_obj:
                                    setattr(
                                        obj, snake_key,
                                        self.model_class_from_name(item_kind)
                                        ())
                                    param_obj = getattr(obj, snake_key)
                                self.__update_object_properties(
                                    param_obj, value)
                            else:
                                if item_kind:
                                    raise KubernetesException(
                                        "Evaluating {0}: encountered unimplemented type {1} in "
                                        "__compare_obj_list() for model {2}".
                                        format(
                                            param_name, item_kind,
                                            self.get_base_model_name_snake(
                                                obj_class)))
                                else:
                                    raise KubernetesException(
                                        "Evaluating {0}: unable to get swagger_type for {1} in "
                                        "__compare_obj_list() for item {2} in model {3}"
                                        .format(
                                            param_name, snake_key, str(item),
                                            self.get_base_model_name_snake(
                                                obj_class)))
                if not found:
                    # Requested item not found. Adding.
                    obj = self.__update_object_properties(
                        self.model_class_from_name(obj_class)(), item)
                    src_value.append(obj)
        else:
            # There isn't a key, or we don't know what it is, so check for all properties to match
            for item in request_value:
                found = False
                for obj in src_value:
                    match = True
                    for item_key, item_value in iteritems(item):
                        # TODO: this should probably take the property type into account
                        snake_key = self.attribute_to_snake(item_key)
                        if getattr(obj, snake_key) != item_value:
                            match = False
                            break
                    if match:
                        found = True
                        break
                if not found:
                    obj = self.__update_object_properties(
                        self.model_class_from_name(obj_class)(), item)
                    src_value.append(obj)