%PDF- %PDF-
Direktori : /usr/lib/python2.7/site-packages/salt/modules/ |
Current File : //usr/lib/python2.7/site-packages/salt/modules/at.py |
# -*- coding: utf-8 -*- ''' Wrapper module for at(1) Also, a 'tag' feature has been added to more easily tag jobs. :platform: linux,openbsd,freebsd .. versionchanged:: 2017.7.0 ''' from __future__ import absolute_import, print_function, unicode_literals # Import python libs import re import time import datetime # Import 3rd-party libs # pylint: disable=import-error,redefined-builtin from salt.ext.six.moves import map # pylint: enable=import-error,redefined-builtin from salt.exceptions import CommandNotFoundError from salt.ext import six # Import salt libs import salt.utils.data import salt.utils.path import salt.utils.platform # OS Families that should work (Ubuntu and Debian are the default) # TODO: Refactor some of this module to remove the checks for binaries # Tested on OpenBSD 5.0 BSD = ('OpenBSD', 'FreeBSD') __virtualname__ = 'at' def __virtual__(): ''' Most everything has the ability to support at(1) ''' if salt.utils.platform.is_windows() or salt.utils.platform.is_sunos(): return (False, 'The at module could not be loaded: unsupported platform') if salt.utils.path.which('at') is None: return (False, 'The at module could not be loaded: at command not found') return __virtualname__ def _cmd(binary, *args): ''' Wrapper to run at(1) or return None. ''' binary = salt.utils.path.which(binary) if not binary: raise CommandNotFoundError('{0}: command not found'.format(binary)) cmd = [binary] + list(args) return __salt__['cmd.run_stdout']([binary] + list(args), python_shell=False) def atq(tag=None): ''' List all queued and running jobs or only those with an optional 'tag'. CLI Example: .. code-block:: bash salt '*' at.atq salt '*' at.atq [tag] salt '*' at.atq [job number] ''' jobs = [] # Shim to produce output similar to what __virtual__() should do # but __salt__ isn't available in __virtual__() # Tested on CentOS 5.8 if __grains__['os_family'] == 'RedHat': output = _cmd('at', '-l') else: output = _cmd('atq') if output is None: return '\'at.atq\' is not available.' # No jobs so return if output == '': return {'jobs': jobs} # Jobs created with at.at() will use the following # comment to denote a tagged job. job_kw_regex = re.compile(r'^### SALT: (\w+)') # Split each job into a dictionary and handle # pulling out tags or only listing jobs with a certain # tag for line in output.splitlines(): job_tag = '' # Redhat/CentOS if __grains__['os_family'] == 'RedHat': job, spec = line.split('\t') specs = spec.split() elif __grains__['os'] == 'OpenBSD': if line.startswith(' Rank'): continue else: tmp = line.split() timestr = ' '.join(tmp[1:5]) job = tmp[6] specs = datetime.datetime(*(time.strptime(timestr, '%b %d, %Y ' '%H:%M')[0:5])).isoformat().split('T') specs.append(tmp[7]) specs.append(tmp[5]) elif __grains__['os'] == 'FreeBSD': if line.startswith('Date'): continue else: tmp = line.split() timestr = ' '.join(tmp[1:6]) job = tmp[8] specs = datetime.datetime(*(time.strptime(timestr, '%b %d %H:%M:%S %Z %Y')[0:5])).isoformat().split('T') specs.append(tmp[7]) specs.append(tmp[6]) else: job, spec = line.split('\t') tmp = spec.split() timestr = ' '.join(tmp[0:5]) specs = datetime.datetime(*(time.strptime(timestr) [0:5])).isoformat().split('T') specs.append(tmp[5]) specs.append(tmp[6]) # Search for any tags atc_out = _cmd('at', '-c', job) for line in atc_out.splitlines(): tmp = job_kw_regex.match(line) if tmp: job_tag = tmp.groups()[0] if __grains__['os'] in BSD: job = six.text_type(job) else: job = int(job) # If a tag is supplied, only list jobs with that tag if tag: # TODO: Looks like there is a difference between salt and salt-call # If I don't wrap job in an int(), it fails on salt but works on # salt-call. With the int(), it fails with salt-call but not salt. if tag == job_tag or tag == job: jobs.append({'job': job, 'date': specs[0], 'time': specs[1], 'queue': specs[2], 'user': specs[3], 'tag': job_tag}) else: jobs.append({'job': job, 'date': specs[0], 'time': specs[1], 'queue': specs[2], 'user': specs[3], 'tag': job_tag}) return {'jobs': jobs} def atrm(*args): ''' Remove jobs from the queue. CLI Example: .. code-block:: bash salt '*' at.atrm <jobid> <jobid> .. <jobid> salt '*' at.atrm all salt '*' at.atrm all [tag] ''' # Need to do this here also since we use atq() if not salt.utils.path.which('at'): return '\'at.atrm\' is not available.' if not args: return {'jobs': {'removed': [], 'tag': None}} # Convert all to strings args = salt.utils.data.stringify(args) if args[0] == 'all': if len(args) > 1: opts = list(list(map(str, [j['job'] for j in atq(args[1])['jobs']]))) ret = {'jobs': {'removed': opts, 'tag': args[1]}} else: opts = list(list(map(str, [j['job'] for j in atq()['jobs']]))) ret = {'jobs': {'removed': opts, 'tag': None}} else: opts = list(list(map(str, [i['job'] for i in atq()['jobs'] if six.text_type(i['job']) in args]))) ret = {'jobs': {'removed': opts, 'tag': None}} # Shim to produce output similar to what __virtual__() should do # but __salt__ isn't available in __virtual__() output = _cmd('at', '-d', ' '.join(opts)) if output is None: return '\'at.atrm\' is not available.' return ret def at(*args, **kwargs): # pylint: disable=C0103 ''' Add a job to the queue. The 'timespec' follows the format documented in the at(1) manpage. CLI Example: .. code-block:: bash salt '*' at.at <timespec> <cmd> [tag=<tag>] [runas=<user>] salt '*' at.at 12:05am '/sbin/reboot' tag=reboot salt '*' at.at '3:05am +3 days' 'bin/myscript' tag=nightly runas=jim ''' if len(args) < 2: return {'jobs': []} # Shim to produce output similar to what __virtual__() should do # but __salt__ isn't available in __virtual__() binary = salt.utils.path.which('at') if not binary: return '\'at.at\' is not available.' if 'tag' in kwargs: stdin = '### SALT: {0}\n{1}'.format(kwargs['tag'], ' '.join(args[1:])) else: stdin = ' '.join(args[1:]) cmd = [binary, args[0]] cmd_kwargs = {'stdin': stdin, 'python_shell': False} if 'runas' in kwargs: cmd_kwargs['runas'] = kwargs['runas'] output = __salt__['cmd.run'](cmd, **cmd_kwargs) if output is None: return '\'at.at\' is not available.' if output.endswith('Garbled time'): return {'jobs': [], 'error': 'invalid timespec'} if output.startswith('warning: commands'): output = output.splitlines()[1] if output.startswith('commands will be executed'): output = output.splitlines()[1] output = output.split()[1] if __grains__['os'] in BSD: return atq(six.text_type(output)) else: return atq(int(output)) def atc(jobid): ''' Print the at(1) script that will run for the passed job id. This is mostly for debugging so the output will just be text. CLI Example: .. code-block:: bash salt '*' at.atc <jobid> ''' # Shim to produce output similar to what __virtual__() should do # but __salt__ isn't available in __virtual__() output = _cmd('at', '-c', six.text_type(jobid)) if output is None: return '\'at.atc\' is not available.' elif output == '': return {'error': 'invalid job id \'{0}\''.format(jobid)} return output def _atq(**kwargs): ''' Return match jobs list ''' jobs = [] runas = kwargs.get('runas', None) tag = kwargs.get('tag', None) hour = kwargs.get('hour', None) minute = kwargs.get('minute', None) day = kwargs.get('day', None) month = kwargs.get('month', None) year = kwargs.get('year', None) if year and len(six.text_type(year)) == 2: year = '20{0}'.format(year) jobinfo = atq()['jobs'] if not jobinfo: return {'jobs': jobs} for job in jobinfo: if not runas: pass elif runas == job['user']: pass else: continue if not tag: pass elif tag == job['tag']: pass else: continue if not hour: pass elif '{0:02d}'.format(int(hour)) == job['time'].split(':')[0]: pass else: continue if not minute: pass elif '{0:02d}'.format(int(minute)) == job['time'].split(':')[1]: pass else: continue if not day: pass elif '{0:02d}'.format(int(day)) == job['date'].split('-')[2]: pass else: continue if not month: pass elif '{0:02d}'.format(int(month)) == job['date'].split('-')[1]: pass else: continue if not year: pass elif year == job['date'].split('-')[0]: pass else: continue jobs.append(job) if not jobs: note = 'No match jobs or time format error' return {'jobs': jobs, 'note': note} return {'jobs': jobs} def jobcheck(**kwargs): ''' Check the job from queue. The kwargs dict include 'hour minute day month year tag runas' Other parameters will be ignored. CLI Example: .. code-block:: bash salt '*' at.jobcheck runas=jam day=13 salt '*' at.jobcheck day=13 month=12 year=13 tag=rose ''' if not kwargs: return {'error': 'You have given a condition'} return _atq(**kwargs)