Skip to content
This repository was archived by the owner on Sep 12, 2024. It is now read-only.

Commit e3969e2

Browse files
authored
Merge pull request #561 from todor-ivanov/feature_Rucio_Phedex_DBS_consist_check
Adding Rucio to DBS-Phedex consistency check
2 parents 32b9e92 + 892a255 commit e3969e2

4 files changed

Lines changed: 180 additions & 3 deletions

File tree

RucioClient.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env python
2+
"""
3+
Encapsulates requests to Rucio API
4+
Requieres:
5+
rucio-client
6+
Environment:
7+
export X509_USER_PROXY=/tmp/x509up_$UID
8+
export RUCIO_HOME=~/.local/
9+
${RUCIO_HOME}/rucio.cfg
10+
"""
11+
12+
from rucio.client import Client
13+
14+
class RucioClient(Client):
15+
"""
16+
A wrapper class for the Rucio client.
17+
"""
18+
def __init__(self, **kwargs):
19+
"""
20+
Default configuration provided directly into the constructor to avoid
21+
the need of an external configuration file.
22+
All arguments passed to the constructor supersede the defaults.
23+
"""
24+
25+
defaultConfig = {
26+
'rucio_host': 'http://cms-rucio.cern.ch',
27+
'auth_host': 'https://cms-rucio-auth.cern.ch',
28+
'auth_type': 'x509_proxy',
29+
'ca_cert': '/etc/grid-security/certificates/',
30+
'account': 'unified'
31+
}
32+
33+
defaultConfig.update(kwargs)
34+
35+
super(RucioClient, self).__init__(**defaultConfig)
36+
self.scope = 'cms'
37+
38+
def getFileCountDataset(self, dataset):
39+
"""
40+
Returns the number of files registered in Rucio
41+
"""
42+
try:
43+
files = list(self.list_files(self.scope, dataset))
44+
except Exception as e:
45+
print(str(e))
46+
return 0
47+
return len(files)
48+
49+
def getFileNamesDataset(self, dataset):
50+
"""
51+
Returns a set of file names in a dataset registered in Rucio
52+
"""
53+
try:
54+
files = list(self.list_files(self.scope, dataset))
55+
except Exception as e:
56+
print(str(e))
57+
return []
58+
fileNames = [_file['name'] for _file in files]
59+
return fileNames
60+
61+
def getBlockNamesDataset(self, dataset):
62+
"""
63+
Returns a set of block names in a dataset registerd in Rucio
64+
"""
65+
try:
66+
blockNames = [block['name'] for block in self.list_content(self.scope, dataset)]
67+
except Exception as e:
68+
print(str(e))
69+
return []
70+
return blockNames
71+
72+
def getFileCountBlock(self, block):
73+
"""
74+
Returns the number of files in a block registered in Rucio
75+
"""
76+
try:
77+
numFiles = self.get_metadata(self.scope, block)['length']
78+
except Exception as e:
79+
print(str(e))
80+
return 0
81+
return numFiles
82+
83+
def getFileCountPerBlock(self, dataset):
84+
"""
85+
Returns the number of files per block in a dataset registered in Rucio
86+
"""
87+
# we need blocks to be a list of tuples so we can create a set out of this
88+
try:
89+
blocks = []
90+
for block in self.getBlockNamesDataset(dataset):
91+
blocks.append((block, self.getFileCountBlock(block)))
92+
except Exception as e:
93+
print(str(e))
94+
return 0
95+
return blocks
96+

Unified/RucioClient.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../RucioClient.py

Unified/checkor.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import time
1616
import random
1717
import math
18+
from RucioClient import RucioClient
1819
from McMClient import McMClient
1920
from JIRAClient import JIRAClient
2021
from htmlor import htmlor
@@ -1012,10 +1013,43 @@ def upward( ns ):
10121013

10131014
time_point("checked custodiality", sub_lap=True)
10141015

