From 09ba202f73a519355f86b845b210b5126ea1dacf Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 3 Jan 2021 22:20:15 +0100 Subject: VPN work. --- acme.yaml | 27 +++ out/phase-1.yaml | 234 ++++++++++++++------- out/vs0.yaml | 106 ++++++++++ src/main/java/io/trygvis/rules/acme/AcmeIo.java | 52 ++++- src/main/java/io/trygvis/rules/engine/Main.java | 13 +- .../java/io/trygvis/rules/machine/Machine.java | 1 + src/main/resources/io/trygvis/rules/acme/acme.drl | 22 ++ src/main/resources/io/trygvis/rules/acme/vpn.drl | 50 +++++ src/main/resources/io/trygvis/rules/dba/dba.drl | 6 - .../io/trygvis/rules/terraform/terraform.drl | 22 +- 10 files changed, 427 insertions(+), 106 deletions(-) create mode 100644 out/vs0.yaml create mode 100644 src/main/resources/io/trygvis/rules/acme/vpn.drl diff --git a/acme.yaml b/acme.yaml index b7a17c5..6e9f617 100644 --- a/acme.yaml +++ b/acme.yaml @@ -23,3 +23,30 @@ data: type: io.trygvis.rules.machine.Machine data: name: acme-3 + +# Workstations +--- +type: io.trygvis.rules.machine.Machine +data: + name: ws-1 +--- +type: io.trygvis.rules.machine.Machine +data: + name: ws-2 + +--- +type: io.trygvis.rules.acme.WgNet +data: + name: vs0 + domain: vpn.acme.com + +--- +type: io.trygvis.rules.acme.WgHost +data: + name: ws-1 + net: vs0 +--- +type: io.trygvis.rules.acme.WgHost +data: + name: ws-2 + net: vs0 diff --git a/out/phase-1.yaml b/out/phase-1.yaml index 2d7bbed..c8dfa11 100644 --- a/out/phase-1.yaml +++ b/out/phase-1.yaml @@ -1,47 +1,121 @@ --- type: "io.trygvis.rules.acme.AcmeMyApp" +data: + environment: "production" + dockerTag: "master" +--- +type: "io.trygvis.rules.acme.AcmeMyApp" data: environment: "ci" dockerTag: "development" --- -type: "io.trygvis.rules.acme.AcmeMyApp" +type: "io.trygvis.rules.acme.AcmeServer" data: - environment: "production" - dockerTag: "master" + machine: + name: "acme-3" + fqdn: "acme-3.machine.acme.com" --- -type: "io.trygvis.rules.dba.Cluster" +type: "io.trygvis.rules.acme.AcmeServer" data: - name: "acme-ci" + machine: + name: "acme-2" + fqdn: "acme-2.machine.acme.com" +--- +type: "io.trygvis.rules.acme.AcmeServer" +data: + machine: + name: "acme-1" + fqdn: "acme-1.machine.acme.com" +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "acme-3" + machine: + name: "acme-3" + fqdn: "acme-3.machine.acme.com" + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "ws-2" + machine: null + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "acme-1" + machine: + name: "acme-1" + fqdn: "acme-1.machine.acme.com" + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "ws-1" + machine: null + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "acme-2" + machine: + name: "acme-2" + fqdn: "acme-2.machine.acme.com" + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgNet" +data: + name: "vs0" + domain: "vpn.acme.com" --- type: "io.trygvis.rules.dba.Cluster" data: name: "acme-production" --- +type: "io.trygvis.rules.dba.Cluster" +data: + name: "acme-ci" +--- type: "io.trygvis.rules.dba.Container" data: cluster: name: "acme-production" name: "db" - machineRole: "pdb" - image: "postgresql" - tag: "13" + machineRole: "mdb" + image: "mongodb" + tag: "3.2" --- type: "io.trygvis.rules.dba.Container" data: cluster: - name: "acme-ci" + name: "acme-production" name: "db" - machineRole: "mdb" - image: "mongodb" - tag: "3.2" + machineRole: "pdb" + image: "postgresql" + tag: "13" --- type: "io.trygvis.rules.dba.Container" data: cluster: name: "acme-ci" name: "app" - machineRole: "4tune-api" - image: "4tune-api" + machineRole: "4tune-web" + image: "4tune-web" tag: "development" --- type: "io.trygvis.rules.dba.Container" @@ -49,8 +123,8 @@ data: cluster: name: "acme-production" name: "app" - machineRole: "4tune-web" - image: "4tune-web" + machineRole: "statera" + image: "statera" tag: "master" --- type: "io.trygvis.rules.dba.Container" @@ -58,26 +132,26 @@ data: cluster: name: "acme-production" name: "app" - machineRole: "statera" - image: "statera" + machineRole: "statera-console" + image: "statera-console" tag: "master" --- type: "io.trygvis.rules.dba.Container" data: cluster: name: "acme-ci" - name: "app" - machineRole: "statera" - image: "statera" - tag: "development" + name: "db" + machineRole: "pdb" + image: "postgresql" + tag: "13" --- type: "io.trygvis.rules.dba.Container" data: cluster: name: "acme-production" name: "app" - machineRole: "4tune-api" - image: "4tune-api" + machineRole: "4tune-web" + image: "4tune-web" tag: "master" --- type: "io.trygvis.rules.dba.Container" @@ -85,8 +159,8 @@ data: cluster: name: "acme-production" name: "app" - machineRole: "statera-console" - image: "statera-console" + machineRole: "4tune-api" + image: "4tune-api" tag: "master" --- type: "io.trygvis.rules.dba.Container" @@ -94,15 +168,6 @@ data: cluster: name: "acme-ci" name: "db" - machineRole: "pdb" - image: "postgresql" - tag: "13" ---- -type: "io.trygvis.rules.dba.Container" -data: - cluster: - name: "acme-production" - name: "db" machineRole: "mdb" image: "mongodb" tag: "3.2" @@ -112,8 +177,8 @@ data: cluster: name: "acme-ci" name: "app" - machineRole: "4tune-web" - image: "4tune-web" + machineRole: "statera-console" + image: "statera-console" tag: "development" --- type: "io.trygvis.rules.dba.Container" @@ -121,98 +186,105 @@ data: cluster: name: "acme-ci" name: "app" - machineRole: "statera-console" - image: "statera-console" + machineRole: "statera" + image: "statera" tag: "development" --- -type: "io.trygvis.rules.dns.DnsEntry" +type: "io.trygvis.rules.dba.Container" data: - fqdn: "acme-3.machine.acme.com" - type: "A" + cluster: + name: "acme-ci" + name: "app" + machineRole: "4tune-api" + image: "4tune-api" + tag: "development" --- type: "io.trygvis.rules.dns.DnsEntry" data: - fqdn: "acme-2.machine.acme.com" + fqdn: "acme-1.vpn.acme.com" type: "A" --- type: "io.trygvis.rules.dns.DnsEntry" data: - fqdn: "acme-2.machine.acme.com" - type: "AAAA" + fqdn: "ws-1.vpn.acme.com" + type: "A" --- type: "io.trygvis.rules.dns.DnsEntry" data: - fqdn: "acme-1.machine.acme.com" - type: "AAAA" + fqdn: "ws-2.vpn.acme.com" + type: "A" --- type: "io.trygvis.rules.dns.DnsEntry" data: - fqdn: "acme-3.machine.acme.com" - type: "AAAA" + fqdn: "acme-2.vpn.acme.com" + type: "A" --- type: "io.trygvis.rules.dns.DnsEntry" data: - fqdn: "acme-1.machine.acme.com" + fqdn: "acme-3.vpn.acme.com" type: "A" --- -type: "io.trygvis.rules.dns.DnsEntryTerraformExpression" +type: "io.trygvis.rules.engine.KeyValue" data: - entry: - fqdn: "acme-3.machine.acme.com" - type: "A" - key: "acme-3" - expression: "scaleway_instance_ip.acme-3.address" + key: "rm-gen" + value: null --- -type: "io.trygvis.rules.dns.DnsEntryTerraformExpression" +type: "io.trygvis.rules.machine.Machine" data: - entry: - fqdn: "acme-2.machine.acme.com" - type: "A" - key: "acme-2" - expression: "scaleway_instance_ip.acme-2.address" + name: "ws-2" + fqdn: null --- -type: "io.trygvis.rules.dns.DnsEntryTerraformExpression" +type: "io.trygvis.rules.machine.Machine" data: - entry: - fqdn: "acme-1.machine.acme.com" - type: "A" - key: "acme-1" - expression: "scaleway_instance_ip.acme-1.address" + name: "acme-2" + fqdn: "acme-2.machine.acme.com" --- -type: "io.trygvis.rules.engine.KeyValue" +type: "io.trygvis.rules.machine.Machine" data: - key: "rm-gen" - value: null + name: "acme-1" + fqdn: "acme-1.machine.acme.com" --- type: "io.trygvis.rules.machine.Machine" data: - name: "acme-2" + name: "ws-1" + fqdn: null --- type: "io.trygvis.rules.machine.Machine" data: name: "acme-3" + fqdn: "acme-3.machine.acme.com" --- -type: "io.trygvis.rules.machine.Machine" +type: "io.trygvis.rules.terraform.ScalewayMachine" data: - name: "acme-1" + machine: + name: "ws-2" + fqdn: null + key: "ws-2" --- type: "io.trygvis.rules.terraform.ScalewayMachine" data: machine: - name: "acme-2" - key: "acme-2" - fqdn: "acme-2.machine.acme.com" + name: "acme-3" + fqdn: "acme-3.machine.acme.com" + key: "acme-3" --- type: "io.trygvis.rules.terraform.ScalewayMachine" data: machine: name: "acme-1" + fqdn: "acme-1.machine.acme.com" key: "acme-1" - fqdn: "acme-1.machine.acme.com" --- type: "io.trygvis.rules.terraform.ScalewayMachine" data: machine: - name: "acme-3" - key: "acme-3" - fqdn: "acme-3.machine.acme.com" + name: "acme-2" + fqdn: "acme-2.machine.acme.com" + key: "acme-2" +--- +type: "io.trygvis.rules.terraform.ScalewayMachine" +data: + machine: + name: "ws-1" + fqdn: null + key: "ws-1" diff --git a/out/vs0.yaml b/out/vs0.yaml new file mode 100644 index 0000000..c400981 --- /dev/null +++ b/out/vs0.yaml @@ -0,0 +1,106 @@ +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "acme-3" + machine: + name: "acme-3" + fqdn: "acme-3.machine.acme.com" + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "ws-2" + machine: null + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "acme-1" + machine: + name: "acme-1" + fqdn: "acme-1.machine.acme.com" + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "ws-1" + machine: null + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgHost" +data: + name: "acme-2" + machine: + name: "acme-2" + fqdn: "acme-2.machine.acme.com" + net: "vs0" + publicName: null + netToNetIp: null + networkIp: null +--- +type: "io.trygvis.rules.acme.WgNet" +data: + name: "vs0" + domain: "vpn.acme.com" +--- +type: "io.trygvis.rules.dns.DnsEntry" +data: + fqdn: "acme-1.vpn.acme.com" + type: "A" +--- +type: "io.trygvis.rules.dns.DnsEntry" +data: + fqdn: "ws-1.vpn.acme.com" + type: "A" +--- +type: "io.trygvis.rules.dns.DnsEntry" +data: + fqdn: "ws-2.vpn.acme.com" + type: "A" +--- +type: "io.trygvis.rules.dns.DnsEntry" +data: + fqdn: "acme-2.vpn.acme.com" + type: "A" +--- +type: "io.trygvis.rules.dns.DnsEntry" +data: + fqdn: "acme-3.vpn.acme.com" + type: "A" +--- +type: "io.trygvis.rules.machine.Machine" +data: + name: "ws-2" + fqdn: null +--- +type: "io.trygvis.rules.machine.Machine" +data: + name: "acme-2" + fqdn: "acme-2.machine.acme.com" +--- +type: "io.trygvis.rules.machine.Machine" +data: + name: "acme-1" + fqdn: "acme-1.machine.acme.com" +--- +type: "io.trygvis.rules.machine.Machine" +data: + name: "ws-1" + fqdn: null +--- +type: "io.trygvis.rules.machine.Machine" +data: + name: "acme-3" + fqdn: "acme-3.machine.acme.com" diff --git a/src/main/java/io/trygvis/rules/acme/AcmeIo.java b/src/main/java/io/trygvis/rules/acme/AcmeIo.java index 67dd4cb..9235992 100644 --- a/src/main/java/io/trygvis/rules/acme/AcmeIo.java +++ b/src/main/java/io/trygvis/rules/acme/AcmeIo.java @@ -1,9 +1,11 @@ package io.trygvis.rules.acme; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import org.drools.core.common.DefaultFactHandle; +import org.kie.api.KieBase; import org.kie.api.runtime.rule.FactHandle; import java.io.File; @@ -12,19 +14,21 @@ import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.function.Function; public class AcmeIo { private final ObjectMapper mapper; - public AcmeIo() { + public AcmeIo(KieBase kieBase) { var factory = new YAMLFactory(); factory.enable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID); factory.enable(YAMLGenerator.Feature.USE_NATIVE_OBJECT_ID); mapper = new ObjectMapper(factory); + var typeFactory = TypeFactory.defaultInstance() + .withClassLoader(new AcmeClassLoader(kieBase)); + mapper.setTypeFactory(typeFactory); mapper.findAndRegisterModules(); } @@ -36,7 +40,7 @@ public class AcmeIo { List items = new ArrayList<>(objects.size()); for (AcmeObject object : objects) { try { - var type = Class.forName(object.type); + var type = mapper.getTypeFactory().findClass(object.type); var x = mapper.treeToValue(object.data, type); items.add(x); } catch (ClassNotFoundException e) { @@ -48,6 +52,10 @@ public class AcmeIo { } public void dump(String s, Collection factHandles) throws IOException { + dump(s, factHandles, (o) -> true); + } + + public void dump(String s, Collection factHandles, Function filter) throws IOException { var out = new File("out"); if (!out.isDirectory()) { @@ -59,9 +67,14 @@ public class AcmeIo { List> facts = new ArrayList<>(factHandles.size()); for (var handle : factHandles) { if (handle instanceof DefaultFactHandle h) { + var obj = h.getObject(); + if (!filter.apply(obj)) { + continue; + } + facts.add(new AbstractMap.SimpleImmutableEntry<>( h.getObjectClassName(), - h.getObject())); + obj)); } } @@ -78,4 +91,33 @@ public class AcmeIo { } } } + + private static class AcmeClassLoader extends ClassLoader { + private final KieBase kieBase; + + public AcmeClassLoader(KieBase kieBase) {this.kieBase = kieBase;} + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + try { + return super.loadClass(name); + } catch (ClassNotFoundException e) { + var i = name.lastIndexOf('.'); + String pkg, klass; + if (i == -1) { + pkg = null; + klass = name; + } else { + pkg = name.substring(0, i); + klass = name.substring(i + 1); + } + var clazz = kieBase.getFactType(pkg, klass); + if (clazz == null) { + throw e; + } + + return clazz.getFactClass(); + } + } + } } diff --git a/src/main/java/io/trygvis/rules/engine/Main.java b/src/main/java/io/trygvis/rules/engine/Main.java index d469f3a..a3b0259 100644 --- a/src/main/java/io/trygvis/rules/engine/Main.java +++ b/src/main/java/io/trygvis/rules/engine/Main.java @@ -1,6 +1,8 @@ package io.trygvis.rules.engine; import io.trygvis.rules.acme.AcmeIo; +import io.trygvis.rules.dns.DnsEntry; +import io.trygvis.rules.machine.Machine; import org.drools.core.audit.WorkingMemoryConsoleLogger; import org.kie.api.KieServices; import org.kie.api.event.rule.AgendaEventListener; @@ -10,12 +12,13 @@ import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { - var io = new AcmeIo(); + var services = KieServices.Factory.get(); + var container = services.getKieClasspathContainer(); + var kieBase = container.getKieBase(); + var io = new AcmeIo(kieBase); var objects = io.load("acme.yaml"); - var services = KieServices.Factory.get(); - var container = services.getKieClasspathContainer(); var session = container.newKieSession(); session.setGlobal("te", new TemplateEngine()); @@ -35,6 +38,10 @@ public class Main { io.dump("phase-1", session.getFactHandles()); + io.dump("vs0", session.getFactHandles(), (Object o) -> { + return o.getClass().getName().contains("Wg") || o instanceof Machine || o instanceof DnsEntry; + }); + session.dispose(); } } diff --git a/src/main/java/io/trygvis/rules/machine/Machine.java b/src/main/java/io/trygvis/rules/machine/Machine.java index c2a7460..cc3f2ed 100644 --- a/src/main/java/io/trygvis/rules/machine/Machine.java +++ b/src/main/java/io/trygvis/rules/machine/Machine.java @@ -2,6 +2,7 @@ package io.trygvis.rules.machine; public class Machine { public String name; + public String fqdn; public Machine() { } diff --git a/src/main/resources/io/trygvis/rules/acme/acme.drl b/src/main/resources/io/trygvis/rules/acme/acme.drl index 2439ddb..e2cb9da 100644 --- a/src/main/resources/io/trygvis/rules/acme/acme.drl +++ b/src/main/resources/io/trygvis/rules/acme/acme.drl @@ -1,8 +1,13 @@ package io.trygvis.rules.acme; +import io.trygvis.rules.machine.Machine; import io.trygvis.rules.dba.Cluster; import io.trygvis.rules.dba.Container; +declare AcmeServer + machine : Machine +end + rule "Ops" when $ops: AcmeOps() @@ -28,3 +33,20 @@ then insert(new Container(cluster, "db", "pdb", "postgresql", "13")); insert(new Container(cluster, "db", "mdb", "mongodb", "3.2")); end + +rule "Create Acme servers" +when + $m : Machine(name.startsWith("acme-")) +then + var s = new AcmeServer(); + s.machine = $m; + insert(s) +end + +rule "Set public domain for ACME servers" +when + $s : AcmeServer() +then + var fqdn = "%s.machine.acme.com".formatted($s.machine.name); + $s.machine.fqdn = fqdn; +end diff --git a/src/main/resources/io/trygvis/rules/acme/vpn.drl b/src/main/resources/io/trygvis/rules/acme/vpn.drl new file mode 100644 index 0000000..3f62fbd --- /dev/null +++ b/src/main/resources/io/trygvis/rules/acme/vpn.drl @@ -0,0 +1,50 @@ +package io.trygvis.rules.acme; + +import io.trygvis.rules.machine.Machine; +import io.trygvis.rules.dns.DnsEntry; + +dialect "mvel" + +declare WgNet + name : String + domain : String +end + +declare WgHost + name : String + machine : Machine + net : String + publicName : String + netToNetIp : String + networkIp : String +end + +rule "Set name from machine's name" + salience 10 +when + $h : WgHost(name == null, machine != null) +then + $h.name = $h.machine.name; + + update($h) +end + +rule "WgHost VPN machines" +when + $machine : Machine(name.startsWith("acme-")) + $wgNet : WgNet(name == "vs0") +then + var wgHost = new WgHost(); + wgHost.machine = $machine; + wgHost.net = $wgNet.name; + insert(wgHost) +end + +rule "Make DNS entries for all VPN hosts" +when + $h : WgHost() + $net : WgNet(name == $h.net) +then + var fqdn = "%s.%s".formatted($h.name, $net.domain); + insert(DnsEntry.a(fqdn)) +end diff --git a/src/main/resources/io/trygvis/rules/dba/dba.drl b/src/main/resources/io/trygvis/rules/dba/dba.drl index 7df1c5d..7beceef 100644 --- a/src/main/resources/io/trygvis/rules/dba/dba.drl +++ b/src/main/resources/io/trygvis/rules/dba/dba.drl @@ -1,7 +1 @@ package io.trygvis.rules.dba; - - -rule "Dba" - when - then -end diff --git a/src/main/resources/io/trygvis/rules/terraform/terraform.drl b/src/main/resources/io/trygvis/rules/terraform/terraform.drl index 1de3123..40b9f7c 100644 --- a/src/main/resources/io/trygvis/rules/terraform/terraform.drl +++ b/src/main/resources/io/trygvis/rules/terraform/terraform.drl @@ -12,30 +12,30 @@ global io.trygvis.rules.engine.TemplateEngine te; declare ScalewayMachine machine : Machine key : String - fqdn : String end rule "Terraform for Machine" when $machine: Machine() then - var fqdn = "%s.machine.acme.com".formatted($machine.name); - var a = DnsEntry.a(fqdn); - var aaaa = DnsEntry.aaaa(fqdn); + ScalewayMachine scw = new ScalewayMachine(); - var scw = new ScalewayMachine(); scw.setKey($machine.name); scw.setMachine($machine); - scw.setFqdn(fqdn); - - var ipv4 = "scaleway_instance_ip.%s.address".formatted($machine.name); -// var ipv6 = "scaleway_instance_server.%s.public_ipv6.address".formatted($machine.name); insert(scw); +end + +rule "Create DNS entry for Terraform Machine" +when + $machine : Machine(fqdn != null) + not(DnsEntry(fqdn == $machine.fqdn)) +then + var a = DnsEntry.a($machine.fqdn); insert(a); - insert(aaaa); + + var ipv4 = "scaleway_instance_ip.%s.address".formatted($machine.name); insert(new DnsEntryTerraformExpression(a, $machine.name, ipv4)); -// insert(new DnsEntryValue(aaaa, ipv6)); end rule "TF for TerraformMachine" -- cgit v1.2.3