wmglobalqueue 2.4.0.2__py3-none-any.whl → 2.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wmglobalqueue might be problematic. Click here for more details.

Files changed (103) hide show
  1. Utils/CertTools.py +38 -0
  2. WMCore/Database/CMSCouch.py +86 -5
  3. WMCore/Database/CouchMonitoring.py +450 -0
  4. WMCore/Services/Rucio/Rucio.py +5 -2
  5. WMCore/Services/RucioConMon/RucioConMon.py +24 -31
  6. WMCore/Services/WMStatsServer/WMStatsServer.py +2 -2
  7. WMCore/WMInit.py +176 -27
  8. WMCore/WMSpec/WMWorkloadTools.py +17 -5
  9. WMCore/__init__.py +1 -1
  10. wmglobalqueue-2.4.2.dist-info/METADATA +26 -0
  11. {wmglobalqueue-2.4.0.2.dist-info → wmglobalqueue-2.4.2.dist-info}/RECORD +102 -101
  12. {wmglobalqueue-2.4.0.2.dist-info → wmglobalqueue-2.4.2.dist-info}/WHEEL +1 -1
  13. wmglobalqueue-2.4.0.2.dist-info/METADATA +0 -24
  14. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/bin/wmc-dist-patch +0 -0
  15. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/bin/wmc-dist-unpatch +0 -0
  16. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/bin/wmc-httpd +0 -0
  17. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/.couchapprc +0 -0
  18. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/README.md +0 -0
  19. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/index.html +0 -0
  20. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/js/ElementInfoByWorkflow.js +0 -0
  21. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/js/StuckElementInfo.js +0 -0
  22. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/js/WorkloadInfoTable.js +0 -0
  23. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/js/dataTable.js +0 -0
  24. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/js/namespace.js +0 -0
  25. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/_attachments/style/main.css +0 -0
  26. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/couchapp.json +0 -0
  27. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/filters/childQueueFilter.js +0 -0
  28. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/filters/filterDeletedDocs.js +0 -0
  29. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/filters/queueFilter.js +0 -0
  30. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/language +0 -0
  31. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lib/mustache.js +0 -0
  32. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lib/validate.js +0 -0
  33. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lib/workqueue_utils.js +0 -0
  34. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lists/elementsDetail.js +0 -0
  35. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lists/filter.js +0 -0
  36. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lists/stuckElements.js +0 -0
  37. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lists/workRestrictions.js +0 -0
  38. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/lists/workflowSummary.js +0 -0
  39. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/rewrites.json +0 -0
  40. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/shows/redirect.js +0 -0
  41. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/shows/status.js +0 -0
  42. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/ElementSummaryByWorkflow.html +0 -0
  43. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/StuckElementSummary.html +0 -0
  44. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/TaskStatus.html +0 -0
  45. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/WorkflowSummary.html +0 -0
  46. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/partials/workqueue-common-lib.html +0 -0
  47. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/partials/yui-lib-remote.html +0 -0
  48. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/templates/partials/yui-lib.html +0 -0
  49. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/updates/in-place.js +0 -0
  50. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/validate_doc_update.js +0 -0
  51. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.couch.app.js +0 -0
  52. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/vendor/couchapp/_attachments/jquery.pathbinder.js +0 -0
  53. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/activeData/map.js +0 -0
  54. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/activeData/reduce.js +0 -0
  55. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/activeParentData/map.js +0 -0
  56. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/activeParentData/reduce.js +0 -0
  57. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/activePileupData/map.js +0 -0
  58. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/activePileupData/reduce.js +0 -0
  59. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/analyticsData/map.js +0 -0
  60. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/analyticsData/reduce.js +0 -0
  61. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/availableByPriority/map.js +0 -0
  62. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/conflicts/map.js +0 -0
  63. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elements/map.js +0 -0
  64. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByData/map.js +0 -0
  65. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByParent/map.js +0 -0
  66. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByParentData/map.js +0 -0
  67. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByPileupData/map.js +0 -0
  68. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByStatus/map.js +0 -0
  69. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsBySubscription/map.js +0 -0
  70. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByWorkflow/map.js +0 -0
  71. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsByWorkflow/reduce.js +0 -0
  72. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/elementsDetailByWorkflowAndStatus/map.js +0 -0
  73. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/map.js +0 -0
  74. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobInjectStatusByRequest/reduce.js +0 -0
  75. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobStatusByRequest/map.js +0 -0
  76. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobStatusByRequest/reduce.js +0 -0
  77. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/map.js +0 -0
  78. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndPriority/reduce.js +0 -0
  79. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/map.js +0 -0
  80. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByChildQueueAndStatus/reduce.js +0 -0
  81. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByRequest/map.js +0 -0
  82. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByRequest/reduce.js +0 -0
  83. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByStatus/map.js +0 -0
  84. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByStatus/reduce.js +0 -0
  85. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/map.js +0 -0
  86. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/jobsByStatusAndPriority/reduce.js +0 -0
  87. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/openRequests/map.js +0 -0
  88. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/recent-items/map.js +0 -0
  89. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/map.js +0 -0
  90. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/siteWhitelistByRequest/reduce.js +0 -0
  91. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/specsByWorkflow/map.js +0 -0
  92. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/stuckElements/map.js +0 -0
  93. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/map.js +0 -0
  94. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/wmbsInjectStatusByRequest/reduce.js +0 -0
  95. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/wmbsUrl/map.js +0 -0
  96. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/wmbsUrl/reduce.js +0 -0
  97. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/map.js +0 -0
  98. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/wmbsUrlByRequest/reduce.js +0 -0
  99. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/workflowSummary/map.js +0 -0
  100. {wmglobalqueue-2.4.0.2.data → wmglobalqueue-2.4.2.data}/data/data/couchapps/WorkQueue/views/workflowSummary/reduce.js +0 -0
  101. {wmglobalqueue-2.4.0.2.dist-info → wmglobalqueue-2.4.2.dist-info/licenses}/LICENSE +0 -0
  102. {wmglobalqueue-2.4.0.2.dist-info → wmglobalqueue-2.4.2.dist-info/licenses}/NOTICE +0 -0
  103. {wmglobalqueue-2.4.0.2.dist-info → wmglobalqueue-2.4.2.dist-info}/top_level.txt +0 -0
