from durable.engine import MessageObservedException from durable.lang import * import os import os.path import yaml class VimScore: @staticmethod def make(env: str, tag: str): return {"type": "vimscore-application", "env": env, "tag": tag} @staticmethod def declare_rules(): @when_all((m.type == "vimscore-application")) def vsApp(c): print(f"vimscoreApplication: {c.m}") cluster = f"vimscore-{c.m.env}" tag = f"{c.m.tag}" # c.assert_fact(dba.cluster(cluster)) for f in [ dba.container(cluster, "app", "statera", "statera", tag), dba.container(cluster, "app", "statera-console", "statera-console", tag), dba.container(cluster, "app", "4tune-web", "4tune-web", tag), dba.container(cluster, "app", "4tune-api", "4tune-api", tag), dba.container(cluster, "db", "pdb", "postgresql", "13"), dba.container(cluster, "db", "mdb", "mongodb", "3.2"), ]: c.assert_fact(f) class VsOperations: @staticmethod def make(): return {"type": "vimscore-ops"} @staticmethod def declare_rules(): @when_all((m.type == "vimscore-ops")) def vsOps(c): cluster = "vimscore-ops" c.assert_fact(dba.cluster(cluster)) c.assert_fact(dba.container(cluster, "app", "pdb", "postgresql", "11")) c.assert_fact(dba.container(cluster, "app", "n8n", "n8n", "0.84.1")) # pgadmin, loki class DockerBasedApplications: @staticmethod def cluster(key: str): return {"type": "dba-cluster", "key": key} @staticmethod def container(cluster: str, machineRole: str, name: str, image: str, tag: str): return {"type": "dba-container", "key": f"{cluster}/{name}", "cluster": cluster, "machineRole": machineRole, "name": name, "image": image, "tag": tag} dba = DockerBasedApplications with ruleset("my-rules"): VimScore.declare_rules() VsOperations.declare_rules() @when_all(+s.exception) def second(c): print("Processing failed!") print(c.s["exception"]) c.s.exception = None @when_all(pri(1000), (m.type == 'dba-container')) def dba_container(c): print(f"dba-container: {c.m}") @when_all(pri(900), (m.type == 'dba-container') & (m.image == "statera") & -m.ports) def addPortsToStatera(c): c.retract_fact(c.m) c.m.ports = [8090] c.assert_fact(c.m) @when_all(pri(900), (m.type == 'dba-container') & (m.image == "statera-console") & -m.ports) def addPortsToStateraConsole(c): c.retract_fact(c.m) c.m.ports = [80] c.assert_fact(c.m) # The none() part doesn't work as is, but it is worked around with the try/except block. @when_all( (c.container << m.type == "dba-container"), none((m.type == "dba-cluster") & (m.key == c.container.cluster)), ) def dbCluster(c): cluster = c.container.cluster try: c.assert_fact(dba.cluster(cluster)) print(f"NEW CLUSTER: c.container={c.container}") except MessageObservedException: pass # @when_all(pri(40), # (c.container << m.type == "dba-container"), # (c.cluster << (m.type == "dba-cluster") & (m.key == c.container.cluster)), # ) # def dbCluster(c): # print("dba-cluster: CATCH ALL") # print(f"c.container: {c.container}") # print(f"c.cluster: {c.cluster}") # pass vimscoreCi = VimScore.make("ci", "development") vimscoreProduction = VimScore.make("production", "master") vsOps = VsOperations.make() #x = assert_fact("my-rules", vimscoreCi); print(f"x: {x}") x = assert_fact("my-rules", vimscoreProduction); print(f"x: {x}") #x = assert_fact("my-rules", vsOps); print(f"x: {x}") if True: print("Facts:") for f in get_facts("my-rules"): print(f"fact: {f}") print("dba-clusters:") for f in [f for f in get_facts("my-rules") if f["type"] == "dba-cluster"]: cluster_name = f["key"] del f["key"] print(f" cluster:") print(f" key: {cluster_name}") print(f" json: {f}") print(" dba-containers:") for f in [f for f in get_facts("my-rules") if f.get("cluster") == cluster_name and f["type"] == "dba-container"]: del f["cluster"] del f["type"] print(f" container: {f}") with ruleset("phase-2"): @when_all(+s.exception) def second(c): print("Processing failed!") print(c.s["exception"]) c.s.exception = None # @when_all(pri(100), m.type == "dba-cluster") # def container(c): # print(f"default: cluster: {c.m}") @when_all((m.type == "dba-container") & -m.ports_classified) def mark_public_containers(c): # print(f"marking container.. {c.m}") item = c.m c.retract_fact(item) # print(f"marking container.. {c.m.name}, ports={c.m.ports}") item["public_ports"] = len(item.ports or []) > 0 item["ports_classified"] = True # print(f"marking container.. {item}") c.assert_fact(item) @when_all(pri(50), c.cluster << (m.type == "dba-cluster"), # c.container << ((m.type == "dba-container") & (m.cluster == c.cluster.key) & m.ports.anyItem(item > 0)) c.container << ((m.type == "dba-container") & +m.ports_classified & (m.public_ports > 0)) ) def container(c): print(f"public container") print(f" cluster: {c.cluster}") print(f" container: {c.container}") @when_all(((m.type == "dba-container") & (+m.ports_classified) & (m.public_ports == 0))) def container(c): print(f"private container: {c.m}") print("PHASE 2") for f in [f for f in get_facts("my-rules") if f["type"] in ("dba-cluster", "dba-container")]: assert_fact("phase-2", f) def write_facts(ruleset: set): facts = get_facts(ruleset) types = set((f.get("type") for f in facts)) print(f"types: {types}") out_dir = "out" if not os.path.exists(out_dir): os.mkdir(out_dir) basedir = os.path.join(out_dir, ruleset) if os.path.exists(basedir): for f in os.listdir(basedir): p = os.path.join(basedir, f) if os.path.isdir(p): for f2 in os.listdir(p): os.remove(os.path.join(p, f2)) os.rmdir(p) else: os.remove(p) os.rmdir(basedir) os.mkdir(basedir) for t in types: typedir = os.path.join(basedir, t) os.mkdir(typedir) fs = [] for f in facts: if f["type"] != t: continue del f["sid"] fs.append(f) i = 0 for fact in sorted(fs, key=lambda f: f["key"]): key = fact["key"] path = os.path.join(typedir, f"{key.replace('/', '_')}.yaml") with open(path, "w") as f: s = yaml.dump(fact) f.write(s) i = i + 1 write_facts("phase-2")