rda-python-metrics 1.0.34__tar.gz → 1.0.36__tar.gz

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 rda-python-metrics might be problematic. Click here for more details.

Files changed (65) hide show
  1. {rda_python_metrics-1.0.34/src/rda_python_metrics.egg-info → rda_python_metrics-1.0.36}/PKG-INFO +1 -1
  2. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/pyproject.toml +3 -1
  3. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillawsusage.py +4 -3
  4. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillglobususage.py +4 -8
  5. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillosdfusage.py +1 -64
  6. rda_python_metrics-1.0.36/src/rda_python_metrics/viewawsusage.py +321 -0
  7. rda_python_metrics-1.0.36/src/rda_python_metrics/viewawsusage.usg +190 -0
  8. rda_python_metrics-1.0.36/src/rda_python_metrics/viewosdfusage.py +321 -0
  9. rda_python_metrics-1.0.36/src/rda_python_metrics/viewosdfusage.usg +190 -0
  10. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36/src/rda_python_metrics.egg-info}/PKG-INFO +1 -1
  11. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics.egg-info/SOURCES.txt +4 -0
  12. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics.egg-info/entry_points.txt +2 -0
  13. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/LICENSE +0 -0
  14. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/MANIFEST.in +0 -0
  15. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/README.md +0 -0
  16. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/setup.cfg +0 -0
  17. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/PgIPInfo.py +0 -0
  18. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/PgView.py +0 -0
  19. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/__init__.py +0 -0
  20. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillawsusage.usg +0 -0
  21. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillcdgusage.py +0 -0
  22. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillcdgusage.usg +0 -0
  23. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillcodusage.py +0 -0
  24. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillcodusage.usg +0 -0
  25. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillcountry.py +0 -0
  26. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillendtime.py +0 -0
  27. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillgdexusage.py +0 -0
  28. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillgdexusage.usg +0 -0
  29. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillglobususage.usg +0 -0
  30. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillipinfo.py +0 -0
  31. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillipinfo.usg +0 -0
  32. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/filloneorder.py +0 -0
  33. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/filloneorder.usg +0 -0
  34. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillosdfusage.usg +0 -0
  35. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillrdadb.py +0 -0
  36. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/fillrdadb.usg +0 -0
  37. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/filltdsusage.py +0 -0
  38. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/filltdsusage.usg +0 -0
  39. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/filluser.py +0 -0
  40. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/filluser.usg +0 -0
  41. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/logarch.py +0 -0
  42. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/logarch.usg +0 -0
  43. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/pgperson.py +0 -0
  44. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/pgsyspath.py +0 -0
  45. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/pgusername.py +0 -0
  46. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewallusage.py +0 -0
  47. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewallusage.usg +0 -0
  48. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewcheckusage.py +0 -0
  49. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewcheckusage.usg +0 -0
  50. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewcodusage.py +0 -0
  51. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewcodusage.usg +0 -0
  52. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewordusage.py +0 -0
  53. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewordusage.usg +0 -0
  54. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewrqstusage.py +0 -0
  55. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewrqstusage.usg +0 -0
  56. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewtdsusage.py +0 -0
  57. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewtdsusage.usg +0 -0
  58. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewwebfile.py +0 -0
  59. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewwebfile.usg +0 -0
  60. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewwebusage.py +0 -0
  61. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics/viewwebusage.usg +0 -0
  62. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics.egg-info/dependency_links.txt +0 -0
  63. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics.egg-info/requires.txt +0 -0
  64. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/src/rda_python_metrics.egg-info/top_level.txt +0 -0
  65. {rda_python_metrics-1.0.34 → rda_python_metrics-1.0.36}/tests/test_metrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_metrics
3
- Version: 1.0.34
3
+ Version: 1.0.36
4
4
  Summary: RDA Python Package to gather and view data usage metrics
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-metrics
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "rda_python_metrics"
9
- version = "1.0.34"
9
+ version = "1.0.36"
10
10
  authors = [
11
11
  { name="Zaihua Ji", email="zji@ucar.edu" },
12
12
  ]
