/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
CondCore/Utilities/scripts/conddb
3 005 строк
134 KB
Shahzad Malik Muzaffar
[ALCA-DB] py2/3 compatibility:drop use of __future__
22 ноя 2024, 20:15
22 ноя 2024, 20:15
c26340c
Код
Авторство
О чём код?
#!/usr/bin/env python3 '''CMS Conditions DB command-line tool. ''' import argparse import datetime import getpass import logging import os import re import sys import stat import subprocess import tempfile import textwrap import time import pwd import socket import calendar import sqlalchemy import json from prettytable import PrettyTable import CondCore.Utilities.conddblib as conddb import CondCore.Utilities.cond2xml as cond2xml import CondCore.Utilities.conddb_serialization_metadata as serialization_metadata import CondCore.Utilities.conddb_time as conddb_time from CondCore.Utilities.tier0 import Tier0Handler, Tier0Error, tier0Url # ------------------------------------------------------------------------------------------------------- # TODO: Diffs may look better in the -/+ mode, instead the 2 columns mode. # TODO: Colored diff! (green +, red -) # TODO: Support the old connection string syntax, e.g. sqlite_file://... maxSince = 18446744073709551615 sizeOfTimestamp = 19 tag_db_lock_access_code = 8 tag_db_write_access_code = 2 tag_db_read_access_code = 1 tag_db_no_protection_code = 0 db_key_credential_type_code = 1 db_cmsuser_credential_type_code = 2 db_session_credential_type_code = 4 db_access_code_map = { tag_db_write_access_code: "W", tag_db_lock_access_code: "L" } db_credential_type_map = { db_key_credential_type_code : ("DB KEY",'K'), db_cmsuser_credential_type_code : ("CMS USER",'U'), db_session_credential_type_code : ("DB SESSION",'S'), } # Utility functions def _rawdict(obj): return dict([(str(column), getattr(obj, column)) for column in obj.__table__.columns.keys()]) def _rawdict_selection(obj): return dict([(str(column), getattr(obj, column)) for column in obj._fields]) def _get_payload_full_hash(session, payload, check=True): # Limited to 2 to know whether there is more than one in a single query Payload = session.get_dbtype(conddb.Payload) payloads = session.query(Payload.hash).\ filter(Payload.hash.like('%s%%' % payload.lower())).\ limit(2).\ all() if check: if len(payloads) == 0: raise Exception('There is no payload matching %s in the database.' % payload) if len(payloads) > 1: raise Exception('There is more than one payload matching %s in the database. Please provide a longer prefix.' % payload) return payloads[0].hash if len(payloads) == 1 else None def _dump_payload(session, payload, loadonly): Payload = session.get_dbtype(conddb.Payload) data = session.query(Payload.data).\ filter(Payload.hash == payload).\ one()[0] logging.info('Loading %spayload %s of length %s ...', '' if loadonly else 'and dumping ', payload, len(data)) print('Data (TODO: Replace with the call to the actual compiled C++ tool):', repr(data)) def _identify_object(session, objtype, name): # We can't just use get() here since frontier fetches the entire # BLOBs by default when requesting them in a column Tag = session.get_dbtype(conddb.Tag) GlobalTag = session.get_dbtype(conddb.GlobalTag) if objtype is not None: # Check the type is correct (i.e. if the object exists) if objtype == 'tag': if not _exists(session, Tag.name, name): raise Exception('There is no tag named %s in the database.' % name) elif objtype == 'gt': if not _exists(session, GlobalTag.name, name): # raise Exception('There is no global tag named %s in the database.' % name) logging.info('There is no global tag table in the database.') elif objtype == 'payload': # In the case of a payload, check and also return the full hash return objtype, _get_payload_full_hash(session, name) return objtype, name # Search for the object tag = _exists(session, Tag.name, name) global_tag = _exists(session, GlobalTag.name, name) payload_hash = _get_payload_full_hash(session, name, check = False) count = len([x for x in filter(None, [tag, global_tag, payload_hash])]) if count > 1: raise Exception('There is more than one object named %s in the database.' % name) if count == 0: raise Exception('There is no tag, global tag or (unique) payload named %s in the database.' % name) if tag: return 'tag', name elif global_tag: return 'gt', name elif payload_hash is not None: return 'payload', payload_hash raise Exception('Should not have arrived here.') def _get_editor(args): if args.editor is not None: return args.editor editor = os.environ.get('EDITOR') if editor is None: raise Exception('An editor was not provided and the EDITOR environment variable does not exist either.') return editor def _run_editor(editor, tempfd): tempfd.flush() subprocess.check_call('%s %s' % (editor, tempfd.name), shell=True) tempfd.seek(0) def _parse_timestamp(timestamp): try: return datetime.datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S.%f') except ValueError: pass try: return datetime.datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S') except ValueError: pass try: return datetime.datetime.strptime(timestamp, '%Y-%m-%d') except ValueError: pass raise Exception("Could not parse timestamp '%s'" % timestamp) def _confirm_changes(args): if not args.yes: output(args, 'Confirm changes? [n]', newline=False) if input().lower() not in ['y', 'yes']: raise Exception('Aborted by the user.') def _get_user_note(args,message): output(args, message, newline=False) note = input() if note == '' or note == ' ': output(args,'Provided note is invalid, please provide a non-empty string: ',newline=False) note = input() if note == '' or note == ' ': raise Exception('Sorry, bailing out...') return note def _exists(session, primary_key, value): ret = None try: ret = session.query(primary_key).\ filter(primary_key == value).\ count() != 0 except sqlalchemy.exc.OperationalError: pass return ret def _regexp(connection, field, regexp): '''To be used inside filter(). ''' if connection.is_oracle or connection.is_frontier: return sqlalchemy.func.regexp_like(field, regexp) elif connection.is_sqlite: # Relies on being a SingletonThreadPool connection.engine.pool.connect().create_function('regexp', 2, lambda data, regexp: re.search(regexp, data) is not None) return sqlalchemy.func.regexp(field, regexp) else: raise Exception('Unimplemented.') def _ilike_or_regexp(args, connection, field, term): '''To be used inside filter(). ''' if args.regexp: return _regexp(connection, field, term) return field.ilike('%%%s%%' % term) def _ilike_or_regexp_highlight(args, string, term): '''Highlights the strings that would have matched _ilike_or_regexp() in the database, i.e. performs the same search client-side and adds colors around the matches ''' highlight = colors.bold_red + '\\1' + colors.end if args.regexp: return re.sub('(%s)' % term, highlight, string) return re.sub('(%s)' % re.escape(term), highlight, string, flags=re.IGNORECASE) def _list_object(obj): table = [] for column in obj.__table__.columns.keys(): table.append([column, getattr(obj, column)]) return table def _output_list_object(args, obj): output_table(args, _list_object(obj), ['Property', 'Value'], ) def _diff_objects(object1, object2): table = [] columns = object1.__table__.columns.keys() columns.remove('name') for column in columns: value1 = getattr(object1, column) value2 = getattr(object2, column) if value1 != value2: table.append([column, value1, value2]) return table def _output_diff_objects(args, object1, object2): output_table(args, _diff_objects(object1, object2), ['Property', '%s Value' % str_db_object(args.db, args.first), '%s Value' % str_db_object(args.destdb, args.second)], ) def _default(value, default_value='-'): return default_value if value is None else value def _truefalse(value): return 'Present' if value else '-' def _check_same_object(args): if (args.destdb is None or args.db == args.destdb) and (args.second is None or args.first == args.second): raise Exception('The source object and the destination object are the same (i.e. same database and same name): %s' % str_db_object(args.db, args.first)) def _connect(db, init, read_only, args, as_admin=False): logging.debug('Preparing connection to %s ...', db) url = conddb.make_url( db, read_only) pretty_url = url if url.drivername == 'oracle+frontier': ws = url.host.rsplit('%2F') if ws is not None: pretty_url = 'frontier://%s/%s' %(ws[-1],url.database) connTo = '%s [%s]' %(db,pretty_url) logging.info('Connecting to %s', connTo) logging.debug('DB url: %s',url) verbose= 0 if args.verbose is not None: verbose = args.verbose - 1 connection = conddb.connect(url, args.authPath, verbose, as_admin) if not read_only: if connection.is_read_only: raise Exception('Impossible to edit a read-only database.') if connection.is_official: if args.force: if not args.yes: logging.warning('You are going to edit an official database. If you are not one of the Offline DB experts but have access to the password for other reasons, please stop now.') else: raise Exception('Editing official databases is forbidden. Use the official DropBox to upload conditions. If you need a special intervention on the database, see the contact help: %s' % conddb.contact_help) # for sqlite we trigger the implicit schema creation if url.drivername == 'sqlite': if init: connection.init() if not connection._is_valid: raise Exception('No valid schema found in the database.') return connection def connect(args, init=False, read_only=True, as_admin=False): args.force = args.force if 'force' in dir(args) else False if 'destdb' in args: if args.destdb is None: args.destdb = args.db if args.db == args.destdb: conn1 = _connect(args.destdb, init, read_only, args) return conn1, conn1 conn1 = _connect( args.db, init, True, args) conn2url = conddb.make_url(args.destdb, False) if conn2url.drivername == 'sqlite' and not os.path.exists(args.destdb): init = True conn2 = _connect(args.destdb, init, False, args) return conn1, conn2 return _connect( args.db, init, read_only, args, as_admin) def str_db_object(db, name): return '%s::%s' % (db, name) def str_iov(since, insertion_time): return '(%s, %s)' % (since, insertion_time) def str_record(record, label): return '(%s, %s)' % (record, label) class Colors(object): normal_template = '\033[9%sm' bold_template = '\033[9%s;1m' bold = '\033[1m' black = normal_template % 0 red = normal_template % 1 green = normal_template % 2 yellow = normal_template % 3 blue = normal_template % 4 magenta = normal_template % 5 cyan = normal_template % 6 white = normal_template % 7 bold_black = bold_template % 0 bold_red = bold_template % 1 bold_green = bold_template % 2 bold_yellow = bold_template % 3 bold_blue = bold_template % 4 bold_magenta = bold_template % 5 bold_cyan = bold_template % 6 bold_white = bold_template % 7 end = '\033[0m' def __init__(self, args): if ( stat.S_ISFIFO(os.fstat(sys.stdout.fileno()).st_mode) or # we are running in a pipe args.nocolors ): self.noColors() def noColors(self): for member in dir(self): if not member.startswith('_'): setattr(self, member, '') colors = None def output(args, string, *parameters, **kwargs): if args.quiet: return output_file = kwargs.get('output_file', sys.stdout) to_print = string + colors.end if len(parameters)>0: to_print = string % parameters + colors.end print(to_print, end=' ', file=output_file) if kwargs.get('newline', True): print(file=output_file) def _strip_colors(args, string): '''Strips colors (i.e. ANSI sequences). ''' if args.nocolors: return string return re.sub('\x1b\\[[;\\d]*[A-Za-z]', '', string) def _ljust_colors(args, string, width, fillchar=' '): '''Same as string.ljust(width, fillchar) but supporting colors. ''' if args.nocolors: return string.ljust(width, fillchar) return string + fillchar * (width - len(_strip_colors(args, string))) def output_table(args, table, headers, filters=None, output_file=None, no_first_header=False, no_max_length=False): if args.quiet: return if output_file is None: output_file = sys.stdout if filters is None: filters = [None] * len(headers) def max_length_filter(s): #s = str(s).replace('\n', '\\n') s = str(s).replace('\n', ' ') s = str(s).replace(chr(13),' ') return '%s...' % s[:conddb.name_length] if ( len(s) > conddb.name_length and not no_max_length ) else s new_table = [[] for i in range(len(table))] for column_index in range(len(headers)): for row_index, row in enumerate(table): cell = max_length_filter(row[column_index]) if filters[column_index] is not None: cell = filters[column_index](cell) new_table[row_index].append(cell) # Calculate the width of each column widths = [] for column_index in range(len(headers)): width = len(headers[column_index]) for row in new_table: width = max(width, len(_strip_colors(args, row[column_index]))) widths.append(width) # Print the table header_separator = '-' column_separator = '' for column_index, header in enumerate(headers): output(args, colors.bold + _ljust_colors(args, header, widths[column_index]) + ' ' + column_separator, newline=False, output_file=output_file) output(args, '', output_file=output_file) for column_index in range(len(headers)): output(args, (' ' if column_index == 0 and no_first_header else header_separator) * widths[column_index] + ' ' + column_separator, newline=False, output_file=output_file) output(args, '', output_file=output_file) for row in new_table: for column_index, cell in enumerate(row): output(args, _ljust_colors(args, cell, widths[column_index]) + ' ' + column_separator, newline=False, output_file=output_file) output(args, '', output_file=output_file) output(args, '', output_file=output_file) # Commands def help(args): output(args, colors.bold + 'CMS Condition DB command-line tool.') output(args, '') output(args, colors.bold + 'Usage') output(args, colors.bold + '-----') output(args, '') output(args, ' This tool provides several subcommands, each of those') output(args, ' serves a well-defined purpose.') output(args, '') output(args, ' To see the list of available subcommands and the global options, run:') output(args, '') output(args, ' conddb -h') output(args, '') output(args, ' To see the help of a subcommand and its options, run:') output(args, '') output(args, ' conddb <command> -h.') output(args, ' e.g. conddb list -h') output(args, '') output(args, '') output(args, colors.bold + 'Exit status') output(args, colors.bold + '-----------') output(args, '') output(args, ' 0 = OK.') output(args, ' 1 = Runtime error (i.e. any kind of error not related to syntax).') output(args, ' 2 = Usage/syntax error.') output(args, '') output(args, '') output(args, colors.bold + 'Database parameter (--db)') output(args, colors.bold + '-------------------------') output(args, ' ' + '\n '.join(textwrap.dedent(conddb.database_help).splitlines())) output(args, '') output(args, '') output(args, colors.bold + 'Contact help') output(args, colors.bold + '------------') output(args, '') output(args, ' ' + '\n '.join(textwrap.wrap(conddb.contact_help))) output(args, '') def init(args): connection = connect(args, init=True, read_only=False) def status(args): connection = connect(args) valid = connection.is_valid() output(args, 'Database Status:') output(args, '') output(args, ' Schema: %s', 'OK (required tables are present)' if valid else 'Wrong (missing required tables)') if not valid: return session = connection.session() Tag = session.get_dbtype(conddb.Tag) Payload = session.get_dbtype(conddb.Payload) GlobalTag = session.get_dbtype(conddb.GlobalTag) tag_count = session.query(Tag.name).count() payload_count = session.query(Payload.hash).count() global_tag_count = session.query(GlobalTag.name).count() output(args, ' # tags: %s %s', tag_count, '(the last %s inserted are shown below)' % args.limit if tag_count > 0 else '') output(args, ' # payloads: %s %s', payload_count, '(the last %s inserted are shown below)' % args.limit if payload_count > 0 else '') output(args, ' # global tags: %s %s', global_tag_count, '(the last %s inserted are shown below)' % args.limit if global_tag_count > 0 else '') output(args, '') if tag_count > 0: output_table(args, session.query(Tag.name, Tag.time_type, Tag.object_type, Tag.synchronization, Tag.insertion_time, Tag.description).\ order_by(Tag.insertion_time.desc()).\ limit(args.limit).\ all(), ['Name', 'Time Type', 'Object Type', 'Synchronization', 'Insertion Time', 'Description'], ) if payload_count > 0: output_table(args, session.query(Payload.hash, Payload.object_type, Payload.version, Payload.insertion_time).\ order_by(Payload.insertion_time.desc()).\ limit(args.limit).\ all(), ['Payload', 'Object Type', 'Version', 'Insertion Time'], ) if global_tag_count > 0: output_table(args, session.query(GlobalTag.name, GlobalTag.release, GlobalTag.insertion_time, GlobalTag.description).\ order_by(GlobalTag.insertion_time.desc()).\ limit(args.limit).\ all(), ['Global Tag', 'Release', 'Insertion Time', 'Description'], ) def search(args): connection = connect(args) session = connection.session() max_limit = 100 if args.limit is not None and int(args.limit) > max_limit: raise Exception('The limit on the number of returned results is capped at %s. Please use a reasonable limit.' % max_limit) if connection.is_frontier and ':' in args.string: raise Exception('Sorry, the colon : character is not allowed in queries to Frontier (yet). Please use another search term or connect to Oracle directly.') logging.info('Searching with a limit of %s results per type of object, starting from the latest inserted ones. If you do not find your object, please try to be more specific or increase the limit of returned results.', args.limit) if args.nocolors: _ilike_or_regexp_highlight_filter = None else: def _ilike_or_regexp_highlight_filter(cell): return _ilike_or_regexp_highlight(args, cell, args.string) def size(cell): return str( sys.getsizeof( bytearray(cell,encoding='utf8') ) ) Tag = session.get_dbtype(conddb.Tag) output_table(args, session.query(Tag.name, Tag.time_type, Tag.object_type, Tag.synchronization, Tag.insertion_time, Tag.description).\ filter( _ilike_or_regexp(args, connection, Tag.name, args.string) | _ilike_or_regexp(args, connection, Tag.object_type, args.string) | _ilike_or_regexp(args, connection, Tag.description, args.string) ).\ order_by(Tag.insertion_time.desc()).\ limit(args.limit).\ all(), ['Tag', 'Time Type', 'Object Type', 'Synchronization', 'Insertion Time', 'Description'], filters = [_ilike_or_regexp_highlight_filter, None, _ilike_or_regexp_highlight_filter, None, None, _ilike_or_regexp_highlight_filter], ) Payload = session.get_dbtype(conddb.Payload) output_table(args, session.query(Payload.hash, Payload.object_type, Payload.version, Payload.insertion_time, Payload.data).\ filter( _ilike_or_regexp(args, connection, Payload.hash, args.string) | _ilike_or_regexp(args, connection, Payload.object_type, args.string) ).\ order_by(Payload.insertion_time.desc()).\ limit(args.limit).\ all(), ['Payload', 'Object Type', 'Version', 'Insertion Time', 'Size'], filters = [_ilike_or_regexp_highlight_filter, _ilike_or_regexp_highlight_filter, None, None, size], ) try: GlobalTag = session.get_dbtype(conddb.GlobalTag) output_table(args, session.query(GlobalTag.name, GlobalTag.release, GlobalTag.insertion_time, GlobalTag.description).\ filter( _ilike_or_regexp(args, connection, GlobalTag.name, args.string) | _ilike_or_regexp(args, connection, GlobalTag.release, args.string) | _ilike_or_regexp(args, connection, GlobalTag.description, args.string) ).\ order_by(GlobalTag.insertion_time.desc()).\ limit(args.limit).\ all(), ['Global Tag', 'Release', 'Insertion Time', 'Description'], filters = [_ilike_or_regexp_highlight_filter, _ilike_or_regexp_highlight_filter, None, _ilike_or_regexp_highlight_filter], ) except sqlalchemy.exc.OperationalError: sys.stderr.write("No table for GlobalTags found in DB.\n\n") def _inserted_before(_IOV,timestamp): '''To be used inside filter(). ''' if timestamp is None: # XXX: Returning None does not get optimized (skipped) by SQLAlchemy, # and returning True does not work in Oracle (generates "and 1" # which breaks Oracle but not SQLite). For the moment just use # this dummy condition. return sqlalchemy.literal(True) == sqlalchemy.literal(True) return _IOV.insertion_time <= _parse_timestamp(timestamp) def _high(n): return int(n) >> 32 def _low(n): return int(n) & 0xffffffff def _convertTimeType(since): #try: # return str(datetime.datetime.utcfromtimestamp(_high(since)).replace(microsecond = _low(since))) #except ValueError: # return str(datetime.datetime.utcfromtimestamp(_high(since)).replace(microsecond = _low(since)/1000)) # looks like the format of the lower part of the encoding is broken. Better ignore it... return str(datetime.datetime.utcfromtimestamp(_high(since)).replace(microsecond = 0)) def _since_filter(time_type): '''Returns a filter function for the given time type that returns a human-readable string of the given since. For run (sinces are 32-bit unsigned integers), hash (sinces are strings) and user (sinces are strings) the filter returns the sinces unchanged. The time sinces are 64-bit integers built from a pair (UNIX time, microseconds), each 32-bit wide. The filter returns a readable timestamp, including the microseconds. The lumi sinces are 64-bit integers built from a pair (run, lumi), each 32-bit wide. The filter returns a string with both numbers, split. ''' if time_type == conddb.TimeType.Time.value: return lambda since: '%s (%s)' % (_convertTimeType(since), since) if time_type == conddb.TimeType.Lumi.value: return lambda since: '%s : %5s (%s)' % (_high(since), _low(since), since) return lambda since: since def _get_hlt_fcsr( session, timeType ): RunInfo = session.get_dbtype(conddb.RunInfo) lastRun = session.query(sqlalchemy.func.max(RunInfo.run_number)).scalar() fcsr = lastRun+1 if timeType == 'Time': raise Exception('Cannot find time for non-existing runs.') ret = _convert_time( session, timeType, fcsr ) if timeType == 'Run': logging.info('Found fcsr for hlt: %s' %fcsr) else: logging.info('Found fcsr for hlt: %s ( %s as %s type )' %(fcsr,ret,timeType)) return ret def _get_prompt_fcsr( session, timeType ): tier0timeout = 5 tier0maxtime = 60 tier0retries = 3 tier0retryPeriod = 5 tier0proxy = None try: t0DataSvc = Tier0Handler( tier0Url, tier0timeout, tier0maxtime, tier0retries, tier0retryPeriod, tier0proxy, False ) try: fcsr = t0DataSvc.getFirstSafeRun() except ValueError as e: logging.error('ValueError for firstConditionSafeRun from Tier-0 %s ' % (str(e),) ) # We got an answer but it is invalid. So far this usually means # "None" which is not JSON, when the Tier0 is stopped. raise Exception('Invalid firstConditionSafeRun from Tier-0') except Tier0Error: # Impossible to get anything from the server after retries, # i.e. unreachable, so no data. raise Exception('Tier-0 is unreachable, i.e. no firstConditionSafeRun') except Exception as e: raise Exception('Error setting up Tier-0 data service: %s' %str(e)) ret = _convert_time( session, timeType, fcsr ) if timeType == 'Run': logging.info('Found Tier0 fcsr for prompt: %s' %fcsr) else: logging.info('Found Tier0 fcsr for prompt: %s ( %s as %s type )' %(fcsr,ret,timeType)) return ret def _get_last_frozen_since( session, tagName, fcsr=None ): IOV = session.get_dbtype(conddb.IOV) query = session.query(sqlalchemy.func.max(IOV.since)).filter(IOV.tag_name == tagName ) if fcsr is not None: query = query.filter(IOV.since<fcsr) res = query.scalar() logging.debug('Last frozen since in destination tag is %s' %res) return res def _get_maxtime_for_boost_version( session, timeType, boost_version): BoostRunMap = session.get_dbtype(conddb.BoostRunMap) q = session.query(BoostRunMap).order_by(BoostRunMap.boost_version.asc()) time = (maxSince,maxSince,maxSince) for r in q: r= _rawdict(r) if boost_version < r['boost_version']: tlumi = r['run_number']<<32|0x1 time = (r['run_number'],tlumi,r['run_start_time']) break if timeType=='Run': return time[0] elif timeType=='Lumi': return time[1] elif timeType=='Time': return time[2] return None class run_to_timestamp( object ): def __init__( self, session ): self.session = session def convertOne( self, runNumber ): logging.debug('Converting run %s to timestamp...' %runNumber) RunInfo = self.session.get_dbtype(conddb.RunInfo) bestRun = self.session.query(RunInfo.run_number,RunInfo.start_time, RunInfo.end_time).filter(RunInfo.run_number >= runNumber).first() if bestRun is None: raise Exception("Run %s can't be matched with an existing run in the database." %runNumber) return bestRun[1],bestRun[2] def convertIovs( self, iovs ): ks = sorted(iovs.keys()) logging.info('Converting %s run-based iovs to time-based' %len(iovs) ) RunInfo = self.session.get_dbtype(conddb.RunInfo) maxRun = ks[-1] upperRun = self.session.query(RunInfo.run_number).filter(RunInfo.run_number >= maxRun ).first() if upperRun is None: raise Exception("Upper limit run %s cannot be matched with an existing run in the database." %maxRun) upperRun = upperRun[0] runs = self.session.query(RunInfo.run_number,RunInfo.start_time).filter(RunInfo.run_number >= ks[0],RunInfo.run_number <=upperRun).\ order_by(RunInfo.run_number).all() newiovs = {} for since in ks: # take the smallest greater or equal to the target bestRun = min([run for run in runs if run[0] >= since],key=lambda x: x[0]) bestRunTime = calendar.timegm( bestRun[1].utctimetuple() ) << 32 newiovs[bestRunTime] = iovs[since] return newiovs class timestamp_to_run( object ): def __init__( self, session ): self.session = session def convertIovs( self, iovs ): ks = sorted(iovs.keys()) logging.info('Converting %s time-based iovs to run-based' %len(iovs) ) RunInfo = self.session.get_dbtype(conddb.RunInfo) minTs = datetime.datetime.utcfromtimestamp( int(ks[0]) >> 32 ) maxTs = datetime.datetime.utcfromtimestamp( int(ks[len(ks)-1]) >> 32 ) if self.session.query(RunInfo.end_time).filter(RunInfo.end_time > minTs).count() == 0: raise Exception("Lower IOV sincetimestamp %s cannot be matched with an existing run in the database."%minTs) firstRun = self.session.query(sqlalchemy.func.min(RunInfo.run_number)).filter(RunInfo.end_time > minTs).one()[0] if self.session.query(RunInfo.start_time).filter(RunInfo.start_time < maxTs).count() == 0: raise Exception("Upper iov since timestamp %s cannot be matched with an existing run in the database"%maxTs) lastRun = self.session.query(sqlalchemy.func.max(RunInfo.run_number)).filter(RunInfo.start_time < maxTs).one()[0] runs = self.session.query(RunInfo.run_number,RunInfo.start_time,RunInfo.end_time).filter(RunInfo.run_number >= firstRun).filter(RunInfo.run_number <= lastRun ).order_by(RunInfo.run_number).all() newiovs = {} prevRun = None for since in ks: ts = datetime.datetime.utcfromtimestamp( since >> 32 ) run = None for r in runs: if ts >= r[1] and ts <= r[2]: run = r[0] break if run is not None: if run == prevRun: logging.info('Skipping iov with since %s, because it corresponds to an already mapped run %s' %(since,run)) else: prevRun = run newiovs[run] = iovs[since] else: logging.info('Skipping iov with since %s, because no run is matching that time.'%since ) return newiovs def _convert_time( session, toTimeType, runNumber ): if toTimeType == 'Run': return runNumber elif toTimeType == 'Lumi': lumiId = runNumber<<32|0x1 logging.debug('Run %s encoded in lumi id %s' %(runNumber,lumiId)) return lumiId elif toTimeType == 'Time': converter = run_to_timestamp( session ) start, stop = converter.convertOne( runNumber ) logging.debug('Run %s coverted in time (start) %s' %(runNumber,start)) timest = calendar.timegm( start.utctimetuple() ) << 32 return timest else: raise Exception('Cannot convert to runs to time type %s' %toTimeType) class hlt_synchro_policy( object ): def __init__(self, session1, session2, timeType, destTag): if timeType in ('Time','Lumi'): raise Exception("Can't synchronize a tag with time type '%s' to hlt" %timeType) session = conddb.getSessionOnMasterDB( session1, session2 ) self.fcsr = _get_hlt_fcsr( session, timeType ) self.lastFrozenSince = _get_last_frozen_since( session2, destTag, self.fcsr ) def validate( self, iovs ): new_iovs = {} late_iovs = [] for since in sorted(iovs.keys(),reverse=True): if since >= self.fcsr: new_iovs[since] = iovs[since] else: if self.lastFrozenSince is None or since > self.lastFrozenSince: if self.fcsr not in new_iovs.keys(): new_iovs[self.fcsr] = iovs[since] else: late_iovs.append(since) else: late_iovs.append(since) nlate = len(late_iovs) if nlate>0: logging.warning('%s IOV(s) with since less than the hlt FCSR (%s) have been discarded.' %(nlate,self.fcsr) ) return True, new_iovs class prompt_synchro_policy( object ): def __init__(self, session1, session2, timeType, destTag): session = conddb.getSessionOnMasterDB( session1, session2 ) self.fcsr = _get_prompt_fcsr( session, timeType ) self.lastFrozenSince = _get_last_frozen_since( session2, destTag, self.fcsr ) def validate( self, iovs ): new_iovs = {} late_iovs = [] for since in sorted(iovs.keys(),reverse=True): if since >= self.fcsr: new_iovs[since] = iovs[since] else: if self.lastFrozenSince is None or since > self.lastFrozenSince: if self.fcsr not in new_iovs.keys(): new_iovs[self.fcsr] = iovs[since] else: late_iovs.append(since) else: late_iovs.append(since) nlate = len(late_iovs) if nlate>0: logging.warning('%s IOV(s) with since less than the tier0 FCSR (%s) have been discarded.' %(nlate,self.fcsr) ) return True, new_iovs class pcl_synchro_policy( object ): def __init__(self, session1, session2, timeType, destTag): session = conddb.getSessionOnMasterDB( session1, session2 ) self.fcsr = _get_prompt_fcsr(session, timeType) def validate( self, iovs ): new_iovs = {} late_iovs = [] ret = True for since in sorted(iovs.keys(),reverse=True): if since >= self.fcsr: new_iovs[since] = iovs[since] else: late_iovs.append(since) nlate = len(late_iovs) if nlate>0: logging.error('%s IOV(s) with since less than the tier0 FCSR (%s) have been discarded.' %(nlate,self.fcsr) ) ret = False return ret, new_iovs class mc_synchro_policy( object ): def __init__(self, session1, session2, timeType, destTag): self.lastFrozenSince = _get_last_frozen_since( session2, destTag ) def validate( self, iovs ): new_iovs = {} niovs = len(iovs) ret = True if self.lastFrozenSince is None: if 1 not in iovs.keys(): raise Exception( 'Could not find an iov with since 1 in the source tag.') new_iovs[1] = iovs[1] if niovs>1: logging.warning('%s IOV(s) with since greater than the expected mc since=1 will be discarded.' %(niovs-1)) else: if niovs>0: ret = False logging.warning('The destination tag is frozen - no iov can be added.') return ret, new_iovs class runmc_synchro_policy( object ): def __init__(self, session1, session2, timeType, destTag): self.lastFrozenSince = _get_last_frozen_since( session2, destTag ) def validate( self, iovs ): new_iovs = {} niovs = len(iovs) ret = True if self.lastFrozenSince is not None: if niovs>0: ret = False logging.warning('The destination tag is frozen - no iov can be added.') return ret, new_iovs class offline_synchro_policy( object ): def __init__(self, session1, session2, timeType, destTag): self.lastFrozenSince = _get_last_frozen_since( session2, destTag ) def validate( self, iovs ): new_iovs = {} late_iovs = [] for since in sorted(iovs.keys(),reverse=True): if self.lastFrozenSince is None or since > self.lastFrozenSince: new_iovs[since] = iovs[since] else: late_iovs.append(since) nlate = len(late_iovs) ret = True if nlate>0: ret = False logging.warning('%s IOV(s) with since less than the last since in the destination tag (%s) have been discarded.' %(nlate,self.lastFrozenSince) ) return ret, new_iovs class no_synchro_policy( object ): def __init__(self, session1=None, session2=None, timeType=None, destTag=None): pass def validate( self, iovs ): return True, iovs _synchro_map = { 'hlt': hlt_synchro_policy, 'express': hlt_synchro_policy, 'prompt': prompt_synchro_policy, 'pcl':pcl_synchro_policy, 'mc': mc_synchro_policy, 'offline': offline_synchro_policy, 'any':no_synchro_policy, 'validation':no_synchro_policy, 'runmc': runmc_synchro_policy } def _get_synchro_policy( synchronization ): if synchronization not in _synchro_map.keys(): raise Exception('Cannot handle synchronization %s' %synchronization) return _synchro_map[synchronization] def mc_validate( session, tag ): IOV = session.get_dbtype(conddb.IOV) niovs = session.query(IOV).filter(IOV.tag_name==tag).count() if niovs>1: logging.error('Validation of tag content for synchronization "mc" failed: more than one IOV found.') return False if niovs>0: r = int(session.query(IOV.since).filter(IOV.tag_name==tag).one()[0]) if r!=1: logging.error('Validation of tag content for synchronization "mc" failed: IOV since=%s (expected=1)' %r) return False return True def listTags_(args): connection = connect(args) session = connection.session() Tag = session.get_dbtype(conddb.Tag) output_table(args, session.query(Tag.name, Tag.time_type, Tag.object_type, Tag.synchronization, Tag.end_of_validity, Tag.insertion_time, Tag.description ).\ order_by(Tag.insertion_time, Tag.name).\ all(), ['Name', 'TimeType', 'ObjectType', 'Synchronisation', 'EndOfValidity', 'Insertion_time', 'Description'], ) return 0 def listParentTags_(args): connection = connect(args) session = connection.session() IOV = session.get_dbtype(conddb.IOV) Tag = session.get_dbtype(conddb.Tag) query_result = session.query(IOV.tag_name).filter(IOV.payload_hash == args.hash_name).all() tag_names = map(lambda entry : entry[0], query_result) listOfOccur=[] for tag in tag_names: synchro = session.query(Tag.synchronization).filter(Tag.name == tag).all() iovs = session.query(IOV.since).filter(IOV.tag_name == tag).filter(IOV.payload_hash == args.hash_name).all() times = session.query(IOV.insertion_time).filter(IOV.tag_name == tag).filter(IOV.payload_hash == args.hash_name).all() synchronization = [item[0] for item in synchro] listOfIOVs = [item[0] for item in iovs] listOfTimes = [str(item[0]) for item in times] for iEntry in range(0,len(listOfIOVs)): listOfOccur.append({"tag": tag, "synchronization" : synchronization[0], "since" : listOfIOVs[iEntry] , "insertion_time" : listOfTimes[iEntry] }) t = PrettyTable(['hash', 'since','tag','synch','insertion time']) for element in listOfOccur: t.add_row([args.hash_name,element['since'],element['tag'],element['synchronization'],element['insertion_time']]) print(t) def diffGlobalTagsAtRun_(args): connection = connect(args) session = connection.session() IOV = session.get_dbtype(conddb.IOV) TAG = session.get_dbtype(conddb.Tag) GT = session.get_dbtype(conddb.GlobalTag) GTMAP = session.get_dbtype(conddb.GlobalTagMap) RUNINFO = session.get_dbtype(conddb.RunInfo) #################################### # Get the time info for the test run #################################### if(not args.lastIOV): if(int(args.testRunNumber)<0): raise Exception("Run %s (default) can't be matched with an existing run in the database. \n\t\t Please specify a run with the option --run." % args.testRunNumber) if(int(args.testRunNumber)!=1): bestRun = session.query(RUNINFO.run_number, RUNINFO.start_time, RUNINFO.end_time).filter(RUNINFO.run_number == int(args.testRunNumber)).first() if bestRun is None: raise Exception("Run %s can't be matched with an existing run in the database." % args.testRunNumber) print("Run",args.testRunNumber," |Start time",bestRun[1]," |End time",bestRun[2],".") #################################### # Get the Global Tag snapshots #################################### refSnap = session.query(GT.snapshot_time).\ filter(GT.name == args.refGT).all()[0][0] tarSnap = session.query(GT.snapshot_time).\ filter(GT.name == args.tarGT).all()[0][0] print("reference GT (",args.refGT ,") snapshot: ",refSnap," | target GT (",args.tarGT,") snapshot",tarSnap) #################################### # Get the Global Tag maps #################################### GTMap_ref = session.query(GTMAP.record, GTMAP.label, GTMAP.tag_name).\ filter(GTMAP.global_tag_name == args.refGT).\ order_by(GTMAP.record, GTMAP.label).\ all() GTMap_tar = session.query(GTMAP.record, GTMAP.label, GTMAP.tag_name).\ filter(GTMAP.global_tag_name == args.tarGT).\ order_by(GTMAP.record, GTMAP.label).\ all() text_file = open(("diff_%s_vs_%s.twiki") % (args.refGT,args.tarGT), "w") differentTags = {} for element in GTMap_ref: RefRecord = element[0] RefLabel = element[1] RefTag = element[2] for element2 in GTMap_tar: if (RefRecord == element2[0] and RefLabel==element2[1]): if RefTag != element2[2]: differentTags[(RefRecord,RefLabel)]=(RefTag,element2[2]) #################################### ## Search for Records,Label not-found in the other list #################################### temp1 = [item for item in GTMap_ref if (item[0],item[1]) not in list(zip(list(zip(*GTMap_tar))[0],list(zip(*GTMap_tar))[1]))] for elem in temp1: differentTags[(elem[0],elem[1])]=(elem[2],"") temp2 = [item for item in GTMap_tar if (item[0],item[1]) not in list(zip(list(zip(*GTMap_ref))[0],list(zip(*GTMap_ref))[1]))] for elem in temp2: differentTags[(elem[0],elem[1])]=("",elem[2]) text_file.write("| *Record* | *"+args.refGT+"* | *"+args.tarGT+"* | Remarks | \n") t = PrettyTable() if(args.isVerbose): t.field_names = ['/','',args.refGT,args.tarGT,refSnap,tarSnap] else: t.field_names = ['/','',args.refGT,args.tarGT] t.hrules=1 if(args.isVerbose): t.add_row(['Record','label','Reference Tag','Target Tag','hash1:time1:since1','hash2:time2:since2']) else: t.add_row(['Record','label','Reference Tag','Target Tag']) isDifferent=False #################################### # Loop on the difference #################################### for Rcd in sorted(differentTags): # empty lists at the beginning refTagIOVs=[] tarTagIOVs=[] if( differentTags[Rcd][0]!=""): refTagIOVs = session.query(IOV.since,IOV.payload_hash,IOV.insertion_time).filter(IOV.tag_name == differentTags[Rcd][0]).all() refTagInfo = session.query(TAG.synchronization,TAG.time_type).filter(TAG.name == differentTags[Rcd][0]).all()[0] if( differentTags[Rcd][1]!=""): tarTagIOVs = session.query(IOV.since,IOV.payload_hash,IOV.insertion_time).filter(IOV.tag_name == differentTags[Rcd][1]).all() tarTagInfo = session.query(TAG.synchronization,TAG.time_type).filter(TAG.name == differentTags[Rcd][1]).all()[0] if(differentTags[Rcd][0]!="" and differentTags[Rcd][1]!=""): if(tarTagInfo[1] != refTagInfo[1]): print(colors.bold_red+" *** Warning *** found mismatched time type for",Rcd,"entry. \n"+differentTags[Rcd][0],"has time type",refTagInfo[1],"while",differentTags[Rcd][1],"has time type",tarTagInfo[1]+". These need to be checked by hand. \n\n"+ colors.end) if(args.lastIOV): if(sorted(differentTags).index(Rcd)==0): print("\n") print(33 * "=") print("|| COMPARING ONLY THE LAST IOV ||") print(33 * "=") print("\n") lastSinceRef=-1 lastSinceTar=-1 hash_lastRefTagIOV = "" time_lastRefTagIOV = "" hash_lastTarTagIOV = "" time_lastTarTagIOV = "" for i in refTagIOVs: if (i[0]>lastSinceRef): lastSinceRef = i[0] hash_lastRefTagIOV = i[1] time_lastRefTagIOV = str(i[2]) for j in tarTagIOVs: if (j[0]>lastSinceTar): lastSinceTar = j[0] hash_lastTarTagIOV = j[1] time_lastTarTagIOV = str(j[2]) if(hash_lastRefTagIOV!=hash_lastTarTagIOV): isDifferent=True text_file.write("| ="+Rcd[0]+"= ("+Rcd[1]+") | =="+differentTags[Rcd][0]+"== | =="+differentTags[Rcd][1]+"== | | \n") text_file.write("|^|"+hash_lastRefTagIOV+" <br> ("+time_lastRefTagIOV+") "+ str(lastSinceRef) +" | "+hash_lastTarTagIOV+" <br> ("+time_lastTarTagIOV+") " + str(lastSinceTar)+" | ^| \n") if(args.isVerbose): t.add_row([Rcd[0],Rcd[1],differentTags[Rcd][0],differentTags[Rcd][1],str(hash_lastRefTagIOV)+"\n"+str(time_lastRefTagIOV)+"\n"+str(lastSinceRef),str(hash_lastTarTagIOV)+"\n"+str(time_lastTarTagIOV)+"\n"+str(lastSinceTar)]) else: t.add_row([Rcd[0],Rcd[1],differentTags[Rcd][0]+"\n"+str(hash_lastRefTagIOV),differentTags[Rcd][1]+"\n"+str(hash_lastTarTagIOV)]) else: ### reset all defaults theGoodRefIOV=-1 theGoodTarIOV=-1 sinceRefTagIOV=0 sinceTarTagIOV=0 RefIOVtime = datetime.datetime(1970, 1, 1, 0, 0, 0) TarIOVtime = datetime.datetime(1970, 1, 1, 0, 0, 0) theRefPayload="" theTarPayload="" theRefTime="" theTarTime="" ### loop on the reference IOV list for refIOV in refTagIOVs: ## logic for retrieving the the last payload active on a given IOV ## - the new IOV since is less than the run under consideration ## - the payload insertion time is lower than the GT snapshot ## - finall either: ## - the new IOV since is larger then the last saved ## - the new IOV since is equal to the last saved but it has a more recent insertion time if ( (refIOV[0] <= int(args.testRunNumber)) and (refIOV[0]>sinceRefTagIOV) or ((refIOV[0]==sinceRefTagIOV) and (refIOV[2]>RefIOVtime)) and (refIOV[2]<=refSnap) ): sinceRefTagIOV = refIOV[0] RefIOVtime = refIOV[2] theGoodRefIOV=sinceRefTagIOV theRefPayload=refIOV[1] theRefTime=str(refIOV[2]) ### loop on the target IOV list for tarIOV in tarTagIOVs: if ( (tarIOV[0] <= int(args.testRunNumber)) and (tarIOV[0]>sinceTarTagIOV) or ((tarIOV[0]==sinceTarTagIOV) and (tarIOV[2]>=TarIOVtime)) and (tarIOV[2]<=tarSnap) ): sinceTarTagIOV = tarIOV[0] tarIOVtime = tarIOV[2] theGoodTarIOV=sinceTarTagIOV theTarPayload=tarIOV[1] theTarTime=str(tarIOV[2]) #print Rcd[0],theRefPayload,theTarPayload if(theRefPayload!=theTarPayload): isDifferent=True text_file.write("| ="+Rcd[0]+"= ("+Rcd[1]+") | =="+differentTags[Rcd][0]+"== | =="+differentTags[Rcd][1]+"== |\n") text_file.write("|^|"+theRefPayload+" ("+theRefTime+") | "+theTarPayload+" ("+theTarTime+") |\n") ### determinte if it is to be shown isMatched=False tokens=args.stringToMatch.split(",") decisions = [bool(Rcd[0].find(x)!=-1) for x in tokens] for decision in decisions: isMatched = (isMatched or decision) if(args.isVerbose): if (args.stringToMatch=="" or isMatched): t.add_row([Rcd[0],Rcd[1],differentTags[Rcd][0],differentTags[Rcd][1],str(theRefPayload)+"\n"+str(theRefTime)+"\n"+str(theGoodRefIOV),str(theTarPayload)+"\n"+str(theTarTime)+"\n"+str(theGoodTarIOV)]) else: if (args.stringToMatch=="" or isMatched): t.add_row([Rcd[0],Rcd[1],differentTags[Rcd][0]+"\n"+str(theRefPayload),differentTags[Rcd][1]+"\n"+str(theTarPayload)]) if(not isDifferent): if(args.isVerbose): t.add_row(["None","None","None","None","None","None"]) else: t.add_row(["None","None","None"]) print(t) def listGTsForTag_(args): connection = connect(args) session = connection.session() GlobalTagMap = session.get_dbtype(conddb.GlobalTagMap) output_table(args, session.query(GlobalTagMap.global_tag_name, GlobalTagMap.tag_name, GlobalTagMap.record, GlobalTagMap.label).\ filter(GlobalTagMap.tag_name == args.name).\ order_by(GlobalTagMap.global_tag_name).\ all(), ['GT_name', 'Tag_name', 'record', 'label'], ) def listGTs_(args): connection = connect(args) session = connection.session() GlobalTag = session.get_dbtype(conddb.GlobalTag) output_table(args, session.query(GlobalTag.name, GlobalTag.description, GlobalTag.release, GlobalTag.snapshot_time, GlobalTag.insertion_time).\ order_by(GlobalTag.insertion_time, GlobalTag.name).\ all(), ['GT_name', 'Description', 'Release', 'Snapshot_time', 'Insertion_time'], ) def listRuns_(args): connection = connect(args) session = connection.session() RunInfo = session.get_dbtype(conddb.RunInfo) fromRun = None toRun = None match = args.match limit = None if args.last: match = session.query(sqlalchemy.func.max(RunInfo.run_number)).one()[0] if match is None: fromTime = getattr(args, 'from') if fromTime is not None: fromTime = str(fromTime) fromRun = fromTime start = None if fromTime.isnumeric(): if len(fromTime) >= sizeOfTimestamp: start = datetime.datetime.utcfromtimestamp( int(fromTime) >> 32 ) else: start = datetime.datetime.strptime(fromTime,'%Y-%m-%d %H:%M:%S') if start is not None: fromRun = session.query(sqlalchemy.func.min(RunInfo.run_number)).filter(RunInfo.end_time > start).one()[0] logging.debug('run lower boundary: %s (%s)'%(fromRun, start.strftime('%Y-%m-%d %H:%M:%S'))) toTime = getattr(args, 'to') if toTime is not None: toTime = str(toTime) toRun = toTime end = None if toTime.isnumeric(): if len(toTime) >= sizeOfTimestamp: end = datetime.datetime.utcfromtimestamp( int(toTime) >> 32 ) else: end=datetime.datetime.strptime(toTime,'%Y-%m-%d %H:%M:%S') if end is not None: toRun = session.query(sqlalchemy.func.max(RunInfo.run_number)).filter(RunInfo.start_time < end).one()[0] logging.debug('run upper boundary: %s (%s)' %(toRun,end.strftime('%Y-%m-%d %H:%M:%S'))) q = session.query(RunInfo.run_number,RunInfo.start_time,RunInfo.end_time) sel = False if match is not None: q = q.filter(RunInfo.run_number == match) else: if fromRun is not None: q = q.filter(RunInfo.run_number >= fromRun) sel = True if toRun is not None: q = q.filter(RunInfo.run_number <= toRun) sel = True if not sel and args.limit is not None: limit = args.limit q = q.order_by(RunInfo.run_number.desc()) q = q.limit(limit) q = q.from_self() table = q.order_by(RunInfo.run_number).all() if len(table)==0: sel = '' msg = 'No Run found' if args.match is not None: sel = 'matching Run=%s' %args.match else: fromTime = getattr(args, 'from') if fromTime is not None: sel = "with from='%s'"%fromTime if args.to is not None: if len(sel): sel = sel +' and ' else: sel = 'with ' sel = sel + "to='%s'"%args.to msg = msg + ' %s'%sel print(msg) return 1 else: if limit is not None: logging.info('Run entries limited to %s'%limit) else: logging.info('Found %s Run entries.'%len(table)) for i in range(len(table)): table[i] = table[i] + ( (calendar.timegm( table[i][1].utctimetuple() ) << 32), (calendar.timegm( table[i][2].utctimetuple() ) << 32) ) # check if last run is ongoing last_start = table[len(table)-1][1] last_end = table[len(table)-1][2] if last_start==last_end: table[len(table)-1]=(table[len(table)-1][0],table[len(table)-1][1],'on going...',table[len(table)-1][3],'-') output_table(args, table, ['Run_number','Start_time','End_time','Start_IOV','End_IOV'], ) return 0 def showFcsr_(args): connection = connect(args) session = connection.session() session = conddb.getSessionOnMasterDB( session, session ) run_hlt_fcsr = _get_hlt_fcsr( session, 'Run' ) lumi_hlt_fcsr = _convert_time( session, 'Lumi', run_hlt_fcsr ) run_pcl_fcsr = _get_prompt_fcsr( session, 'Run' ) lumi_pcl_fcsr = _convert_time( session, 'Lumi', run_pcl_fcsr ) time_converter = run_to_timestamp( session ) start, stop = time_converter.convertOne( run_pcl_fcsr ) time_pcl_fcsr = calendar.timegm( start.utctimetuple() ) << 32 output(args,'FCSR for HLT (last Run started +1): %s ( Lumi: %s, Time: undefined )' %(run_hlt_fcsr,lumi_hlt_fcsr)) output(args,'FCSR for PCL (from Tier0 service) : %s ( Lumi: %s, Time: %s [%s])' %(run_pcl_fcsr,lumi_pcl_fcsr,time_pcl_fcsr,start), newLine=False) def list_(args): connection = connect(args) session = connection.session() Tag = session.get_dbtype(conddb.Tag) IOV = session.get_dbtype(conddb.IOV) Payload = session.get_dbtype(conddb.Payload) GlobalTag = session.get_dbtype(conddb.GlobalTag) GlobalTagMap = session.get_dbtype(conddb.GlobalTagMap) for name in args.name: is_tag = _exists(session, Tag.name, name) if is_tag: if args.long: _output_list_object(args, session.query(Tag).get(name)) logging.info('Listing with a limit of %s IOVs, starting from the highest since. If you need to see more, please increase the limit of returned results.', args.limit) time_type = session.query(Tag.time_type).\ filter(Tag.name == name).\ scalar() sinceLabel = 'Since: Run ' if time_type == conddb.TimeType.Time.value: sinceLabel = 'Since: UTC (timestamp)' if time_type == conddb.TimeType.Lumi.value: sinceLabel = ' Run : Lumi (rawSince)' output_table(args, session.query(IOV.since, IOV.insertion_time, IOV.payload_hash, Payload.object_type).\ join(IOV.payload).\ filter( IOV.tag_name == name, _inserted_before(IOV,args.snapshot), ).\ order_by(IOV.since.desc(), IOV.insertion_time.desc()).\ limit(args.limit).\ from_self().\ order_by(IOV.since, IOV.insertion_time).\ all(), [sinceLabel, 'Insertion Time', 'Payload', 'Object Type'], filters = [_since_filter(time_type), None, None, None], ) try: is_global_tag = _exists(session, GlobalTag.name, name) if is_global_tag: if args.long: _output_list_object(args, session.query(GlobalTag).get(name)) output_table(args, session.query(GlobalTagMap.record, GlobalTagMap.label, GlobalTagMap.tag_name).\ filter(GlobalTagMap.global_tag_name == name).\ order_by(GlobalTagMap.record, GlobalTagMap.label).\ all(), ['Record', 'Label', 'Tag'], ) except sqlalchemy.exc.OperationalError: sys.stderr.write("No table for GlobalTags found in DB.\n\n") if not is_tag and not is_global_tag: raise Exception('There is no tag or global tag named %s in the database.' % name) def _diff_tags(args, session1, session2, first, second): Tag1 = session1.get_dbtype(conddb.Tag) Tag2 = session2.get_dbtype(conddb.Tag) IOV1 = session1.get_dbtype(conddb.IOV) IOV2 = session2.get_dbtype(conddb.IOV) tag1 = session1.query(Tag1).get(first) tag2 = session2.query(Tag2).get(second) if args.long: _output_diff_objects(args, tag1, tag2) if tag1.time_type != tag2.time_type: output(args, 'Skipping diff of IOVs, since the time_type is different.') else: iovs1 = dict(session1.query(IOV1.since, IOV1.payload_hash).\ filter( IOV1.tag_name == first, _inserted_before(IOV1,args.snapshot), ).\ all() ) iovs2 = dict(session2.query(IOV2.since, IOV2.payload_hash).\ filter( IOV2.tag_name == second, _inserted_before(IOV2,args.snapshot), ).\ all() ) table = [] iovs = [(x, iovs1.get(x), iovs2.get(x)) for x in sorted(set(iovs1) | set(iovs2))] # Since 1 != 2 and both are != than any payload, # this will trigger printing the last line [last_since, Infinity) iovs.append(('Infinity', 1, 2)) prev_since, prev_payload1, prev_payload2, prev_equal = None, None, None, None for since, payload1, payload2 in iovs: if prev_since is None: # First time prev_equal = payload1 == payload2 prev_since = since prev_payload1, prev_payload2 = payload1, payload2 continue # If None, the payloads are the previous one if payload1 is None: payload1 = prev_payload1 if payload2 is None: payload2 = prev_payload2 if prev_equal: # If the previous payloads were equal and these ones # were too, we do not print anything (and we do not update # the prev_since). If the previous were equal but these # are different, the equal-range has finished: we print it. if payload1 != payload2: if not args.short: table.append(('[%s, %s)' % (prev_since, since), '=', '=')) prev_since = since else: # If the previous payloads were not equal, we print them, # since we print all the different ranges (even if they are # contiguous). However, we skip in the case these payloads # and both equal to the previous ones (and we do not # update the prev_since). Should not be common, since # there is no point on having contiguous IOVs with the same # payloads in a tag. if payload1 != prev_payload1 or payload2 != prev_payload2: table.append(('[%s, %s)' % (prev_since, since), _default(prev_payload1), _default(prev_payload2))) prev_since = since prev_equal = payload1 == payload2 prev_payload1, prev_payload2 = payload1, payload2 output_table(args, table, ['Range', '%s Payload' % str_db_object(args.db, first), '%s Payload' % str_db_object(args.destdb, second)], ) def diff(args): _check_same_object(args) connection1, connection2 = connect(args) session1, session2 = connection1.session(), connection2.session() if args.second is None: args.second = args.first Tag1 = session1.get_dbtype(conddb.Tag) Tag2 = session2.get_dbtype(conddb.Tag) is_tag1 = _exists(session1, Tag1.name, args.first) is_tag2 = _exists(session2, Tag2.name, args.second) if is_tag1 and is_tag2: _diff_tags(args, session1, session2, args.first, args.second) GlobalTag1 = session1.get_dbtype(conddb.GlobalTag) GlobalTag2 = session2.get_dbtype(conddb.GlobalTag) is_global_tag1 = _exists(session1, GlobalTag1.name, args.first) is_global_tag2 = _exists(session2, GlobalTag2.name, args.second) if is_global_tag1 and is_global_tag2: global_tag1 = session1.query(GlobalTag1).get(args.first) global_tag2 = session2.query(GlobalTag2).get(args.second) if args.long: _output_diff_objects(args, global_tag1, global_tag2) GlobalTagMap1 = session1.get_dbtype(conddb.GlobalTagMap) GlobalTagMap2 = session2.get_dbtype(conddb.GlobalTagMap) map1 = dict([(tuple(x[:2]), x[2]) for x in session1.query(GlobalTagMap1.record, GlobalTagMap1.label, GlobalTagMap1.tag_name).\ filter(GlobalTagMap1.global_tag_name == args.first) ]) map2 = dict([(tuple(x[:2]), x[2]) for x in session2.query(GlobalTagMap2.record, GlobalTagMap2.label, GlobalTagMap2.tag_name).\ filter(GlobalTagMap2.global_tag_name == args.second) ]) records = sorted(set(map1) | set(map2)) table = [] diff_tags = set([]) for record in records: value1 = map1.get(record) value2 = map2.get(record) if value1 is None or value2 is None or value1 != value2: table.append((record[0], record[1], _default(value1), _default(value2))) diff_tags.add((value1, value2)) output_table(args, table, ['Record', 'Label', '%s Tag' % str_db_object(args.db, args.first), '%s Tag' % str_db_object(args.destdb, args.second)], ) if args.deep: for tag1, tag2 in diff_tags: _diff_tags(args, session1, session2, tag1, tag2) if not (is_tag1 and is_tag2) and not (is_global_tag1 and is_global_tag2): raise Exception('There are no tag or global tag pairs named %s and %s in the database(s).' % (args.first, args.second)) def convertRunToTimes( session, fromRun, toRun ): fromTime = None fromLumi = None toTime = None toLumi = None # the time we get may be a bit delayed (7-10 sec according to Salvatore) if not fromRun is None: if fromRun == 1: fromTime = 1 else: conv = run_to_timestamp( session ) startTime1, stopTime1 = conv.convertOne( fromRun ) fromTime = time.mktime( startTime1.timetuple() )-15. fromLumi = fromRun<<32|0x1 if not toRun is None: if toRun == 1: toTime = 1 else: conv = run_to_timestamp( session ) startTime2, stopTime2 = conv.convertOne( toRun ) toTime = time.mktime( stopTime2.timetuple() )+15. toLumi = toRun<<32|0x1 timeMap = { 'from' : { 'hash' : None, 'run' : fromRun, 'time' : fromTime, # the time we get may be a bit delayed (7-10 sec according to Salvatore) 'lumi' : fromLumi, }, 'to' : { 'hash' : None, 'run' : toRun, 'time' : toTime, # the time we get may be a bit delayed (7-10 sec according to Salvatore) 'lumi' : toLumi, } } logging.debug("convertRunToTimes> start: %s stop %s \n timeMap: %s " % (fromRun, toRun, str(timeMap))) return timeMap def _update_tag_log(session,the_tag,the_timestamp,the_action,note): # run parameters userName = pwd.getpwuid(os.getuid()).pw_name hostName = socket.getfqdn() userCommand = " ".join(sys.argv[0:]) TagLog = session.get_dbtype(conddb.TagLog) session.add(TagLog(tag_name=the_tag, event_time=the_timestamp, action=the_action, user_name=userName, host_name=hostName, command=userCommand, user_text=note )) def _copy_payload( args, copyTime, session1, session2, payloadHash, payloadSerializationVersionMap=None ): Payload1 = session1.get_dbtype(conddb.Payload) Payload2 = session2.get_dbtype(conddb.Payload) ret = False streamerInfo = None if _exists(session2, Payload2.hash, payloadHash): logging.debug('Skipping copy of payload %s to %s since it already exists...', str_db_object(args.db, payloadHash), str_db_object(args.destdb, payloadHash)) if payloadSerializationVersionMap is not None: q = session1.query(Payload1.streamer_info).filter(Payload1.hash == payloadHash).one() streamerInfo = q[0] else: logging.info('Copying payload %s to %s ...', str_db_object(args.db, payloadHash), str_db_object(args.destdb, payloadHash)) q = session1.query(Payload1).filter(Payload1.hash == payloadHash).one() payload = _rawdict(q) payload['insertion_time'] = copyTime streamerInfo = payload['streamer_info'] session2.add(Payload2(** payload)) ret = True if payloadSerializationVersionMap is not None: serialization_version = serialization_metadata.get_boost_version_from_streamer_info(streamerInfo) payloadSerializationVersionMap[payloadHash] = serialization_version return ret def _copy_tag(args, copyTime, session1, session2, first, second, fromIOV=None, toIOV=None, timeMap=None): ret = True Tag1 = session1.get_dbtype(conddb.Tag) Tag2 = session2.get_dbtype(conddb.Tag) # Copy the tag obj = session1.query(Tag1.name, Tag1.time_type, Tag1.object_type, Tag1.synchronization, Tag1.description, Tag1.last_validated_time, Tag1.end_of_validity, Tag1.insertion_time, Tag1.modification_time).filter(Tag1.name == first).first() tag = _rawdict_selection(obj) tag['name'] = second if session2._is_sqlite: if tag['end_of_validity'] >= maxSince: tag['end_of_validity'] = -1 else: if tag['end_of_validity'] == -1 or tag['end_of_validity'] > maxSince : tag['end_of_validity'] = maxSince tag['insertion_time'] = copyTime tag['modification_time'] = copyTime if timeMap: fromIOV = timeMap['from'][ tag['time_type'].lower().strip() ] toIOV = timeMap['to'] [ tag['time_type'].lower().strip() ] if fromIOV is None: fromIOV = 1 selectStr = 'from since=%s' %fromIOV if toIOV is not None: selectStr += ' to since=%s' %toIOV if args.snapshot is not None: selectStr += ' selecting insertion time < %s' %args.snapshot logging.info('Copying tag %s to %s %s', str_db_object(args.db, first), str_db_object(args.destdb, second), selectStr) query = session2.query(Tag2.time_type, Tag2.object_type, Tag2.synchronization).filter(Tag2.name == second ) destExists = False destPayloadType = None destTimeType = None destSynchro = None for t in query: destExists = True t = _rawdict_selection(t) destPayloadType = t['object_type'] destTimeType = t['time_type'] destSynchro = t['synchronization'] if args.toTimestamp: if tag['time_type'] == 'Time': logging.info('Source Tag timeType=Time. Ignoring request of conversion to Timestamp') args.toTimestamp = False else: if not tag['time_type']=='Run': logging.error('Conversion from %s to Timestamp is not supported.' %tag['time_type']) raise Exception("Cannot execute the copy.") if args.toRun: if tag['time_type'] == 'Run': logging.info('Source Tag timeType=Run. Ignoring request of conversion to Run') args.toRun = False else: if not tag['time_type']=='Time': logging.error('Conversion from %s to Run is not supported.' %tag['time_type']) raise Exception("Cannot execute the copy.") if destExists: logging.warning('Destination tag "%s" already exists.' %second ) if destPayloadType != tag['object_type']: logging.error('Cannot copy iovs from tag %s (object type: %s) to tag %s (object type: %s), since the object types are different.' %(first,tag['object_type'],second,destPayloadType)) raise Exception('Object type mismatch, bailing out.') destTimeTypeOk = (destTimeType == tag['time_type']) if args.toTimestamp: if not destTimeType=='Time': logging.error('TimeType of target tag %s does not allow conversion to Time.' %destTimeType) raise Exception("Cannot execute the copy.") else: destTimeTypeOk = True if args.toRun: if not destTimeType=='Run': logging.error('TimeType of target tag %s does not allow conversion to Run.' %destTimeType) raise Exception("Cannot execute the copy.") else: destTimeTypeOk = True if not destTimeTypeOk: logging.error('Cannot copy iovs from tag %s (time type: %s) to tag %s (time type: %s), since the time types are different.' %(first,tag['time_type'],second,destTimeType)) raise Exception('Time type mismatch, bailing out.') if not args.yes: output(args, 'Confirm the update of the existing tag "%s" in %s [n]?' %(second,args.destdb), newline=False) if input().lower() not in ['y', 'yes']: raise Exception('Aborted by the user.') else: destSynchro = 'any' if args.toTimestamp: tag['time_type'] = 'Time' if args.toRun: tag['time_type'] = 'Run' destTimeType = tag['time_type'] dest = Tag2(**tag) dest.synchronization = destSynchro session2.add(dest) note = args.note if note is None or note=='' or note==' ': note = '-' _update_tag_log(session2,second,copyTime,'New tag created.',note) IOV1 = session1.get_dbtype(conddb.IOV) IOV2 = session2.get_dbtype(conddb.IOV) # Get the closest smaller IOV than the given starting point (args.from), # since it may lie between two sinces. For the ending point (args.to) # is not needed, since the last IOV of a tag always goes up to infinity. # In the case where the starting point is before any IOV, we do not need # to cut the query anyway. prev_iov = None if fromIOV is not None: fromVal = fromIOV logging.debug("checking FROM %s of type %s for tag: %s " % (fromIOV, tag['time_type'], str(tag['name'])) ) prev_iov = session1.query(IOV1.since).\ filter( IOV1.tag_name == first, IOV1.since <= fromVal, _inserted_before(IOV1,args.snapshot) ).\ order_by(IOV1.since.desc()).\ limit(1).\ scalar() logging.debug('The closest smaller IOV than the given starting one (--from %s) is %s...', fromVal, prev_iov) # Select the input IOVs query = session1.query(IOV1).filter(IOV1.tag_name == first) if prev_iov is not None: query = query.filter(IOV1.since >= prev_iov) if toIOV is not None: query = query.filter(IOV1.since <= toIOV) query = query.filter(_inserted_before(IOV1,args.snapshot)) iovs = {} hashes = set() payloadSerializationVersionMap = None if session2.is_oracle: payloadSerializationVersionMap = {} if not args.o2oTest: query = query.order_by(IOV1.since, IOV1.insertion_time.desc()) for iov in query: iov = _rawdict(iov) # In the first IOV of the tag we need to use the starting point given # by the user, instead of the one coming from the source tag; unless # the starting point was before any IOV: in such case, up to the first # IOV there is no payload, so we use the one from the source tag. # Note that we need to replace it for every insertion time (since # the primary key is (since, insertion_time). if prev_iov is not None and iov['since'] == prev_iov: iov['since'] = fromIOV since = iov['since'] if since not in iovs.keys(): # for a given since, only the most recent will be added. iovs[since] = iov['payload_hash'] else: logging.warning('Skipping older iov with since %s...', since) sourceIovSize = len(iovs) logging.info('Selected %s source iov(s)' %sourceIovSize) if not args.nosynchro: # synchronize lower boundary when required logging.info('Destination tag synchronization is %s' %destSynchro) policy_type = _get_synchro_policy( destSynchro ) synchro_policy = policy_type( session1, session2, destTimeType, second ) ret, iovs = synchro_policy.validate( iovs ) if args.toTimestamp: converter = run_to_timestamp( conddb.getSessionOnMasterDB( session1, session2 ) ) iovs = converter.convertIovs( iovs ) if args.toRun: converter = timestamp_to_run( conddb.getSessionOnMasterDB( session1, session2 ) ) iovs = converter.convertIovs( iovs ) # making the list of the payloads to export... for since in iovs.keys(): hashes.add( iovs[since] ) logging.debug('%s iov(s) to copy with %s payload(s)' %(len(iovs),len(hashes))) else: maxTime = _get_maxtime_for_boost_version( session1, tag['time_type'], cond2xml.boost_version_for_this_release()) logging.info('Max time for boost version %s is %s'%(cond2xml.boost_version_for_this_release(),maxTime)) query = query.order_by(IOV1.since.desc(), IOV1.insertion_time.desc()) lastIov = None prevIovSince = None targetIovSince = None targetIovPayload = None for iov in query: iov = _rawdict(iov) since = iov['since'] if lastIov is None: lastIov = since else: if lastIov != since: if targetIovSince is None: targetIovSince = since if since < maxTime: targetIovPayload = iov['payload_hash'] prevIovSince = since break iovs[prevIovSince]=targetIovPayload iovs[targetIovSince]=targetIovPayload hashes.add(targetIovPayload) logfun = logging.info if len(iovs)==0: logfun = logging.warning logfun('Found %s iovs and %s referenced payloads to copy.',len(iovs), len(hashes)) # Copy the payloads referenced in the selected iovs np = 0 for h in hashes: if _copy_payload( args, copyTime, session1, session2, h, payloadSerializationVersionMap ): np += 1 if not np==0: logging.info('%s payload(s) copied.',np) # Calculate if extra iovs are needed - for the override mode ( they will have already their payloads copied ) extraiovs = {} if args.override: # the interval to be overriden is defined by the new iov set boundaries, # or by the actual user-provided boundaries - when available l_b = sorted(iovs.keys())[0] h_b = sorted(iovs.keys())[-1] if fromIOV is not None: l_b = fromIOV if toIOV is not None: h_b = toIOV query = session2.query(IOV2).filter(IOV2.tag_name == second) query = query.filter(IOV2.since >= l_b).filter(IOV2.since <= h_b) query = query.order_by(IOV2.since, IOV2.insertion_time.desc()) for iov in query: iov = _rawdict(iov) since = iov['since'] if since not in extraiovs.keys() and since not in iovs.keys(): for newSince in sorted(iovs.keys(),reverse=True): if newSince < since: extraiovs[since] = iovs[newSince] break # re-assemble the 2 iov set if len(extraiovs): logging.info('Adding %s extra iovs for overriding the existing ones with the payloads from the new iovs...' %len(extraiovs)) if args.override and len(extraiovs)==0: logging.info('No extra iovs required for overriding the existing ones with the new ones.') for k,v in extraiovs.items(): iovs[k] = extraiovs[k] # Copy the set of IOVs collected session2.merge(Tag2(name=second,modification_time=copyTime)) minIov = None if payloadSerializationVersionMap is not None: BoostRunMap = session2.get_dbtype(conddb.BoostRunMap) q = session2.query(BoostRunMap).order_by(BoostRunMap.run_number) boost_run_map = [] for r in q: r = _rawdict(r) boost_run_map.append( (r['run_number'],r['run_start_time'],r['boost_version']) ) TagMetadata = session2.get_dbtype(conddb.TagMetadata) q = session2.query(TagMetadata.min_serialization_v,TagMetadata.min_since).filter(TagMetadata.tag_name == second ) tagBoostVersion = None for r in q: tagBoostVersion = r[0] minIov = r[1] break currentTagBoostVersion = tagBoostVersion if len(iovs)>0 and destExists and currentTagBoostVersion is None: raise Exception('No information found about the destination tag boost version. Cannot proceed with the update.') logging.info('Destination tag boost version is %s' %currentTagBoostVersion ) niovs = 0 for k,v in iovs.items(): logging.debug('Copying IOV %s -> %s...', k, v) session2.add(IOV2(tag_name=second,since=k,insertion_time=copyTime,payload_hash=v)) niovs += 1 if payloadSerializationVersionMap is not None: if v in payloadSerializationVersionMap.keys(): tagBoostVersion = serialization_metadata.do_update_tag_boost_version(tagBoostVersion,minIov,payloadSerializationVersionMap[v], k, destTimeType, boost_run_map ) if minIov is None or k<minIov: minIov = k if not niovs==0: logging.info('%s iov(s) copied.',niovs) merge = False if payloadSerializationVersionMap is not None and tagBoostVersion is not None: if currentTagBoostVersion is not None: if currentTagBoostVersion != tagBoostVersion: if serialization_metadata.cmp_boost_version( currentTagBoostVersion, tagBoostVersion )<0: if destSynchro not in ['any','validation']: raise Exception('Cannot update existing tag %s, since the minimum serialization version %s is not compatible with the combined boost version of the payloads to add (%s)' %(second,currentTagBoostVersion,tagBoostVersion)) merge = True if merge: session2.merge(TagMetadata(tag_name=second,min_serialization_v=tagBoostVersion,min_since=minIov,modification_time=copyTime)) logging.info('Destination Tag boost Version set to %s ( was %s )' %(tagBoostVersion,currentTagBoostVersion) ) return ret, niovs def copy(args): _check_same_object(args) connection1, connection2 = connect(args, read_only=False) session1, session2 = connection1.session(), connection2.session() args.type, args.first = _identify_object(session1, args.type, args.first) copyTime = datetime.datetime.utcnow() if args.type == 'payload': if args.second is None: args.second = args.first elif args.first != args.second: raise Exception('Cannot modify the name (hash) of a payload while copying, since the hash has to match the data.') if _copy_payload( args, copyTime, session1, session2, args.first ): _confirm_changes(args) session2.commit() elif args.type == 'tag': if args.second is None: args.second = args.first if args.force and args.yes: if args.note is None or args.note=='' or args.note==' ': raise Exception('Cannot run in force edit mode without to provide a non-empty editing note.') if args.o2oTest: if args.to is not None or getattr(args, 'from') is not None or args.snapshot is not None or args.override or args.nosynchro or args.toTimestamp: raise Exception('Cannot execute the copy for the o2o test with the options from, to, override, nosynchro, snapshot or toTimestamp.') try: ret, niovs = _copy_tag(args, copyTime, session1, session2, args.first, args.second, getattr(args, 'from'), args.to) if niovs!=0: _confirm_changes(args) note = args.note if args.force and args.note is None: note = _get_user_note(args,'Force edit mode requires an editing note to be provided: ') if note is None or note=='' or note==' ': note = '-' _update_tag_log(session2,args.second,copyTime,'%s iov(s) inserted.' %niovs,note) session2.commit() logging.info('Changes committed.') except Exception as e: session2.rollback() logging.error('Changes rolled back.') raise e return 1*( not ret ) elif args.type == 'gt': if args.second is None: args.second = args.first # 'from' is a keyword! session = conddb.getSessionOnMasterDB( session1, session2 ) timeMap = convertRunToTimes(session, getattr(args, 'from'), args.to) logging.info('Copying global tag %s to %s ...', str_db_object(args.db, args.first), str_db_object(args.destdb, args.second)) GlobalTag1 = session1.get_dbtype(conddb.GlobalTag) GlobalTag2 = session2.get_dbtype(conddb.GlobalTag) GlobalTagMap1 = session1.get_dbtype(conddb.GlobalTagMap) GlobalTagMap2 = session2.get_dbtype(conddb.GlobalTagMap) # Prepare the copy global_tag = _rawdict(session1.query(GlobalTag1).get(args.first)) global_tag['name'] = args.second global_tag['validity'] = 0 # XXX: SQLite does not work with long ints... if args.snapshot is None: args.snapshot = str(global_tag['snapshot_time'].strftime("%Y-%m-%d %H:%M:%S")) else: global_tag['snapshot_time'] = _parse_timestamp(args.snapshot) if _exists(session2, GlobalTag2.name, args.second): raise Exception('A GlobalTag named "%s" already exists in %s' %(args.second, args.destdb)) # Copy the tags of the global tag logging.debug('Creating query for tag %s filter %s ...', GlobalTagMap1.tag_name, args.first) query = session1.query(GlobalTagMap1.tag_name).filter(GlobalTagMap1.global_tag_name == args.first).distinct() copyTime = datetime.datetime.utcnow() for (tag, ) in query: logging.debug('Copying tag %s to %s for GT %s ...', str_db_object(args.db, tag), str_db_object(args.destdb, tag), str_db_object(args.destdb, args.second)) Tag2 = session2.get_dbtype(conddb.Tag) if _exists(session2, Tag2.name, tag ): logging.warn('Skipping copy of tag %s to %s since it already exists... *The tags may differ in content*', str_db_object(args.db, tag), str_db_object(args.destdb, tag)) else: logging.debug('going to copy tag %s to %s ... ', str_db_object(args.db, tag), str_db_object(args.destdb, tag)) _copy_tag(args, copyTime, session1, session2, tag, tag, timeMap=timeMap) # Copy the global tag global_tag2 = GlobalTag2(**global_tag) copyTime = datetime.datetime.utcnow() global_tag2.snapshot_time = copyTime global_tag2.insertion_time = copyTime session2.add(global_tag2) # Copy the map of the global tag query = session1.query(GlobalTagMap1).filter(GlobalTagMap1.global_tag_name == args.first) for map_ in query: logging.debug('Copying global tag map %s -> %s ...', str_record(map_.record, map_.label), map_.tag_name) map_ = _rawdict(map_) map_['global_tag_name'] = args.second session2.add(GlobalTagMap2(**map_)) _confirm_changes(args) session2.commit() return 0 def edit(args): global colors colors.noColors() connection = connect(args, read_only=False) session = connection.session() args.type, name = _identify_object(session, args.type, args.name) if args.editor is None: editor = _get_editor(args) with tempfile.NamedTemporaryFile(mode='r+') as tempfd: if args.type == 'payload': raise Exception('TODO') Payload = session1.get_dbtype(conddb.Payload) properties = session.query(Payload.object_type, Payload.version, Payload.insertion_time).\ filter(Payload.hash == name).\ one() columns = properties.keys() tempfd.write('''# Editing payload %s # # You can modify rows/lines after the headers. Then, save the file and # quit the editor. The changes will be recognized and you will be asked # for confirmation before the changes are written into the database. # # The order of the rows does not matter. Whitespace is not important. # Lines starting with # are ignored. # # You can edit the insertion time -- however, note that if these conditions # are to be uploaded to an official database, the times will be anyway # replaced with the actual insertion times. ''' % payload_hash) table = zip(columns, properties) output_table(args, table, ['Property', 'Value'], output_file = tempfd, ) _run_editor(editor, tempfd) new_table = [] in_table = False for line in tempfd.readlines(): line = line.strip() if len(line) == 0 or line.startswith('#'): continue if not in_table: if all([x == '-' for x in line.replace(' ','')]): in_table = True continue key, value = line.split(None, 1) if key == 'insertion_time': value = _parse_timestamp(value) new_table.append((key, value)) table = set(table) new_table = set(new_table) added = new_table - table deleted = table - new_table if len(added) == 0 and len(deleted) == 0: raise Exception('No changes found.') values = dict(new_table) if set(values.keys()) != set(columns): raise Exception('It is not possible to modify the name of the properties or add/remove them. Please only modify the values.') changes = [('+' if x in added else '-', x[0], x[1]) for x in added | deleted] output_table(args, sorted(changes, key=lambda x: (x[1], 0 if x[0] == '-' else 1)), ['', 'Property', 'Value'], no_first_header = True, ) _confirm_changes(args) payload = session.query(Payload).\ filter(Payload.hash == payload_hash).\ update(dict(added | deleted)) session.commit() elif args.type == 'tag': if args.header: Tag = session.get_dbtype(conddb.Tag) table = session.query(Tag.description,Tag.synchronization,Tag.end_of_validity).\ filter(Tag.name == name).\ all() table = [ (str(x[0].strip()),str(x[1]),str(x[2])) for x in table ] output_table( args, table, ['Description','Synchronization','End of Validity'], output_file = tempfd, no_max_length = True ) tempfd.write(''' # Editing tag %s # # You can add, remove or modify rows/lines after the headers. # Then, save the file and quit the editor. # The changes will be recognized and you will be asked for confirmation # before the changes are written into the database. # # Whitespace is not important. # Lines starting with # are ignored. ''' % name) _run_editor(editor, tempfd) new_table = [] editRe = re.compile(r'^(.*)\s+([a-z]+)\s+([-]?\d+)\s*$') for index, line in enumerate(tempfd.readlines()): if index in {0, 1}: continue line = line.strip() if len(line) == 0 or line.startswith('#'): continue editMatch = editRe.match(line) if editMatch: description,synchronization,endOfValidity = editMatch.groups() if synchronization not in conddb.synch_list: raise Exception('Invalid Synchronization value set: "%s"' %synchronization ) if int(endOfValidity)< -1: raise Exception('Invalid End Of Validity set: "%s"' %endOfValidity ) else: raise Exception('Each line must contain the Description, Synchronization and End Of Validity fields in the required format.') new_table.append((description.strip(),synchronization,endOfValidity)) header = table[0] new_header = new_table[0] if new_table == table: logging.info('No changes found.') session.rollback() return changes = [] changes.append(('+',new_header[0],new_header[1],new_header[2])) changes.append(('-',header[0],header[1],header[2])) output_table(args, sorted(changes, key=lambda x: (0 if x[0] == '-' else 1)), ['', 'Description', 'Synchronization', 'End Of Validity'], no_first_header = True, ) _confirm_changes(args) note = '-' if args.force: note = _get_user_note(args,'Please provide an editing note: ') action = '' if header[0] != new_header[0]: action += 'Description updated' if header[1] != new_header[1]: # validate the synchro requested( based on the tag IOV content ) if new_header[1] == 'mc': if not mc_validate( session, name ): return if len(action): action += ', ' action += 'Synchronization changed' if header[2] != new_header[2]: if len(action): action += ', ' action += 'End Of Validity changed' if len(action): action += '.' updatedHeader = Tag(name=name,description=new_header[0],synchronization=new_header[1],end_of_validity=new_header[2],modification_time=datetime.datetime.utcnow()) session.merge(updatedHeader) _update_tag_log(session,name,datetime.datetime.utcnow(),action,note) session.commit() logging.info('Tag header updated. Action(s): %s' %action) return IOV = session.get_dbtype(conddb.IOV) Payload = session.get_dbtype(conddb.Payload) table = session.query(IOV.since, IOV.insertion_time, IOV.payload_hash).\ filter(IOV.tag_name == name).\ order_by(IOV.since, IOV.insertion_time).\ all() output_table(args, table, ['Since', 'Insertion Time', 'Payload'], output_file = tempfd, ) tempfd.write(''' # Editing tag %s # # You can add, remove or modify rows/lines after the headers. # Then, save the file and quit the editor. # The changes will be recognized and you will be asked for confirmation # before the changes are written into the database. # # The order of the rows does not matter. Whitespace is not important. # Lines starting with # are ignored. # # Payload hashes do not need to be full -- a prefix is enough if unique. # The program will fill find the full hash. # # You can edit insertion times -- however, note that if these conditions # are to be uploaded to an official database, the times will be anyway # replaced with the actual insertion times. The format must be # one of the following: '2013-01-20', '2013-01-20 10:11:12' or # '2013-01-20 10:11:12.123123'. # If the insertion time desired is the one of the command execution, # you can simply write a '-' in the corresponding column # # Suggestion: open another terminal to copy the payloads you need. ''' % name) _run_editor(editor, tempfd) new_table = [] for index, line in enumerate(tempfd.readlines()): if index in {0, 1}: continue line = line.strip() if len(line) == 0 or line.startswith('#'): continue splitted = line.split() if len(splitted) == 3: since, insertion_timestamp, payload = splitted elif len(splitted) == 4: since, insertion_date, insertion_time, payload = splitted insertion_timestamp = '%s %s' % (insertion_date, insertion_time) else: raise Exception('Each line must contain the since, timestamp and payload fields in the required format.') # check payload hash format and existance... if len(payload) > conddb.hash_length: raise Exception('Payload hash "%s" too long.' %payload ) elif len(payload) < conddb.hash_length: raise Exception('Payload hash "%s" too short.' %payload ) if not _exists(session, Payload.hash, payload): raise Exception('Payload hash "%s" not found in the database' %payload ) if insertion_timestamp == '-': insertion_time = datetime.datetime.utcnow() else: insertion_time = _parse_timestamp(insertion_timestamp) new_table.append((int(since), insertion_time, payload)) table = set(table) new_table = set(new_table) added = new_table - table deleted = table - new_table sizeNew = len(new_table) sizeUnique = len( set([(x[0],x[1]) for x in new_table]) ) if connection.is_official: added = set([(x[0],'-',x[2]) for x in added]) sizeNew = len(added) + len(table) sizeUnique = len( set([x[0] for x in added]) ) + len(table) if len(deleted): logging.info("The %s deleted entries won't be removed." %len(deleted)) deleted = set() if len(added) == 0 and len(deleted) == 0: logging.info('No changes found.') session.rollback() return changes = [('+' if x in added else '-', x[0], x[1], x[2]) for x in added | deleted] output_table(args, sorted(changes, key=lambda x: (x[1], 0 if x[0] == '-' else 1)), ['', 'Since', 'Insertion Time', 'Payload'], no_first_header = True, ) logging.debug('size of modified table: %s - unique (since+timestamp) entries: %s' %(sizeNew,sizeUnique)) if sizeNew != sizeUnique: raise Exception('Duplicated since.') _confirm_changes(args) note = '-' if args.force: note = _get_user_note(args,'Please provide an editing note: ') action = '' if len(added): action += '%s iov(s) inserted' %len(added) if len(deleted): if len(action): action += ', ' action += '%s iov(s) deleted' %len(deleted) # Use session.delete() instead of bulk delete to let SQLAlchemy use UPDATE # (since we may disable DELETE in Oracle for the tables) for since, insertion_time, _ in deleted: session.query(IOV).filter(IOV.tag_name==name, IOV.since==since, IOV.insertion_time==insertion_time).delete() #session.delete(session.query(IOV).filter(IOV.tag_name==name, IOV.since==since, IOV.insertion_time==insertion_time)) for since, insertion_time, payload in added: if connection.is_official: insertion_time = datetime.datetime.utcnow() session.add(IOV(tag_name=name, since=since, insertion_time=insertion_time, payload_hash=payload)) _update_tag_log(session,name,datetime.datetime.utcnow(),action,note) session.commit() elif args.type == 'gt': GlobalTagMap = session.get_dbtype(conddb.GlobalTagMap) table = session.query(GlobalTagMap.record, GlobalTagMap.label, GlobalTagMap.tag_name).\ filter(GlobalTagMap.global_tag_name == name).\ order_by(GlobalTagMap.record, GlobalTagMap.label).\ all() output_table(args, table, ['Record', 'Label', 'Tag'], output_file = tempfd, ) tempfd.write(''' # Editing global tag %s # # You can add, remove or modify rows/lines after the headers. # Then, save the file and quit the editor. # The changes will be recognized and you will be asked for confirmation # before the changes are written into the database. # # To mark records without label, use a single '%s' character. # # The order of the rows does not matter. Whitespace is not important. # Lines starting with # are ignored. ''' % (name, conddb.empty_label)) _run_editor(editor, tempfd) new_table = [] for index, line in enumerate(tempfd.readlines()): if index in {0, 1}: continue line = line.strip() if len(line) == 0 or line.startswith('#'): continue record, label, tag = line.split() new_table.append((record, label, tag)) if len(new_table) != len(set([(x[0], x[1]) for x in new_table])): raise Exception('Duplicated (record, label) pair.') table = set(table) new_table = set(new_table) added = new_table - table deleted = table - new_table if len(added) == 0 and len(deleted) == 0: raise Exception('No changes found.') changes = [('+' if x in added else '-', x[0], x[1], x[2]) for x in added | deleted] output_table(args, sorted(changes, key=lambda x: (x[1], 0 if x[0] == '-' else 1)), ['', 'Record', 'Label', 'Tag'], no_first_header = True, ) _confirm_changes(args) # Use session.delete() instead of bulk delete to let SQLAlchemy use UPDATE # (since we may disable DELETE in Oracle for the tables) for record, label, _ in deleted: session.delete(session.query(GlobalTagMap).get((name, record, label))) for record, label, tag in added: session.add(GlobalTagMap(global_tag_name=name, record=record, label=label, tag_name=tag)) session.commit() def delete(args): connection = connect(args, read_only=False) session = connection.session() args.type, name = _identify_object(session, args.type, args.name) if args.type == 'payload': output_table(args, [('-', name, )], ['', 'Payload'], no_first_header = True, ) _confirm_changes(args) Payload = session.get_dbtype(conddb.Payload) session.query(Payload).\ filter(Payload.hash == name).\ delete() session.commit() elif args.type == 'tag': output_table(args, [('-', name, )], ['', 'Tag'], no_first_header = True, ) _confirm_changes(args) Tag = session.get_dbtype(conddb.Tag) IOV = session.get_dbtype(conddb.IOV) TagLog = session.get_dbtype(conddb.TagLog) TagMetadata = session.get_dbtype(conddb.TagMetadata) session.query(IOV).\ filter(IOV.tag_name == name).\ delete() session.query(TagLog).\ filter(TagLog.tag_name == name).\ delete() session.query(TagMetadata).\ filter(TagMetadata.tag_name == name).\ delete() session.query(Tag).\ filter(Tag.name == name).\ delete() session.commit() elif args.type == 'gt': output_table(args, [('-', name, )], ['', 'Global Tag'], no_first_header = True, ) _confirm_changes(args) GlobalTag = session.get_dbtype(conddb.GlobalTag) GlobalTagMap = session.get_dbtype(conddb.GlobalTagMap) session.query(GlobalTagMap).\ filter(GlobalTagMap.global_tag_name == name).\ delete() session.query(GlobalTag).\ filter(GlobalTag.name == name).\ delete() session.commit() def dump(args): connection = connect(args) session = connection.session() IOV = session.get_dbtype(conddb.IOV) GlobalTag = session.get_dbtype(conddb.GlobalTag) GlobalTagMap = session.get_dbtype(conddb.GlobalTagMap) args.type, name = _identify_object(session, args.type, args.name) xmlProcessor = None if args.format == 'xml': xmlProcessor = cond2xml.CondXmlProcessor(conddb) if args.destfile != None: #The file for XML dump will be cleaned up and automatically closed after this with open(args.destfile, 'w'): pass if args.type == 'payload': if args.format == 'xml': xmlProcessor.payload2xml(session, name, args.destfile) else: _dump_payload(session, name, args.loadonly) elif args.type == 'tag': for payload, in session.query(IOV.payload_hash).\ filter(IOV.tag_name == name).\ distinct(): if args.format == 'xml': xmlProcessor.payload2xml(session, payload, args.destfile) else: _dump_payload(session, payload, args.loadonly) elif args.type == 'gt' and _exists(session, GlobalTag.name, name) != None: for payload, in session.query(IOV.payload_hash).\ filter(GlobalTagMap.global_tag_name == name, IOV.tag_name == GlobalTagMap.tag_name).\ distinct(): if args.format == 'xml': xmlProcessor.payload2xml(session, payload, args.destfile) else: _dump_payload(session, payload, args.loadonly) if xmlProcessor: del xmlProcessor def toLumi_(args): lumiTime = conddb_time.to_lumi_time( int(args.run), int(args.lumi_id) ) if args.quiet: print('%s' %lumiTime) else: output(args,'Lumi timetype for run=%s, lumisection id=%s: %s' %(args.run,args.lumi_id, lumiTime)) def fromLumi_(args): run, lumisection_id = conddb_time.from_lumi_time( int(args.lumiTime) ) if args.quiet: print('%s,%s' %(run, lumisection_id)) else: output(args,'For Lumi timetype %s: run=%s, lumisection id=%s' %(args.lumiTime,run,lumisection_id)) def toTimestamp_( args ): ts = conddb_time.string_to_timestamp( args.datetime ) if args.quiet: print('%s' %ts) else: output(args,"Time timetype for string '%s': %s" %(args.datetime, ts)) def fromTimestamp_( args ): sdt = conddb_time.string_from_timestamp( int(args.timestamp) ) if args.quiet: print('%s' %sdt) else: output(args,"String date time for timestamp %s: '%s'" %(args.timestamp, sdt)) def showProtections( args ): connection = connect(args, False, True, True) session = connection.session() Tag = session.get_dbtype(conddb.Tag) result = session.query(Tag.name, Tag.protection_code).filter(Tag.name==args.tag).all() get_authorizations = False table = [] for res in result: protection_fl = '-' protection_str = 'not protected' if res[1]!=tag_db_no_protection_code: get_authorizations = True write_flag = res[1] & tag_db_write_access_code lock_flag = res[1] & tag_db_lock_access_code protection_fl = '' protection_str = '' if write_flag != 0: protection_fl += db_access_code_map[tag_db_write_access_code] protection_str += 'write protected' if lock_flag != 0: protection_fl += db_access_code_map[tag_db_lock_access_code] if protection_str != '': protection_str += ',' protection_str += 'locked' table.append((args.tag,protection_fl,protection_str)) break if len(table)==0: logging.error('Tag %s does not exists.'%args.tag) return 1 output_table(args,table,['Tag','Flags','Protection']) if get_authorizations: TagAuthorization = session.get_dbtype(conddb.TagAuthorization) results = session.query(TagAuthorization.access_type, TagAuthorization.credential, TagAuthorization.credential_type).filter(TagAuthorization.tag_name==args.tag).all() table = [] for r in results: table.append((db_access_code_map[r[0]],db_credential_type_map[r[2]][0],r[1])) output_table(args,table,['Access Type','Credential Type','Credential']) return 0 def setProtection( args ): if not args.remove and args.accesstype == db_access_code_map[tag_db_lock_access_code]: logging.error("Lock can't be set by command line tool action.") return 2 connection = connect(args, False, True, True) session = connection.session() Tag = session.get_dbtype(conddb.Tag) result = session.query(Tag.name, Tag.protection_code).filter(Tag.name==args.tag).all() full_protection_code = None for res in result: full_protection_code = res[1] if full_protection_code is None: logging.error('Tag %s does not exists.'%args.tag) return 1 input_access_code = None for k in db_access_code_map.keys(): if db_access_code_map[k] == args.accesstype: input_access_code = k new_protection_code = 0 action = 'Access restriction altered.' note = '' if args.remove: TagAuthorization = session.get_dbtype(conddb.TagAuthorization) query = session.query(TagAuthorization).filter(TagAuthorization.tag_name == args.tag) query = query.filter(TagAuthorization.access_type == input_access_code) for code in db_access_code_map.keys(): if code != input_access_code: new_protection_code |= (full_protection_code & code) note = '%s restrictions removed'%args.accesstype query = query.delete() else: new_protection_code = full_protection_code | input_access_code note = '%s restriction set'%args.accesstype session.merge(Tag(name=args.tag,protection_code=new_protection_code)) _update_tag_log(session,args.tag,datetime.datetime.utcnow(),action,note) session.commit() logging.info(note) logging.info('Tag header updated. Action(s): %s' %action) return 0 def setPermission( args ): if args.credential is not None and args.credentialtype is None: logging.error('Specified option "credential" requires option "credentialtype') return 1 if args.accesstype == db_access_code_map[tag_db_lock_access_code]: logging.error("Lock ownership can't be altered.") return 1 connection = connect(args, False, True, True) session = connection.session() Tag = session.get_dbtype(conddb.Tag) result = session.query(Tag.name, Tag.protection_code).filter(Tag.name==args.tag).all() full_protection_code = None for res in result: full_protection_code = res[1] if full_protection_code is None: logging.error('Tag %s does not exists.'%args.tag) return 2 if full_protection_code == 0: logging.error('Tag %s is not protected.' %args.tag) return 3 TagAuthorization = session.get_dbtype(conddb.TagAuthorization) input_access_code = None for k in db_access_code_map.keys(): if db_access_code_map[k] == args.accesstype: input_access_code = k if full_protection_code & input_access_code==0: logging.error('Tag %s is not protected for access %s.'%(args.tag,args.accessType)) return 3 input_credential = None input_credential_code = None input_credential_type = None if args.credential is not None: input_credential = args.credential for k in db_credential_type_map.keys(): if db_credential_type_map[k][1] == args.credentialtype: input_credential_code = k input_credential_type = db_credential_type_map[k][0] action = 'Access permission altered.' note = '' if args.remove: query = session.query(TagAuthorization).filter(TagAuthorization.tag_name == args.tag) query = query.filter(TagAuthorization.access_type == input_access_code) if input_credential is not None: query = query.filter(TagAuthorization.credential == input_credential) query = query.filter(TagAuthorization.credential_type == input_credential_code) note = '%s permission for %s "%s" removed'%(args.accesstype,input_credential_type,args.credential) else: note = '%s restrictions removed'%args.accesstype query = query.delete() else: if input_credential is not None: session.add(TagAuthorization(tag_name=args.tag, access_type=input_access_code, credential=input_credential, credential_type=input_credential_code )) note = '%s permission for %s "%s" added'%(args.accesstype,input_credential_type,args.credential) else: note = '%s restriction set'%args.accesstype _update_tag_log(session,args.tag,datetime.datetime.utcnow(),action,note) session.commit() logging.info(note) logging.info('Tag access permissions updated. Action(s): %s' %action) return 0 def query_object(args): connection = connect(args) session = connection.session() if not args.tag and not args.global_tag and not args.payload: logging.error('The object type for the query has not been specified.') return -1 if (args.tag and args.global_tag) or (args.tag and args.payload) or (args.global_tag and args.payload): logging.error('Only one object type for the query can be specified.') return -1 found = 1 if args.tag: Tag = session.get_dbtype(conddb.Tag) query = session.query(Tag.description,Tag.time_type,Tag.object_type,Tag.synchronization,Tag.insertion_time,Tag.modification_time).filter(Tag.name == args.unique_key).all() table = [] for res in query: found = 0 table.append((args.unique_key,res[0],res[1],res[2],res[3],res[4],res[5])) if found==0: output_table(args,table,['Tag name','Description','Time Type','Object Type','Synchronization','Insertion Time','Modification Time']) else: logging.info('Tag %s has not been found.'%args.unique_key) if args.global_tag: GlobalTag = session.get_dbtype(conddb.GlobalTag) query = session.query(GlobalTag.description,GlobalTag.release,GlobalTag.insertion_time,GlobalTag.snapshot_time).filter(GlobalTag.name == args.unique_key).all() table = [] for res in query: found = 0 table.append((args.unique_key,res[0],res[1],res[2],res[3])) if found==0: output_table(args,table,['Global Tag name','Description','Release','Insertion Time','Snapshot Time']) else: logging.info('Global Tag %s has not been found.'%args.unique_key) if args.payload: Payload = session.get_dbtype(conddb.Payload) query = session.query(Payload.object_type,Payload.streamer_info,Payload.insertion_time).filter(Payload.hash == args.unique_key).all() table = [] header = None for res in query: found = 0 streamer_info = res[1] row = (args.unique_key,res[0],) header = ['Payload hash','Object type'] if streamer_info != b'0': payload_md = json.loads(streamer_info) for k in sorted(payload_md.keys()): header.append(k) row += (payload_md[k],) else: row += (' ',) header.append('Streamer Info') row += (res[2],) table.append(row) header.append('Insertion Time') if found==0: output_table(args,table,header) else: logging.info('Payload %s has not been found.'%args.unique_key) return found def main(): '''Entry point. ''' global colors if len(sys.argv) == 1: class Args(object): quiet = False nocolors = False colors = Colors(Args()) help(Args()) sys.exit(2) parser = argparse.ArgumentParser(description='CMS Condition DB command-line tool. For general help (manual page), use the help subcommand.', epilog='Contact help: %s' % conddb.contact_help) parser.add_argument('--db', '-d', default='pro', help='Database to run the command on. Run the help subcommand for more information: conddb help') parser.add_argument('--verbose', '-v', action='count', help='Verbosity level. -v prints debugging information of this tool, like tracebacks in case of errors. -vv prints, in addition, all SQL statements issued. -vvv prints, in addition, all results returned by queries.') parser.add_argument('--quiet', '-q', action='store_true', help='Quiet mode. Disables all standard output.') parser.add_argument('--yes', '-y', action='store_true', help='Acknowledged mode. Disables confirmation prompts before writes to the database.') parser.add_argument('--nocolors', action='store_true', help='Disable colors. This is automatically done when the output is connected to a pipe (e.g. " conddb ... | less" ).') parser.add_argument('--editor', '-e', default=None, help='Editor to use. Default: the content of the EDITOR environment variable.') parser.add_argument('--force', action='store_true', help='Force edit in official databases. Only meant for experts.') parser.add_argument('--noLimit', action='store_true', help='Ignore the limit setting for the subcommand. This may generate a _lot_ of output and put some load on the DB, so please use with care.') parser.add_argument('--authPath','-a', default=None, help='Path of the authentication .netrc file. Default: the content of the COND_AUTH_PATH environment variable, when specified.') parser_subparsers = parser.add_subparsers(title='Available subcommands') parser_help = parser_subparsers.add_parser('help', description='General help (manual page).') parser_help.set_defaults(func=help) parser_init = parser_subparsers.add_parser('init', description='Initializes a CMS Condition DB, i.e. creates tables, sequences, indexes, etc. if they do not exist.') parser_init.set_defaults(func=init) parser_status = parser_subparsers.add_parser('status', description='Shows a summary of the status of a database.') parser_status.add_argument('--limit', '-L', type=int, default=5, help='Limit on the number of results per type of object. The returned results are the latest N inserted into the database.') parser_status.set_defaults(func=status) parser_list = parser_subparsers.add_parser('list', description='Lists the contents of objects. For a tag, a list of IOVs. For a global tag, a mapping tag <-> record. If there is ambiguity, all are listed.') parser_list.add_argument('name', nargs='+', help="Name of the object. This can be a tag's name or a global tag's name. It must exactly match -- if needed, use the search command first to look for it.") parser_list.add_argument('--long', '-l', action='store_true', help='Long output. Lists the properties (e.g. description) of the objects as well (not only their content).') parser_list.add_argument('--snapshot', '-T', default=None, help="Snapshot time. If provided, the output will represent the state of the IOVs inserted into database up to the given time. The format of the string must be one of the following: '2013-01-20', '2013-01-20 10:11:12' or '2013-01-20 10:11:12.123123'.") parser_list.add_argument('--limit', '-L', type=int, default=500, help='Limit on the number of IOVs returned. The returned results are the latest N IOVs. Only applies when listing tags.') parser_list.set_defaults(func=list_) parser_listTags = parser_subparsers.add_parser('listTags', description='Lists all the Tags available in the DB.') parser_listTags.set_defaults(func=listTags_) parser_listParentTags = parser_subparsers.add_parser('listParentTags', description='Lists all the Tags available in the DB, containing the matched payload hash.') parser_listParentTags.add_argument('hash_name', help="Payload hash to match.") parser_listParentTags.set_defaults(func=listParentTags_) parser_diffGlobalTagsAtRun = parser_subparsers.add_parser('diffGlobalTagsAtRun', description='Diffs two global tags, but showing only the differences relevant for a given run number.') parser_diffGlobalTagsAtRun.add_argument('--last', '-L', dest='lastIOV', action='store_true', default=False, help='Diff the Global tags at the last open IOV.') parser_diffGlobalTagsAtRun.add_argument('--reference', '-R', dest='refGT', help="Reference Global Tag") parser_diffGlobalTagsAtRun.add_argument('--target', '-T', dest='tarGT', help="Target Global Tag") parser_diffGlobalTagsAtRun.add_argument('--run', '-r', dest='testRunNumber', help="target run to compare",default=-1) parser_diffGlobalTagsAtRun.add_argument('--verbose','-v',help='returns more info', dest='isVerbose',action='store_true',default=False) parser_diffGlobalTagsAtRun.add_argument('--match','-m',help='print only matching',dest='stringToMatch',action='store',default='') parser_diffGlobalTagsAtRun.set_defaults(func=diffGlobalTagsAtRun_) parser_listGTsForTag = parser_subparsers.add_parser('listGTsForTag', description='Lists the GTs which contain a given tag.') parser_listGTsForTag.add_argument('name', help="Name of the tag.") parser_listGTsForTag.set_defaults(func=listGTsForTag_) parser_listGTs = parser_subparsers.add_parser('listGTs', description='Lists the GTs available in the DB.') parser_listGTs.set_defaults(func=listGTs_) parser_listRuns = parser_subparsers.add_parser('listRuns', description='Lists all the Runs available in the DB, possibly applying the optional search criteria.') parser_listRuns.add_argument('--limit','-L',type=int,default=50,help='Limit on the number of Run entries returned. The returned results are the latest N Runs. Only applies when no selection is specified.') parser_listRuns.add_argument('--from', '-f', type=str, help='Select items from this "Time" onwards. Supported "Time" formats: Run, encoded TimeStamp, string TimeStamp (format: YYYY-mm-dd hh24:MM:SS)') parser_listRuns.add_argument('--to', '-t', type=str, help='Ignore items from this "Time" onwards. Supported "Time" formats: Run, encoded TimeStamp, string TimeStamp (format: YYYY-mm-dd hh24:MM:SS)') parser_listRuns.add_argument('--match', '-m', type=int, help='Search an exact match with this Run.') parser_listRuns.add_argument('--last','-l', action='store_true', help='Select the last available Run entry.') parser_listRuns.set_defaults(func=listRuns_) parser_diff = parser_subparsers.add_parser('diff', description='Compares the contents of two objects. For tags, their IOVs are compared to determine which ranges have different payloads. For global tags, their tag names are compared. Both objects must be of the same type. If there is more than one valid pair (ambiguity), all diffs are listed.') parser_diff.add_argument('first', help="Name of the first object (i.e. source, old). This can be a tag's name or a global tag's name. It must exactly match -- if needed, use the search command first to look for it.") parser_diff.add_argument('second', nargs='?', default=None, help='Name of the second object (i.e. destination, new). Ditto. Default: same as the first object (i.e. useful to compare the same object in different databases).') parser_diff.add_argument('--destdb', '-d', default=None, help='Database of the second object (destination database). Same values allowed as for --db. Default: same as the first database.') parser_diff.add_argument('--short', '-s', action='store_true', help='Short diff. In tag diffs, do not include the ranges where IOVs are equal (while they do not provide more information, they make the output readable).') parser_diff.add_argument('--long', '-l', action='store_true', help='Long output. Compares the properties (e.g. description) of the objects as well (not only their content).') parser_diff.add_argument('--deep', '-D', action='store_true', help='Deep diff. In global tag diffs, if two tag names are different for the same record, it compares the tags themselves with a tag diff (different tags are probably similar in a global tag, e.g. two versions of a tag).') parser_diff.add_argument('--payload', '-p', action='store_true', help='TODO: Payload diff. In a tag diff or a --deep global tag diff, for each range where a payload is different, the payloads are compared via a diff on the dump of both payloads.') parser_diff.add_argument('--snapshot', '-T', default=None, help="Snapshot time. If provided, the output will represent the state of the IOVs inserted into database up to the given time. The format of the string must be one of the following: '2013-01-20', '2013-01-20 10:11:12' or '2013-01-20 10:11:12.123123'.") parser_diff.set_defaults(func=diff) parser_search = parser_subparsers.add_parser('search', description='Searches various types of objects matching a case-insensitive string: tags (by name, object type and description), payloads (by SHA1 hash), global tags (by name, release and description) and records (by name, label and object type). The returned list is limited, by default, to 10 per type of object.') parser_search.add_argument('string', help='Search string. Case-insensitive.') parser_search.add_argument('--regexp', '-r', action='store_true', help='Regexp mode. The search string is a regular expression.') parser_search.add_argument('--limit', '-L', type=int, default=100, help='Limit on the number of results per type of object. The returned results are the latest N inserted into the database.') parser_search.set_defaults(func=search) parser_copy = parser_subparsers.add_parser('copy', description='Copies objects between databases. For tags, their dependent payloads are copied automatically if they do not exist in the destination database yet (or skipped if they already do). For global tags, their dependent tags are copied automatically if they do not exist in the destination database yet. However, if they exist, a warning is printed (TODO: do not print the warning if they do not differ).') parser_copy.add_argument('first', help="Name of the first object (i.e. source, old). This can be a tag's name, a global tag's name or a payload's SHA1 hexadecimal hash (or a prefix if unique). It must exactly match -- if needed, use the search command first to look for it.") parser_copy.add_argument('second', nargs='?', default=None, help='Name of the second object (i.e. destination, new). Ditto. Default: same as the first object. (i.e. useful to keep the name when copying an object between databases). Note that for payloads the names must be equal (since it is the SHA1 hash of the data) -- therefore, when copying payloads you should omit this parameter to take the default (same name).') parser_copy.add_argument('--destdb', '-d', default=None, help='Database of the second object (destination database). Same values allowed as for --db. Default: same as the first database.') parser_copy.add_argument('--from', '-f', type=int, help='From IOV: copy only from this IOV onwards. Only valid when copying tags.') parser_copy.add_argument('--to', '-t', type=int, help='To IOV: copy only up to this IOV. Only valid when copying tags.') parser_copy.add_argument('--type', default=None, choices=['tag', 'gt', 'payload'], help='Type of the objects. Use it if there is ambiguity (should be really rare).') parser_copy.add_argument('--note','-n', help='Editing note.') parser_copy.add_argument('--override','-o', action='store_true', help='Override the existing iovs for the interval covered by the new iovs.') parser_copy.add_argument('--snapshot','-s', help="Timestamp of the snapshot to consider for the source iovs. The format of the string must be one of the following: '2013-01-20', '2013-01-20 10:11:12' or '2013-01-20 10:11:12.123123'.") parser_copy.add_argument('--o2oTest', action='store_true', help='Special copy for o2o test. Copy the second to last iov of the source tag, to allow to run the o2o procedure to add the last iov. It cannot be executed with the from, to, ovveride and snapshot options.') parser_copy.add_argument('--synchronize',action='store_true',help='No effect, since the synchronization is applied by default for tags. The option is kept for backward compatibility') parser_copy.add_argument('--nosynchro',action='store_true',help='For tags, disable the synchronization of the destination iovs. No effect for other object type copy') parser_copy.add_argument('--toTimestamp',action='store_true',help='For tags, triggers the conversion from run-based iovs to timestamp-based iovs. It will return an error for any combination with input tag non run-based, and existing destination tag non timestamp-based. Not supported with synchronization.') parser_copy.add_argument('--toRun',action='store_true',help='For tags, triggers the conversion from timestamp-based iovs to run-based iovs. When multiple timestamped IOVs are found matching the same run, only the first is considered. IOVs with timestamp not matching any run are skipped. It will return an error for any combination with input tag non timestamp-based, and existing destination tag non run-based. Not supported with synchronization.') parser_copy.set_defaults(func=copy) parser_edit = parser_subparsers.add_parser('edit', description='Edits an object. Opens up your $EDITOR with prefilled text about the object. There you can modify the data. Save the file and quit the editor. The modified data will be written into the database. e.g. for a tag, its attributes and the list of IOVs/payloads appears and are modifiable.') parser_edit.add_argument('name', help="Name of the object. This can be a tag's name (edits its attributes and its IOVs/payloads), a global tag's name (edits its attributes and its mapping records <-> tags) or a payload's SHA1 hexadecimal hash (or a prefix if unique; TODO: edits its attributes). It must exactly match -- if needed, use the search command first to look for it.") parser_edit.add_argument('--header', default=False, action='store_true', help='Edit the header attributes of the object.') parser_edit.add_argument('--type', default=None, choices=['tag', 'gt', 'payload'], help='Type of the object. Use it if there is ambiguity (should be really rare).') parser_edit.set_defaults(func=edit) parser_delete = parser_subparsers.add_parser('delete', description='Deletes an object. Fails if the object is referenced somewhere else in the database.') parser_delete.add_argument('name', help="Name of the object. This can be a tag's name, a global tag's name or a payload's SHA1 hexadecimal hash (or a prefix if unique). It must exactly match -- if needed, use the search command first to look for it.") parser_delete.add_argument('--deep', '-D', action='store_true', help='TODO: Deep delete. In tag deletes, deletes its payloads (fails if they are used in other tags). In global tag deletes, deletes its tags (fails if they are used by another global tag).') parser_delete.add_argument('--type', default=None, choices=['tag', 'gt', 'payload'], help='Type of the object. Use it if there is ambiguity (should be really rare).') parser_delete.set_defaults(func=delete) parser_dump = parser_subparsers.add_parser('dump', description='Dumps deserialized payloads, using the current CMSSW release.') parser_dump.add_argument('name', help="Name of the object. This can be a payload's SHA1 hexadecimal hash (or a prefix if unique), a tag's name (all payloads referenced in the tag will be dumped) or a global tag's name (all payloads referenced in the global tag will be dumped).") parser_dump.add_argument('--loadonly', action='store_true', help='Load only: Do not dump, only load the (deserialize) payload in memory -- useful for testing the load of an entire global tag with the current CMSSW release.') parser_dump.add_argument('--type', default=None, choices=['payload', 'tag', 'gt'], help='Type of the object. Use it if there is ambiguity (should be really rare).') parser_dump.add_argument('--format', default="xml", choices=['xml', 'raw'], help='Output format. Choice between XML and raw hexdump.') parser_dump.add_argument('--destfile','-d',default=None,help="Destination file for the dump.") parser_dump.set_defaults(func=dump) parser_showFcsr = parser_subparsers.add_parser('showFCSR', description='Dumps the FCSR values for hlt and pcl') parser_showFcsr.set_defaults(func=showFcsr_) parser_toLumi = parser_subparsers.add_parser('toLumi', description='Generates the Lumi timetype from run number and lumisection id') parser_toLumi.add_argument('run', help="Run id") parser_toLumi.add_argument('lumi_id', help="Lumisection id") parser_toLumi.set_defaults(func=toLumi_) parser_fromLumi = parser_subparsers.add_parser('fromLumi', description='Decodes the Lumi timetype extracting run number and lumisection id') parser_fromLumi.add_argument('lumiTime', help="The Lumi timetype value") parser_fromLumi.set_defaults(func=fromLumi_) parser_toTimestamp = parser_subparsers.add_parser('toTimestamp', description='Generates the Time timetype from the date string') parser_toTimestamp.add_argument('datetime', help="The string representing the date time, in the format 'Y-m-d H:M:S.f'" ) parser_toTimestamp.set_defaults(func=toTimestamp_) parser_fromTimestamp = parser_subparsers.add_parser('fromTimestamp', description='Decodes the Time timetype extracting the date time string') parser_fromTimestamp.add_argument('timestamp', help="The Time timetype value") parser_fromTimestamp.set_defaults(func=fromTimestamp_) parser_showProtections = parser_subparsers.add_parser('showProtections', description='Display the access restrictions and permissions for the specified tag') parser_showProtections.add_argument('tag', help="The tag name") parser_showProtections.set_defaults(func=showProtections) parser_setProtection = parser_subparsers.add_parser('setProtection', description='Set an access restriction for the specified tag') parser_setProtection.add_argument('tag', help="The tag name") parser_setProtection.add_argument('--accesstype','-a', choices=[db_access_code_map[tag_db_write_access_code],db_access_code_map[tag_db_lock_access_code]], required=True, help='The access type of the protection (flag)') parser_setProtection.add_argument('--remove','-r',action='store_true', help='Remove the specified protection') parser_setProtection.set_defaults(func=setProtection) parser_setPermission = parser_subparsers.add_parser('setPermission', description='Set an access permission for the specified tag') parser_setPermission.add_argument('tag', help="The tag name") parser_setPermission.add_argument('--accesstype','-a', choices=[db_access_code_map[tag_db_write_access_code],db_access_code_map[tag_db_lock_access_code]], required=True, help='The access type of the permission (flag)') parser_setPermission.add_argument('--credential','-c', help='The credential entitled with the permission') parser_setPermission.add_argument('--credentialtype','-t', choices=[db_credential_type_map[db_key_credential_type_code][1],db_credential_type_map[db_cmsuser_credential_type_code][1]],help='The type of the credential provided. Required for "credential" option') parser_setPermission.add_argument('--remove','-r',action='store_true', help='Remove the specified permission') parser_setPermission.set_defaults(func=setPermission) parser_query = parser_subparsers.add_parser('query', description='Query the database to get information about condition metadata') parser_query.add_argument('unique_key', help="The unique key for the query") parser_query.add_argument('--tag','-t',action='store_true', help="Query a tag object") parser_query.add_argument('--global_tag','-gt',action='store_true', help="Query a global tag object") parser_query.add_argument('--payload','-p',action='store_true', help="Query a payload object") parser_query.set_defaults(func=query_object) args = parser.parse_args() logging.basicConfig( format = '[%(asctime)s] %(levelname)s: %(message)s', level = logging.DEBUG if args.verbose is not None and args.verbose >= 1 else logging.INFO, ) colors = Colors(args) if args.noLimit: args.limit = None logging.info("noLimit specified, setting limit to %s" % str(args.limit)) if args.verbose is not None and args.verbose >= 1: # Include the traceback return args.func(args) else: # Only one error line try: sys.exit(args.func(args)) except Exception as e: logging.error(e) sys.exit(1) if __name__ == '__main__': main()