@@ -11,7 +11,6 @@ from future import standard_library
11
11
 
12
12
  from urllib.parse import urlencode
13
13
 
14
- import gzip
15
14
  import json
16
15
  import logging
17
16
 
@@ -40,14 +39,13 @@ class RucioConMon(Service):
40
39
  super(RucioConMon, self).__init__(configDict)
41
40
  self['logger'].debug("Initializing RucioConMon with url: %s", self['endpoint'])
42
41
 
43
- def _getResult(self, uri, callname="", clearCache=False, args=None, binary=False):
42
+ def _getResult(self, uri, callname="", clearCache=False, args=None):
44
43
  """
45
44
  Either fetch data from the cache file or query the data-service
46
45
  :param uri: The endpoint uri
47
46
  :param callname: alias for caller function
48
47
  :param clearCache: parameter to control the cache behavior
49
48
  :param args: additional parameters to HTTP request call
50
- :param binary: specifies request for binary object from HTTP requests (e.g. zipped content)
51
49
  :return: A dictionary
52
50
  """
53
51
 
@@ -67,32 +65,25 @@ class RucioConMon(Service):
67
65
 
68
66
  if clearCache:
69
67
  self.clearCache(cachedApi, args)
70
- results = '{}' # explicitly define results which will be loaded by json.loads below
71
- if binary:
72
- with self.refreshCache(cachedApi, apiUrl, decoder=False, binary=True) as istream:
73
- results = gzip.decompress(istream.read())
74
- return results
75
- else:
76
- with self.refreshCache(cachedApi, apiUrl) as istream:
77
- results = istream.read()
78
-
79
- results = json.loads(results)
80
- return results
68
+ with self.refreshCache(cachedApi, apiUrl, decoder=True, binary=False) as istream:
69
+ return json.load(istream)
81
70
 
82
- def _getResultZipped(self, uri, callname="", clearCache=True, args=None):
71
+ def _getResultZipped(self, uri, callname="", clearCache=True):
83
72
  """
84
- This method is retrieving a zipped file from the uri privided, instead
85
- of the normal json
73
+ This method retrieves gzipped content, instead of the standard json format.
86
74
  :param uri: The endpoint uri
87
75
  :param callname: alias for caller function
88
76
  :param clearCache: parameter to control the cache behavior
89
- :param args: additional parameters to HTTP request call
90
- :return: a list of LFNs
77
+ :return: yields a single record from the data retrieved
91
78
  """
