rda-python-dscheck 2.0.8__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.
@@ -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['GDEXUSER']),
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['GDEXUSER']:
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['GDEXUSER']):
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['GDEXUSER'] else ""
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['GDEXUSER']):
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['GDEXUSER']):
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'])
@@ -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['GDEXUSER']: record['specialist'] = PgOPT.params['LN']
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['GDEXUSER'] and (time.time()%(3*PgSIG.PGSIG['CTIME'])) < 60:
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['GDEXUSER']:
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['GDEXUSER'] and (time.time()%(3*PgSIG.PGSIG['CTIME'])) < 60:
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['GDEXUSER']:
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['GDEXUSER']:
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:
@@ -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['GDEXUSER']: record['specialist'] = self.params['LN']
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['GDEXUSER'] and (time.time()%(3*self.PGSIG['CTIME'])) < 60:
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['GDEXUSER']:
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['GDEXUSER'] and (time.time()%(3*self.PGSIG['CTIME'])) < 60:
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['GDEXUSER']:
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['GDEXUSER']:
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:
@@ -9,18 +9,30 @@ well as any specialist-defined command.
9
9
 
10
10
  The mental model has three layers:
11
11
 
12
- 1. A check record - a row in GDEXDB that captures one deferred command:
13
- its name, arguments, owner, working directory, target
14
- host, retry policy, and current status.
15
- 2. A daemon control - a row in GDEXDB that tells the centralized 'dscheck'
16
- daemon how many concurrent processes of a given
17
- command a given specialist may run on a given host,
18
- and at what host priority.
19
- 3. The dscheck daemon - a long-running process that wakes on a fixed
20
- interval, adds due 'dsupdt'/'dsrqst' check records,
21
- and starts (or restarts) commands from check
22
- records on hosts chosen according to daemon
23
- control configuration.
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
 
@@ -101,20 +113,29 @@ are accepted, and aliases are noted with each option.
101
113
  dscheck -h -AC
102
114
 
103
115
  List your own daemon control records:
116
+
104
117
  dscheck -GD
105
118
 
106
119
  List your own active check records:
120
+
107
121
  dscheck -GC
108
122
 
109
123
  Add a deferred run of a script on PBS:
124
+
110
125
  dscheck -AC -CM myscript.sh -HN PBS
111
126
 
112
127
  Email yourself the status of all your active checks:
128
+
113
129
  dscheck -EC
114
130
 
115
- Start the dscheck daemon (typical for the operator):
131
+ Start the dscheck driver as a long-running daemon (typical for the operator):
132
+
116
133
  dscheck -PC -DM start
117
134
 
135
+ Or run the dscheck driver from crontab every minute (lightweight alternative):
136
+
137
+ * * * * * dscheck -PC
138
+
118
139
  2.2 Filters and Special Characters in Queries
119
140
 
120
141
  For Get-style actions (-GD, -GC), Info options are interpreted as query
@@ -439,7 +460,13 @@ Unlock Check - clear leftover lock information after an abnormal exit.
439
460
 
440
461
  3.3 Check Process Actions
441
462
 
442
- The dscheck daemon starts and restarts deferred commands automatically.
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.
443
470
  Operators (and, in non-daemon mode, specialists) can also drive command
444
471
  execution from the command line, interrupt running commands, and email
445
472
  status summaries.
@@ -482,11 +509,28 @@ Available actions:
482
509
  -DM stop, -DM logon, and -DM logoff stop the daemon, enable detailed
483
510
  logging, and disable detailed logging respectively.
484
511
 
485
- Non-daemon mode:
486
- Without -DM, dscheck processes the current set of check records once.
487
- -WU and -WR must be set explicitly if you want due 'dsupdt'/'dsrqst'
488
- work to be added before processing. -CI restricts processing to
489
- specific check indices.
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').
490
534
 
491
535
  3.3.2 Interrupt Check
492
536
  -IC or -InterruptCheck, stops a running command and recursively kills
@@ -653,7 +697,8 @@ multiple values is an error.
653
697
  input files. Defaults to '<!>'.
654
698
 
655
699
  -WI or -WaitInterval, the time the dscheck daemon sleeps between
656
- 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.
657
702
 
658
703
  5.2 Multi-Value Info Options
659
704
 
@@ -190,7 +190,7 @@ class PgCheck(PgOPT, PgCMD):
190
190
  "Miss check index per Info option -CI(-CheckIndex)",
191
191
  "Need Machine Hostname per -HN for new daemon control",
