summaryrefslogtreecommitdiff
path: root/src/caas/services/helpers.py
diff options
context:
space:
mode:
authorckonstanski <kostcarl@isu.edu>2026-07-30 18:17:14 -0600
committerckonstanski <kostcarl@isu.edu>2026-07-30 18:17:14 -0600
commit640ff61422bc0ee3966941b93d9889ddbbd38d77 (patch)
treeabf1c08f5d38ee53ec8b29dc4f425722517505e6 /src/caas/services/helpers.py
parent22dae02a86c1fce71091bfa5289cf99abba1b217 (diff)
more filesHEADmaster
Diffstat (limited to 'src/caas/services/helpers.py')
-rw-r--r--src/caas/services/helpers.py136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/caas/services/helpers.py b/src/caas/services/helpers.py
new file mode 100644
index 0000000..9145d1f
--- /dev/null
+++ b/src/caas/services/helpers.py
@@ -0,0 +1,136 @@
+import ipaddress
+import jinja2
+import os
+import subprocess
+
+
+class Shell():
+ @staticmethod
+ def run_shell_command(cmd):
+ p = subprocess.Popen([cmd],
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env={})
+ out, err = p.communicate()
+ if p.returncode != 0:
+ raise Exception("Error running shell command:\n%s\n%s" % (out, err))
+ return out, err
+
+
+class Jinja():
+ @staticmethod
+ def render(template_name, **kwargs):
+ cwd = os.path.dirname(os.path.abspath(__file__))
+ loader = jinja2.FileSystemLoader([".", "/"])
+ extensions = ["jinja2.ext.with_", "jinja2.ext.loopcontrols"]
+ environment = jinja2.Environment(trim_blocks = True,
+ lstrip_blocks = True,
+ extensions = extensions,
+ loader = loader)
+ template_names = ["%s/jinja/%s" % (cwd, template_name)]
+ template = environment.select_template(template_names)
+ return template.render(kwargs)
+
+
+class RawQuery():
+ @staticmethod
+ def dict_fetchall(cursor):
+ rows = cursor.fetchall()
+ if len(rows) == 0:
+ return None
+ else:
+ columns = [col[0] for col in cursor.description]
+ return [dict(zip(columns, row)) for row in rows]
+
+ @staticmethod
+ def query_single_value(cursor, query, column_name):
+ cursor.execute(query)
+ rows = RawQuery.dict_fetchall(cursor)
+ if rows == {}:
+ return None
+ else:
+ return rows[0][column_name]
+
+
+class Address():
+ @staticmethod
+ def coalesce(ip, default):
+ if ip is None:
+ return default
+ else:
+ return ip
+
+ @staticmethod
+ def get_quads(addr):
+ return list(filter(lambda x: x, str(addr).split("/")[0].split(":")))
+
+ @staticmethod
+ def address_add(ip, index):
+ return ipaddress.IPv6Address(ip) + index
+
+ """
+ Assumes a 5-quad 'subnet' as import input. Adds the 6th quad which is always 40a.
+ """
+ @staticmethod
+ def add_40a(subnet):
+ return Address.address_add(subnet, 0x040a00000000)
+
+ @staticmethod
+ def next_address(ip, subnet, block_begin_hex):
+ beginning_address = Address.coalesce(ip, Address.address_add(subnet, block_begin_hex))
+ if ip is None:
+ return beginning_address
+ else:
+ return Address.address_add(beginning_address, 0x1)
+
+ @staticmethod
+ def add_cidr(subnet, cidr = 64):
+ subnet_quads = Address.get_quads(subnet)
+ return "%s::/%s" % (":".join(subnet_quads), cidr)
+
+ @staticmethod
+ def remove_cidr(subnet):
+ return ipaddress.IPv6Address(str(subnet).split("/")[0])
+
+ @staticmethod
+ def gateway_to_subnet(gateway, numquads = 5):
+ # The subnet is always the first 5 quads of the gateway.
+ # TODO: make sure this holds true in MTCE and labs as well as production.
+ quads = Address.get_quads(gateway)
+ return ipaddress.IPv6Address("%s::" % ":".join(quads[:numquads]))
+
+ @staticmethod
+ def gateway_to_subnet_new(gateway):
+ quads = Address.get_quads(gateway)
+ return ipaddress.IPv6Address("%s:40a::" % ":".join(quads[:5]))
+
+ @staticmethod
+ def subnet_to_4_quads(subnet):
+ quads = Address.get_quads(gateway)
+ return ipaddress.IPv6Address("%s::" % ":".join(quads[:4]))
+
+ @staticmethod
+ def strip_brackets(ip):
+ return ip.replace("[", "").replace("]", "")
+
+
+class Hostname():
+ @staticmethod
+ def make_oam_hostname(ilo_hostname):
+ return ilo_hostname.replace("-pe0", "-pe2")
+
+ """
+ Note: this method does not deal with the index at the end of the
+ hostname. Doing so would require database access. This is the
+ responsibility of the service classes. See dnsservice.py
+ """
+ @staticmethod
+ def make_vip_hostname(ilo_hostname, cluster_name):
+ index = int(cluster_name[-3:])
+ return "%s-%s" % (ilo_hostname.replace("-pe0", "-pe1")[:-4], f"{index + 0:03}")
+
+ @staticmethod
+ def increment_hostname(hostname):
+ index = int(hostname[-3:])
+ return "%s-%s" % (hostname[:-4], f"{index + 1:03}")