92
- data = self._getResult(uri, callname, clearCache, args, binary=True)
93
- # convert bytes which we received upstream to string
94
- data = decodeBytesToUnicode(data)
95
- return [f for f in data.split('\n') if f]
79
+ cachedApi = callname
80
+ if clearCache:
81
+ self.clearCache(cachedApi)
82
+
83
+ with self.refreshCache(cachedApi, uri, decoder=False, binary=True) as istream:
84
+ for line in istream:
85
+ line = decodeBytesToUnicode(line).replace("\n", "")
86
+ yield line
96
87
 
97
88
  def getRSEStats(self):
98
89
  """
@@ -109,7 +100,7 @@ class RucioConMon(Service):
109
100
  Gets the list of all unmerged files in an RSE
110
101
  :param rseName: The RSE whose list of unmerged files to be retrieved
111
102
  :param zipped: If True the interface providing the zipped lists will be called
112
- :return: A list of unmerged files for the RSE in question
103
+ :return: a generator of unmerged files for the RSE in question
113
104
  """
114
105
  # NOTE: The default API provided by Rucio Consistency Monitor is in a form of a
115
106
  # zipped file/stream. Currently we are using the newly provided json API
@@ -117,12 +108,14 @@ class RucioConMon(Service):
117
108
  # implement the method with the zipped API and use disc cache for
118
109
  # reading/streaming from file. This will prevent any set arithmetic
119
110
  # in the future.
120
- if not zipped:
121
- uri = "files?rse=%s&format=json" % rseName
122
- rseUnmerged = self._getResult(uri, callname=rseName)
123
- return rseUnmerged
124
- else:
111
+ if zipped:
125
112
  uri = "files?rse=%s&format=raw" % rseName
126
113
  callname = '{}.zipped'.format(rseName)
127
- rseUnmerged = self._getResultZipped(uri, callname=callname, clearCache=True)
128
- return rseUnmerged
114
+ rseUnmerged = self._getResultZipped(uri, callname=callname, clearCache=True)
115
+ else:
116
+ uri = "files?rse=%s&format=json" % rseName
117
+ callname = '{}.json'.format(rseName)
118
+ rseUnmerged = self._getResult(uri, callname=callname)
119
+ # now lazily return items
120
+ for item in rseUnmerged:
121
+ yield item
@@ -128,7 +128,7 @@ class WMStatsServer(Service):
128
128
  def getProtectedLFNs(self):
129
129
  """
130
130
  A method to be used for fetching a list of all protected lfns from WMStatServer
131
- :returns: A list of lfns
131
+ :returns: a unique list of protected LFNs
132
132
  """
133
133
  callname = 'protectedlfns'
134
- return self._getResult(callname, verb="GET")
134
+ return list(set(self._getResult(callname, verb="GET")))
WMCore/WMInit.py CHANGED
@@ -13,6 +13,8 @@ import os.path
13
13
  import sys
14
14
  import threading
15
15
  import traceback
16
+ import warnings
17
+ import wmcoredb
16
18
 
17
19
  from WMCore.Configuration import loadConfigurationFile
18
20
  from WMCore.DAOFactory import DAOFactory
@@ -20,7 +22,6 @@ from WMCore.Database.DBFactory import DBFactory
20
22
  from WMCore.Database.Transaction import Transaction
21
23
  from WMCore.WMBase import getWMBASE
22
24
  from WMCore.WMException import WMException
23
- from WMCore.WMFactory import WMFactory
24
25
 
25
26
 
26
27
  class WMInitException(WMException):
@@ -54,11 +55,12 @@ def connectToDB():
54
55
 
55
56
  socketLoc = getattr(wmAgentConfig.CoreDatabase, "socket", None)
56
57
  connectUrl = getattr(wmAgentConfig.CoreDatabase, "connectUrl", None)
57
- (dialect, junk) = connectUrl.split(":", 1)
58
+ (dialect, _) = connectUrl.split(":", 1)
58
59
 
