from durable.engine import MessageObservedException from durable.lang import * import shutil import os import os.path import jinja2 from utils import * class Machine: @staticmethod def make(name: str): return {"type": "machine", "key": name, "name": name} class Acme: @staticmethod def make(env: str, tag: str): return {"type": "acme-application", "key": env, "env": env, "tag": tag} @staticmethod def declare_rules(): @when_all((m.type == "acme-application")) def acmeApp(c): cluster = f"acme-{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 AcmeOperations: @staticmethod def make(): return {"type": "acme-ops", "key": "acme-ops"} @staticmethod def declare_rules(): @when_all((m.type == "acme-ops")) def acmeOps(c): cluster = "acme-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("phase-1"): Acme.declare_rules() AcmeOperations.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 == 'machine')) def defaultMachine(c): pass @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 m1 = Machine.make("acme-1") m2 = Machine.make("acme-2") m3 = Machine.make("acme-3") acmeCi = Acme.make("ci", "development") acmeProduction = Acme.make("production", "master") acmeOps = AcmeOperations.make() x = assert_fact("phase-1", acmeCi); print(f"x: {x}") x = assert_fact("phase-1", acmeProduction); print(f"x: {x}") x = assert_fact("phase-1", acmeOps); print(f"x: {x}") x = assert_fact("phase-1", m1); print(f"x: {x}") x = assert_fact("phase-1", m2); print(f"x: {x}") x = assert_fact("phase-1", m3); print(f"x: {x}") if True: print("Facts:") for f in get_facts("phase-1"): print(f"fact: {f}") print("dba-clusters:") for f in [f for f in get_facts("phase-1") 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("phase-1") if f.get("cluster") == cluster_name and f["type"] == "dba-container"]: del f["cluster"] del f["type"] print(f" container: {f}") write_facts("phase-1") 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("phase-1") if f["type"] in ("dba-cluster", "dba-container")]: x = assert_fact("phase-2", f); print(f"x: {x}") write_facts("phase-2") # Prepare if os.path.isdir("gen"): shutil.rmtree("gen") os.mkdir("gen") os.mkdir("gen/platform") os.mkdir("gen/platform/terraform") os.mkdir("gen/platform/ansible") print("PHASE 3") file_loader = jinja2.FileSystemLoader("j2") j2 = jinja2.Environment(loader=file_loader) with ruleset("phase-3"): @when_all(pri(1), (m.type == "machine")) def terraformForMachine(c): template = j2.get_template("terraform-machine.j2") with open(f"gen/platform/terraform/{c.m.key}.tf", "w") as f: s = template.render(**{"m": c.m}) f.write(s.strip()) f.write("\n") @when_all(pri(1), (m.type == "machine")) def ansibleForMachine(c): template = j2.get_template("platform-ansible.j2") with open(f"gen/platform/ansible/{c.m.key}.tf", "w") as f: s = template.render(**{"m": c.m}) f.write(s.strip()) f.write("\n") for f in [f for f in get_facts("phase-1") if f["type"] in ("machine")]: x = assert_fact("phase-3", f); print(f"x: {x}") write_facts("phase-3")