rda-python-dscheck 2.0.7__py3-none-any.whl → 3.0.0__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.
- rda_python_dscheck/PgCheck.py +6 -6
- rda_python_dscheck/__init__.py +26 -0
- rda_python_dscheck/ds_check.py +6 -6
- rda_python_dscheck/dscheck.py +6 -6
- rda_python_dscheck/dscheck.usg +83 -54
- rda_python_dscheck/pg_check.py +9 -7
- rda_python_dscheck-3.0.0.dist-info/METADATA +183 -0
- rda_python_dscheck-3.0.0.dist-info/RECORD +12 -0
- rda_python_dscheck-2.0.7.dist-info/METADATA +0 -22
- rda_python_dscheck-2.0.7.dist-info/RECORD +0 -12
- {rda_python_dscheck-2.0.7.dist-info → rda_python_dscheck-3.0.0.dist-info}/WHEEL +0 -0
- {rda_python_dscheck-2.0.7.dist-info → rda_python_dscheck-3.0.0.dist-info}/entry_points.txt +0 -0
- {rda_python_dscheck-2.0.7.dist-info → rda_python_dscheck-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {rda_python_dscheck-2.0.7.dist-info → rda_python_dscheck-3.0.0.dist-info}/top_level.txt +0 -0
rda_python_dscheck/PgCheck.py
CHANGED
|
@@ -211,7 +211,7 @@ def check_dscheck_options(cact, aname):
|
|
|
211
211
|
"Miss check index per Info option -CI(-CheckIndex)",
|
|
212
212
|
"Need Machine Hostname per -HN for new daemon control",
|
|
213
213
|
"Need Application command name per -CM for new daemon control",
|
|
214
|
-
"Must be {} to process Checks in daemon mode".format(PgLOG.PGLOG['
|
|
214
|
+
"Must be {} to process Checks in daemon mode".format(PgLOG.PGLOG['COMMONUSER']),
|
|
215
215
|
"Miss Command information per Info option -CM(-Command)",
|
|
216
216
|
]
|
|
217
217
|
erridx = -1
|
|
@@ -223,7 +223,7 @@ def check_dscheck_options(cact, aname):
|
|
|
223
223
|
if 'DM' in PgOPT.params:
|
|
224
224
|
if cact != "PC":
|
|
225
225
|
erridx = 0
|
|
226
|
-
elif PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['
|
|
226
|
+
elif PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['COMMONUSER']:
|
|
227
227
|
erridx = 5
|
|
228
228
|
elif 'CI' in PgOPT.params:
|
|
229
229
|
erridx = 1
|
|
@@ -280,7 +280,7 @@ def check_dscheck_options(cact, aname):
|
|
|
280
280
|
wtime = PgOPT.params['WI'] if 'WI' in PgOPT.params else 30
|
|
281
281
|
logon = PgOPT.params['LO'] if 'LO' in PgOPT.params else 1
|
|
282
282
|
PgSIG.start_none_daemon(aname, cact, PgOPT.params['LN'], 1, wtime, logon)
|
|
283
|
-
if not ('CI' in PgOPT.params or 'DS' in PgOPT.params or PgOPT.params['LN'] == PgLOG.PGLOG['
|
|
283
|
+
if not ('CI' in PgOPT.params or 'DS' in PgOPT.params or PgOPT.params['LN'] == PgLOG.PGLOG['COMMONUSER']):
|
|
284
284
|
PgOPT.set_default_value("SN", PgOPT.params['LN'])
|
|
285
285
|
|
|
286
286
|
# minimal wait interval in seconds for next check
|
|
@@ -581,7 +581,7 @@ def start_one_dscheck(pgrec, logact = 0):
|
|
|
581
581
|
|
|
582
582
|
lidx = get_process_host(limits, pgrec['hostname'], pgrec['command'], pgrec['action'], logact)
|
|
583
583
|
if lidx < 0 or skip_dscheck_record(pgrec, host, logact): return 0
|
|
584
|
-
cmd = "pgstart_{} ".format(specialist) if PgLOG.PGLOG['CURUID'] == PgLOG.PGLOG['
|
|
584
|
+
cmd = "pgstart_{} ".format(specialist) if PgLOG.PGLOG['CURUID'] == PgLOG.PGLOG['COMMONUSER'] else ""
|
|
585
585
|
if not PgUtil.pgcmp(host, PgLOG.PGLOG['PBSNAME'], 1):
|
|
586
586
|
if reach_dataset_limit(pgrec): return 0
|
|
587
587
|
cmd += get_specialist_shell(specialist) + 'qsub '
|
|
@@ -1532,7 +1532,7 @@ def validate_daemons():
|
|
|
1532
1532
|
if not pgrec:
|
|
1533
1533
|
PgOPT.action_error("Daemon Control Index '{}' is not in RDADB".format(val))
|
|
1534
1534
|
elif(PgOPT.OPTS[PgOPT.PGOPT['CACT']][2] > 0 and PgOPT.params['LN'] != pgrec['specialist'] and
|
|
1535
|
-
PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['
|
|
1535
|
+
PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['COMMONUSER']):
|
|
1536
1536
|
PgOPT.action_error("{}: must be {}, owner of Daemon Control Index {}".format(PgOPT.params['LN'], pgrec['specialist'], val))
|
|
1537
1537
|
else: # found none-equal condition sign
|
|
1538
1538
|
pgrec = PgDBI.pgmget("dsdaemon", "DISTINCT dindex",
|
|
@@ -1573,7 +1573,7 @@ def validate_checks():
|
|
|
1573
1573
|
if not pgrec:
|
|
1574
1574
|
PgOPT.action_error("Check Index '{}' is not in RDADB".format(val))
|
|
1575
1575
|
elif(PgOPT.OPTS[PgOPT.PGOPT['CACT']][2] > 0 and PgOPT.params['LN'] != pgrec['specialist'] and
|
|
1576
|
-
PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['
|
|
1576
|
+
PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['COMMONUSER']):
|
|
1577
1577
|
PgOPT.action_error("{}: must be {}, owner of Check Index {}".format(PgOPT.params['LN'], pgrec['specialist'], val))
|
|
1578
1578
|
else: # found none-equal condition sign
|
|
1579
1579
|
pgrec = PgDBI.pgmget("dscheck", "cindex", PgDBI.get_field_condition("cindex", PgOPT.params['CI'], 0, 1), PgOPT.PGOPT['extlog'])
|
rda_python_dscheck/__init__.py
CHANGED
|
@@ -1 +1,27 @@
|
|
|
1
|
+
"""rda_python_dscheck: dataset check (dscheck) utility package.
|
|
1
2
|
|
|
3
|
+
This package exposes two parallel APIs:
|
|
4
|
+
|
|
5
|
+
1. Legacy module-based API (back-compat). Import the capitalized
|
|
6
|
+
submodule and call its module-level functions, e.g.::
|
|
7
|
+
|
|
8
|
+
from rda_python_dscheck import PgCheck
|
|
9
|
+
|
|
10
|
+
2. Class-based API (preferred for new code). Import the class from the
|
|
11
|
+
lower-case module and either instantiate or subclass it, e.g.::
|
|
12
|
+
|
|
13
|
+
from rda_python_dscheck.pg_check import PgCheck
|
|
14
|
+
|
|
15
|
+
The legacy submodule is eagerly imported below so that
|
|
16
|
+
``from rda_python_dscheck import PgCheck`` continues to return the module
|
|
17
|
+
object that existing callers expect.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from . import PgCheck
|
|
21
|
+
|
|
22
|
+
__version__ = "2.0.8"
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"PgCheck",
|
|
26
|
+
"__version__",
|
|
27
|
+
]
|
rda_python_dscheck/ds_check.py
CHANGED
|
@@ -279,7 +279,7 @@ def set_daemon_info():
|
|
|
279
279
|
if pgrec:
|
|
280
280
|
modcnt += PgDBI.pgupdt(tname, record, cnd, PgOPT.PGOPT['extlog'])
|
|
281
281
|
else:
|
|
282
|
-
if 'specialist' not in record and PgOPT.params['LN'] != PgLOG.PGLOG['
|
|
282
|
+
if 'specialist' not in record and PgOPT.params['LN'] != PgLOG.PGLOG['COMMONUSER']: record['specialist'] = PgOPT.params['LN']
|
|
283
283
|
didx = PgDBI.pgadd(tname, record, PgOPT.PGOPT['extlog']|PgLOG.AUTOID)
|
|
284
284
|
if didx:
|
|
285
285
|
PgLOG.pglog("Daemon Control Index {} added".format(didx), PgOPT.PGOPT['wrnlog'])
|
|
@@ -506,12 +506,12 @@ def process_dschecks():
|
|
|
506
506
|
|
|
507
507
|
logact = PgLOG.LOGERR
|
|
508
508
|
|
|
509
|
-
if PgLOG.PGLOG['CURUID'] == PgLOG.PGLOG['
|
|
509
|
+
if PgLOG.PGLOG['CURUID'] == PgLOG.PGLOG['COMMONUSER'] and (time.time()%(3*PgSIG.PGSIG['CTIME'])) < 60:
|
|
510
510
|
logact |= PgLOG.EMEROL
|
|
511
511
|
|
|
512
512
|
cnd = PgOPT.get_hash_condition("dscheck", "ST", None, 1)
|
|
513
513
|
if cnd: cnd += " AND "
|
|
514
|
-
if 'SN' not in PgOPT.params and PgOPT.params['LN'] != PgLOG.PGLOG['
|
|
514
|
+
if 'SN' not in PgOPT.params and PgOPT.params['LN'] != PgLOG.PGLOG['COMMONUSER']:
|
|
515
515
|
cnd += "specialist = '{}' AND ".format(PgOPT.params['LN'])
|
|
516
516
|
|
|
517
517
|
if 'WR' in PgOPT.params: PgCheck.start_dsrqsts(cnd, logact)
|
|
@@ -530,12 +530,12 @@ def process_dscheck_options():
|
|
|
530
530
|
|
|
531
531
|
logact = PgLOG.LOGERR
|
|
532
532
|
|
|
533
|
-
if PgLOG.PGLOG['CURUID'] == PgLOG.PGLOG['
|
|
533
|
+
if PgLOG.PGLOG['CURUID'] == PgLOG.PGLOG['COMMONUSER'] and (time.time()%(3*PgSIG.PGSIG['CTIME'])) < 60:
|
|
534
534
|
logact |= PgLOG.EMEROL
|
|
535
535
|
|
|
536
536
|
cnd = PgOPT.get_hash_condition("dscheck", "ST", None, 1)
|
|
537
537
|
if cnd: cnd += " AND "
|
|
538
|
-
if 'SN' not in PgOPT.params and PgOPT.params['LN'] != PgLOG.PGLOG['
|
|
538
|
+
if 'SN' not in PgOPT.params and PgOPT.params['LN'] != PgLOG.PGLOG['COMMONUSER']:
|
|
539
539
|
cnd += "specialist = '{}' AND ".format(PgOPT.params['LN'])
|
|
540
540
|
|
|
541
541
|
acnd = PgOPT.get_hash_condition("dscheck", None, "ST", 1)
|
|
@@ -654,7 +654,7 @@ def check_host_connection():
|
|
|
654
654
|
hostname = pgrecs['hostname'][i]
|
|
655
655
|
cmd = "ssh {} ps".format(hostname)
|
|
656
656
|
if specialist != PgLOG.PGLOG['CURUID']:
|
|
657
|
-
if PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['
|
|
657
|
+
if PgLOG.PGLOG['CURUID'] != PgLOG.PGLOG['COMMONUSER']:
|
|
658
658
|
PgLOG.pglog("{}: Cannot check connection to '{}' for {}".format(PgLOG.PGLOG['CURUID'], hostname, specialist), PgLOG.LOGERR)
|
|
659
659
|
continue
|
|
660
660
|
else:
|
rda_python_dscheck/dscheck.py
CHANGED
|
@@ -225,7 +225,7 @@ class DsCheck(PgCheck):
|
|
|
225
225
|
if pgrec:
|
|
226
226
|
modcnt += self.pgupdt(tname, record, cnd, self.PGOPT['extlog'])
|
|
227
227
|
else:
|
|
228
|
-
if 'specialist' not in record and self.params['LN'] != self.PGLOG['
|
|
228
|
+
if 'specialist' not in record and self.params['LN'] != self.PGLOG['COMMONUSER']: record['specialist'] = self.params['LN']
|
|
229
229
|
didx = self.pgadd(tname, record, self.PGOPT['extlog']|self.AUTOID)
|
|
230
230
|
if didx:
|
|
231
231
|
self.pglog("Daemon Control Index {} added".format(didx), self.PGOPT['wrnlog'])
|
|
@@ -411,11 +411,11 @@ class DsCheck(PgCheck):
|
|
|
411
411
|
# process the checks
|
|
412
412
|
def process_dschecks(self):
|
|
413
413
|
logact = self.LOGERR
|
|
414
|
-
if self.PGLOG['CURUID'] == self.PGLOG['
|
|
414
|
+
if self.PGLOG['CURUID'] == self.PGLOG['COMMONUSER'] and (time.time()%(3*self.PGSIG['CTIME'])) < 60:
|
|
415
415
|
logact |= self.EMEROL
|
|
416
416
|
cnd = self.get_hash_condition("dscheck", "ST", None, 1)
|
|
417
417
|
if cnd: cnd += " AND "
|
|
418
|
-
if 'SN' not in self.params and self.params['LN'] != self.PGLOG['
|
|
418
|
+
if 'SN' not in self.params and self.params['LN'] != self.PGLOG['COMMONUSER']:
|
|
419
419
|
cnd += "specialist = '{}' AND ".format(self.params['LN'])
|
|
420
420
|
if 'WR' in self.params: self.start_dsrqsts(cnd, logact)
|
|
421
421
|
if 'WU' in self.params: self.start_dsupdts(cnd, logact)
|
|
@@ -427,11 +427,11 @@ class DsCheck(PgCheck):
|
|
|
427
427
|
# process the checks
|
|
428
428
|
def process_dscheck_options(self):
|
|
429
429
|
logact = self.LOGERR
|
|
430
|
-
if self.PGLOG['CURUID'] == self.PGLOG['
|
|
430
|
+
if self.PGLOG['CURUID'] == self.PGLOG['COMMONUSER'] and (time.time()%(3*self.PGSIG['CTIME'])) < 60:
|
|
431
431
|
logact |= self.EMEROL
|
|
432
432
|
cnd = self.get_hash_condition("dscheck", "ST", None, 1)
|
|
433
433
|
if cnd: cnd += " AND "
|
|
434
|
-
if 'SN' not in self.params and self.params['LN'] != self.PGLOG['
|
|
434
|
+
if 'SN' not in self.params and self.params['LN'] != self.PGLOG['COMMONUSER']:
|
|
435
435
|
cnd += "specialist = '{}' AND ".format(self.params['LN'])
|
|
436
436
|
acnd = self.get_hash_condition("dscheck", None, "ST", 1)
|
|
437
437
|
if acnd: acnd += " AND "
|
|
@@ -513,7 +513,7 @@ class DsCheck(PgCheck):
|
|
|
513
513
|
hostname = pgrecs['hostname'][i]
|
|
514
514
|
cmd = "ssh {} ps".format(hostname)
|
|
515
515
|
if specialist != self.PGLOG['CURUID']:
|
|
516
|
-
if self.PGLOG['CURUID'] != self.PGLOG['
|
|
516
|
+
if self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']:
|
|
517
517
|
self.pglog("{}: Cannot check connection to '{}' for {}".format(self.PGLOG['CURUID'], hostname, specialist), self.LOGERR)
|
|
518
518
|
continue
|
|
519
519
|
else:
|
rda_python_dscheck/dscheck.usg
CHANGED
|
@@ -9,18 +9,30 @@ well as any specialist-defined command.
|
|
|
9
9
|
|
|
10
10
|
The mental model has three layers:
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
A check record - a row in GDEXDB that captures one deferred command:
|
|
13
|
+
its name, arguments, owner, working directory,
|
|
14
|
+
target host, retry policy, and current status.
|
|
15
|
+
daemon/crontab control - a row in GDEXDB that tells the centralized
|
|
16
|
+
'dscheck' driver (whether running as a long-lived
|
|
17
|
+
daemon or as a short-lived crontab invocation) how
|
|
18
|
+
many concurrent processes of a given command a
|
|
19
|
+
given specialist may run on a given host, and at
|
|
20
|
+
what host priority.
|
|
21
|
+
The dscheck driver - a process that wakes on a fixed interval, adds
|
|
22
|
+
due 'dsupdt'/'dsrqst' check records, and starts
|
|
23
|
+
(or restarts) commands from check records on
|
|
24
|
+
hosts chosen according to daemon control
|
|
25
|
+
configuration. The driver may run either as a
|
|
26
|
+
long-running daemon ('-PC -DM start') or as a
|
|
27
|
+
short-lived crontab invocation ('-PC' every
|
|
28
|
+
minute via cron). It may run as the specialist's
|
|
29
|
+
own loginname, or as PGLOG['COMMONUSER'] (default
|
|
30
|
+
'gdexdata'). When it runs as COMMONUSER it also
|
|
31
|
+
submits PBS jobs (via qsub) on behalf of every
|
|
32
|
+
specialist whose loginname belongs to the same
|
|
33
|
+
group as COMMONUSER and who has a properly
|
|
34
|
+
installed pgstart_<loginname> binary (see the
|
|
35
|
+
rda_python_setuid README, '-p|--pgstart').
|
|
24
36
|
|
|
25
37
|
Typical lifecycle of a deferred command:
|
|
26
38
|
|
|
@@ -80,7 +92,7 @@ into an action.
|
|
|
80
92
|
Notation:
|
|
81
93
|
[] - the enclosed element is optional.
|
|
82
94
|
(A|B) - either A or B may be used (a short form and a long form).
|
|
83
|
-
|
|
95
|
+
-<OPT> - OPT is an option name. Names are case-insensitive; values are not.
|
|
84
96
|
|
|
85
97
|
Every dscheck invocation has at most one Action option, which selects the
|
|
86
98
|
task to perform. Mode options change how the chosen action behaves. Info
|
|
@@ -95,26 +107,34 @@ are accepted, and aliases are noted with each option.
|
|
|
95
107
|
2.1 Quick Start
|
|
96
108
|
|
|
97
109
|
Show the full document, paged through 'more':
|
|
98
|
-
|
|
110
|
+
dscheck
|
|
99
111
|
|
|
100
112
|
Show the description of a single option:
|
|
101
|
-
|
|
102
|
-
dscheck -AC -h
|
|
113
|
+
dscheck -h -AC
|
|
103
114
|
|
|
104
115
|
List your own daemon control records:
|
|
105
|
-
|
|
116
|
+
|
|
117
|
+
dscheck -GD
|
|
106
118
|
|
|
107
119
|
List your own active check records:
|
|
108
|
-
|
|
120
|
+
|
|
121
|
+
dscheck -GC
|
|
109
122
|
|
|
110
123
|
Add a deferred run of a script on PBS:
|
|
111
|
-
|
|
124
|
+
|
|
125
|
+
dscheck -AC -CM myscript.sh -HN PBS
|
|
112
126
|
|
|
113
127
|
Email yourself the status of all your active checks:
|
|
114
|
-
dscheck -EC
|
|
115
128
|
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
dscheck -EC
|
|
130
|
+
|
|
131
|
+
Start the dscheck driver as a long-running daemon (typical for the operator):
|
|
132
|
+
|
|
133
|
+
dscheck -PC -DM start
|
|
134
|
+
|
|
135
|
+
Or run the dscheck driver from crontab every minute (lightweight alternative):
|
|
136
|
+
|
|
137
|
+
* * * * * dscheck -PC
|
|
118
138
|
|
|
119
139
|
2.2 Filters and Special Characters in Queries
|
|
120
140
|
|
|
@@ -135,20 +155,9 @@ Every option except -IF (-InputFile) may be supplied either on the command
|
|
|
135
155
|
line or in an input file. -IF is itself only valid on the command line.
|
|
136
156
|
A single dscheck invocation may combine command-line options with one or
|
|
137
157
|
more input files. If the only options are inside a single input file, the
|
|
138
|
-
-IF prefix may be omitted
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
See the description of -IF in Section 5.2 for the input-file format
|
|
143
|
-
(comments, action/mode markers, single-value assignments, and tabular
|
|
144
|
-
multi-value assignments, including delimiter overrides).
|
|
145
|
-
|
|
146
|
-
2.4 Getting Help
|
|
147
|
-
|
|
148
|
-
dscheck # full document, displayed via 'more'
|
|
149
|
-
dscheck -(h|help) # full document
|
|
150
|
-
dscheck [Option] -(h|help) # description of [Option]
|
|
151
|
-
dscheck -(h|help) [Option] # same as above
|
|
158
|
+
-IF prefix may be omitted. See the description of -IF in Section 5.2 for
|
|
159
|
+
the input-file format (comments, action/mode markers, single-value assignments,
|
|
160
|
+
and tabular multi-value assignments, including delimiter overrides).
|
|
152
161
|
|
|
153
162
|
A printable copy of this document is the file dscheck.usg installed under
|
|
154
163
|
the python package rda_python_dscheck.
|
|
@@ -224,16 +233,6 @@ Delete Daemon Control - remove daemon control records by index.
|
|
|
224
233
|
CM = ALL - apply to any command not otherwise configured for this
|
|
225
234
|
specialist.
|
|
226
235
|
|
|
227
|
-
Example - configure schuster on PBS for any command, with up to 4
|
|
228
|
-
concurrent checks at priority 1 (lower number = higher priority), driven
|
|
229
|
-
from input file daemon.ctl:
|
|
230
|
-
|
|
231
|
-
dscheck -SD -ND -IF daemon.ctl
|
|
232
|
-
|
|
233
|
-
<<Content of input file daemon.ctl>>
|
|
234
|
-
DaemonIndex<:>Specialist<:>Command<:>Hostname<:>ProcessLimit<:>Priority<:>
|
|
235
|
-
0<:>schuster<:>ALL<:>PBS<:>4<:>1<:>
|
|
236
|
-
|
|
237
236
|
|
|
238
237
|
3.1.2 Get Daemon Control
|
|
239
238
|
-GD or -GetDaemon, retrieves daemon control records. With no Info-option
|
|
@@ -364,7 +363,7 @@ Unlock Check - clear leftover lock information after an abnormal exit.
|
|
|
364
363
|
|
|
365
364
|
Add the executable 'test3' for deferred execution on PBS:
|
|
366
365
|
|
|
367
|
-
|
|
366
|
+
dscheck -AC -CM test3 -HN PBS
|
|
368
367
|
|
|
369
368
|
The command 'test3' must be executable from the working directory on
|
|
370
369
|
the PBS machine.
|
|
@@ -461,7 +460,13 @@ Unlock Check - clear leftover lock information after an abnormal exit.
|
|
|
461
460
|
|
|
462
461
|
3.3 Check Process Actions
|
|
463
462
|
|
|
464
|
-
The dscheck
|
|
463
|
+
The dscheck driver starts and restarts deferred commands automatically.
|
|
464
|
+
It can run either as a long-running daemon ('-PC -DM start'), or as a
|
|
465
|
+
short-lived crontab invocation ('-PC' run every minute by cron). The
|
|
466
|
+
driver may run as the specialist's own loginname, or as
|
|
467
|
+
PGLOG['COMMONUSER'] (default 'gdexdata'); when run as COMMONUSER it
|
|
468
|
+
also submits PBS jobs on behalf of every specialist in COMMONUSER's
|
|
469
|
+
group that has a properly installed pgstart_<loginname> binary.
|
|
465
470
|
Operators (and, in non-daemon mode, specialists) can also drive command
|
|
466
471
|
execution from the command line, interrupt running commands, and email
|
|
467
472
|
status summaries.
|
|
@@ -504,11 +509,28 @@ Available actions:
|
|
|
504
509
|
-DM stop, -DM logon, and -DM logoff stop the daemon, enable detailed
|
|
505
510
|
logging, and disable detailed logging respectively.
|
|
506
511
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
+
Crontab mode (cron-driven, no -DM):
|
|
513
|
+
The same -PC action can be driven from cron instead of running as a
|
|
514
|
+
long-lived daemon. A typical setup is to run it every minute:
|
|
515
|
+
* * * * * dscheck -PC
|
|
516
|
+
Each invocation performs one cycle (add due 'dsupdt'/'dsrqst' work,
|
|
517
|
+
then start/restart checks) and exits. -WI is ignored because the
|
|
518
|
+
cron schedule controls the cadence.
|
|
519
|
+
|
|
520
|
+
Non-daemon (one-shot) mode:
|
|
521
|
+
Without -DM and not driven by cron, dscheck processes the current
|
|
522
|
+
set of check records once. -WU and -WR must be set explicitly if you
|
|
523
|
+
want due 'dsupdt'/'dsrqst' work to be added before processing. -CI
|
|
524
|
+
restricts processing to specific check indices.
|
|
525
|
+
|
|
526
|
+
Running user (daemon or crontab mode):
|
|
527
|
+
The driver may run as the specialist's own loginname (handling only
|
|
528
|
+
that specialist's checks), or as PGLOG['COMMONUSER'] (default
|
|
529
|
+
'gdexdata'). When run as COMMONUSER, it also submits PBS jobs (via
|
|
530
|
+
qsub) on behalf of every specialist whose loginname is in the same
|
|
531
|
+
group as COMMONUSER and who has a properly installed
|
|
532
|
+
pgstart_<loginname> binary (see rda_python_setuid, option
|
|
533
|
+
'-p|--pgstart').
|
|
512
534
|
|
|
513
535
|
3.3.2 Interrupt Check
|
|
514
536
|
-IC or -InterruptCheck, stops a running command and recursively kills
|
|
@@ -571,6 +593,7 @@ Available actions:
|
|
|
571
593
|
[-(MO|Modules) ModuleList]
|
|
572
594
|
[-(EV|Environments) EnvironmentPairList]
|
|
573
595
|
[-(QS|QsubOptions) PBSBatchOptions]
|
|
596
|
+
[-(SH|SSHHostname) RemoteHostname]
|
|
574
597
|
[-(DB|Debug) DebugModeInfo]
|
|
575
598
|
|
|
576
599
|
|
|
@@ -665,11 +688,17 @@ multiple values is an error.
|
|
|
665
688
|
-ON or -OrderNames, a string of single-letter field codes that
|
|
666
689
|
controls the sort order of -GC (-GetCheck) output.
|
|
667
690
|
|
|
691
|
+
-SH or -SSHHostname, used with -SO (-SetOptions): remote host name on
|
|
692
|
+
which the dynamic-option command should run. When supplied, the command
|
|
693
|
+
is invoked via 'ssh <hostname> ...' instead of locally. Defaults to
|
|
694
|
+
running locally when omitted.
|
|
695
|
+
|
|
668
696
|
-AO or -ActOption, the token that marks Action and Mode options in
|
|
669
697
|
input files. Defaults to '<!>'.
|
|
670
698
|
|
|
671
699
|
-WI or -WaitInterval, the time the dscheck daemon sleeps between
|
|
672
|
-
cycles. Defaults to 120 seconds (2 minutes).
|
|
700
|
+
cycles. Defaults to 120 seconds (2 minutes). Ignored when -PC is
|
|
701
|
+
driven from cron, since the cron schedule controls the cadence.
|
|
673
702
|
|
|
674
703
|
5.2 Multi-Value Info Options
|
|
675
704
|
|
rda_python_dscheck/pg_check.py
CHANGED
|
@@ -62,6 +62,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
62
62
|
'MT': [1, 'MaxrunTime', 0],
|
|
63
63
|
'OF': [1, 'OutputFile', 0],
|
|
64
64
|
'ON': [1, 'OrderNames', 0],
|
|
65
|
+
'SH': [1, 'SSHHostname', 0],
|
|
65
66
|
'AO': [1, 'ActOption', 1], # default to <!>
|
|
66
67
|
'WI': [1, 'WaitInterval', 1],
|
|
67
68
|
'AN': [2, 'ActionName', 0],
|
|
@@ -189,7 +190,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
189
190
|
"Miss check index per Info option -CI(-CheckIndex)",
|
|
190
191
|
"Need Machine Hostname per -HN for new daemon control",
|
|
191
192
|
"Need Application command name per -CM for new daemon control",
|
|
192
|
-
"Must be {} to process Checks in daemon mode".format(self.PGLOG['
|
|
193
|
+
"Must be {} to process Checks in daemon mode".format(self.PGLOG['COMMONUSER']),
|
|
193
194
|
"Miss Command information per Info option -CM(-Command)",
|
|
194
195
|
]
|
|
195
196
|
erridx = -1
|
|
@@ -199,7 +200,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
199
200
|
if 'DM' in self.params:
|
|
200
201
|
if cact != "PC":
|
|
201
202
|
erridx = 0
|
|
202
|
-
elif self.PGLOG['CURUID'] != self.PGLOG['
|
|
203
|
+
elif self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']:
|
|
203
204
|
erridx = 5
|
|
204
205
|
elif 'CI' in self.params:
|
|
205
206
|
erridx = 1
|
|
@@ -253,7 +254,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
253
254
|
wtime = self.params['WI'] if 'WI' in self.params else 30
|
|
254
255
|
logon = self.params['LO'] if 'LO' in self.params else 1
|
|
255
256
|
self.start_none_daemon(aname, cact, self.params['LN'], 1, wtime, logon)
|
|
256
|
-
if not ('CI' in self.params or 'DS' in self.params or self.params['LN'] == self.PGLOG['
|
|
257
|
+
if not ('CI' in self.params or 'DS' in self.params or self.params['LN'] == self.PGLOG['COMMONUSER']):
|
|
257
258
|
self.set_default_value("SN", self.params['LN'])
|
|
258
259
|
# minimal wait interval in seconds for next check
|
|
259
260
|
self.PGOPT['minlimit'] = self.params['WI'] = self.PGSIG['WTIME']
|
|
@@ -492,7 +493,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
492
493
|
return 0
|
|
493
494
|
lidx = self.get_process_host(limits, pgrec['hostname'], pgrec['command'], pgrec['action'], logact)
|
|
494
495
|
if lidx < 0 or self.skip_dscheck_record(pgrec, host, logact): return 0
|
|
495
|
-
cmd = "pgstart_{} ".format(specialist) if self.PGLOG['CURUID'] == self.PGLOG['
|
|
496
|
+
cmd = "pgstart_{} ".format(specialist) if self.PGLOG['CURUID'] == self.PGLOG['COMMONUSER'] else ""
|
|
496
497
|
if not self.pgcmp(host, self.PGLOG['PBSNAME'], 1):
|
|
497
498
|
if self.reach_dataset_limit(pgrec): return 0
|
|
498
499
|
cmd += self.get_specialist_shell(specialist) + 'qsub '
|
|
@@ -680,7 +681,8 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
680
681
|
if not pgrec or options != pgrec[optname]: return options
|
|
681
682
|
record = {}
|
|
682
683
|
errmsg = ''
|
|
683
|
-
|
|
684
|
+
sshhost = self.params.get('SH')
|
|
685
|
+
record[optname] = options = self.get_dynamic_options(options[1:], pgcheck['oindex'], pgcheck['otype'], sshhost)
|
|
684
686
|
if not options and self.PGLOG['SYSERR']:
|
|
685
687
|
record['status'] = pgcheck['status'] = 'E'
|
|
686
688
|
record['pid'] = 0
|
|
@@ -1272,7 +1274,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
1272
1274
|
if not pgrec:
|
|
1273
1275
|
self.action_error("Daemon Control Index '{}' is not in RDADB".format(val))
|
|
1274
1276
|
elif(self.OPTS[self.PGOPT['CACT']][2] > 0 and self.params['LN'] != pgrec['specialist'] and
|
|
1275
|
-
self.PGLOG['CURUID'] != self.PGLOG['
|
|
1277
|
+
self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']):
|
|
1276
1278
|
self.action_error("{}: must be {}, owner of Daemon Control Index {}".format(self.params['LN'], pgrec['specialist'], val))
|
|
1277
1279
|
else: # found none-equal condition sign
|
|
1278
1280
|
pgrec = self.pgmget("dsdaemon", "DISTINCT dindex",
|
|
@@ -1308,7 +1310,7 @@ class PgCheck(PgOPT, PgCMD):
|
|
|
1308
1310
|
if not pgrec:
|
|
1309
1311
|
self.action_error("Check Index '{}' is not in RDADB".format(val))
|
|
1310
1312
|
elif(self.OPTS[self.PGOPT['CACT']][2] > 0 and self.params['LN'] != pgrec['specialist'] and
|
|
1311
|
-
self.PGLOG['CURUID'] != self.PGLOG['
|
|
1313
|
+
self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']):
|
|
1312
1314
|
self.action_error("{}: must be {}, owner of Check Index {}".format(self.params['LN'], pgrec['specialist'], val))
|
|
1313
1315
|
else: # found none-equal condition sign
|
|
1314
1316
|
pgrec = self.pgmget("dscheck", "cindex", self.get_field_condition("cindex", self.params['CI'], 0, 1), self.PGOPT['extlog'])
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rda_python_dscheck
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: RDA python package to add and process batch jobs
|
|
5
|
+
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
|
+
Project-URL: Homepage, https://github.com/NCAR/rda-python-dscheck
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Requires-Python: >=3.7
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: rda_python_common
|
|
15
|
+
Requires-Dist: rda_python_setuid
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# dscheck
|
|
19
|
+
|
|
20
|
+
Python project to add and process batch jobs for the
|
|
21
|
+
[NSF NCAR Geoscience Data Exchange (GDEX)](https://gdex.ucar.edu).
|
|
22
|
+
|
|
23
|
+
The user guide for this utility tool can be viewed at:
|
|
24
|
+
[User guide](https://gdex-docs-dscheck.readthedocs.io).
|
|
25
|
+
|
|
26
|
+
## Source layout
|
|
27
|
+
|
|
28
|
+
The package lives under `src/rda_python_dscheck/`. The three files most
|
|
29
|
+
relevant to setup and customization are:
|
|
30
|
+
|
|
31
|
+
- **`dscheck.py`** — entry point installed as the `dscheck` console script.
|
|
32
|
+
Defines the `DsCheck` class which subclasses `PgCheck`, parses command-line
|
|
33
|
+
options via `self.parsing_input`, and dispatches to the appropriate action
|
|
34
|
+
handler (`add_check_info`, `process_check`, `get_check_info`,
|
|
35
|
+
`set_dscheck_options`, ...). Build new actions by adding a method here and
|
|
36
|
+
routing to it from `start_actions()`.
|
|
37
|
+
|
|
38
|
+
- **`pg_check.py`** — defines the `PgCheck` class (inherits from `PgCMD` in
|
|
39
|
+
`rda_python_common`). Holds the master `OPTS` option table, the `ALIAS`
|
|
40
|
+
map for long/alias names, the `TBLHASH` table field maps for `dscheck` and
|
|
41
|
+
`dsdaemon`, and the helper methods shared by every action (option
|
|
42
|
+
validation, dynamic batch-option resolution, daemon control,
|
|
43
|
+
host/specialist resolution, etc.). Add or change options here, then
|
|
44
|
+
document them in `dscheck.usg`.
|
|
45
|
+
|
|
46
|
+
- **`dscheck.usg`** — single source of truth for the user-facing documentation
|
|
47
|
+
displayed by `dscheck -?` and rendered as the
|
|
48
|
+
[user guide](https://gdex-docs-dscheck.readthedocs.io). Section 3 lists
|
|
49
|
+
Action options, Section 4 lists Mode options, and Section 5 lists Single-
|
|
50
|
+
and Multi-Value Info options. When you add a new option to `OPTS` in
|
|
51
|
+
`pg_check.py`, add a matching entry to the appropriate subsection of this
|
|
52
|
+
file and (if relevant) to the per-action usage block in Section 3.
|
|
53
|
+
|
|
54
|
+
## Environment setup
|
|
55
|
+
|
|
56
|
+
Create a Python environment first; package installs in the next section run
|
|
57
|
+
inside whichever environment you activate here.
|
|
58
|
+
|
|
59
|
+
### Option A — Python venv (DECS machines)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
python3 -m venv $ENVHOME # e.g. /glade/u/home/gdexdata/gdexmsenv
|
|
63
|
+
source $ENVHOME/bin/activate
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Option B — Conda (DAV/Casper)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
conda create --prefix $ENVHOME python=3.12 # e.g. /glade/work/gdexdata/conda-envs/pg-gdex
|
|
70
|
+
conda activate $ENVHOME
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Dependencies
|
|
74
|
+
|
|
75
|
+
In addition to `rda_python_common`, this package depends on
|
|
76
|
+
`rda_python_setuid`. When `dscheck` runs as the common user, the
|
|
77
|
+
`start_one_dscheck()` method in `pg_check.py` submits each PBS batch job via a
|
|
78
|
+
`pgstart_<specialist>` wrapper, and those per-specialist `pgstart_*` wrappers
|
|
79
|
+
are provisioned by `rda_python_setuid`. Both dependencies are declared in
|
|
80
|
+
`pyproject.toml` and are pulled in automatically on install.
|
|
81
|
+
|
|
82
|
+
## Installing rda-python-dscheck
|
|
83
|
+
|
|
84
|
+
Pick whichever install mode fits your workflow. All variants pull in the
|
|
85
|
+
transitive dependencies (`rda_python_common` and `rda_python_setuid`)
|
|
86
|
+
automatically.
|
|
87
|
+
|
|
88
|
+
For local development, clone this repo alongside your project and install it
|
|
89
|
+
in editable mode so that changes are picked up without re-installing:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone https://github.com/NCAR/rda-python-dscheck.git
|
|
93
|
+
cd rda-python-dscheck
|
|
94
|
+
pip install -e .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
To test a specific branch (e.g. an in-progress feature or fix branch), pass
|
|
98
|
+
`-b/--branch` to `git clone`:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git clone -b <branch-name> https://github.com/NCAR/rda-python-dscheck.git
|
|
102
|
+
cd rda-python-dscheck
|
|
103
|
+
pip install -e .
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For a regular (non-editable) install from a checkout:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install /path/to/rda-python-dscheck
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
For a production install on a system that uses the published distribution:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pip install rda_python_dscheck
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
To upgrade an existing install to the latest published release:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pip install --upgrade rda_python_dscheck
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Setuid Setup
|
|
125
|
+
|
|
126
|
+
Unlike `dsarch`, `dscheck` is **not** wired as a `setuid_dscheck` link. It
|
|
127
|
+
relies instead on the `pgstart_*` setuid binaries provided by
|
|
128
|
+
`rda_python_setuid` (pulled in automatically as a dependency):
|
|
129
|
+
|
|
130
|
+
- In cron, `dscheck` itself is run as the common user `PGLOG['COMMONUSER']`
|
|
131
|
+
(default `gdexdata`) via `pgstart_<COMMONUSER> dscheck` (e.g.
|
|
132
|
+
`pgstart_gdexdata dscheck`).
|
|
133
|
+
- While running as the common user, `start_one_dscheck()` in `pg_check.py`
|
|
134
|
+
submits each PBS batch job as the owning specialist via
|
|
135
|
+
`pgstart_<specialist> ... qsub ...`, so each job runs under that specialist's
|
|
136
|
+
identity.
|
|
137
|
+
|
|
138
|
+
This means setup is about installing the `pgstart_*` binaries, not creating a
|
|
139
|
+
`dscheck -> pywrapper` symlink.
|
|
140
|
+
|
|
141
|
+
> **Note:** The setuid actions in this section are optional. If
|
|
142
|
+
> `rda_python_setuid` is already installed and fully set up in your
|
|
143
|
+
> environment, you can skip this section.
|
|
144
|
+
|
|
145
|
+
### Install the pgstart binaries (requires sudo access to each user)
|
|
146
|
+
|
|
147
|
+
Run these steps once per environment:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# 1. Compile the pywrapper C binary (once per environment):
|
|
151
|
+
pywrapper-install -c|--compile -n|--username gdexdata
|
|
152
|
+
|
|
153
|
+
# 2. Install pgstart_<COMMONUSER> so cron can run 'pgstart_gdexdata dscheck':
|
|
154
|
+
pywrapper-install -p|--pgstart -n|--username gdexdata
|
|
155
|
+
|
|
156
|
+
# 3. Install a pgstart_<specialist> binary for each specialist whose jobs
|
|
157
|
+
# dscheck submits. Run either by PGLOG['ADMINUSER'] (default zji, if it
|
|
158
|
+
# has 'sudo -u <specialist>'), or by <specialist> directly:
|
|
159
|
+
pywrapper-install -p|--pgstart -n|--username <specialist>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`pywrapper-install` with no arguments displays the full user guide.
|
|
163
|
+
|
|
164
|
+
### Update an existing installation (no sudo required)
|
|
165
|
+
|
|
166
|
+
When the package is upgraded and a new `pywrapper.c` is bundled, recompile and
|
|
167
|
+
reinstall all `pgstart_*` binaries using the existing ones:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
pywrapper-install -u|--update
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Documentation sync
|
|
174
|
+
|
|
175
|
+
The user guide rendered at
|
|
176
|
+
[gdex-docs-dscheck.readthedocs.io](https://gdex-docs-dscheck.readthedocs.io) is
|
|
177
|
+
generated from `src/rda_python_dscheck/dscheck.usg` in this repository. When a
|
|
178
|
+
pull request that modifies `dscheck.usg` is merged here, an automated workflow
|
|
179
|
+
converts the updated `dscheck.usg` into the RST-format source files in the
|
|
180
|
+
[gdex-docs-dscheck](https://github.com/NCAR/gdex-docs-dscheck) repository and
|
|
181
|
+
opens a pull request there with the regenerated docs, ready for review and
|
|
182
|
+
merge. No manual RST editing is required — keep all user-facing content in
|
|
183
|
+
`dscheck.usg` and let the sync produce the docs.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
rda_python_dscheck/PgCheck.py,sha256=c936Q7UwatjxjtVDXYrprs61gZW6-LncXMoKWSXf4RY,64229
|
|
2
|
+
rda_python_dscheck/__init__.py,sha256=4Wtgj9ephcxz20cPTI4SZ_XCuCM0oqtfq9wL8kcVr3Y,734
|
|
3
|
+
rda_python_dscheck/ds_check.py,sha256=9Zjoz12STauUmtucjLJHBzRoCZzqfLrsZk0FKYxTwcM,24315
|
|
4
|
+
rda_python_dscheck/dscheck.py,sha256=XxVtSQZLmfWCjeVPRQK7PCYCOPBdWOVu6InxfYGJadE,24817
|
|
5
|
+
rda_python_dscheck/dscheck.usg,sha256=IpbGbcCdhpNUgrMEKzRSWqX3n_vO6G8SUre3wYl4cQ4,34076
|
|
6
|
+
rda_python_dscheck/pg_check.py,sha256=ecxl1tt0KN72gxDa5mseV_sOiQ_jcclxdtSDF1X-QzE,67488
|
|
7
|
+
rda_python_dscheck-3.0.0.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
|
|
8
|
+
rda_python_dscheck-3.0.0.dist-info/METADATA,sha256=itqH1vqBCI8YSnn0RbiUSYGAutFDqV14-D3OydzprvU,6798
|
|
9
|
+
rda_python_dscheck-3.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
10
|
+
rda_python_dscheck-3.0.0.dist-info/entry_points.txt,sha256=frVByX3Vp_Pd_zq93SXfItr5OMTd5tKeZzu5pbVXiGA,60
|
|
11
|
+
rda_python_dscheck-3.0.0.dist-info/top_level.txt,sha256=NrvWqcHMRlQZJb0w85JrDlSXTp9DF-pDRQaAEABzFts,19
|
|
12
|
+
rda_python_dscheck-3.0.0.dist-info/RECORD,,
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: rda_python_dscheck
|
|
3
|
-
Version: 2.0.7
|
|
4
|
-
Summary: RDA python package to add and process batch jobs
|
|
5
|
-
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
|
-
Project-URL: Homepage, https://github.com/NCAR/rda-python-dscheck
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
-
Classifier: Operating System :: OS Independent
|
|
10
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
-
Requires-Python: >=3.7
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: rda_python_common
|
|
15
|
-
Dynamic: license-file
|
|
16
|
-
|
|
17
|
-
# dscheck
|
|
18
|
-
|
|
19
|
-
Python project to add and process batch jobs for the [NSF NCAR Geoscience Data Exchange (GDEX)](https://gdex.ucar.edu).
|
|
20
|
-
|
|
21
|
-
The user guide for this utility tool can be viewed at: [User guide](https://gdex-docs-dscheck.readthedocs.io).
|
|
22
|
-
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
rda_python_dscheck/PgCheck.py,sha256=lvh0XSWJID9J9fjqmDtpq6xW2ULC-bChAxAkm8MFzbk,64217
|
|
2
|
-
rda_python_dscheck/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
|
-
rda_python_dscheck/ds_check.py,sha256=-js5Ex1k7V8ziE_k-ld5Z0l44QGYhvQtdYri9vsqNJA,24303
|
|
4
|
-
rda_python_dscheck/dscheck.py,sha256=-vv7gw4xYIa1xofWo-o3972dDnR_FQZxZz6_S_kCCuk,24805
|
|
5
|
-
rda_python_dscheck/dscheck.usg,sha256=upCHGwRcjrLoue4Z9nE3pMDZ3s09Qq1ujEH2eJhb2cg,32036
|
|
6
|
-
rda_python_dscheck/pg_check.py,sha256=Riv1nJYocSKLDsOIIYmOmkKlWZLKDrA1uPpbUEYo1uo,67388
|
|
7
|
-
rda_python_dscheck-2.0.7.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
|
|
8
|
-
rda_python_dscheck-2.0.7.dist-info/METADATA,sha256=ezkK1sDQXrTcaTtHRlemEpeBOBQDmCOcHFLwuJainQk,812
|
|
9
|
-
rda_python_dscheck-2.0.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
10
|
-
rda_python_dscheck-2.0.7.dist-info/entry_points.txt,sha256=frVByX3Vp_Pd_zq93SXfItr5OMTd5tKeZzu5pbVXiGA,60
|
|
11
|
-
rda_python_dscheck-2.0.7.dist-info/top_level.txt,sha256=NrvWqcHMRlQZJb0w85JrDlSXTp9DF-pDRQaAEABzFts,19
|
|
12
|
-
rda_python_dscheck-2.0.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|