59
60
  myWMInit = WMInit()
60
61
  myWMInit.setDatabaseConnection(dbConfig=connectUrl, dialect=dialect,
61
62
  socketLoc=socketLoc)
63
+
62
64
  return
63
65
 
64
66
 
@@ -113,12 +115,12 @@ class WMInit(object):
113
115
  return
114
116
 
115
117
  options = {}
116
- if dialect.lower() == 'mysql':
117
- dialect = 'MySQL'
118
+ if dialect.lower() in ['mysql', 'mariadb']:
119
+ dialect = 'mariadb' # Both MySQL and MariaDB use the mariadb directory
118
120
  if socketLoc != None:
119
121
  options['unix_socket'] = socketLoc
120
122
  elif dialect.lower() == 'oracle':
121
- dialect = 'Oracle'
123
+ dialect = 'oracle' # Keep lowercase for consistency
122
124
  elif dialect.lower() == 'http':
123
125
  dialect = 'CouchDB'
124
126
  else:
@@ -146,31 +148,178 @@ class WMInit(object):
146
148
 
147
149
  This method needs to have been preceded by the
148
150
  setDatabaseConnection.
151
+
152
+ @deprecated: Use setSchemaFromModules instead
153
+ """
154
+ warnings.warn("setSchema is deprecated. Use setSchemaFromModules instead.", DeprecationWarning)
155
+
156
+ # create a map of old to new SQL module names
157
+ moduleMap = {
158
+ 'WMCore.WMBS': 'wmbs',
159
+ 'WMCore.ResourceControl': 'resourcecontrol',
160
+ 'WMCore.BossAir': 'bossair',
161
+ 'WMCore.Agent.Database': 'agent',
162
+ 'WMComponent.DBS3Buffer': 'dbs3buffer',
163
+ 'T0.WMBS': 'tier0',
164
+ 'WMQuality.TestDB': 'testdb'
165
+ }
166
+
167
+ # convert old module names to new format
168
+ if modules:
169
+ modules = [moduleMap.get(module, module) for module in modules]
170
+
171
+ self.setSchemaFromModules(modules)
172
+
173
+ def setSchemaFromModules(self, sqlModules):
174
+ """
175
+ Initialize database schema for one or more SQL packages.
176
+ It finds out which dialect is being used and then looks for the
177
+ appropriate SQL files in the sql directory.
178
+
179
+ :param sqlModules: List of SQL database modules to be initialized.
180
+ Current supported values are (default is 'wmbs'):
181
+ - 'wmbs'
182
+ - 'resourcecontrol'
183
+ - 'bossair'
184
+ - 'agent'
185
+ - 'dbs3buffer'
186
+ - 'tier0'
149
187
  """
150
- modules = modules or []
151
188
  myThread = threading.currentThread()
189
+ if not hasattr(myThread, 'dbi'):
190
+ raise WMInitException("Database connection not initialized. Call setDatabaseConnection first.")
191
+
192
+ # Get the database dialect
193
+ dialect = myThread.dialect.lower()
194
+ if dialect not in ['mariadb', 'oracle']:
195
+ raise WMInitException(f"Unsupported database dialect: {dialect}")
196
+
197
+ # Get the base directory (WMCore root)
198
+ if os.environ.get('WMCORE_ROOT'):
199
+ baseDir = os.environ['WMCORE_ROOT']
200
+ logging.info("SQL base directory based on WMCORE_ROOT: %s", baseDir)
201
+ else:
202
+ baseDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
203
+ logging.info("SQL base directory based on WMInit-relative path: %s", baseDir)
204
+
205
+ # Define the SQL files needed for each module and their dependencies
206
+ # The order matters - modules that depend on others should come later
207
+ moduleSQLFiles = {
208
+ 'wmbs': {
209
+ 'files': ['create_wmbs_tables.sql', 'create_wmbs_indexes.sql', 'initial_wmbs_data.sql'],
210
+ 'dependencies': []
211
+ },
212
+ 'resourcecontrol': {
213
+ 'files': ['create_resourcecontrol.sql'],
214
+ 'dependencies': ['wmbs']
215
+ },
216
+ 'bossair': {
217
+ 'files': ['create_bossair.sql'],
218
+ 'dependencies': ['wmbs']
219
+ },
220
+ 'agent': {
221
+ 'files': ['create_agent.sql'],
222
+ 'dependencies': []
223
+ },
224
+ 'dbs3buffer': {
225
+ 'files': ['create_dbs3buffer.sql'],
226
+ 'dependencies': ['wmbs']
227
+ },
228
+ 'tier0': {
229
+ 'files': ['create_tier0_tables.sql', 'create_tier0_indexes.sql', 'create_tier0_functions.sql', 'initial_tier0_data.sql'],
230
+ 'dependencies': ['wmbs', 'dbs3buffer']
231
+ },
232
+ 'testdb': {
233
+ 'files': ['create_testdb.sql'],
234
+ 'dependencies': []
235
+ },
236
+ }
237
+
238
+ # Validate all requested modules exist
239
+ for module in sqlModules:
240
+ if module not in moduleSQLFiles:
241
+ raise WMInitException(f"Unknown module: {module}")
242
+
243
+ # Sort modules based on dependencies
244
+ sorted_modules = []
245
+ remaining_modules = set(sqlModules)
246
+
247
+ while remaining_modules:
248
+ # Find modules with no remaining dependencies
249
+ ready_modules = [
250
+ mod for mod in remaining_modules
251
+ if all(dep in sorted_modules for dep in moduleSQLFiles[mod]['dependencies'])
252
+ ]
253
+
254
+ if not ready_modules:
255
+ # Circular dependency detected
256
+ raise WMInitException("Circular dependency detected in module dependencies")
257
+
258
+ sorted_modules.extend(ready_modules)
259
+ remaining_modules -= set(ready_modules)
260
+
261
+ # Execute SQL files in dependency order
262
+ for module in sorted_modules:
263
+ logging.info("Executing SQL files for: %s", module)
264
+ for sql_file in moduleSQLFiles[module]['files']:
265
+ dialect_sql_file = wmcoredb.get_sql_file(module_name=module, file_name=sql_file, backend=dialect)
266
+
267
+ # now execute each SQL statement
268
+ for stmt in self._getSQLStatements(dialect_sql_file, dialect):
269
+ try:
270
+ myThread.dbi.processData(stmt)
271
+ except Exception as ex:
272
+ msg = f"Error executing SQL file {dialect_sql_file}. "
273
+ msg += f"Statement: {stmt}"
274
+ msg += str(ex)
275
+ raise WMInitException(msg)
152
276
 
153
- parameters = None
154
- flag = False
155
- # Set up for typical DBCreator format: logger, dbi, params
156
- if params != None:
157
- parameters = [None, None, params]
158
- flag = True
159
-
160
- myThread.transaction.begin()
161
- for factoryName in modules:
162
- # need to create these tables for testing.
163
- # notice the default structure: <dialect>/Create
164
- factory = WMFactory(factoryName, factoryName + "." + myThread.dialect)
165
-
166
- create = factory.loadObject("Create", args=parameters, listFlag=flag)
167
- createworked = create.execute(conn=myThread.transaction.conn,
168
- transaction=myThread.transaction)
169
- if createworked:
170
- logging.debug("Tables for " + factoryName + " created")
171
- else:
172
- logging.debug("Tables " + factoryName + " could not be created.")
173
- myThread.transaction.commit()
277
+ return
278
+
279
+ def _getSQLStatements(self, sqlFile, dialect):
280
+ """
281
+ Return the SQL statements from the file.
282
+ For MariaDB, it accepts the whole SQL file content in a single statement.
283
+ For Oracle, it splits the SQL file content into statements using the slash (/) terminator
284
+ when it appears as the first character in a line.
285
+ """
286
+ if not os.path.exists(sqlFile):
287
+ raise WMInitException(f"SQL file not found: {sqlFile}")
288
+
289
+ with open(sqlFile, 'r', encoding='utf-8') as f:
290
+ sql = f.read()
291
+
292
+ if dialect == 'mariadb':
293
+ return [sql]
294
+ elif dialect == 'oracle':
295
+ statements = []
296
+ current_statement = []
297
+
298
+ for line in sql.split('\n'):
299
+ line = line.strip()
300
+ # Skip empty lines and comments
301
+ if not line or line.startswith('--'):
302
+ continue
303
+
304
+ # If we find a slash terminator at the start of a line
305
+ if line == '/':
306
+ # Join all lines collected so far into a statement
307
+ stmt = '\n'.join(current_statement)
308
+ if stmt.strip():
309
+ statements.append(stmt)
310
+ current_statement = []
311
+ else:
312
+ current_statement.append(line)
313
+
314
+ # Add any remaining statement
315
+ if current_statement:
316
+ stmt = '\n'.join(current_statement)
317
+ if stmt.strip():
318
+ statements.append(stmt)
319
+
320
+ return statements
321
+ else:
322
+ raise WMInitException(f"Unsupported database dialect: {dialect}")
174
323
 
175
324
  def clearDatabase(self, modules=None):
176
325
  """
