'Creates image from template.
Ensures that template and image not already exists.
Ensures that base directory exists.
Synchronizes on template fetching.
:fetch_func: Function that creates the base image
Should accept `target` argument.
:filename: Name of the file in the image directory
:size: Size of created image in bytes (optional)'

def cache(self, fetch_func, filename, size=None, *args, **kwargs):

    base_dir = os.path.join(CONF.instances_path, CONF.image_cache_subdirectory_name)
    if (not os.path.exists(base_dir)):
        fileutils.ensure_tree(base_dir)
    base = os.path.join(base_dir, filename)
    @utils.synchronized(filename, external=True, lock_path=self.lock_path)
    def fetch_func_sync(target, *args, **kwargs):
        if ((target != base) or (not os.path.exists(target))):
            fetch_func(target=target, *args, **kwargs)
    if ((not self.exists()) or (not os.path.exists(base))):
        self.create_image(fetch_func_sync, base, size, *args, **kwargs)
    if size:
        if (os.path.exists(base) and (size > self.get_disk_size(base))):
            self.resize_image(size)
        if (self.preallocate and self._can_fallocate() and os.access(self.path, os.W_OK)):
            utils.execute('fallocate', '-n', '-l', size, self.path)