192
192
  "Need Application command name per -CM for new daemon control",
193
- "Must be {} to process Checks in daemon mode".format(self.PGLOG['GDEXUSER']),
193
+ "Must be {} to process Checks in daemon mode".format(self.PGLOG['COMMONUSER']),
194
194
  "Miss Command information per Info option -CM(-Command)",
195
195
  ]
196
196
  erridx = -1
@@ -200,7 +200,7 @@ class PgCheck(PgOPT, PgCMD):
200
200
  if 'DM' in self.params:
201
201
  if cact != "PC":
202
202
  erridx = 0
203
- elif self.PGLOG['CURUID'] != self.PGLOG['GDEXUSER']:
203
+ elif self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']:
204
204
  erridx = 5
205
205
  elif 'CI' in self.params:
206
206
  erridx = 1
@@ -254,7 +254,7 @@ class PgCheck(PgOPT, PgCMD):
254
254
  wtime = self.params['WI'] if 'WI' in self.params else 30
255
255
  logon = self.params['LO'] if 'LO' in self.params else 1
256
256
  self.start_none_daemon(aname, cact, self.params['LN'], 1, wtime, logon)
257
- if not ('CI' in self.params or 'DS' in self.params or self.params['LN'] == self.PGLOG['GDEXUSER']):
257
+ if not ('CI' in self.params or 'DS' in self.params or self.params['LN'] == self.PGLOG['COMMONUSER']):
258
258
  self.set_default_value("SN", self.params['LN'])
259
259
  # minimal wait interval in seconds for next check
260
260
  self.PGOPT['minlimit'] = self.params['WI'] = self.PGSIG['WTIME']
@@ -493,7 +493,7 @@ class PgCheck(PgOPT, PgCMD):
493
493
  return 0
494
494
  lidx = self.get_process_host(limits, pgrec['hostname'], pgrec['command'], pgrec['action'], logact)
495
495
  if lidx < 0 or self.skip_dscheck_record(pgrec, host, logact): return 0
496
- cmd = "pgstart_{} ".format(specialist) if self.PGLOG['CURUID'] == self.PGLOG['GDEXUSER'] else ""
496
+ cmd = "pgstart_{} ".format(specialist) if self.PGLOG['CURUID'] == self.PGLOG['COMMONUSER'] else ""
497
497
  if not self.pgcmp(host, self.PGLOG['PBSNAME'], 1):
498
498
  if self.reach_dataset_limit(pgrec): return 0
499
499
  cmd += self.get_specialist_shell(specialist) + 'qsub '
@@ -1274,7 +1274,7 @@ class PgCheck(PgOPT, PgCMD):
1274
1274
  if not pgrec:
1275
1275
  self.action_error("Daemon Control Index '{}' is not in RDADB".format(val))
1276
1276
  elif(self.OPTS[self.PGOPT['CACT']][2] > 0 and self.params['LN'] != pgrec['specialist'] and
1277
- self.PGLOG['CURUID'] != self.PGLOG['GDEXUSER']):
1277
+ self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']):
1278
1278
  self.action_error("{}: must be {}, owner of Daemon Control Index {}".format(self.params['LN'], pgrec['specialist'], val))
1279
1279
  else: # found none-equal condition sign
1280
1280
  pgrec = self.pgmget("dsdaemon", "DISTINCT dindex",
@@ -1310,7 +1310,7 @@ class PgCheck(PgOPT, PgCMD):
1310
1310
  if not pgrec:
1311
1311
  self.action_error("Check Index '{}' is not in RDADB".format(val))
1312
1312
  elif(self.OPTS[self.PGOPT['CACT']][2] > 0 and self.params['LN'] != pgrec['specialist'] and
1313
- self.PGLOG['CURUID'] != self.PGLOG['GDEXUSER']):
1313
+ self.PGLOG['CURUID'] != self.PGLOG['COMMONUSER']):
1314
1314
  self.action_error("{}: must be {}, owner of Check Index {}".format(self.params['LN'], pgrec['specialist'], val))
1315
1315
  else: # found none-equal condition sign