@@ -61,7 +61,7 @@ def makeLumiList(lumiDict):
61
61
  lumiDict = json.loads(lumiDict)
62
62
  ll = LumiList(compactList=lumiDict)
63
63
  return ll.getCompactList()
64
- except:
64
+ except Exception:
65
65
  raise WMSpecFactoryException("Could not parse LumiList, %s: %s" % (type(lumiDict), lumiDict))
66
66
 
67
67
 
@@ -91,12 +91,24 @@ def _validateArgument(argument, value, argumentDefinition):
91
91
  elif value is None:
92
92
  return value
93
93
 
94
+ # is it a built-in type (int, str, bool, etc.) or a custom function
95
+ expected_type = argumentDefinition["type"]
94
96
  try:
95
- value = argumentDefinition["type"](value)
96
- except Exception:
97
+ if expected_type == str and not isinstance(value, str):
98
+ raise TypeError(f"Argument '{argument}' with value {value} is not a string")
99
+ else:
100
+ # for other data types (or custom functions), just try to cast it to the expected type
101
+ value = expected_type(value)
102
+ except (ValueError, TypeError) as e:
97
103
  msg = "Argument '%s' with value %r, has an incorrect data type: " % (argument, value)
98
- msg += "%s. It must be %s" % (type(value), argumentDefinition["type"])
99
- raise WMSpecFactoryException(msg)
104
+ msg += "%s. It must be convertible by %s" % (type(value), expected_type.__name__)
105
+ if str(e):
106
+ msg += f" (Error: {e})"
107
+ raise WMSpecFactoryException(msg) from None
108
+ except Exception as e:
109
+ msg = f"Generic exception raised during argument validation for argument: {argument} "
110
+ msg += "with value: %r. Error details: %s" % (value, str(e))
111
+ raise WMSpecFactoryException(msg) from None
100
112
 
