Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-11-25 02:29:20

0001 __author__ = 'Giacomo Govi'
0002 
0003 import sqlalchemy
0004 import sqlalchemy.ext.declarative
0005 import subprocess
0006 from datetime import datetime
0007 import os
0008 import sys
0009 import logging
0010 import string
0011 import json
0012 
0013 import CondCore.Utilities.credentials as auth
0014 
0015 prod_db_service = 'cms_orcon_prod'
0016 dev_db_service = 'cms_orcoff_prep'
0017 schema_name = 'CMS_CONDITIONS'
0018 sqlalchemy_tpl = 'oracle://%s:%s@%s'
0019 coral_tpl = 'oracle://%s/%s'
0020 private_db = 'sqlite:///o2o_jobs.db'
0021 startStatus = -1
0022 messageLevelEnvVar = 'O2O_LOG_LEVEL'
0023 logFolderEnvVar = 'O2O_LOG_FOLDER'
0024 logger = logging.getLogger(__name__)
0025 
0026 _Base = sqlalchemy.ext.declarative.declarative_base()
0027 
0028 class O2OJob(_Base):
0029     __tablename__      = 'O2O_JOB'
0030     __table_args__     = {'schema' : schema_name}
0031     name               = sqlalchemy.Column(sqlalchemy.String(100),    primary_key=True)
0032     enabled            = sqlalchemy.Column(sqlalchemy.Integer,        nullable=False)
0033     frequent           = sqlalchemy.Column(sqlalchemy.Integer,        nullable=False)
0034     tag_name           = sqlalchemy.Column(sqlalchemy.String(100),    nullable=False)
0035     interval           = sqlalchemy.Column(sqlalchemy.Integer,        nullable=False)
0036 
0037 class O2OJobConf(_Base):
0038     __tablename__      = 'O2O_JOB_CONF'
0039     __table_args__     = {'schema' : schema_name}
0040     job_name           = sqlalchemy.Column(sqlalchemy.ForeignKey(O2OJob.name),    primary_key=True)
0041     insertion_time     = sqlalchemy.Column(sqlalchemy.TIMESTAMP,      primary_key=True)
0042     configuration      = sqlalchemy.Column(sqlalchemy.String(4000),   nullable=False)
0043 
0044     job                = sqlalchemy.orm.relationship('O2OJob', primaryjoin="O2OJob.name==O2OJobConf.job_name")
0045 
0046 class O2ORun(_Base):
0047     __tablename__      = 'O2O_RUN'
0048     __table_args__     = {'schema' : schema_name}
0049     job_name           = sqlalchemy.Column(sqlalchemy.ForeignKey(O2OJob.name),    primary_key=True)
0050     start_time         = sqlalchemy.Column(sqlalchemy.TIMESTAMP,      primary_key=True)
0051     end_time           = sqlalchemy.Column(sqlalchemy.TIMESTAMP,      nullable=True)
0052     status_code        = sqlalchemy.Column(sqlalchemy.Integer,        nullable=False)
0053     log                = sqlalchemy.Column(sqlalchemy.CLOB,           nullable=True)
0054 
0055     job                = sqlalchemy.orm.relationship('O2OJob', primaryjoin="O2OJob.name==O2ORun.job_name")
0056 
0057 def print_table( headers, table ):
0058     ws = []
0059     for h in headers:
0060         ws.append(len(h))
0061     for row in table:
0062         ind = 0
0063         for c in row:
0064             if ind<len(ws):
0065                 if len(c)> ws[ind]:
0066                     ws[ind] = len(c)
0067             ind += 1
0068 
0069     def printf( row ):
0070         line = ''
0071         ind = 0
0072         for w in ws:
0073             fmt = '{:<%s}' %w
0074             if ind<len(ws):
0075                 line += (fmt.format( row[ind] )+' ') 
0076             ind += 1
0077         print(line)
0078     printf( headers )
0079     hsep = ''
0080     for w in ws:
0081         fmt = '{:-<%s}' %w
0082         hsep += (fmt.format('')+' ')
0083     print(hsep)
0084     for row in table:
0085         printf( row )
0086 
0087 
0088 class O2OJobMgr(object):
0089 
0090     def __init__( self , logLevel):
0091         self.db_connection = None
0092         self.conf_dict = {}
0093         fmt_str = "[%(asctime)s] %(levelname)s: %(message)s"
0094         if messageLevelEnvVar in os.environ:
0095             levStr = os.environ[messageLevelEnvVar]
0096             if levStr == 'DEBUG':
0097                 logLevel = logging.DEBUG
0098         logFormatter = logging.Formatter(fmt_str)
0099 
0100         self.logger = logging.getLogger()        
0101         self.logger.setLevel(logLevel)
0102         consoleHandler = logging.StreamHandler(sys.stdout) 
0103         consoleHandler.setFormatter(logFormatter)
0104         self.logger.addHandler(consoleHandler)
0105         self.eng = None
0106 
0107     def getSession( self, db_service, role, authPath ):
0108         url = None
0109         if db_service is None:
0110             url = private_db
0111         else:
0112             self.logger.info('Getting credentials')
0113             if authPath is not None:
0114                 if not os.path.exists(authPath):
0115                     self.logger.error('Authentication path %s is invalid.' %authPath)
0116                     return None
0117             try:
0118                 (username, account, pwd) = auth.get_credentials_for_schema( db_service, schema_name, role, authPath )
0119             except Exception as e:
0120                 self.logger.debug(str(e))
0121                 username = None
0122                 pwd = None
0123             if username is None:
0124                 self.logger.error('Credentials for service %s are not available' %db_service)
0125                 raise Exception("Cannot connect to db %s" %db_service )
0126             url = sqlalchemy_tpl %(username,pwd,db_service)
0127         session = None
0128         try:
0129             self.eng = sqlalchemy.create_engine( url, max_identifier_length=30)
0130             session = sqlalchemy.orm.scoped_session( sqlalchemy.orm.sessionmaker(bind=self.eng))
0131         except sqlalchemy.exc.SQLAlchemyError as dberror:
0132             self.logger.error( str(dberror) )
0133         return session
0134 
0135     def connect( self, service, args ):
0136         self.session = self.getSession( service, args.role, args.auth )
0137         self.verbose = args.verbose
0138         if self.session is None:
0139             return False
0140         else:
0141             self.db_connection = coral_tpl %(service,schema_name)
0142             self.conf_dict['db']=self.db_connection
0143             return True
0144     def runManager( self ):
0145         return O2ORunMgr( self.db_connection, self.session, self.logger )
0146 
0147     def add( self, job_name, configJson, int_val, freq_flag, en_flag ):
0148         if configJson == '':
0149             return False
0150         res = self.session.query(O2OJob.enabled).filter_by(name=job_name)
0151         enabled = None
0152         for r in res:
0153             enabled = r
0154         if enabled:
0155             self.logger.error( "A job called '%s' exists already.", job_name )
0156             return False
0157         freq_val = 0
0158         if freq_flag:
0159             freq_val = 1
0160         job = O2OJob(name=job_name,tag_name='-',enabled=en_flag,frequent=freq_val,interval=int_val)
0161         config = O2OJobConf( job_name=job_name, insertion_time = datetime.utcnow(), configuration = configJson ) 
0162         self.session.add(job)
0163         self.session.add(config)
0164         self.session.commit()
0165         self.logger.info( "New o2o job '%s' created.", job_name )
0166         return True 
0167 
0168     def set( self, job_name, en_flag, fr_val=None ):
0169         res = self.session.query(O2OJob.enabled).filter_by(name=job_name)
0170         enabled = None
0171         for r in res:
0172             enabled = r
0173         if enabled is None:
0174             self.logger.error( "A job called '%s' does not exist.", job_name )
0175             return
0176         if en_flag is not None and enabled != en_flag:
0177             job = O2OJob(name=job_name,enabled=en_flag)
0178             self.session.merge(job)
0179             self.session.commit()
0180             action = 'enabled'
0181             if not en_flag:
0182                 action = 'disabled'
0183             self.logger.info( "Job '%s' %s." %(job_name,action) )
0184         if fr_val is not None:
0185             job = O2OJob(name=job_name,frequent=fr_val)
0186             self.session.merge(job)
0187             self.session.commit()
0188             if fr_val==1:
0189                 self.logger.info( "Job '%s' set 'frequent'" %job_name)
0190             else:
0191                 self.logger.info( "Job '%s' unset 'frequent'" %job_name)
0192 
0193     def setConfig( self, job_name, configJson ):
0194         if configJson == '':
0195             return False
0196         res = self.session.query(O2OJob.enabled).filter_by(name=job_name)
0197         enabled = None
0198         for r in res:
0199             enabled = r
0200         if enabled is None:
0201             self.logger.error( "A job called '%s' does not exist.", job_name )
0202             return
0203         config = O2OJobConf( job_name=job_name, insertion_time = datetime.utcnow(), configuration = configJson )     
0204         self.session.add(config)
0205         self.session.commit()
0206         self.logger.info( "New configuration inserted for job '%s'", job_name )
0207         return True 
0208 
0209     def setInterval( self, job_name, int_val ):
0210         res = self.session.query(O2OJob.enabled).filter_by(name=job_name)
0211         enabled = None
0212         for r in res:
0213             enabled = r
0214         if enabled is None:
0215             self.logger.error( "A job called '%s' does not exist.", job_name )
0216             return
0217         job = O2OJob(name=job_name,interval=int_val)
0218         self.session.merge(job)
0219         self.session.commit()
0220         self.logger.info( "The execution interval for job '%s' has been updated.", job_name )
0221 
0222     def listJobs( self ):
0223         runs = {}
0224         res = self.session.query(O2ORun.job_name,sqlalchemy.func.max(O2ORun.start_time)).group_by(O2ORun.job_name).order_by(O2ORun.job_name)
0225         for r in res:
0226             runs[r[0]] = str(r[1])
0227         res = self.session.query(O2OJob.name, O2OJob.interval, O2OJob.enabled, O2OJob.frequent).order_by(O2OJob.name).all()
0228         table = []
0229         for r in res:
0230             row = []
0231             row.append(r[0]),
0232             row.append('%5d' %r[1] )
0233             frequent = 'Y' if (r[3]==1) else 'N'
0234             row.append('%4s' %frequent )
0235             enabled = 'Y' if (r[2]==1) else 'N'
0236             row.append('%4s' %enabled )
0237             lastRun = '-'
0238             if r[0] in runs.keys():
0239                 lastRun = runs[r[0]]
0240             row.append( lastRun )
0241             table.append(row)
0242         headers = ['Job name','Interval','Frequent','Enabled','Last run start']
0243         print_table( headers, table ) 
0244 
0245     def listConfig( self, jname ):
0246         res = self.session.query(O2OJob.enabled).filter_by(name=jname)
0247         enabled = None
0248         for r in res:
0249             enabled = r
0250         if enabled is None:
0251             self.logger.error( "A job called '%s' does not exist.", jname )
0252             return
0253         res = self.session.query( O2OJobConf.configuration, O2OJobConf.insertion_time  ).filter_by(job_name=jname).order_by(O2OJobConf.insertion_time)
0254         configs = []
0255         for r in res:
0256             configs.append((str(r[0]),r[1]))
0257         ind = len(configs)
0258         if ind:
0259             print("Configurations for job '%s'" %jname)
0260             for cf in reversed(configs):
0261                 print('#%2d  since: %s' %(ind,cf[1]))
0262                 print(cf[0])
0263                 ind -= 1
0264         else:
0265             self.logger.info("No configuration found for job '%s'" %jname )
0266 
0267     def dumpConfig( self, jname, versionIndex, configFile ):
0268         versionIndex = int(versionIndex)
0269         res = self.session.query(O2OJob.enabled).filter_by(name=jname)
0270         enabled = None
0271         for r in res:
0272             enabled = r
0273         if enabled is None:
0274             self.logger.error( "A job called '%s' does not exist.", jname )
0275             return
0276         res = self.session.query( O2OJobConf.configuration, O2OJobConf.insertion_time  ).filter_by(job_name=jname).order_by(O2OJobConf.insertion_time)
0277         configs = []
0278         for r in res:
0279             configs.append((str(r[0]),r[1]))
0280         ind = len(configs)
0281         if versionIndex>ind or versionIndex==0:
0282             self.logger.error("Configuration for job %s with index %s has not been found." %(jname,versionIndex))
0283             return
0284         print("Configuration #%2d for job '%s'" %(versionIndex,jname))
0285         config = configs[versionIndex-1]
0286         print('#%2d  since %s' %(versionIndex,config[1]))
0287         print(config[0])
0288         if configFile is None or configFile == '':
0289             configFile = '%s_%s.json' %(jname,versionIndex)
0290         with open(configFile,'w') as json_file:
0291             json_file.write(config[0])
0292 
0293             
0294 class O2ORunMgr(object):
0295 
0296     def __init__( self, db_connection, session, logger ):
0297         self.job_name = None
0298         self.start = None
0299         self.end = None
0300         self.conf_dict = {}
0301         self.conf_dict['db'] = db_connection
0302         self.session = session
0303         self.logger = logger
0304 
0305     def startJob( self, job_name ):
0306         self.logger.info('Checking job %s', job_name)
0307         exists = None
0308         enabled = None
0309         try:
0310             res = self.session.query(O2OJob.enabled,O2OJob.tag_name).filter_by(name=job_name)
0311             for r in res:
0312                 exists = True
0313                 enabled = int(r[0])
0314                 self.tag_name = str(r[1]) 
0315             if exists is None:
0316                 self.logger.error( 'The job %s is unknown.', job_name )
0317                 return 2
0318             if enabled:
0319                 res = self.session.query(O2OJobConf.configuration).filter_by(job_name=job_name).order_by(sqlalchemy.desc(O2OJobConf.insertion_time)).first()
0320                 conf = None
0321                 for r in res:
0322                     conf = str(r)
0323                 if conf is None:
0324                     self.logger.warning("No configuration found for job '%s'" %job_name )
0325                 else:
0326                     try:
0327                         self.conf_dict.update( json.loads(conf) )
0328                         self.logger.info('Using configuration: %s ' %conf)
0329                     except Exception as e:
0330                         self.logger.error( str(e) )
0331                         return 6
0332                 self.job_name = job_name
0333                 self.start = datetime.utcnow()
0334                 run = O2ORun(job_name=self.job_name,start_time=self.start,status_code=startStatus)
0335                 self.session.add(run)
0336                 self.session.commit()
0337                 return 0
0338             else:
0339                 self.logger.info( 'The job %s has been disabled.', job_name )
0340                 return 5
0341         except sqlalchemy.exc.SQLAlchemyError as dberror:
0342                 self.logger.error( str(dberror) )
0343                 return 7
0344         return -1
0345 
0346 
0347     def endJob( self, status, log ):
0348         self.end = datetime.utcnow()
0349         try:
0350             run = O2ORun(job_name=self.job_name,start_time=self.start,end_time=self.end,status_code=status,log=log)
0351             self.session.merge(run)
0352             self.session.commit()
0353             self.logger.info( 'Job %s ended.', self.job_name )
0354             return 0
0355         except sqlalchemy.exc.SQLAlchemyError as dberror:
0356             self.logger.error( str(dberror) )
0357             return 8
0358 
0359     def executeJob( self, args ):
0360         job_name = args.name
0361         command = args.executable
0362         logFolder = os.getcwd()
0363         if logFolderEnvVar in os.environ:
0364             logFolder = os.environ[logFolderEnvVar]
0365         datelabel = datetime.utcnow().strftime("%y-%m-%d-%H-%M-%S")
0366         logFileName = '%s-%s.log' %(job_name,datelabel)
0367         logFile = os.path.join(logFolder,logFileName)
0368         started = self.startJob( job_name )
0369         if started !=0:
0370             return started
0371         ret = -1
0372         try:
0373             # replacing %([key])s placeholders...
0374             command = command %(self.conf_dict)
0375             #replacing {[key]} placeholders
0376             command = command.format(**self.conf_dict )
0377         except KeyError as exc:
0378             self.logger.error( "Unresolved template key %s in the command." %str(exc) )
0379             return 3
0380         self.logger.info('Command: "%s"', command )
0381         out = ''
0382         try:
0383             self.logger.info('Executing command...' )
0384             pipe = subprocess.Popen( command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
0385             for line in pipe.stdout:
0386                 if args.verbose is not None and args.verbose>=1:
0387                     sys.stdout.write(line.decode())
0388                     sys.stdout.flush()
0389                 out += line.decode()
0390             pipe.communicate()
0391             self.logger.info( 'Command returned code: %s' %pipe.returncode )
0392             ret = pipe.returncode
0393         except Exception as e:
0394             self.logger.error( str(e) )
0395             return 4
0396         ended = self.endJob( pipe.returncode, out )
0397         if ended != 0:
0398             ret = ended
0399         with open(logFile,'a') as logF:
0400             logF.write(out)
0401         return ret
0402 
0403 def readConfiguration( config_filename ):
0404     config = ''
0405     try:
0406         with open( config_filename, 'r' ) as config_file:
0407             config = config_file.read().strip('\n')
0408             if config == '':
0409                 logging.error( 'The file %s contains an empty string.', config_filename )
0410             else:
0411                 json.loads(config)
0412     except IOError as e:
0413         logging.error( 'The file %s cannot be open.', config_filename )
0414     except ValueError as e:
0415         config = ''
0416         logging.error( 'The file "%s" contains an invalid json string.', config_filename )
0417     return config
0418 
0419 def checkConfiguration( config_string ):
0420     config = config_string
0421     try:
0422         json.loads(config)
0423     except ValueError as e:
0424         config = ''
0425         logging.error( 'The string "%s" is an invalid json format.', config_string )
0426     return config
0427 
0428     
0429 import optparse
0430 import argparse
0431 
0432 class O2OTool():
0433 
0434     def execute(self):
0435         parser = argparse.ArgumentParser(description='CMS o2o command-line tool. For general help (manual page), use the help subcommand.')
0436         parser.add_argument('--db', type=str, help='The target database: pro ( for prod ) or dev ( for prep ). default=pro')
0437         parser.add_argument("--auth","-a", type=str,  help="The path of the authentication file")
0438         parser.add_argument('--verbose', '-v', action='count', help='The verbosity level')
0439         parser_subparsers = parser.add_subparsers(title='Available subcommands')
0440         parser_create = parser_subparsers.add_parser('create', description='Create a new O2O job')
0441         parser_create.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0442         parser_create.add_argument('--configFile', '-c', type=str, help='the JSON configuration file path')
0443         parser_create.add_argument('--configString', '-s', type=str, help='the JSON configuration string')
0444         parser_create.add_argument('--interval', '-i', type=int, help='the chron job interval',default=0)
0445         parser_create.add_argument('--frequent', '-f',action='store_true',help='set the "frequent" flag for this job ("false" by default)')
0446         parser_create.set_defaults(func=self.create,role=auth.admin_role)
0447         parser_setConfig = parser_subparsers.add_parser('setConfig', description='Set a new configuration for the specified job. The configuration is expected as a list of entries "param": "value" (dictionary). The "param" labels will be used to inject the values in the command to execute. The dictionary is stored in JSON format.')
0448         parser_setConfig.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0449         parser_setConfig.add_argument('--configFile', '-c', type=str, help='the JSON configuration file path')
0450         parser_setConfig.add_argument('--configString', '-s', type=str, help='the JSON configuration string')
0451         parser_setConfig.set_defaults(func=self.setConfig,role=auth.admin_role)
0452         parser_setFrequent = parser_subparsers.add_parser('setFrequent',description='Set the "frequent" flag for the specified job')
0453         parser_setFrequent.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0454         parser_setFrequent.add_argument('--flag', '-f', choices=['0','1'], help='the flag value to set',required=True)
0455         parser_setFrequent.set_defaults(func=self.setFrequent,role=auth.admin_role)
0456         parser_setInterval = parser_subparsers.add_parser('setInterval',description='Set a new execution interval for the specified job')
0457         parser_setInterval.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0458         parser_setInterval.add_argument('--interval', '-i', type=int, help='the chron job interval',required=True)
0459         parser_setInterval.set_defaults(func=self.setInterval,role=auth.admin_role)
0460         parser_enable = parser_subparsers.add_parser('enable',description='enable the O2O job')
0461         parser_enable.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0462         parser_enable.set_defaults(func=self.enable,role=auth.admin_role)
0463         parser_disable = parser_subparsers.add_parser('disable',description='disable the O2O job')
0464         parser_disable.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0465         parser_disable.set_defaults(func=self.disable,role=auth.admin_role)
0466         parser_listJobs = parser_subparsers.add_parser('listJobs', description='list the registered jobs')
0467         parser_listJobs.set_defaults(func=self.listJobs,role=auth.reader_role)
0468         parser_listConf = parser_subparsers.add_parser('listConfig', description='shows the configurations for the specified job')
0469         parser_listConf.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0470         parser_listConf.add_argument('--dump', type=int, help='Dump the specified config.',default=0)
0471         parser_listConf.set_defaults(func=self.listConf,role=auth.reader_role)
0472         parser_dumpConf = parser_subparsers.add_parser('dumpConfig', description='dumps a specific job configuration version')
0473         parser_dumpConf.add_argument('versionIndex', type=str,help='the version to dump')
0474         parser_dumpConf.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0475         parser_dumpConf.add_argument('--configFile', '-c', type=str, help='the JSON configuration file name - default:[jobname]_[version].json')
0476         parser_dumpConf.set_defaults(func=self.dumpConf,role=auth.reader_role)
0477         parser_run = parser_subparsers.add_parser('run', description='Wrapper for O2O jobs execution. Supports input parameter injection from the configuration file associated to the job. The formatting syntax supported are the python ones: "command -paramName {paramLabel}" or "command -paramName %(paramLabel)s". where [paramName] is the name of the parameter required for the command, and [paramLabel] is the key of the parameter entry in the config dictionary (recommended to be equal for clarity!"')
0478         parser_run.add_argument('executable', type=str,help='command to execute')
0479         parser_run.add_argument('--name', '-n', type=str, help='The o2o job name',required=True)
0480         parser_run.set_defaults(func=self.run,role=auth.writer_role)
0481 
0482         args = parser.parse_args()
0483         
0484         if args.verbose is not None and args.verbose >=1:
0485             self.setup(args)
0486             return args.func()
0487         else:
0488             try:
0489                 self.setup(args) 
0490                 sys.exit( args.func())
0491             except Exception as e:
0492                 logging.error(e)
0493                 sys.exit(1)
0494 
0495     def setup(self, args):
0496         self.args = args
0497         db_service = prod_db_service
0498         if args.db is not None:
0499             if args.db == 'dev' or args.db == 'oradev' :
0500                 db_service = dev_db_service
0501             elif args.db != 'orapro' and args.db != 'onlineorapro' and args.db != 'pro':
0502                 raise Exception("Database '%s' is not known." %args.db )
0503         
0504         logLevel = logging.DEBUG if args.verbose is not None and args.verbose >= 1 else logging.INFO
0505         self.mgr = O2OJobMgr( logLevel )
0506         return self.mgr.connect( db_service, args )
0507         
0508     def create(self):
0509         configJson = None
0510         if self.args.configFile is not None:
0511             if self.args.configString is not None:
0512                 logging.error('Ambigouous input provided: please specify a configFile OR a configString')
0513                 return False
0514             else:
0515                 configJson = readConfiguration( self.args.configFile )
0516         else:
0517             if self.args.configString is None:
0518                 logging.error('No configuration has been provided: please specify "configFile" or "configString" param.')
0519                 return False
0520             else:
0521                 configJson = checkConfiguration( self.args.configString )
0522         self.mgr.add( self.args.name, configJson, self.args.interval, self.args.frequent, True )
0523 
0524     def setConfig(self):
0525         configJson = None
0526         if self.args.configFile is not None:
0527             if self.args.configString is not None:
0528                 logging.error('Ambigouous input provided: please specify a configFile OR a configString')
0529                 return False
0530             else:
0531                 configJson = readConfiguration( self.args.configFile )
0532         else:
0533             if self.args.configString is None:
0534                 logging.error('No configuration has been provided: please specify "configFile" or "configString" param.')
0535                 return False
0536             else:
0537                 configJson = checkConfiguration( self.args.configString )
0538         self.mgr.setConfig( self.args.name, configJson )
0539 
0540     def setInterval(self):
0541         self.mgr.setInterval( self.args.name, self.args.interval )
0542 
0543     def enable(self):
0544         self.mgr.set( self.args.name, True )
0545     
0546     def disable(self):
0547         self.mgr.set( self.args.name, False )
0548 
0549     def setFrequent(self):
0550         self.mgr.set( self.args.name, None, int(self.args.flag) )
0551 
0552     def listJobs(self):
0553         self.mgr.listJobs()
0554 
0555     def listConf(self):
0556         self.mgr.listConfig( self.args.name )
0557 
0558     def dumpConf(self):
0559         self.mgr.dumpConfig( self.args.name, self.args.versionIndex, self.args.configFile )
0560 
0561     def run(self):
0562         rmgr = self.mgr.runManager()
0563         return rmgr.executeJob( self.args )