Takes a model instance such as V1PodSpec() and updates it with another
    model, which is allowed to be a dict or another model instance of the same
    type. The logger is used to warn if any truthy value in the target is is
    overridden. The target_name parameter can for example be "pod.spec", and
    changes_name parameter could be "extra_pod_config". These parameters allows
    the logger to write out something more meaningful to the user whenever
    something is about to become overridden.

def update_k8s_model(target, changes, logger=None, target_name=None, changes_name=None):
    """
    Takes a model instance such as V1PodSpec() and updates it with another
    model, which is allowed to be a dict or another model instance of the same
    type. The logger is used to warn if any truthy value in the target is is
    overridden. The target_name parameter can for example be "pod.spec", and
    changes_name parameter could be "extra_pod_config". These parameters allows
    the logger to write out something more meaningful to the user whenever
    something is about to become overridden.
    """
    model_type = type(target)
    if not hasattr(target, 'attribute_map'):
        raise AttributeError("Attribute 'target' ({}) must be an object (such as 'V1PodSpec') with an attribute 'attribute_map'.".format(model_type.__name__))
    if not isinstance(changes, model_type) and not isinstance(changes, dict):
        raise AttributeError("Attribute 'changes' ({}) must be an object of the same type as 'target' ({}) or a 'dict'.".format(type(changes).__name__, model_type.__name__))

    changes_dict = _get_k8s_model_dict(model_type, changes)
    for key, value in changes_dict.items():
        if key not in target.attribute_map:
            raise ValueError("The attribute 'changes' ({}) contained '{}' not modeled by '{}'.".format(type(changes).__name__, key, model_type.__name__))
        

        # If changes are passed as a dict, they will only have a few keys/value
        # pairs representing the specific changes. If the changes parameter is a
        # model instance on the other hand, the changes parameter will have a
        # lot of default values as well. These default values, which are also
        # falsy, should not use to override the target's values.
        if isinstance(changes, dict) or value:
            if getattr(target, key):
                if logger and changes_name:
                    warning = "'{}.{}' current value: '{}' is overridden with '{}', which is the value of '{}.{}'.".format(
                        target_name,
                        key,
                        getattr(target, key),
                        value,
                        changes_name,
                        key
                    )
                    logger.warning(warning)
            setattr(target, key, value)

    return target