1316
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,93 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: rda_python_dscheck
3
- Version: 2.0.8
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
-
23
- ## Source layout
24
-
25
- The package lives under `src/rda_python_dscheck/`. The three files most
26
- relevant to setup and customization are:
27
-
28
- - **`dscheck.py`** — entry point installed as the `setuid_dscheck`
29
- console script. Defines the `DsCheck` class which subclasses
30
- `PgCheck`, parses command-line options via `self.parsing_input`, and
31
- dispatches to the appropriate action handler (`add_check_info`,
32
- `process_check`, `get_check_info`, `set_dscheck_options`, ...).
33
- Build new actions by adding a method here and routing to it from
34
- `start_actions()`.
35
-
36
- - **`pg_check.py`** — defines the `PgCheck` class (inherits from
37
- `PgCMD` in `rda_python_common`). Holds the master `OPTS` option
38
- table, the `ALIAS` map for long/alias names, the `TBLHASH` table
39
- field maps for `dscheck` and `dsdaemon`, and the helper methods
40
- shared by every action (option validation, dynamic batch-option
41
- resolution, daemon control, host/specialist resolution, etc.).
42
- Add or change options here, then document them in `dscheck.usg`.
43
-
44
- - **`dscheck.usg`** — single source of truth for the user-facing
45
- documentation displayed by `dscheck -?` and rendered as the
46
- [user guide](https://gdex-docs-dscheck.readthedocs.io). Section 3
47
- lists Action options, Section 4 lists Mode options, and Section 5
48
- lists Single- and Multi-Value Info options. When you add a new
49
- option to `OPTS` in `pg_check.py`, add a matching entry to the
50
- appropriate subsection of this file and (if relevant) to the
51
- per-action usage block in Section 3.
52
-
53
- ### Installing from PyPI
54
-
55
- The package is published on [PyPI](https://pypi.org/project/rda_python_dscheck/),
56
- so the regular install command is:
57
-
58
- ```bash
59
- pip install rda_python_dscheck
60
- ```
61
-
62
- To upgrade an existing install to the latest published release:
63
-
64
- ```bash
65
- pip install --upgrade rda_python_dscheck
66
- ```
67
-
68
- This pulls in `rda_python_common` (which provides `PgCMD`, `PgLOG`,
69
- `PgDBI`, ...) and registers the `setuid_dscheck` console script.
70
-
71
- ### Installing for development
72
-
73
- For local changes, clone the repo and install in editable mode so that
74
- edits are picked up immediately without reinstalling:
75
-
76
- ```bash
77
- git clone https://github.com/NCAR/rda-python-dscheck.git
78
- cd rda-python-dscheck
79
- pip install -e .
80
- ```
81
-
82
- ## Documentation sync
83
-
84
- The user guide rendered at
85
- [gdex-docs-dscheck.readthedocs.io](https://gdex-docs-dscheck.readthedocs.io) is
86
- generated from `src/rda_python_dscheck/dscheck.usg` in this repository. When a
87
- pull request that modifies `dscheck.usg` is merged here, an automated workflow
88
- converts the updated `dscheck.usg` into the RST-format source files in the
89
- [gdex-docs-dscheck](https://github.com/NCAR/gdex-docs-dscheck) repository and
90
- opens a pull request there with the regenerated docs, ready for review and
91
- merge. No manual RST editing is required — keep all user-facing content in
92
- `dscheck.usg` and let the sync produce the docs.
93
-
@@ -1,12 +0,0 @@
1
- rda_python_dscheck/PgCheck.py,sha256=lvh0XSWJID9J9fjqmDtpq6xW2ULC-bChAxAkm8MFzbk,64217
2
- rda_python_dscheck/__init__.py,sha256=4Wtgj9ephcxz20cPTI4SZ_XCuCM0oqtfq9wL8kcVr3Y,734
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=zvghJK0XKXlSNopI1G8PYorRVUkpXoZLmFWQGqGAmBQ,31662
6
- rda_python_dscheck/pg_check.py,sha256=ftmXSGXWeusQPV9FA6-3_fzhbfDCGfDIgjAK5yxi2jA,67476
7
- rda_python_dscheck-2.0.8.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
8
- rda_python_dscheck-2.0.8.dist-info/METADATA,sha256=WDn3PoFKAR6BkmOE16Rfhz9Hbt2kw4mAwm_GyZTZfpE,3689
9
- rda_python_dscheck-2.0.8.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
10
- rda_python_dscheck-2.0.8.dist-info/entry_points.txt,sha256=frVByX3Vp_Pd_zq93SXfItr5OMTd5tKeZzu5pbVXiGA,60
11
- rda_python_dscheck-2.0.8.dist-info/top_level.txt,sha256=NrvWqcHMRlQZJb0w85JrDlSXTp9DF-pDRQaAEABzFts,19
12
- rda_python_dscheck-2.0.8.dist-info/RECORD,,