Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-10-13 23:02:56

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