101
113
  _validateArgFunction(argument, value, argumentDefinition["validate"])
102
114
  return value
WMCore/__init__.py CHANGED
@@ -6,5 +6,5 @@ Core libraries for Workload Management Packages
6
6
 
7
7
  """
8
8
 
9
- __version__ = '2.4.0.2'
9
+ __version__ = '2.4.2'
10
10
  __all__ = []
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: wmglobalqueue
3
+ Version: 2.4.2
4
+ Home-page: https://github.com/dmwm/WMCore
5
+ Maintainer: CMS DMWM Group
6
+ Maintainer-email: hn-cms-wmdevelopment@cern.ch
7
+ License: Apache License, Version 2.0
8
+ License-File: LICENSE
9
+ License-File: NOTICE
10
+ Requires-Dist: CherryPy~=18.10.0
11
+ Requires-Dist: CMSMonitoring~=0.6.13
12
+ Requires-Dist: dbs3-client==4.0.19
13
+ Requires-Dist: future~=1.0.0
14
+ Requires-Dist: httplib2~=0.22.0
15
+ Requires-Dist: psutil~=7.0.0
16
+ Requires-Dist: pycurl~=7.45.6
17
+ Requires-Dist: retry~=0.9.2
18
+ Requires-Dist: rucio-clients~=36.5.0
19
+ Requires-Dist: Sphinx~=5.3.0
20
+ Requires-Dist: PyJWT~=2.9.0
21
+ Dynamic: home-page
22
+ Dynamic: license
23
+ Dynamic: license-file
24
+ Dynamic: maintainer
25
+ Dynamic: maintainer-email
26
+ Dynamic: requires-dist