Execute a wrapper function

        Returns tuple of (json_data, '')

def run_wfunc(self):
        '''
        Execute a wrapper function

        Returns tuple of (json_data, '')
        '''
        # Ensure that opts/grains are up to date
        # Execute routine
        data_cache = False
        data = None
        cdir = os.path.join(self.opts['cachedir'], 'minions', self.id)
        if not os.path.isdir(cdir):
            os.makedirs(cdir)
        datap = os.path.join(cdir, 'ssh_data.p')
        refresh = False
        if not os.path.isfile(datap):
            refresh = True
        else:
            passed_time = (time.time() - os.stat(datap).st_mtime) / 60
            if passed_time > self.opts.get('cache_life', 60):
                refresh = True

        if self.opts.get('refresh_cache'):
            refresh = True
        conf_grains = {}
        # Save conf file grains before they get clobbered
        if 'ssh_grains' in self.opts:
            conf_grains = self.opts['ssh_grains']
        if not data_cache:
            refresh = True
        if refresh:
            # Make the datap
            # TODO: Auto expire the datap
            pre_wrapper = salt.client.ssh.wrapper.FunctionWrapper(
                self.opts,
                self.id,
                fsclient=self.fsclient,
                minion_opts=self.minion_opts,
                **self.target)
            opts_pkg = pre_wrapper['test.opts_pkg']()  # pylint: disable=E1102
            if '_error' in opts_pkg:
                #Refresh failed
                retcode = opts_pkg['retcode']
                ret = salt.utils.json.dumps({'local': opts_pkg})
                return ret, retcode

            opts_pkg['file_roots'] = self.opts['file_roots']
            opts_pkg['pillar_roots'] = self.opts['pillar_roots']
            opts_pkg['ext_pillar'] = self.opts['ext_pillar']
            opts_pkg['extension_modules'] = self.opts['extension_modules']
            opts_pkg['module_dirs'] = self.opts['module_dirs']
            opts_pkg['_ssh_version'] = self.opts['_ssh_version']
            opts_pkg['__master_opts__'] = self.context['master_opts']
            if 'known_hosts_file' in self.opts:
                opts_pkg['known_hosts_file'] = self.opts['known_hosts_file']
            if '_caller_cachedir' in self.opts:
                opts_pkg['_caller_cachedir'] = self.opts['_caller_cachedir']
            else:
                opts_pkg['_caller_cachedir'] = self.opts['cachedir']
            # Use the ID defined in the roster file
            opts_pkg['id'] = self.id

            retcode = 0

            # Restore master grains
            for grain in conf_grains:
                opts_pkg['grains'][grain] = conf_grains[grain]
            # Enable roster grains support
            if 'grains' in self.target:
                for grain in self.target['grains']:
                    opts_pkg['grains'][grain] = self.target['grains'][grain]

            popts = {}
            popts.update(opts_pkg)

            # Master centric operations such as mine.get must have master option loaded.
            # The pillar must then be compiled by passing master opts found in opts_pkg['__master_opts__']
            # which causes the pillar renderer to loose track of salt master options
            #
            # Depending on popts merge order, it will overwrite some options found in opts_pkg['__master_opts__']
            master_centric_funcs = [
              "pillar.items",
              "mine.get"
            ]

            # Pillar compilation is a master centric operation.
            # Master options take precedence during Pillar compilation
            popts.update(opts_pkg['__master_opts__'])

            pillar = salt.pillar.Pillar(
                    popts,
                    opts_pkg['grains'],
                    opts_pkg['id'],
                    opts_pkg.get('saltenv', 'base')
                    )
            pillar_data = pillar.compile_pillar()

            # Once pillar has been compiled, restore priority of minion opts
            if self.fun not in master_centric_funcs:
                log.debug('%s is a minion function', self.fun)
                popts.update(opts_pkg)
            else:
                log.debug('%s is a master function', self.fun)

            # TODO: cache minion opts in datap in master.py
            data = {'opts': opts_pkg,
                    'grains': opts_pkg['grains'],
                    'pillar': pillar_data}
            if data_cache:
                with salt.utils.files.fopen(datap, 'w+b') as fp_:
                    fp_.write(
                            self.serial.dumps(data)
                            )
        if not data and data_cache:
            with salt.utils.files.fopen(datap, 'rb') as fp_:
                data = self.serial.load(fp_)
        opts = data.get('opts', {})
        opts['grains'] = data.get('grains')

        # Restore master grains
        for grain in conf_grains:
            opts['grains'][grain] = conf_grains[grain]
        # Enable roster grains support
        if 'grains' in self.target:
            for grain in self.target['grains']:
                opts['grains'][grain] = self.target['grains'][grain]

        opts['pillar'] = data.get('pillar')
        wrapper = salt.client.ssh.wrapper.FunctionWrapper(
            opts,
            self.id,
            fsclient=self.fsclient,
            minion_opts=self.minion_opts,
            **self.target)
        self.wfuncs = salt.loader.ssh_wrapper(opts, wrapper, self.context)
        wrapper.wfuncs = self.wfuncs

        # We're running in the mine, need to fetch the arguments from the
        # roster, pillar, master config (in that order)
        if self.mine:
            mine_args = None
            mine_fun_data = None
            mine_fun = self.fun

            if self.mine_functions and self.fun in self.mine_functions:
                mine_fun_data = self.mine_functions[self.fun]
            elif opts['pillar'] and self.fun in opts['pillar'].get('mine_functions', {}):
                mine_fun_data = opts['pillar']['mine_functions'][self.fun]
            elif self.fun in self.context['master_opts'].get('mine_functions', {}):
                mine_fun_data = self.context['master_opts']['mine_functions'][self.fun]

            if isinstance(mine_fun_data, dict):
                mine_fun = mine_fun_data.pop('mine_function', mine_fun)
                mine_args = mine_fun_data
            elif isinstance(mine_fun_data, list):
                for item in mine_fun_data[:]:
                    if isinstance(item, dict) and 'mine_function' in item:
                        mine_fun = item['mine_function']
                        mine_fun_data.pop(mine_fun_data.index(item))
                mine_args = mine_fun_data
            else:
                mine_args = mine_fun_data

            # If we found mine_args, replace our command's args
            if isinstance(mine_args, dict):
                self.args = []
                self.kwargs = mine_args
            elif isinstance(mine_args, list):
                self.args = mine_args
                self.kwargs = {}

        try:
            if self.mine:
                result = wrapper[mine_fun](*self.args, **self.kwargs)
            else:
                result = self.wfuncs[self.fun](*self.args, **self.kwargs)
        except TypeError as exc:
            result = 'TypeError encountered executing {0}: {1}'.format(self.fun, exc)
            log.error(result, exc_info_on_loglevel=logging.DEBUG)
            retcode = 1
        except Exception as exc:
            result = 'An Exception occurred while executing {0}: {1}'.format(self.fun, exc)
            log.error(result, exc_info_on_loglevel=logging.DEBUG)
            retcode = 1
        # Mimic the json data-structure that "salt-call --local" will
        # emit (as seen in ssh_py_shim.py)
        if isinstance(result, dict) and 'local' in result:
            ret = salt.utils.json.dumps({'local': result['local']})
        else:
            ret = salt.utils.json.dumps({'local': {'return': result}})
        return ret, retcode