rda-python-common 3.0.14__tar.gz → 3.0.15__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rda_python_common-3.0.14/src/rda_python_common.egg-info → rda_python_common-3.0.15}/PKG-INFO +2 -2
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/README.md +1 -1
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/pyproject.toml +1 -1
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/__init__.py +1 -1
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_dbi.py +111 -23
- {rda_python_common-3.0.14 → rda_python_common-3.0.15/src/rda_python_common.egg-info}/PKG-INFO +2 -2
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/LICENSE +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/setup.cfg +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgCMD.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgDBI.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgFile.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgLOG.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgLock.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgOPT.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgSIG.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgSplit.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/PgUtil.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_cmd.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_file.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_lock.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_log.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_opt.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_password.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_sig.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_split.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pg_util.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pgpassword.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common/pgpassword.usg +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/SOURCES.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/dependency_links.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/entry_points.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/requires.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/top_level.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.15}/test/test_common.py +0 -0
{rda_python_common-3.0.14/src/rda_python_common.egg-info → rda_python_common-3.0.15}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_common
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.15
|
|
4
4
|
Summary: RDA Python common library codes shared by other RDA python packages
|
|
5
5
|
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
6
|
Project-URL: Homepage, https://github.com/NCAR/rda-python-common
|
|
@@ -189,7 +189,7 @@ PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
|
189
189
|
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
You should see the installed version (currently `3.0.
|
|
192
|
+
You should see the installed version (currently `3.0.15`). If the import
|
|
193
193
|
fails, double-check that the active Python environment is the one where you
|
|
194
194
|
ran `pip install`.
|
|
195
195
|
|
|
@@ -165,7 +165,7 @@ PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
|
165
165
|
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
You should see the installed version (currently `3.0.
|
|
168
|
+
You should see the installed version (currently `3.0.15`). If the import
|
|
169
169
|
fails, double-check that the active Python environment is the one where you
|
|
170
170
|
ran `pip install`.
|
|
171
171
|
|
|
@@ -76,7 +76,7 @@ class PgDBI(PgLOG):
|
|
|
76
76
|
using psycopg (v3) when available, falling back to psycopg2. Supports single
|
|
77
77
|
and batch INSERT, SELECT, UPDATE, and DELETE operations, transaction
|
|
78
78
|
management, schema introspection, user lookups, usage tracking, and
|
|
79
|
-
credential retrieval from .pgpass or OpenBao.
|
|
79
|
+
credential retrieval from the environment, .pgpass or OpenBao.
|
|
80
80
|
|
|
81
81
|
Inherits all logging and utility helpers from PgLOG.
|
|
82
82
|
|
|
@@ -96,7 +96,10 @@ class PgDBI(PgLOG):
|
|
|
96
96
|
set from psycopg/psycopg2 depending on which driver is in use.
|
|
97
97
|
DBPORTS (dict): Mapping of database names to non-default TCP port numbers.
|
|
98
98
|
DBPASS (dict): Credentials loaded from .pgpass, keyed by (host, port, db, user).
|
|
99
|
-
DBBAOS (dict): Credentials loaded from OpenBao, keyed by
|
|
99
|
+
DBBAOS (dict): Credentials loaded from OpenBao, keyed by db server node.
|
|
100
|
+
DBNODES (dict): Mapping of database names to their db server nodes, used when the
|
|
101
|
+
node cannot be taken from the host being connected to.
|
|
102
|
+
DBSKEYS (dict): Mapping of login names to secret key names ('<lnname>pass' by default).
|
|
100
103
|
DBNAMES (dict): Mapping of schema names to their parent database names.
|
|
101
104
|
DBSOCKS (dict): Mapping of database names to Unix socket paths.
|
|
102
105
|
VIEWHOMES (dict): Mapping of hostnames to home directories for the view host.
|
|
@@ -139,6 +142,19 @@ class PgDBI(PgLOG):
|
|
|
139
142
|
self.DBPORTS = {'default': 0}
|
|
140
143
|
self.DBPASS = {}
|
|
141
144
|
self.DBBAOS = {}
|
|
145
|
+
# hard coded db server nodes for dbnames, for hosts not named for their nodes; a node
|
|
146
|
+
# names the OpenBao path (kv/gdex/<node>) and the password environment variable
|
|
147
|
+
# (<NODE>_<KEY>) the same secrets are passed in through
|
|
148
|
+
self.DBNODES = {
|
|
149
|
+
'ivaddb': 'pgdb03',
|
|
150
|
+
'ispddb': 'pgdb03',
|
|
151
|
+
'default': 'pgdb01',
|
|
152
|
+
}
|
|
153
|
+
# hard coded secret key names for db login names, defaulting to <lnname>pass
|
|
154
|
+
self.DBSKEYS = {
|
|
155
|
+
'postgres': 'password',
|
|
156
|
+
'metadata': 'metapass',
|
|
157
|
+
}
|
|
142
158
|
# hard coded db names for given schema names
|
|
143
159
|
self.DBNAMES = {
|
|
144
160
|
'ivaddb': 'ivaddb',
|
|
@@ -2617,19 +2633,91 @@ class PgDBI(PgLOG):
|
|
|
2617
2633
|
def get_pgpass_password(self):
|
|
2618
2634
|
"""Return the database password for the current connection settings.
|
|
2619
2635
|
|
|
2620
|
-
Checks PGDBI['PWNAME'] first, then
|
|
2621
|
-
|
|
2636
|
+
Checks PGDBI['PWNAME'] first, then the environment (get_envpassword(), as set
|
|
2637
|
+
for containers on CIRRUS), then the .pgpass file (get_pgpassword()), and
|
|
2638
|
+
finally falls back to OpenBao (get_baopassword()). A password found on local
|
|
2639
|
+
or batch hosts is cached in the environment (set_envpassword()) so that the
|
|
2640
|
+
child processes inherit it instead of looking it up again.
|
|
2622
2641
|
|
|
2623
2642
|
Returns:
|
|
2624
2643
|
str | None: Password string, or None when no credential is found.
|
|
2625
2644
|
"""
|
|
2626
2645
|
if self.PGDBI['PWNAME']: return self.PGDBI['PWNAME']
|
|
2646
|
+
pwname = self.get_envpassword()
|
|
2647
|
+
if pwname: return pwname
|
|
2627
2648
|
pwname = self.get_pgpassword()
|
|
2628
2649
|
if not pwname: pwname = self.get_baopassword()
|
|
2629
|
-
if
|
|
2630
|
-
self.
|
|
2650
|
+
if pwname:
|
|
2651
|
+
self.set_envpassword(pwname)
|
|
2652
|
+
else:
|
|
2653
|
+
self.pglog("Unable to find password for {} in environment, .pgpass or OpenBao".format(self.PGDBI['DBNAME']), self.PGDBI['ERRLOG'])
|
|
2631
2654
|
return pwname
|
|
2632
2655
|
|
|
2656
|
+
def get_dbnodes(self):
|
|
2657
|
+
"""Return the db server nodes holding the secrets of the current connection.
|
|
2658
|
+
|
|
2659
|
+
The node named by DBSHOST comes first, such as pgdb02 for the view-only host,
|
|
2660
|
+
so that a node with its own passwords is served its own secrets. The DBNODES
|
|
2661
|
+
node of the current DBNAME follows it as a fallback, such as pgdb01 for pgdb02,
|
|
2662
|
+
for a node that shares the passwords of the default one without holding secrets
|
|
2663
|
+
of its own.
|
|
2664
|
+
|
|
2665
|
+
Returns:
|
|
2666
|
+
list: Node names, such as ['pgdb02', 'pgdb01'], the first one preferred.
|
|
2667
|
+
"""
|
|
2668
|
+
dbnodes = []
|
|
2669
|
+
ms = re.match(r'^(pgdb\d+)$', self.PGDBI['DBSHOST']) if self.PGDBI['DBSHOST'] else None
|
|
2670
|
+
if ms: dbnodes.append(ms.group(1))
|
|
2671
|
+
dbnode = self.DBNODES.get(self.PGDBI['DBNAME'], self.DBNODES['default'])
|
|
2672
|
+
if dbnode not in dbnodes: dbnodes.append(dbnode)
|
|
2673
|
+
|
|
2674
|
+
return dbnodes
|
|
2675
|
+
|
|
2676
|
+
def get_secret_name(self, dbnode):
|
|
2677
|
+
"""Build the name of the secret holding the password of the current connection.
|
|
2678
|
+
|
|
2679
|
+
The key comes from DBSKEYS for the current LNNAME, defaulting to '<lnname>pass'.
|
|
2680
|
+
The pair names the secret in OpenBao (kv/gdex/<node> key <key>) and the
|
|
2681
|
+
environment variable (<NODE>_<KEY>) the same secret is passed in through
|
|
2682
|
+
on CIRRUS.
|
|
2683
|
+
|
|
2684
|
+
Args:
|
|
2685
|
+
dbnode (str): Db server node holding the secret, such as 'pgdb01'.
|
|
2686
|
+
|
|
2687
|
+
Returns:
|
|
2688
|
+
tuple: (node, key) naming the db server node and the secret key.
|
|
2689
|
+
"""
|
|
2690
|
+
lnname = self.PGDBI['LNNAME']
|
|
2691
|
+
|
|
2692
|
+
return (dbnode, self.DBSKEYS.get(lnname, lnname + 'pass'))
|
|
2693
|
+
|
|
2694
|
+
def get_envpassword(self):
|
|
2695
|
+
"""Look up the password in the environment, as set for containers on CIRRUS.
|
|
2696
|
+
|
|
2697
|
+
The variable name is the uppercased '<node>_<key>' secret name, for example
|
|
2698
|
+
PGDB01_DSSDBPASS for login name dssdb and PGDB03_IVADDBPASS for ivaddb. The
|
|
2699
|
+
fallback nodes of get_dbnodes() are tried in turn.
|
|
2700
|
+
|
|
2701
|
+
Returns:
|
|
2702
|
+
str | None: Password string, or None when no variable is set.
|
|
2703
|
+
"""
|
|
2704
|
+
for dbnode in self.get_dbnodes():
|
|
2705
|
+
pwname = os.environ.get("{}_{}".format(*self.get_secret_name(dbnode)).upper())
|
|
2706
|
+
if pwname: return pwname
|
|
2707
|
+
|
|
2708
|
+
return None
|
|
2709
|
+
|
|
2710
|
+
def set_envpassword(self, pwname):
|
|
2711
|
+
"""Cache a password in the environment under the name get_envpassword() reads.
|
|
2712
|
+
|
|
2713
|
+
Called for a password found in .pgpass or OpenBao, on local and PBS batch hosts,
|
|
2714
|
+
so that the child processes of the current one inherit it and skip the lookup.
|
|
2715
|
+
|
|
2716
|
+
Args:
|
|
2717
|
+
pwname (str): Password to pass on to the child processes.
|
|
2718
|
+
"""
|
|
2719
|
+
os.environ["{}_{}".format(*self.get_secret_name(self.get_dbnodes()[0])).upper()] = pwname
|
|
2720
|
+
|
|
2633
2721
|
def get_pgpassword(self):
|
|
2634
2722
|
"""Look up the password in the cached .pgpass credentials.
|
|
2635
2723
|
|
|
@@ -2646,16 +2734,20 @@ class PgDBI(PgLOG):
|
|
|
2646
2734
|
return pwname
|
|
2647
2735
|
|
|
2648
2736
|
def get_baopassword(self):
|
|
2649
|
-
"""Look up the password from OpenBao for the current
|
|
2737
|
+
"""Look up the password from OpenBao for the current db server node and login name.
|
|
2650
2738
|
|
|
2651
|
-
Loads OpenBao secrets
|
|
2739
|
+
Loads the OpenBao secrets of a node on first call (or when not cached), trying
|
|
2740
|
+
the fallback nodes of get_dbnodes() in turn.
|
|
2652
2741
|
|
|
2653
2742
|
Returns:
|
|
2654
2743
|
str | None: Password string, or None when not found in OpenBao.
|
|
2655
2744
|
"""
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2745
|
+
for dbnode in self.get_dbnodes():
|
|
2746
|
+
if dbnode not in self.DBBAOS: self.read_openbao(dbnode)
|
|
2747
|
+
pwname = self.DBBAOS[dbnode].get(self.PGDBI['LNNAME'])
|
|
2748
|
+
if pwname: return pwname
|
|
2749
|
+
|
|
2750
|
+
return None
|
|
2659
2751
|
|
|
2660
2752
|
def read_pgpass(self):
|
|
2661
2753
|
"""Read the .pgpass file and populate DBPASS with credentials.
|
|
@@ -2675,21 +2767,17 @@ class PgDBI(PgLOG):
|
|
|
2675
2767
|
except Exception:
|
|
2676
2768
|
pass
|
|
2677
2769
|
|
|
2678
|
-
def read_openbao(self):
|
|
2679
|
-
"""Read OpenBao secrets and populate DBBAOS with credentials
|
|
2770
|
+
def read_openbao(self, dbnode):
|
|
2771
|
+
"""Read OpenBao secrets and populate DBBAOS with the credentials of a db server node.
|
|
2680
2772
|
|
|
2681
2773
|
Uses the hvac client to fetch key-value secrets from the configured BAOURL.
|
|
2682
2774
|
Parses keys matching 'pass' patterns to extract database usernames and passwords.
|
|
2775
|
+
|
|
2776
|
+
Args:
|
|
2777
|
+
dbnode (str): Db server node naming the secret path, such as 'pgdb01'.
|
|
2683
2778
|
"""
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
url = 'https://bao.k8s.ucar.edu/'
|
|
2687
|
-
baopath = {
|
|
2688
|
-
'ivaddb': 'gdex/pgdb03',
|
|
2689
|
-
'ispddb': 'gdex/pgdb03',
|
|
2690
|
-
'default': 'gdex/pgdb01'
|
|
2691
|
-
}
|
|
2692
|
-
dbpath = baopath[dbname] if dbname in baopath else baopath['default']
|
|
2779
|
+
self.DBBAOS[dbnode] = {}
|
|
2780
|
+
dbpath = 'gdex/' + dbnode
|
|
2693
2781
|
client = hvac.Client(url=self.PGDBI.get('BAOURL'))
|
|
2694
2782
|
client.token = self.PGLOG.get('BAOTOKEN')
|
|
2695
2783
|
try:
|
|
@@ -2711,4 +2799,4 @@ class PgDBI(PgLOG):
|
|
|
2711
2799
|
baoname = 'metadata' if pre == 'meta' else pre
|
|
2712
2800
|
elif suf == 'word':
|
|
2713
2801
|
baoname = 'postgres'
|
|
2714
|
-
if baoname: self.DBBAOS[
|
|
2802
|
+
if baoname: self.DBBAOS[dbnode][baoname] = baos[key]
|
{rda_python_common-3.0.14 → rda_python_common-3.0.15/src/rda_python_common.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_common
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.15
|
|
4
4
|
Summary: RDA Python common library codes shared by other RDA python packages
|
|
5
5
|
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
6
|
Project-URL: Homepage, https://github.com/NCAR/rda-python-common
|
|
@@ -189,7 +189,7 @@ PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
|
189
189
|
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
You should see the installed version (currently `3.0.
|
|
192
|
+
You should see the installed version (currently `3.0.15`). If the import
|
|
193
193
|
fails, double-check that the active Python environment is the one where you
|
|
194
194
|
ran `pip install`.
|
|
195
195
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/requires.txt
RENAMED
|
File without changes
|
{rda_python_common-3.0.14 → rda_python_common-3.0.15}/src/rda_python_common.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|