@@ -54,9 +54,11 @@ pythonpath = [
54
54
  "pgperson" = "rda_python_metrics.pgperson:main"
55
55
  "pgusername" = "rda_python_metrics.pgusername:main"
56
56
  "viewallusage" = "rda_python_metrics.viewallusage:main"
57
+ "viewawsusage" = "rda_python_metrics.viewawsusage:main"
57
58
  "viewcheckusage" = "rda_python_metrics.viewcheckusage:main"
58
59
  "viewcodusage" = "rda_python_metrics.viewcodusage:main"
59
60
  "viewordusage" = "rda_python_metrics.viewordusage:main"
61
+ "viewosdfusage" = "rda_python_metrics.viewosdfusage:main"
60
62
  "viewrqstusage" = "rda_python_metrics.viewrqstusage:main"
61
63
  "viewtdsusage" = "rda_python_metrics.viewtdsusage:main"
62
64
  "viewwebfile" = "rda_python_metrics.viewwebfile:main"
@@ -94,7 +94,7 @@ def get_log_file_names(option, params):
94
94
  else:
95
95
  pdate = PgUtil.format_date(params[0])
96
96
  if len(params) > 1:
97
- edate = PgUtil.format_date(params[1])
97
+ edate = PgUtil.adddate(PgUtil.format_date(params[1]), 0, 0, 1)
98
98
  else:
99
99
  edate = PgUtil.curdate()
100
100
  while pdate < edate:
@@ -114,13 +114,14 @@ def fill_aws_usages(filenames):
114
114
  year = cntall = addall = 0
115
115
  for pdate in filenames:
116
116
  fnames = filenames[pdate]
117
+ fcnt = len(fnames)
118
+ PgLOG.pglog("{}: Gathering AWS usage info from {} log files at {}".format(pdate, fcnt, PgLOG.current_datetime()), PgLOG.LOGWRN)
117
119
  records = {}
118
120
  cntadd = entcnt = 0
119
121
  for logfile in fnames:
120
122
  if not op.isfile(logfile):
121
123
  PgLOG.pglog("{}: Not exists for Gathering AWS usage".format(logfile), PgLOG.LOGWRN)
122
124
  continue
123
- PgLOG.pglog("Gathering AWS usage info from {} at {}".format(logfile, PgLOG.current_datetime()), PgLOG.LOGWRN)
124
125
  aws = PgFile.open_local_file(logfile)
125
126
  if not aws: continue
126
127
  while True:
@@ -184,7 +185,7 @@ def add_usage_records(records, year):
184
185
  cnt = 0
185
186
  for key in records:
186
187
  record = records[key]
187
- cond = "date = '{}' AND time = '{}' AND ip = '{}' AND dsid = '{}'".format(record['date'], record['time'], record['ip'], record['dsid'])
188
+ cond = "date = '{}' AND time = '{}' AND ip = '{}'".format(record['date'], record['time'], record['ip'])
188
189
  if PgDBI.pgget(USAGE['PGTBL'], '', cond, PgLOG.LGEREX): continue
189
190
  if add_to_allusage(year, record):
190
191
  cnt += PgDBI.pgadd(USAGE['PGTBL'], record, PgLOG.LOGWRN)
@@ -147,18 +147,14 @@ def fill_globus_usages(fnames, datelimits):
147
147
  locflag = 'O' if re.match(r'^https://stratus\.', sline) else 'G'
148
148
  idx = wfile.find('?')
149
149
  if idx > -1: wfile = wfile[:idx]
150
-
151
- if re.match(r'^curl', engine, re.I):
152
- method = "CURL"
153
- elif re.match(r'^wget', engine, re.I):
154
- method = "WGET"
155
- elif re.match(r'^python', engine, re.I):
156
- method = "PYTHN"
150
+ moff = engine.find('/')
151
+ if moff > 0:
152
+ if moff > 20: moff = 20
153
+ method = engine[0:moff].upper()
157
154
  else:
158
155
  method = "WEB"
159
156
 
160
157
  key = "{}:{}:{}".format(ip, dsid, wfile) if stat == '206' else None
161
-
162
158
  if record:
163
159
  if key == pkey:
164
160
  record['size'] += size
@@ -185,7 +185,7 @@ def add_usage_records(records, year):
185
185
  cnt = 0
186
186
  for key in records:
187
187
  record = records[key]
188
- cond = "date = '{}' AND time = '{}' AND ip = '{}' AND dsid = '{}'".format(record['date'], record['time'], record['ip'], record['dsid'])
188
+ cond = "date = '{}' AND time = '{}' AND ip = '{}'".format(record['date'], record['time'], record['ip'])
189
189
  if PgDBI.pgget(USAGE['OSDFTBL'], '', cond, PgLOG.LGEREX): continue
190
190
  if add_to_allusage(year, record):
191
191
  cnt += PgDBI.pgadd(USAGE['OSDFTBL'], record, PgLOG.LOGWRN)
@@ -203,69 +203,6 @@ def add_to_allusage(year, pgrec):
203
203
 
204
204
  return PgDBI.add_yearly_allusage(year, record)
205
205
 
206
-
207
- #
208
- # Fill usage of a single online data file into table dssdb.wusage of DSS PgSQL database
209
- #
210
- def add_file_usage(year, logrec):
211
-
212
- pgrec = get_wfile_wid(logrec['dsid'], logrec['wfile'])
213
- if not pgrec: return 0
214
-
215
- table = "{}_{}".format(USAGE['OSDFTBL'], year)
216
- cond = "wid = {} AND method = '{}' AND date_read = '{}' AND time_read = '{}'".format(pgrec['wid'], logrec['method'], logrec['date'], logrec['time'])
217
- if PgDBI.pgget(USAGE['OSDFTBL'], "", cond, PgLOG.LOGWRN): return 0
218
-
219
- wurec = PgIPInfo.get_wuser_record(logrec['ip'], logrec['date'])
220
- if not wurec: return 0
221
- record = {'wid' : pgrec['wid'], 'dsid' : pgrec['dsid']}
222
- record['wuid_read'] = wurec['wuid']
223
- record['date_read'] = logrec['date']
224
- record['time_read'] = logrec['time']
225
- record['size_read'] = logrec['size']
226
- record['method'] = logrec['method']
227
- record['locflag'] = logrec['locflag']
228
- record['ip'] = logrec['ip']
229
- record['quarter'] = logrec['quarter']
230
-
231
- if add_to_allusage(year, logrec, wurec):
232
- return PgDBI.add_yearly_wusage(year, record)
233
- else:
234
- return 0
235
-
236
- def add_to_allusage(year, logrec, wurec):
237
-
238
- pgrec = {'email' : wurec['email'], 'org_type' : wurec['org_type'],
239
- 'country' : wurec['country'], 'region' : wurec['region']}
240
- pgrec['dsid'] = logrec['dsid']
241
- pgrec['date'] = logrec['date']
242
- pgrec['quarter'] = logrec['quarter']
243
- pgrec['time'] = logrec['time']
244
- pgrec['size'] = logrec['size']
245
- pgrec['method'] = logrec['method']
246
- pgrec['ip'] = logrec['ip']
247
- pgrec['source'] = 'P'
248
- return PgDBI.add_yearly_allusage(year, pgrec)
249
-
250
- #
251
- # return wfile.wid upon success, 0 otherwise
252
- #
253
- def get_wfile_wid(dsid, wfile):
254
-
255
- wfcond = "wfile = '{}'".format(wfile)
256
- pgrec = PgSplit.pgget_wfile(dsid, "*", wfcond)
257
- if pgrec:
258
- pgrec['dsid'] = dsid
259
- else:
260
- pgrec = PgDBI.pgget("wfile_delete", "*", "{} AND dsid = '{}'".format(wfcond, dsid))
261
- if not pgrec:
262
- pgrec = PgDBI.pgget("wmove", "wid, dsid", wfcond)
263
- if pgrec:
264
- pgrec = PgSplit.pgget_wfile(pgrec['dsid'], "*", "wid = {}".format(pgrec['wid']))
265
- if pgrec: pgrec['dsid'] = dsid
266
-
267
- return pgrec
268
-
269
206
  #
270
207
  # call main() to start program
271
208
  #
@@ -0,0 +1,321 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ ###############################################################################
4
+ #
5
+ # Title : viewawsusage
6
+ # Author : Zaihua Ji, zji@ucar.edu
7
+ # Date : 2025-08-13
8
+ # Purpose : python program to view aws usage information
9
+ #
10
+ # Github : https://github.com/NCAR/rda-python-metrics.git
11
+ #
12
+ ###############################################################################
13
+ #
14
+ import os
15
+ import re
16
+ import sys
17
+ from rda_python_common import PgLOG
18
+ from rda_python_common import PgUtil
19
+ from rda_python_common import PgDBI
20
+ from . import PgView
21
+
22
+ VUSG = {
23
+ 'SNMS' : "ABCDEHIKMNOPQRSTUWY", # all available short field names in %FLDS
24
+ 'OPTS' : 'AabcCdDeEhHikLmMnoOqsStTUwyz', # all available options, used for %params
25
+ 'NOPT' : 'abhnwz', # stand alone option without inputs
26
+ 'ACND' : 'cdeiIkmMoqSty', # available array condition options
27
+ 'RCND' : 'DEsT', # available range condition options
28
+ 'CNDS' : 'acdDeEiIkmMnoqsStTy', # condition options, ACND, RCND and 'a'
29
+ 'ECND' : 'my', # condition options need evaluating
30
+ 'SFLD' : 'DEIKNOTUW', # string fields, to be quoted in condition
31
+ 'UFLD' : 'NO', # string fields must be in upper case
32
+ 'LFLD' : 'EMPT' # string fields must be in lower case
33
+ }
34
+
35
+ # keys %FLDS - short field names
36
+ # column 0 - column title showing in usage view
37
+ # column 1 - field name in format as shown in select clauses
38
+ # column 2 - field name shown in where condition query string
39
+ # column 3 - table name that the field belongs to
40
+ # column 4 - output field length, the longer one of data size and comlun title, determine
41
+ # dynamically if it is 0. Negative values indicate right justification
42
+ # column 5 - precision for floating point value if positive and show total value if not zero
43
+ # column 6 - field flag to indicate it is a group, distinct or sum field
44
+ FLDS = {
45
+ # SHRTNM COLUMNNANE FIELDNAME CNDNAME TBLNAM Size Prc Grp/Sum
46
+ 'D' : ['DATE', "date", 'date', 'awsusage', 10, 0, 'G'],
47
+ 'E' : ['EMAIL', "awsusage.email", 'awsusage.email', 'awsusage', 0, 0, 'G'],
48
+ 'I' : ['IP', "ip", 'ip', 'awsusage', 0, 0, 'G'],
49
+ 'M' : ['MONTH', PgDBI.fmtym("date"), 'date', 'awsusage', 7, 0, 'G'],
50
+ 'N' : ['COUNTRY', "country", 'country', 'awsusage', 0, 0, 'G'],
51
+ 'K' : ['REGION', "region", 'region', 'awsusage', 0, 0, 'G'],
52
+ 'O' : ['ORGTYPE', "org_type", 'org_type', 'awsusage', 7, 0, 'G'],
53
+ 'P' : ['DSOWNER', "specialist", 'specialist', 'dsowner', 8, 0, 'G'],
54
+ 'Q' : ['QUARTER', "quarter", 'quarter', 'awsusage', 7, 0, 'G'],
55
+ 'R' : ['DSTITLE', "search.datasets.title", 'search.datasets.title', 'search.datasets', 0, 0, 'G'],
56
+ 'S' : ['BYTESIZE', "size", 'size', 'awsusage', -14, -1, 'G'],
57
+ 'T' : ['DATASET', "awsusage.dsid", 'awsusage.dsid', 'awsusage', 0, 0, 'G'],
58
+ 'W' : ['METHOD', "method", 'method', 'awsusage', 0, 0, 'G'],
59
+ 'Y' : ['YEAR', PgDBI.fmtyr("date"), 'date', 'awsusage', 4, 0, 'G'],
60
+ 'A' : ['DSCOUNT', "awsusage.dsid", 'A', 'awsusage', -7, -1, 'D'],
61
+ 'B' : ['MBYTEREAD', "round(sum(size)/(1000000), 4)", 'B', 'awsusage', -14, 3, 'S'],
62
+ 'C' : ['#UNIQUSER', "awsusage.email", 'C', 'awsusage', -9, -1, 'D'],
63
+ 'U' : ['#UNIQIP', "awsusage.ip", 'U', 'awsusage', -7, -1, 'D'],
64
+ 'H' : ['#ACCESS', "sum(fcount)", 'H', 'awsusage', -8, -1, 'S'],
65
+ 'X' : ['INDEX', "", 'X', '', -6, 0, ' ']
66
+ }
67
+
68
+ # keys %EXPAND - short field names allow zero usage
69
+ # column 0 - expand ID for group of fields
70
+ # column 1 - field name shown in where condition query string
71
+ # column 2 - field name in format as shown in select clauses
72
+ # column 3 - table name that the field belongs to
73
+ EXPAND = {
74
+ # SHRTNM EXPID CNDSTR FIELDNAME TBLNAM
75
+ 'D' : ["TIME", "dDmy"],
76
+ 'M' : ["TIME", "dDmy"],
77
+ 'Q' : ["TIME", "dDmy"],
78
+ 'Y' : ["TIME", "dDmy"],
79
+
80
+ 'E' : ["USER", "ecko", "email", "wuser", "user"],
81
+ 'O' : ["USER", "ecko", "org_type", "wuser", "user"],
82
+ 'N' : ["USER", "ecko", "country", "wuser", "user"],
83
+ 'K' : ["USER", "ecko", "region", "wuser", "user"],
84
+
85
+ 'R' : ["DSID", "StT", "search.datasets.title", "search.datasets"],
86
+ 'T' : ["DSID", "StT", "dataset.dsid", "dataset"],
87
+ 'P' : ["DSID", "StT", "specialist", "dsowner"],
88
+
89
+ 'W' : ["METHOD", "M", "method", "awsusage"]
90
+ }
91
+
92
+ # valid options for %params, a hash array of command line parameters
93
+ # a -- 1 to view all usage info available
94
+ # A -- number or records to return
95
+ # c -- array of specified country codes
96
+ # C -- a string of short field names for viewing usages
97
+ # d -- array of specified dates
98
+ # D -- dates range, array of 1 or 2 dates in format of YYYY-MM-DD
99
+ # e -- array of specified email addresses
100
+ # E -- use given date or date range for email notice of data update
101
+ # h -- for give emails, include their histical emails registered before
102
+ # H -- a string of report title to replace the default one
103
+ # i -- array of specified IP addresses
104
+ # I -- use given email IDs for email notice of data update
105
+ # k -- array of specified region names
106
+ # L -- column delimiter for output
107
+ # m -- array of specified months
108
+ # M -- array of specified download methods
109
+ # o -- array of specified orginization types
110
+ # O -- a string of short field names for sorting on
111
+ # q -- array of the specified quarters, normally combined with years
112
+ # s -- size range, arrage of 1 or 2 sizes in unit of MByte
113
+ # S -- array of login names of specialists who owns the datasets
114
+ # t -- array of specified dataset names
115
+ # T -- dataset range, array of 1 or 2 dataset names
116
+ # U -- given unit for file or data sizes
117
+ # w -- generate view without totals
118
+ # y -- array of specified years
119
+ # z -- generate view including entries without usage
120
+
121
+ params = {}
122
+
123
+ # relationship between parameter options and short field names, A option is not
124
+ # related to a field name if it is not in keys %SNS
125
+ SNS = {
126
+ 'c' : 'N', 'd' : 'D', 'D' : 'D', 'e' : 'E', 'i' : 'I', 'k' : 'K', 'm' : 'M',
127
+ 'M' : 'W', 'o' : 'O', 'q' : 'Q', 's' : 'S', 'S' : 'P', 't' : 'T', 'T' : 'T', 'y' : 'Y'
128
+ }
129
+
130
+ tablenames = fieldnames = condition = ''
131
+ sfields = []
132
+ gfields = []
133
+ dfields = []
134
+ pgname = 'viewawsusage'
135
+
136
+ #
137
+ # main function to run this program
138
+ #
139
+ def main():
140
+
141
+ PgDBI.view_dbinfo()
142
+ argv = sys.argv[1:]
143
+ inputs = []
144
+ option = 'C' # default option
145
+
146
+ for arg in argv:
147
+ if re.match(r'^-.*$', arg):
148
+ curopt = arg[1:2]
149
+ if curopt and VUSG['OPTS'].find(curopt) > -1:
150
+ if VUSG['NOPT'].find(option) > -1:
151
+ params[option] = 1
152
+ elif inputs:
153
+ params[option]= inputs # record input array
154
+ inputs = [] # empty input array
155
+ option = curopt # start a new option
156
+ else:
157
+ PgLOG.pglog(arg + ": Unknown Option", PgLOG.LGWNEX)
158
+ else:
159
+ val = arg
160
+ if val != '!':
161
+ if option == 's':
162
+ val = int(val)*1000000 # convert MBytes to Bytes
163
+ elif option in SNS:
164
+ sfld = SNS[option]
165
+ if VUSG['SFLD'].find(sfld) > -1:
166
+ if VUSG['UFLD'].find(sfld) > -1:
167
+ val = arg.upper() # in case not in upper case
168
+ elif VUSG['LFLD'].find(sfld) > -1:
169
+ val = arg.lower() # in case not in lower case
170
+ if option == 'c':
171
+ val = PgView.get_country_name(val)
172
+ elif option == 't' or option == 'T':
173
+ val = PgUtil.format_dataset_id(val) # add 'ds' if only numbers
174
+ val = "'{}'".format(val)
175
+ inputs.append(val)
176
+
177
+ # record the last option
178
+ if VUSG['NOPT'].find(option) > -1:
179
+ params[option] = 1
180
+ elif inputs:
181
+ params[option] = inputs # record input array
182
+
183
+ if not params:
184
+ PgLOG.show_usage(pgname)
185
+ else:
186
+ check_enough_options()
187
+
188
+ if 'o' not in params:
189
+ if 'e' not in params:
190
+ params['o'] = ['!', "'DSS'"] # default to exclude 'DSS' for organization
191
+ elif params['o'][0] == "'ALL'":
192
+ del params['o']
193
+
194
+ usgtable = "awsusage"
195
+ build_query_strings(usgtable) # build tablenames, fieldnames, and conditions
196
+ records = PgDBI.pgmget(tablenames, fieldnames, condition, PgLOG.UCLWEX)
197
+ if not records: PgLOG.pglog("No Usage Found For Given Conditions", PgLOG.LGWNEX)
198
+ totals = None if 'w' in params else {}
199
+ if dfields or totals != None:
200
+ records = PgView.compact_hash_groups(records, gfields, sfields, dfields, totals)
201
+ if 'z' in params: records = expand_records(records)
202
+ ostr = params['O'][0] if 'O' in params else params['C'][0]
203
+ records = PgView.order_records(records, ostr.replace('X', ''))
204
+ PgView.simple_output(params, FLDS, records, totals)
205
+
206
+ PgLOG.pgexit(0)
207
+
208
+ #
209
+ # cehck if enough information entered on command line for generate view/report, exit if not
210
+ #
211
+ def check_enough_options():
212
+
213
+ cols = params['C'][0] if 'C' in params else 'X'
214
+ if cols == 'X': PgLOG.pglog("{}: miss field names '{}'".format(pgname, VUSG['SNMS']), PgLOG.LGWNEX)
215
+
216
+ if cols.find('Q') > -1 and cols.find('Y') < 0: # add Y if Q included
217
+ cols = re.sub('Q', 'YQ', cols)
218
+ params['C'][0] = cols
219
+
220
+ for sn in cols:
221
+ if sn == 'X': continue # do not process INDEX field
222
+ if VUSG['SNMS'].find(sn) < 0:
223
+ PgLOG.pglog("{}: Field {} must be in field names '{}X'".format(pgname, sn, VUSG['SNMS']), PgLOG.LGWNEX)
224
+ if 'z' not in params or sn in EXPAND: continue
225
+ fld = FLDS[sn]
226
+ if fld[6] != 'G': continue
227
+ PgLOG.pglog("{}: cannot show zero usage for unexpandable field {} - {}".formt(pgname, sn, fld[0]), PgLOG.LGWNEX)
228
+
229
+ if 'E' in params or 'I' in params:
230
+ if 'z' in params:
231
+ PgLOG.pglog(pgname + ": option -z and -E/-I can not be present at the same time", PgLOG.LGWNEX)
232
+ elif 't' not in params or len(params['t']) > 1:
233
+ PgLOG.pglog(pgname + ": specify one dataset for viewing usage of notified users", PgLOG.LGWNEX)
234
+ elif 'E' in params and 'I' in params:
235
+ PgLOG.pglog(pgname + ": option -E and -I can not be present at the same time", PgLOG.LGWNEX)
236
+
237
+ for opt in params:
238
+ if VUSG['CNDS'].find(opt) > -1: return
239
+ PgLOG.pglog("{}: miss condition options '{}'".format(pgname, VUSG['CNDS']), PgLOG.LGWNEX)
240
+
241
+ #
242
+ # process parameter options to build aws query strings
243
+ # global variables are used directly and nothing passes in and returns back
244
+ #
245
+ def build_query_strings(usgtable):
246
+
247
+ # initialize query strings
248
+ global condition, fieldnames, tablenames
249
+ joins = groupnames = ''
250
+ tablenames = usgtable
251
+ cols = params['C'][0]
252
+
253
+ if 'U' in params: # reset units for file and read sizes
254
+ if cols.find('B') > -1: FLDS['B'] = PgView.set_data_unit(FLDS['B'], params['U'][0], "sum(size)")
255
+ if cols.find('S') > -1: FLDS['S'] = PgView.set_data_unit(FLDS['S'], params['U'][0], "size")
256
+
257
+ if 'e' in params and 'h' in params: params['e'] = PgView.include_historic_emails(params['e'], 3)
258
+
259
+ for opt in params:
260
+ if opt == 'C': # build field, table and group names
261
+ for sn in cols:
262
+ if sn == 'X': continue # do not process INDEX field
263
+ fld = FLDS[sn]
264
+ if fieldnames: fieldnames += ', '
265
+ fieldnames += "{} {}".format(fld[1], sn) # add to field name string
266
+ (tablenames, joins) = PgView.join_query_tables(fld[3], tablenames, joins, usgtable)
267
+ if fld[6] == 'S':
268
+ sfields.append(sn)
269
+ else:
270
+ if groupnames: groupnames += ', '
271
+ groupnames += sn # add to group name string
272
+ if fld[6] == 'D':
273
+ dfields.append(sn)
274
+ else:
275
+ gfields.append(sn)
276
+ elif opt == 'O':
277
+ continue # order records later
278
+ elif VUSG['CNDS'].find(opt) > -1:
279
+ if VUSG['NOPT'].find(opt) > -1: continue
280
+ sn = SNS[opt]
281
+ fld = FLDS[sn]
282
+ # build having and where conditon strings
283
+ cnd = PgView.get_view_condition(opt, sn, fld, params, VUSG)
284
+ if cnd:
285
+ if condition: condition += ' AND '
286
+ condition += cnd
287
+ (tablenames, joins) = PgView.join_query_tables(fld[3], tablenames, joins, usgtable)
288
+
289
+
290
+ # append joins, group by, order by, and having strings to condition string
291
+ if 'E' in params or 'I' in params:
292
+ (tablenames, joins) = PgView.join_query_tables("emreceive", tablenames, joins, usgtable)
293
+ if joins:
294
+ if condition:
295
+ condition = "{} AND {}".format(joins, condition)
296
+ else:
297
+ condition = joins
298
+ if 'E' in params or 'I' in params:
299
+ condition += PgView.notice_condition(params['E'], None, params['t'][0])
300
+ if groupnames and sfields: condition += " GROUP BY " + groupnames
301
+
302
+
303
+ def expand_records(records):
304
+
305
+ recs = PgView.expand_query("TIME", records, params, EXPAND)
306
+
307
+ trecs = PgView.expand_query("USER", records, params, EXPAND, VUSG, SNS, FLDS)
308
+ recs = PgUtil.crosshash(recs, trecs)
309
+
310
+ trecs = PgView.expand_query("DSID", records, params, EXPAND, VUSG, SNS, FLDS)
311
+ recs = PgUtil.crosshash(recs, trecs)
312
+
313
+ trecs = PgView.expand_query("METHOD", records, params, EXPAND, VUSG, SNS, FLDS)
314
+ recs = PgUtil.crosshash(recs, trecs)
315
+
316
+ return PgUtil.joinhash(records, recs, 0, 1)
317
+
318
+ #
319
+ # call main() to start program
320
+ #
321
+ if __name__ == "__main__": main()