umnetdb-utils 0.1.1__py3-none-any.whl → 0.1.3__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.
umnetdb_utils/base.py
CHANGED
@@ -45,7 +45,7 @@ class UMnetdbBase:
|
|
45
45
|
val = self._env.get(var, getenv(var))
|
46
46
|
|
47
47
|
if not val:
|
48
|
-
raise ValueError(f"Undefined environment variable {
|
48
|
+
raise ValueError(f"Undefined environment variable {var} in {url}")
|
49
49
|
url = re.sub(r"{" + var + "}", val, url)
|
50
50
|
|
51
51
|
return url
|
@@ -92,8 +92,9 @@ class UMnetdbBase:
|
|
92
92
|
ex: "node_ip nip"
|
93
93
|
:joins: a list of strings representing join statements. Include the actual 'join' part!
|
94
94
|
ex: ["join node n on nip.mac = n.mac", "join device d on d.ip = n.switch"]
|
95
|
-
:where:
|
96
|
-
|
95
|
+
:where: For a single where statement, provide a string. For multiple provide a list.
|
96
|
+
The list of statements are "anded". If you need "or", embed it in one of your list items
|
97
|
+
DO NOT provide the keyword 'where' - it is auto-added.
|
97
98
|
ex: ["node_ip.ip = '1.2.3.4'", "node.switch = '10.233.0.5'"]
|
98
99
|
:order_by: A string representing a column name (or names) to order by
|
99
100
|
:group_by: A string representing a column name (or names) to group by
|
@@ -115,9 +116,12 @@ class UMnetdbBase:
|
|
115
116
|
sql += f"{j}\n"
|
116
117
|
|
117
118
|
# Next are the filters. They are 'anded'
|
118
|
-
if where:
|
119
|
+
if where and isinstance(where, list):
|
120
|
+
|
119
121
|
sql += "where\n"
|
120
122
|
sql += " and\n".join(where) + "\n"
|
123
|
+
elif where:
|
124
|
+
sql += f"where {where}\n"
|
121
125
|
|
122
126
|
# Finally the other options
|
123
127
|
if order_by:
|
@@ -151,4 +155,19 @@ class UMnetdbBase:
|
|
151
155
|
elif rows:
|
152
156
|
return rows
|
153
157
|
else:
|
154
|
-
return []
|
158
|
+
return []
|
159
|
+
|
160
|
+
def execute(self, sql:str, rows_as_dict:bool=True, fetch_one:bool=False):
|
161
|
+
"""
|
162
|
+
Executes a sqlalchemy command and gives all the results. Does not open a session - you must
|
163
|
+
open one yourself
|
164
|
+
"""
|
165
|
+
result = self.session.execute(text(sql))
|
166
|
+
|
167
|
+
if rows_as_dict:
|
168
|
+
result = result.mappings()
|
169
|
+
|
170
|
+
if fetch_one:
|
171
|
+
return result.fetchone()
|
172
|
+
|
173
|
+
return result.fetchall()
|
umnetdb_utils/umnetdb.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
|
2
2
|
from typing import List
|
3
|
+
import logging
|
4
|
+
|
3
5
|
|
4
6
|
from sqlalchemy import text
|
5
7
|
from .base import UMnetdbBase
|
@@ -9,7 +11,7 @@ class UMnetdb(UMnetdbBase):
|
|
9
11
|
|
10
12
|
URL="postgresql+psycopg://{UMNETDB_USER}:{UMNETDB_PASSWORD}@wintermute.umnet.umich.edu/umnetdb"
|
11
13
|
|
12
|
-
def
|
14
|
+
def get_neighbors(
|
13
15
|
self, device: str, known_devices_only: bool = True
|
14
16
|
) -> List[dict]:
|
15
17
|
"""
|
@@ -33,6 +35,11 @@ class UMnetdb(UMnetdbBase):
|
|
33
35
|
"l.parent",
|
34
36
|
"n_l.parent as remote_parent"
|
35
37
|
]
|
38
|
+
joins = [
|
39
|
+
"join device n_d on n_d.hostname=n.remote_device",
|
40
|
+
"left outer join lag l on l.device=n.device and l.member=n.port",
|
41
|
+
"left outer join lag n_l on n_l.device=n_d.name and n_l.member=n.remote_port",
|
42
|
+
]
|
36
43
|
else:
|
37
44
|
select = [
|
38
45
|
"n.port",
|
@@ -41,18 +48,65 @@ class UMnetdb(UMnetdbBase):
|
|
41
48
|
"l.parent",
|
42
49
|
"n_l.parent as remote_parent"
|
43
50
|
]
|
44
|
-
|
51
|
+
joins = [
|
52
|
+
"left outer join device n_d on n_d.hostname=n.remote_device",
|
53
|
+
"left outer join lag l on l.device=n.device and l.member=n.port",
|
54
|
+
"left outer join lag n_l on n_l.device=n_d.name and n_l.member=n.remote_port",
|
55
|
+
]
|
56
|
+
|
45
57
|
table = "neighbor n"
|
46
58
|
|
47
|
-
|
48
|
-
"left outer join device n_d on n_d.hostname=n.remote_device",
|
49
|
-
"left outer join lag l on l.device=n.device and l.member=n.port",
|
50
|
-
"left outer join lag n_l on n_l.device=n_d.name and n_l.member=n.remote_port",
|
51
|
-
]
|
59
|
+
|
52
60
|
|
53
61
|
where = [f"n.device='{device}'"]
|
54
62
|
|
55
63
|
query = self._build_select(select, table, joins, where)
|
56
64
|
result = self.session.execute(text(query))
|
57
65
|
|
58
|
-
return [dict(zip(result.keys(), r)) for r in result]
|
66
|
+
return [dict(zip(result.keys(), r)) for r in result]
|
67
|
+
|
68
|
+
|
69
|
+
def get_dlzone(self, zone_name:str) -> List[dict]:
|
70
|
+
"""
|
71
|
+
Gets all devices within a DL zone based on walking the 'neighbors'
|
72
|
+
table.
|
73
|
+
|
74
|
+
For each device, the following attributes are returned:
|
75
|
+
"name", "ip", "version", "vendor", "model", "serial"
|
76
|
+
"""
|
77
|
+
device_cols = ["name", "ip", "version", "vendor", "model", "serial"]
|
78
|
+
|
79
|
+
# step 1 is to find DLs in the database - we'll seed our zone with them
|
80
|
+
query = self._build_select(select=device_cols, table="device",where=f"name similar to '(d-|dl-){zone_name}-(1|2)'")
|
81
|
+
dls = self.execute(query)
|
82
|
+
|
83
|
+
if not dls:
|
84
|
+
raise ValueError(f"No DLs found in umnetdb for zone {zone_name}")
|
85
|
+
|
86
|
+
devices_by_name = {d['name']:d for d in dls}
|
87
|
+
|
88
|
+
# now we'll look for neighbors on each device within the zone.
|
89
|
+
# Note that outside of the DLs we only expect to find devices that start with
|
90
|
+
# "s-" anything else is considered 'outside the zone'
|
91
|
+
todo = list(devices_by_name.keys())
|
92
|
+
while(len(todo) != 0):
|
93
|
+
|
94
|
+
device = todo.pop()
|
95
|
+
|
96
|
+
# note that by default this method only returns neighbors in the 'device' table,
|
97
|
+
# any others are ignored
|
98
|
+
neighs = self.get_neighbors(device)
|
99
|
+
|
100
|
+
for neigh in neighs:
|
101
|
+
if neigh["remote_device"].startswith("s-"):
|
102
|
+
|
103
|
+
query = self._build_select(select=device_cols, table="device", where=f"name = '{neigh['remote_device']}'")
|
104
|
+
neigh_device = self.execute(query, fetch_one=True)
|
105
|
+
|
106
|
+
if neigh_device["name"] not in devices_by_name:
|
107
|
+
todo.append(neigh_device["name"])
|
108
|
+
|
109
|
+
devices_by_name[neigh_device["name"]] = neigh_device
|
110
|
+
|
111
|
+
|
112
|
+
return list(devices_by_name.values())
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: umnetdb-utils
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: Helper classes for querying UMnet databases
|
5
5
|
License: MIT
|
6
6
|
Author: Amy Liebowitz
|
@@ -25,7 +25,7 @@ This package is hosted on pypi - you can install it with `pip install umnetdb-ut
|
|
25
25
|
|
26
26
|
## Database Helper Classes
|
27
27
|
As of May 2025 this repo defines db wrapper classes for Equipdb, Netinfo, Netdisco and UMnetdb (populated by agador, hosted on wintermute).
|
28
|
-
To use these classes you need to
|
28
|
+
To use these classes you need to provide credentials, either in a config file that you pass into the initializer, in `.env`, or in your environment:
|
29
29
|
* Netinfo: `NETINFO_USERNAME`, `NETINFO_PASSSWORD`
|
30
30
|
* Netdisco: `NETDISCO_DB_USER`, `NETDISCO_DB_PASSWORD`
|
31
31
|
* Equipdb: `EQUIP_DB_USER`, `EQUIP_DB_PASSWORD`
|
@@ -1,10 +1,10 @@
|
|
1
1
|
umnetdb_utils/__init__.py,sha256=QJaytbr4ccKESiwaKjpf1b4b8s2cHNfCDdnCOs1tmoI,131
|
2
|
-
umnetdb_utils/base.py,sha256=
|
3
|
-
umnetdb_utils/umnetdb.py,sha256=
|
2
|
+
umnetdb_utils/base.py,sha256=aIcCdeQ2FTrWV4Az_gdPc-aXuEwRjhef1Xj9SVak438,5878
|
3
|
+
umnetdb_utils/umnetdb.py,sha256=AWA-UTiWIqi6i2SDkinjQR0ONoRcF0v6MAmiEllo0Z0,4058
|
4
4
|
umnetdb_utils/umnetdisco.py,sha256=Z2XwT79jKO_avd3w_z99DDEdAikrfKxYm1JYHRWqvG4,7841
|
5
5
|
umnetdb_utils/umnetequip.py,sha256=jOW5kvk0FXtdHv8PA4rYT_PWfLdMiq83Mjwmy-c1DN8,5701
|
6
6
|
umnetdb_utils/umnetinfo.py,sha256=MH1YDW4OWtHD46qfYb5Pv40vPSbL0GrMNW5gAhdlihE,18445
|
7
7
|
umnetdb_utils/utils.py,sha256=wU6QMYfofj7trX3QeqXty0btbGdhP_RUaSqA7QTflFM,991
|
8
|
-
umnetdb_utils-0.1.
|
9
|
-
umnetdb_utils-0.1.
|
10
|
-
umnetdb_utils-0.1.
|
8
|
+
umnetdb_utils-0.1.3.dist-info/METADATA,sha256=5Y2fRGaGfuri9u2JMQYV6TiyzbPIug3W6YJbHBCPUHA,1555
|
9
|
+
umnetdb_utils-0.1.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
10
|
+
umnetdb_utils-0.1.3.dist-info/RECORD,,
|
File without changes
|