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 {val} in {url}")
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: A list of 'where' statements without the 'where'. The list of statements are
96
- "anded". If you need "or", embed it in one of your list items
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 get_device_neighbors(
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
- joins = [
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.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 set specific environment variables with the credentials for each db respectively:
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=PCtc08eZ1BwExSY1nm-eGWMTd_V56fsZXhXq2D6rU0Q,5231
3
- umnetdb_utils/umnetdb.py,sha256=2jPsZsJWFtwWKIRqww86B8tRWBQ0cbw3iOk9PwAXaxY,1948
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.1.dist-info/METADATA,sha256=T0ycl5URR_p5V8qWkm-IBk1VuDLsvEkwGZbUMYZFm-M,1521
9
- umnetdb_utils-0.1.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
10
- umnetdb_utils-0.1.1.dist-info/RECORD,,
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,,