Call a state directly with the low data structure, verify data
        before processing.

def call(self, low, chunks=None, running=None, retries=1):
        '''
        Call a state directly with the low data structure, verify data
        before processing.
        '''
        use_uptime = False
        if os.path.isfile('/proc/uptime'):
            use_uptime = True
            with salt.utils.files.fopen('/proc/uptime', 'r') as fp_:
                start_uptime = float(fp_.readline().split()[0])
        utc_start_time = datetime.datetime.utcnow()
        local_start_time = utc_start_time - (datetime.datetime.utcnow() - datetime.datetime.now())
        log.info('Running state [%s] at time %s',
            low['name'].strip() if isinstance(low['name'], six.string_types)
                else low['name'],
            local_start_time.time().isoformat()
        )
        errors = self.verify_data(low)
        if errors:
            ret = {
                'result': False,
                'name': low['name'],
                'changes': {},
                'comment': '',
                }
            for err in errors:
                ret['comment'] += '{0}\n'.format(err)
            ret['__run_num__'] = self.__run_num
            self.__run_num += 1
            format_log(ret)
            self.check_refresh(low, ret)
            return ret
        else:
            ret = {'result': False, 'name': low['name'], 'changes': {}}

        self.state_con['runas'] = low.get('runas', None)

        if low['state'] == 'cmd' and 'password' in low:
            self.state_con['runas_password'] = low['password']
        else:
            self.state_con['runas_password'] = low.get('runas_password', None)

        if not low.get('__prereq__'):
            log.info(
                'Executing state %s.%s for [%s]',
                low['state'],
                low['fun'],
                low['name'].strip() if isinstance(low['name'], six.string_types)
                    else low['name']
            )

        if 'provider' in low:
            self.load_modules(low)

        state_func_name = '{0[state]}.{0[fun]}'.format(low)
        cdata = salt.utils.args.format_call(
            self.states[state_func_name],
            low,
            initial_ret={'full': state_func_name},
            expected_extra_kws=STATE_INTERNAL_KEYWORDS
        )
        inject_globals = {
            # Pass a copy of the running dictionary, the low state chunks and
            # the current state dictionaries.
            # We pass deep copies here because we don't want any misbehaving
            # state module to change these at runtime.
            '__low__': immutabletypes.freeze(low),
            '__running__': immutabletypes.freeze(running) if running else {},
            '__instance_id__': self.instance_id,
            '__lowstate__': immutabletypes.freeze(chunks) if chunks else {}
        }

        if '__env__' in low:
            inject_globals['__env__'] = six.text_type(low['__env__'])

        if self.inject_globals:
            inject_globals.update(self.inject_globals)

        if low.get('__prereq__'):
            test = sys.modules[self.states[cdata['full']].__module__].__opts__['test']
            sys.modules[self.states[cdata['full']].__module__].__opts__['test'] = True
        try:
            # Let's get a reference to the salt environment to use within this
            # state call.
            #
            # If the state function accepts an 'env' keyword argument, it
            # allows the state to be overridden(we look for that in cdata). If
            # that's not found in cdata, we look for what we're being passed in
            # the original data, namely, the special dunder __env__. If that's
            # not found we default to 'base'
            if ('unless' in low and '{0[state]}.mod_run_check'.format(low) not in self.states) or \
                    ('onlyif' in low and '{0[state]}.mod_run_check'.format(low) not in self.states):
                ret.update(self._run_check(low))

            if not self.opts.get('lock_saltenv', False):
                # NOTE: Overriding the saltenv when lock_saltenv is blocked in
                # salt/modules/state.py, before we ever get here, but this
                # additional check keeps use of the State class outside of the
                # salt/modules/state.py from getting around this setting.
                if 'saltenv' in low:
                    inject_globals['__env__'] = six.text_type(low['saltenv'])
                elif isinstance(cdata['kwargs'].get('env', None), six.string_types):
                    # User is using a deprecated env setting which was parsed by
                    # format_call.
                    # We check for a string type since module functions which
                    # allow setting the OS environ also make use of the "env"
                    # keyword argument, which is not a string
                    inject_globals['__env__'] = six.text_type(cdata['kwargs']['env'])

            if '__env__' not in inject_globals:
                # Let's use the default environment
                inject_globals['__env__'] = 'base'

            if '__orchestration_jid__' in low:
                inject_globals['__orchestration_jid__'] = \
                    low['__orchestration_jid__']

            if 'result' not in ret or ret['result'] is False:
                self.states.inject_globals = inject_globals
                if self.mocked:
                    ret = mock_ret(cdata)
                else:
                    # Execute the state function
                    if not low.get('__prereq__') and low.get('parallel'):
                        # run the state call in parallel, but only if not in a prereq
                        ret = self.call_parallel(cdata, low)
                    else:
                        self.format_slots(cdata)
                        if cdata['full'].split('.')[-1] == '__call__':
                            # __call__ requires OrderedDict to preserve state order
                            # kwargs are also invalid overall
                            ret = self.states[cdata['full']](cdata['args'], module=None, state=cdata['kwargs'])
                        else:
                            ret = self.states[cdata['full']](*cdata['args'], **cdata['kwargs'])
                self.states.inject_globals = {}
            if 'check_cmd' in low and '{0[state]}.mod_run_check_cmd'.format(low) not in self.states:
                ret.update(self._run_check_cmd(low))
        except Exception as exc:
            log.debug('An exception occurred in this state: %s', exc,
                      exc_info_on_loglevel=logging.DEBUG)
            trb = traceback.format_exc()
            # There are a number of possibilities to not have the cdata
            # populated with what we might have expected, so just be smart
            # enough to not raise another KeyError as the name is easily
            # guessable and fallback in all cases to present the real
            # exception to the user
            name = (cdata.get('args') or [None])[0] or cdata['kwargs'].get('name')
            if not name:
                name = low.get('name', low.get('__id__'))

            ret = {
                'result': False,
                'name': name,
                'changes': {},
                'comment': 'An exception occurred in this state: {0}'.format(trb)
            }
        finally:
            if low.get('__prereq__'):
                sys.modules[self.states[cdata['full']].__module__].__opts__['test'] = test

            self.state_con.pop('runas', None)
            self.state_con.pop('runas_password', None)

        if not isinstance(ret, dict):
            return ret

        # If format_call got any warnings, let's show them to the user
        if 'warnings' in cdata:
            ret.setdefault('warnings', []).extend(cdata['warnings'])

        if 'provider' in low:
            self.load_modules()

        if low.get('__prereq__'):
            low['__prereq__'] = False
            return ret

        ret['__sls__'] = low.get('__sls__')
        ret['__run_num__'] = self.__run_num
        self.__run_num += 1
        format_log(ret)
        self.check_refresh(low, ret)
        if use_uptime:
            with salt.utils.files.fopen('/proc/uptime', 'r') as fp_:
                finish_uptime = float(fp_.readline().split()[0])
        utc_finish_time = datetime.datetime.utcnow()
        timezone_delta = datetime.datetime.utcnow() - datetime.datetime.now()
        local_finish_time = utc_finish_time - timezone_delta
        local_start_time = utc_start_time - timezone_delta
        ret['start_time'] = local_start_time.time().isoformat()
        if use_uptime:
            duration = (finish_uptime - start_uptime) * 1000.0
        else:
            delta = (utc_finish_time - utc_start_time)
            # duration in milliseconds.microseconds
            duration = (delta.seconds * 1000000 + delta.microseconds) / 1000.0
        ret['duration'] = duration
        ret['__id__'] = low['__id__']
        log.info(
            'Completed state [%s] at time %s (duration_in_ms=%s)',
            low['name'].strip() if isinstance(low['name'], six.string_types)
                else low['name'],
            local_finish_time.time().isoformat(),
            duration
        )
        if 'retry' in low:
            low['retry'] = self.verify_retry_data(low['retry'])
            if not sys.modules[self.states[cdata['full']].__module__].__opts__['test']:
                if low['retry']['until'] != ret['result']:
                    if low['retry']['attempts'] > retries:
                        interval = low['retry']['interval']
                        if low['retry']['splay'] != 0:
                            interval = interval + random.randint(0, low['retry']['splay'])
                        log.info(
                            'State result does not match retry until value, '
                            'state will be re-run in %s seconds', interval
                        )
                        self.functions['test.sleep'](interval)
                        retry_ret = self.call(low, chunks, running, retries=retries+1)
                        orig_ret = ret
                        ret = retry_ret
                        ret['comment'] = '\n'.join(
                                [(
                                     'Attempt {0}: Returned a result of "{1}", '
                                     'with the following comment: "{2}"'.format(
                                         retries,
                                         orig_ret['result'],
                                         orig_ret['comment'])
                                 ),
                                 '' if not ret['comment'] else ret['comment']])
                        ret['duration'] = ret['duration'] + orig_ret['duration'] + (interval * 1000)
                        if retries == 1:
                            ret['start_time'] = orig_ret['start_time']
            else:
                ret['comment'] = '  '.join(
                        ['' if not ret['comment'] else ret['comment'],
                         ('The state would be retried every {1} seconds '
                          '(with a splay of up to {3} seconds) '
                          'a maximum of {0} times or until a result of {2} '
                          'is returned').format(low['retry']['attempts'],
                                                low['retry']['interval'],
                                                low['retry']['until'],
                                                low['retry']['splay'])])
        return ret