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.
@@ -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'])
@@ -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
+ ]
@@ -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
 
@@ -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
- -OPT - an option name. Names are case-insensitive; values are not.
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
- dscheck
110
+ dscheck
99
111
 
100
112
  Show the description of a single option:
101
- dscheck -h -AC
102
- dscheck -AC -h
113
+ dscheck -h -AC
103
114
 
104
115
  List your own daemon control records:
105
- dscheck -GD
116
+
117
+ dscheck -GD
106
118
 
107
119
  List your own active check records:
108
- dscheck -GC
120
+
121
+ dscheck -GC
109
122
 
110
123
  Add a deferred run of a script on PBS:
111
- dscheck -AC -CM myscript.sh -HN PBS
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
- Start the dscheck daemon (typical for the operator):
117
- dscheck -PC -DM start
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
- dscheck mycheck.in
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
- dscheck -AC -CM test3 -HN PBS
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 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.
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
- Non-daemon mode:
508
- Without -DM, dscheck processes the current set of check records once.
509
- -WU and -WR must be set explicitly if you want due 'dsupdt'/'dsrqst'
510
- work to be added before processing. -CI restricts processing to
511
- 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').
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
 
@@ -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['GDEXUSER']),
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['GDEXUSER']:
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['GDEXUSER']):
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['GDEXUSER'] else ""
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
- record[optname] = options = self.get_dynamic_options(options[1:], pgcheck['oindex'], pgcheck['otype'])
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['GDEXUSER']):
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['GDEXUSER']):
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,,