1015-
## presence in phedex
1016+
## presence in phedex and/or rucio
10161017
phedex_presence ={}
1018+
rucioClient = RucioClient()
10171019
for output in wfi.request['OutputDatasets']:
1018-
phedex_presence[output] = phedexClient.getFileCountDataset(url, output )
1020+
_,dsn,process_string,tier = output.split('/')
1021+
if tier in set(UC.get('tiers_to_rucio_relval')) | set(UC.get('tiers_to_rucio_nonrelval')):
1022+
# - creates lists of tuples ot the type: ('blockName', numFiles)
1023+
# for all blockNames per Dataset known to both Phedex and Rucio
1024+
# - creates the union of the two sets in order to avoid any duplicates
1025+
# (files present in both systems)
1026+
# - sums the number of files for the union set
1027+
# - assigns the value to 'phedex_presence' even though the full sum
1028+
# of the files is present in both systems - this way we avoid
1029+
# changing the code for the rest of the consistency checks
1030+
phedex_filecount_pb = phedexClient.getFileCountPerBlock(url, output)
1031+
rucio_filecount_pb = rucioClient.getFileCountPerBlock(output)
1032+
all_filecount_pb = set(phedex_filecount_pb) | set(rucio_filecount_pb)
1033+
all_blocks = set(map(lambda x: x[0], phedex_filecount_pb)) | set(map(lambda x: x[0], rucio_filecount_pb))
1034+
1035+
# bellow we will misscount in case there are same blocks in both
1036+
# Rucio and Phedex but with different number of files in the two
1037+
# systems - they will enter the sum twice, because the two tuples
1038+
# will be concidered as two different blocks from the two subsets
1039+
# hence the following check:
1040+
if len(all_blocks) == len(all_filecount_pb):
1041+
phedex_presence[output] = sum(map(lambda x: x[1], all_filecount_pb))
1042+
else:
1043+
# TODO: to check if we need to rise a higher level of alarm here.
1044+
msg = "There are inconsistences of number of files per block"
1045+
msg += "between Phedex and Rucio for dataset: {}".format(output)
1046+
wfi.sendLog('checkor', msg)
1047+
phedex_presence[output] = 0
1048+
# we do not announce this output untill the discrepancy from above is resolved
1049+
del(all_filecount_pb)
1050+
del(all_blocks)
1051+
else:
1052+
phedex_presence[output] = phedexClient.getFileCountDataset(url, output)
10191053

10201054
one_output_not_in_phedex = any([Nfiles==0 for Nfiles in phedex_presence.values()])
10211055
if one_output_not_in_phedex and 'announce' in assistance_tags:
@@ -1055,7 +1089,16 @@ def upward( ns ):
10551089
assistance_tags.add('filemismatch')
10561090
#print this for show and tell if no recovery on-going
10571091
for out in dbs_presence:
1058-
_,_,missing_phedex,missing_dbs = getDatasetFiles(url, out)
1092+
dbs_filenames,phedex_filenames,missing_phedex,missing_dbs = getDatasetFiles(url, out)
1093+
1094+
# Corrections to the lists of files present in Phedex for the data Tiers managed by Rucio
1095+
_,dsn,process_string,tier = output.split('/')
1096+
if tier in set(UC.get('tiers_to_rucio_relval')) | set(UC.get('tiers_to_rucio_nonrelval')):
1097+
# Here recalculating the filenames as a union of the phedex_files | rucio_files
1098+
all_filenames = set(phedex_filenames) | set(rucioClient.getFileNamesDataset(out))
1099+
missing_phedex = list(set(dbs_filenames) - all_filenames)
1100+
missing_dbs = list(all_filenames - set(dbs_filenames))
1101+
10591102
if missing_phedex:
10601103
wfi.sendLog('checkor',"These %d files are missing in phedex, or extra in dbs, showing %s only\n%s"%(len(missing_phedex),show_N_only,
10611104
"\n".join( missing_phedex[:show_N_only] )))

phedexClient.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,43 @@ def getFileCountDataset(url, dataset):
141141
for block in result['phedex']['block']:
142142
files += block['files']
143143
return files
144+
145+
def getFileCountPerBlock(url, dataset):
146+
"""
147+
Returns the number of files per block in a dataset registered in phedex
148+
"""
149+
result = phedexGet(url, '/phedex/datasvc/json/prod/blockreplicas?dataset='+dataset, auth=False)
150+
if 'block' not in result['phedex']:
151+
return {}
152+
elif not result['phedex']['block']:
153+
return {}
154+
# we need blocks to be a list of tuples so we can create a set out of this
155+
blocks = []
156+
#check all blocks
157+
for block in result['phedex']['block']:
158+
# blocks.append({'name':block['name'],
159+
# 'files':block['files']})
160+
blocks.append((block['name'],block['files']))
161+
162+
return blocks
163+
164+
165+
def getFileNamesDataset(url, dataset):
166+
"""
167+
Returns a set of file names in a dataset registered in phedex
168+
"""
169+
result = phedexGet(url, '/phedex/datasvc/json/prod/filereplicas?dataset='+dataset, auth=False)
170+
if 'block' not in result['phedex']:
171+
return set()
172+
elif not result['phedex']['block']:
173+
return set()
174+
files = []
175+
# check all blocks
176+
for block in result['phedex']['block']:
177+
for _file in block['file']:
178+
files.append(_file['name'])
179+
return set(files)
180+
144181

145182
def getTransferPercentage(url, dataset, site):
146183
"""

0 commit comments

Comments
 (0)