From 9504c7efb9b57aeacf5e2717a43c3cf178a65aee Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 6 Jan 2021 12:37:26 +0100 Subject: Splitting ACME out from the generic parts. --- acme.yaml | 6 +- module/acme/classpath.txt | 57 +++++ module/acme/pom.xml | 24 ++ .../src/main/java/io/trygvis/acme/AcmeMyApp.java | 6 + .../src/main/java/io/trygvis/acme/AcmeOps.java | 4 + .../src/main/java/io/trygvis/acme/VpnMain.java | 25 ++ .../acme/src/main/resources/META-INF/kmodule.xml | 11 + .../src/main/resources/io/trygvis/acme/acme.drl | 58 +++++ module/ri-engine/pom.xml | 1 - .../main/java/io/trygvis/rules/acme/AcmeIo.java | 260 --------------------- .../main/java/io/trygvis/rules/acme/AcmeMyApp.java | 6 - .../java/io/trygvis/rules/acme/AcmeObject.java | 16 -- .../main/java/io/trygvis/rules/acme/AcmeOps.java | 4 - .../main/java/io/trygvis/rules/engine/DbIo.java | 259 ++++++++++++++++++++ .../java/io/trygvis/rules/engine/DbObject.java | 16 ++ .../main/java/io/trygvis/rules/engine/Engine.java | 46 ++++ .../main/java/io/trygvis/rules/engine/Main.java | 53 ----- .../src/main/resources/META-INF/kmodule.xml | 5 +- .../main/resources/io/trygvis/rules/acme/acme.drl | 58 ----- .../main/resources/io/trygvis/rules/dba/dba.drl | 1 - .../resources/io/trygvis/rules/engine/default.drl | 1 + .../resources/io/trygvis/rules/machine/machine.drl | 6 - .../src/main/resources/META-INF/kmodule.xml | 2 +- out/phase-1.yaml | 10 +- pom.xml | 7 + 25 files changed, 524 insertions(+), 418 deletions(-) create mode 100644 module/acme/classpath.txt create mode 100644 module/acme/pom.xml create mode 100644 module/acme/src/main/java/io/trygvis/acme/AcmeMyApp.java create mode 100644 module/acme/src/main/java/io/trygvis/acme/AcmeOps.java create mode 100644 module/acme/src/main/java/io/trygvis/acme/VpnMain.java create mode 100644 module/acme/src/main/resources/META-INF/kmodule.xml create mode 100644 module/acme/src/main/resources/io/trygvis/acme/acme.drl delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeMyApp.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeObject.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeOps.java create mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java create mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java create mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java delete mode 100644 module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java delete mode 100644 module/ri-engine/src/main/resources/io/trygvis/rules/acme/acme.drl delete mode 100644 module/ri-engine/src/main/resources/io/trygvis/rules/dba/dba.drl delete mode 100644 module/ri-engine/src/main/resources/io/trygvis/rules/machine/machine.drl diff --git a/acme.yaml b/acme.yaml index 24c07cb..5f3dca3 100644 --- a/acme.yaml +++ b/acme.yaml @@ -1,14 +1,14 @@ -type: io.trygvis.rules.acme.AcmeMyApp +type: io.trygvis.acme.AcmeMyApp data: environment: ci dockerTag: development --- -type: io.trygvis.rules.acme.AcmeMyApp +type: io.trygvis.acme.AcmeMyApp data: environment: production dockerTag: master --- -type: io.trygvis.rules.acme.AcmeOps +type: io.trygvis.acme.AcmeOps --- diff --git a/module/acme/classpath.txt b/module/acme/classpath.txt new file mode 100644 index 0000000..5d086d8 --- /dev/null +++ b/module/acme/classpath.txt @@ -0,0 +1,57 @@ +io.trygvis.rules-sandbox:acme:1.0-SNAPSHOT:jar +ch.obermuhlner:big-math:2.0.1:jar +ch.qos.logback:logback-classic:1.2.3:jar +ch.qos.logback:logback-core:1.2.3:jar +com.fasterxml.jackson.core:jackson-annotations:2.12.0:jar +com.fasterxml.jackson.core:jackson-core:2.12.0:jar +com.fasterxml.jackson.core:jackson-databind:2.12.0:jar +com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.0:jar +com.github.virtuald:curvesapi:1.06:jar +com.google.code.findbugs:annotations:3.0.1:jar +com.google.errorprone:error_prone_annotations:2.1.3:jar +com.google.guava:guava:25.0-jre:jar +com.google.j2objc:j2objc-annotations:1.1:jar +com.google.re2j:re2j:1.2:jar +com.googlecode.java-ipv6:java-ipv6:0.17:jar +com.hubspot.jinjava:jinjava:2.5.6:jar +com.thoughtworks.xstream:xstream:1.4.14:jar +com.zaxxer:SparseBitSet:1.2:jar +commons-codec:commons-codec:1.11:jar +commons-io:commons-io:2.6:jar +commons-net:commons-net:2.2:jar +io.trygvis.rules-sandbox:ri-engine:1.0-SNAPSHOT:jar +io.trygvis.rules-sandbox:ri-wireguard:1.0-SNAPSHOT:jar +org.antlr:antlr-runtime:3.5.2:jar +org.apache.commons:commons-collections4:4.4:jar +org.apache.commons:commons-compress:1.19:jar +org.apache.commons:commons-lang3:3.9:jar +org.apache.commons:commons-math3:3.4.1:jar +org.apache.poi:poi:4.1.2:jar +org.apache.poi:poi-ooxml:4.1.2:jar +org.apache.poi:poi-ooxml-schemas:4.1.2:jar +org.apache.xmlbeans:xmlbeans:3.1.0:jar +org.checkerframework:checker-compat-qual:2.0.0:jar +org.codehaus.mojo:animal-sniffer-annotations:1.14:jar +org.drools:drools-compiler:7.47.0.Final:jar +org.drools:drools-core:7.47.0.Final:jar +org.drools:drools-core-dynamic:7.47.0.Final:jar +org.drools:drools-core-reflective:7.47.0.Final:jar +org.drools:drools-decisiontables:7.47.0.Final:jar +org.drools:drools-ecj:7.47.0.Final:jar +org.drools:drools-mvel:7.47.0.Final:jar +org.drools:drools-templates:7.47.0.Final:jar +org.javassist:javassist:3.26.0-GA:jar +org.jsoup:jsoup:1.8.3:jar +org.kie:kie-api:7.47.0.Final:jar +org.kie:kie-internal:7.47.0.Final:jar +org.kie:kie-memory-compiler:7.47.0.Final:jar +org.kie.soup:kie-soup-commons:7.47.0.Final:jar +org.kie.soup:kie-soup-maven-support:7.47.0.Final:jar +org.kie.soup:kie-soup-project-datamodel-api:7.47.0.Final:jar +org.kie.soup:kie-soup-project-datamodel-commons:7.47.0.Final:jar +org.kie.soup:kie-soup-xstream:7.47.0.Final:jar +org.mvel:mvel2:2.4.10.Final:jar +org.slf4j:slf4j-api:1.7.26:jar +org.yaml:snakeyaml:1.26:jar +xmlpull:xmlpull:1.2.0:jar +xpp3:xpp3_min:1.2.0:jar diff --git a/module/acme/pom.xml b/module/acme/pom.xml new file mode 100644 index 0000000..b3fc43c --- /dev/null +++ b/module/acme/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + + io.trygvis.rules-sandbox + rules-sandbox + 1.0-SNAPSHOT + ../../pom.xml + + + acme + + + + ${project.groupId} + ri-engine + ${project.version} + + + + diff --git a/module/acme/src/main/java/io/trygvis/acme/AcmeMyApp.java b/module/acme/src/main/java/io/trygvis/acme/AcmeMyApp.java new file mode 100644 index 0000000..dfe374b --- /dev/null +++ b/module/acme/src/main/java/io/trygvis/acme/AcmeMyApp.java @@ -0,0 +1,6 @@ +package io.trygvis.acme; + +public class AcmeMyApp { + public String environment; + public String dockerTag; +} diff --git a/module/acme/src/main/java/io/trygvis/acme/AcmeOps.java b/module/acme/src/main/java/io/trygvis/acme/AcmeOps.java new file mode 100644 index 0000000..844c7f0 --- /dev/null +++ b/module/acme/src/main/java/io/trygvis/acme/AcmeOps.java @@ -0,0 +1,4 @@ +package io.trygvis.acme; + +public class AcmeOps { +} diff --git a/module/acme/src/main/java/io/trygvis/acme/VpnMain.java b/module/acme/src/main/java/io/trygvis/acme/VpnMain.java new file mode 100644 index 0000000..d5f986d --- /dev/null +++ b/module/acme/src/main/java/io/trygvis/acme/VpnMain.java @@ -0,0 +1,25 @@ +package io.trygvis.acme; + +import io.trygvis.rules.dns.DnsEntry; +import io.trygvis.rules.engine.Engine; +import io.trygvis.rules.machine.Machine; +import io.trygvis.rules.network.Ipv4Address; +import io.trygvis.rules.network.Ipv4Cidr; + +import java.io.IOException; + +public class VpnMain { + public static void main(String[] args) throws IOException { + try (var engine = new Engine("acme.yaml")) { + engine.io.dump("phase-1", engine.session.getFactHandles()); + + engine.io.dump("vpn0", engine.session.getFactHandles(), (Object o) -> + o.getClass().getName().contains("Wg") + || o instanceof Machine + || o instanceof DnsEntry + || o instanceof Ipv4Cidr + || o instanceof Ipv4Address + ); + } + } +} diff --git a/module/acme/src/main/resources/META-INF/kmodule.xml b/module/acme/src/main/resources/META-INF/kmodule.xml new file mode 100644 index 0000000..351a25e --- /dev/null +++ b/module/acme/src/main/resources/META-INF/kmodule.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/module/acme/src/main/resources/io/trygvis/acme/acme.drl b/module/acme/src/main/resources/io/trygvis/acme/acme.drl new file mode 100644 index 0000000..d978579 --- /dev/null +++ b/module/acme/src/main/resources/io/trygvis/acme/acme.drl @@ -0,0 +1,58 @@ +package io.trygvis.acme; + +import io.trygvis.rules.machine.Machine; +import io.trygvis.rules.dba.Cluster; +import io.trygvis.rules.dba.Container; + +dialect "mvel" + +declare AcmeServer + name : String + machine : Machine +end + +rule "Ops" +when + $ops: AcmeOps() +then + var cluster = new Cluster("acme-ops"); + insert(cluster); + insert(new Container(cluster, "app", "pdb", "postgresql", "11")); + insert(new Container(cluster, "app", "n8n", "n8n", "0.84.1")); +end + +rule "MyApp" +when + $app: AcmeMyApp() +then + var cluster = new Cluster("acme-" + $app.environment); + insert(cluster); + + var tag = $app.dockerTag; + insert(new Container(cluster, "app", "statera", "statera", tag)); + insert(new Container(cluster, "app", "statera-console", "statera-console", tag)); + insert(new Container(cluster, "app", "4tune-web", "4tune-web", tag)); + insert(new Container(cluster, "app", "4tune-api", "4tune-api", tag)); + 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-")) + not(AcmeServer(name == $m.name)) +then + var s = new AcmeServer(); + s.name = $m.name; + s.machine = $m; + insert(s); +end + +rule "Set public domain for ACME servers" +when + $m : Machine(fqdn == null) + $s : AcmeServer(machine == $m) +then + $s.machine.fqdn = "%s.machine.acme.com".formatted($s.machine.name); + update($s.machine) +end diff --git a/module/ri-engine/pom.xml b/module/ri-engine/pom.xml index addd8c5..fd9ba7c 100644 --- a/module/ri-engine/pom.xml +++ b/module/ri-engine/pom.xml @@ -74,7 +74,6 @@ commons-io commons-io - 2.8.0 diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java b/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java deleted file mode 100644 index 456195d..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeIo.java +++ /dev/null @@ -1,260 +0,0 @@ -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.apache.commons.collections4.OrderedMap; -import org.drools.core.common.DefaultFactHandle; -import org.kie.api.KieBase; -import org.kie.api.runtime.rule.FactHandle; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.*; -import java.util.function.Function; - -@SuppressWarnings("unchecked") -public class AcmeIo { - private final ObjectMapper mapper; - - 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(); - } - - public List load(String file) throws IOException { - var parser = mapper.getFactory().createParser(new File(file)); - - var objects = mapper.readValues(parser, AcmeObject.class).readAll(new ArrayList<>()); - - List items = new ArrayList<>(objects.size()); - for (AcmeObject object : objects) { - try { - var type = mapper.getTypeFactory().findClass(object.type); - var x = mapper.treeToValue(object.data, type); - items.add(x); - } catch (ClassNotFoundException e) { - throw new IOException(e); - } - } - - return items; - } - - public void dump(String s, Collection factHandles) throws IOException { - dump(s, factHandles, (o) -> true); - } - - // This should just sort by all getters instead. - static class FactCollection { - public final Class type; - public final List values; - - public FactCollection(Class type) { - this.type = type; - this.values = new ArrayList<>(); - } - - public void sort() { - var comparator = comparable(type); - - this.values.sort(comparator); - } - } - - private static final Map, Comparator> comparators = new HashMap<>(); - - private static > Comparator comparable(Class klass) { - var comparator = comparators.get(klass); - if (comparator != null) { - return comparator; - } - - // TODO: check if klass is a Comparable directly. - - var prioritizedKeys = List.of("key", "name", "fqdn"); - - var discoveredFieldsP1 = new LinkedHashMap>(); - var discoveredFieldsP2 = new LinkedHashMap>(); - - var prioritizedTypes = List.of(String.class, int.class, Number.class); - - for (var f : klass.getDeclaredFields()) { - if (f.getDeclaringClass() == Object.class) { - continue; - } - - if (!f.trySetAccessible()) { - continue; - } - - var collection = discoveredFieldsP2; - - if (prioritizedTypes.contains(f.getType())) { - collection = discoveredFieldsP1; - } - - collection.put(f.getName(), (Object o) -> { - try { - return f.get(o); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - -// for (var m : klass.getFields()) { -// if (m.getParameterCount() != 0) { -// continue; -// } -// -// var name = m.getName(); -// -// if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(4))) { -// name = name.substring(3, 3).toLowerCase() + name.substring(4); -// } else { -// continue; -// } -// -// if (!m.isAccessible()) { -// if (!m.trySetAccessible()) -// return null; -// } -// -// discoveredFields.put(name, m); -// } - -// System.out.printf("Sorting %s by:%n", klass.getName()); - - var discoveredFields = new LinkedHashMap<>(discoveredFieldsP1); - discoveredFields.putAll(discoveredFieldsP2); - - List> accessors = new ArrayList<>(); - for (String prioritizedKey : prioritizedKeys) { - var m = discoveredFields.remove(prioritizedKey); - if (m == null) { - continue; - } - - accessors.add(m); -// System.out.println(" + " + prioritizedKey); - } - accessors.addAll(discoveredFields.values()); -// discoveredFields.keySet().forEach((s)-> System.out.println(" - " + s)); - - comparator = (a, b) -> { -// if (klass.getName().contains("AcmeServer")) { -// System.out.println("AcmeIo.comparable"); -// } - - for (var method : accessors) { - var x = method.apply(a); - var y = method.apply(b); - - if (x == null && y == null) { - continue; - } - - if (x == null) { - return -1; - } else if (y == null) { - return 1; - } else { - var res = x.toString().compareTo(y.toString()); - if (res != 0) { - return res; - } - } - } - - return 0; - }; - - comparators.put(klass, comparator); - - return comparator; - } - - public void dump(String s, Collection factHandles, Function filter) throws IOException { - var out = new File("out"); - - if (!out.isDirectory()) { - if (!out.mkdirs()) { - throw new IOException("Could not create directory: " + out); - } - } - - var facts = new TreeMap, FactCollection>(Comparator.comparing(Class::getName)); - for (var handle : factHandles) { - if (handle instanceof DefaultFactHandle h) { - var obj = h.getObject(); - if (!filter.apply(obj)) { - continue; - } - - Class type = obj.getClass(); - var collection = facts.get(type); - - if (collection == null) { - collection = new FactCollection(type); - facts.put(type, collection); - } - - collection.values.add(obj); - } - } - - var factory = mapper.getFactory(); - try (var writer = new FileWriter(new File(out, s + ".yaml")); - var g = factory.createGenerator(writer)) { - for (var e : facts.entrySet()) { - var name = e.getKey().getName(); - - var collection = e.getValue(); - collection.sort(); - for (var fact : collection.values) { - g.writeObject(new AcmeObject(name, mapper.valueToTree(fact))); - } - } - } - } - - 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/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeMyApp.java b/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeMyApp.java deleted file mode 100644 index a1340e7..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeMyApp.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.trygvis.rules.acme; - -public class AcmeMyApp { - public String environment; - public String dockerTag; -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeObject.java b/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeObject.java deleted file mode 100644 index a75c4ba..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeObject.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.trygvis.rules.acme; - -import com.fasterxml.jackson.databind.node.ObjectNode; - -public final class AcmeObject { - public String type; - public ObjectNode data; - - public AcmeObject() { - } - - public AcmeObject(String type, ObjectNode data) { - this.type = type; - this.data = data; - } -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeOps.java b/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeOps.java deleted file mode 100644 index 147fcfa..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/acme/AcmeOps.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.trygvis.rules.acme; - -public class AcmeOps { -} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java new file mode 100644 index 0000000..b835da5 --- /dev/null +++ b/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbIo.java @@ -0,0 +1,259 @@ +package io.trygvis.rules.engine; + +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; +import java.io.FileWriter; +import java.io.IOException; +import java.util.*; +import java.util.function.Function; + +@SuppressWarnings("unchecked") +public class DbIo { + private final ObjectMapper mapper; + + public DbIo(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(); + } + + public List load(String file) throws IOException { + var parser = mapper.getFactory().createParser(new File(file)); + + var objects = mapper.readValues(parser, DbObject.class).readAll(new ArrayList<>()); + + List items = new ArrayList<>(objects.size()); + for (DbObject object : objects) { + try { + var type = mapper.getTypeFactory().findClass(object.type); + var x = mapper.treeToValue(object.data, type); + items.add(x); + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + } + + return items; + } + + public void dump(String s, Collection factHandles) throws IOException { + dump(s, factHandles, (o) -> true); + } + + // This should just sort by all getters instead. + static class FactCollection { + public final Class type; + public final List values; + + public FactCollection(Class type) { + this.type = type; + this.values = new ArrayList<>(); + } + + public void sort() { + var comparator = comparable(type); + + this.values.sort(comparator); + } + } + + private static final Map, Comparator> comparators = new HashMap<>(); + + private static > Comparator comparable(Class klass) { + var comparator = comparators.get(klass); + if (comparator != null) { + return comparator; + } + + // TODO: check if klass is a Comparable directly. + + var prioritizedKeys = List.of("key", "name", "fqdn"); + + var discoveredFieldsP1 = new LinkedHashMap>(); + var discoveredFieldsP2 = new LinkedHashMap>(); + + var prioritizedTypes = List.of(String.class, int.class, Number.class); + + for (var f : klass.getDeclaredFields()) { + if (f.getDeclaringClass() == Object.class) { + continue; + } + + if (!f.trySetAccessible()) { + continue; + } + + var collection = discoveredFieldsP2; + + if (prioritizedTypes.contains(f.getType())) { + collection = discoveredFieldsP1; + } + + collection.put(f.getName(), (Object o) -> { + try { + return f.get(o); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + } + +// for (var m : klass.getFields()) { +// if (m.getParameterCount() != 0) { +// continue; +// } +// +// var name = m.getName(); +// +// if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(4))) { +// name = name.substring(3, 3).toLowerCase() + name.substring(4); +// } else { +// continue; +// } +// +// if (!m.isAccessible()) { +// if (!m.trySetAccessible()) +// return null; +// } +// +// discoveredFields.put(name, m); +// } + +// System.out.printf("Sorting %s by:%n", klass.getName()); + + var discoveredFields = new LinkedHashMap<>(discoveredFieldsP1); + discoveredFields.putAll(discoveredFieldsP2); + + List> accessors = new ArrayList<>(); + for (String prioritizedKey : prioritizedKeys) { + var m = discoveredFields.remove(prioritizedKey); + if (m == null) { + continue; + } + + accessors.add(m); +// System.out.println(" + " + prioritizedKey); + } + accessors.addAll(discoveredFields.values()); +// discoveredFields.keySet().forEach((s)-> System.out.println(" - " + s)); + + comparator = (a, b) -> { +// if (klass.getName().contains("AcmeServer")) { +// System.out.println("AcmeIo.comparable"); +// } + + for (var method : accessors) { + var x = method.apply(a); + var y = method.apply(b); + + if (x == null && y == null) { + continue; + } + + if (x == null) { + return -1; + } else if (y == null) { + return 1; + } else { + var res = x.toString().compareTo(y.toString()); + if (res != 0) { + return res; + } + } + } + + return 0; + }; + + comparators.put(klass, comparator); + + return comparator; + } + + public void dump(String s, Collection factHandles, Function filter) throws IOException { + var out = new File("out"); + + if (!out.isDirectory()) { + if (!out.mkdirs()) { + throw new IOException("Could not create directory: " + out); + } + } + + var facts = new TreeMap, FactCollection>(Comparator.comparing(Class::getName)); + for (var handle : factHandles) { + if (handle instanceof DefaultFactHandle h) { + var obj = h.getObject(); + if (!filter.apply(obj)) { + continue; + } + + Class type = obj.getClass(); + var collection = facts.get(type); + + if (collection == null) { + collection = new FactCollection(type); + facts.put(type, collection); + } + + collection.values.add(obj); + } + } + + var factory = mapper.getFactory(); + try (var writer = new FileWriter(new File(out, s + ".yaml")); + var g = factory.createGenerator(writer)) { + for (var e : facts.entrySet()) { + var name = e.getKey().getName(); + + var collection = e.getValue(); + collection.sort(); + for (var fact : collection.values) { + g.writeObject(new DbObject(name, mapper.valueToTree(fact))); + } + } + } + } + + 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/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java new file mode 100644 index 0000000..6b9817e --- /dev/null +++ b/module/ri-engine/src/main/java/io/trygvis/rules/engine/DbObject.java @@ -0,0 +1,16 @@ +package io.trygvis.rules.engine; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +public final class DbObject { + public String type; + public ObjectNode data; + + public DbObject() { + } + + public DbObject(String type, ObjectNode data) { + this.type = type; + this.data = data; + } +} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java new file mode 100644 index 0000000..2565112 --- /dev/null +++ b/module/ri-engine/src/main/java/io/trygvis/rules/engine/Engine.java @@ -0,0 +1,46 @@ +package io.trygvis.rules.engine; + +import org.drools.core.audit.WorkingMemoryConsoleLogger; +import org.kie.api.KieServices; +import org.kie.api.event.rule.AgendaEventListener; +import org.kie.api.event.rule.RuleRuntimeEventListener; +import org.kie.api.runtime.KieSession; + +import java.io.Closeable; +import java.io.IOException; + +public class Engine implements Closeable { + public final DbIo io; + public final KieSession session; + + public Engine(String database) throws IOException { + var services = KieServices.Factory.get(); + var container = services.getKieClasspathContainer(); + var kieBase = container.getKieBase(); + + io = new DbIo(kieBase); + var objects = io.load(database); + + session = container.newKieSession(); + + session.setGlobal("te", new TemplateEngine()); + + for (var object : objects) { + System.out.println("object = " + object); + session.insert(object); + } + + var logger = new WorkingMemoryConsoleLogger(session); + session.addEventListener((AgendaEventListener) logger); + session.addEventListener((RuleRuntimeEventListener) logger); + + session.getAgenda().getAgendaGroup("init").setFocus(); + + session.fireAllRules(); + } + + @Override + public void close() { + session.dispose(); + } +} diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java deleted file mode 100644 index 7c96be6..0000000 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/Main.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.trygvis.rules.engine; - -import io.trygvis.rules.acme.AcmeIo; -import io.trygvis.rules.dns.DnsEntry; -import io.trygvis.rules.machine.Machine; -import io.trygvis.rules.network.Ipv4Address; -import io.trygvis.rules.network.Ipv4Cidr; -import org.drools.core.audit.WorkingMemoryConsoleLogger; -import org.kie.api.KieServices; -import org.kie.api.event.rule.AgendaEventListener; -import org.kie.api.event.rule.RuleRuntimeEventListener; - -import java.io.IOException; - -public class Main { - public static void main(String[] args) throws IOException { - 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 session = container.newKieSession(); - - session.setGlobal("te", new TemplateEngine()); - - for (var object : objects) { - System.out.println("object = " + object); - session.insert(object); - } - - var logger = new WorkingMemoryConsoleLogger(session); - session.addEventListener((AgendaEventListener) logger); - session.addEventListener((RuleRuntimeEventListener) logger); - - session.getAgenda().getAgendaGroup("init").setFocus(); - - session.fireAllRules(); - - io.dump("phase-1", session.getFactHandles()); - - io.dump("vpn0", session.getFactHandles(), (Object o) -> - o.getClass().getName().contains("Wg") - || o instanceof Machine - || o instanceof DnsEntry - || o instanceof Ipv4Cidr - || o instanceof Ipv4Address - ); - - session.dispose(); - } -} diff --git a/module/ri-engine/src/main/resources/META-INF/kmodule.xml b/module/ri-engine/src/main/resources/META-INF/kmodule.xml index 7a46b1a..ffba357 100644 --- a/module/ri-engine/src/main/resources/META-INF/kmodule.xml +++ b/module/ri-engine/src/main/resources/META-INF/kmodule.xml @@ -3,9 +3,6 @@ xmlns="http://www.drools.org/xsd/kmodule" xsi:schemaLocation="http://www.drools.org/xsd/kmodule https://www.drools.org/xsd/kmodule_7_1.xsd"> - - - + diff --git a/module/ri-engine/src/main/resources/io/trygvis/rules/acme/acme.drl b/module/ri-engine/src/main/resources/io/trygvis/rules/acme/acme.drl deleted file mode 100644 index 7d53763..0000000 --- a/module/ri-engine/src/main/resources/io/trygvis/rules/acme/acme.drl +++ /dev/null @@ -1,58 +0,0 @@ -package io.trygvis.rules.acme; - -import io.trygvis.rules.machine.Machine; -import io.trygvis.rules.dba.Cluster; -import io.trygvis.rules.dba.Container; - -dialect "mvel" - -declare AcmeServer - name : String - machine : Machine -end - -rule "Ops" -when - $ops: AcmeOps() -then - var cluster = new Cluster("acme-ops"); - insert(cluster); - insert(new Container(cluster, "app", "pdb", "postgresql", "11")); - insert(new Container(cluster, "app", "n8n", "n8n", "0.84.1")); -end - -rule "MyApp" -when - $app: AcmeMyApp() -then - var cluster = new Cluster("acme-" + $app.environment); - insert(cluster); - - var tag = $app.dockerTag; - insert(new Container(cluster, "app", "statera", "statera", tag)); - insert(new Container(cluster, "app", "statera-console", "statera-console", tag)); - insert(new Container(cluster, "app", "4tune-web", "4tune-web", tag)); - insert(new Container(cluster, "app", "4tune-api", "4tune-api", tag)); - 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-")) - not(AcmeServer(name == $m.name)) -then - var s = new AcmeServer(); - s.name = $m.name; - s.machine = $m; - insert(s); -end - -rule "Set public domain for ACME servers" -when - $m : Machine(fqdn == null) - $s : AcmeServer(machine == $m) -then - $s.machine.fqdn = "%s.machine.acme.com".formatted($s.machine.name); - update($s.machine) -end diff --git a/module/ri-engine/src/main/resources/io/trygvis/rules/dba/dba.drl b/module/ri-engine/src/main/resources/io/trygvis/rules/dba/dba.drl deleted file mode 100644 index 7beceef..0000000 --- a/module/ri-engine/src/main/resources/io/trygvis/rules/dba/dba.drl +++ /dev/null @@ -1 +0,0 @@ -package io.trygvis.rules.dba; diff --git a/module/ri-engine/src/main/resources/io/trygvis/rules/engine/default.drl b/module/ri-engine/src/main/resources/io/trygvis/rules/engine/default.drl index 090fddf..a933bd9 100644 --- a/module/ri-engine/src/main/resources/io/trygvis/rules/engine/default.drl +++ b/module/ri-engine/src/main/resources/io/trygvis/rules/engine/default.drl @@ -1,4 +1,5 @@ package io.trygvis.rules.engine; + import java.util.Map import org.apache.commons.io.FileSystem import org.apache.commons.io.FileUtils diff --git a/module/ri-engine/src/main/resources/io/trygvis/rules/machine/machine.drl b/module/ri-engine/src/main/resources/io/trygvis/rules/machine/machine.drl deleted file mode 100644 index a9a379f..0000000 --- a/module/ri-engine/src/main/resources/io/trygvis/rules/machine/machine.drl +++ /dev/null @@ -1,6 +0,0 @@ -package io.trygvis.rules.machine; - -import io.trygvis.rules.dba.Cluster; -import io.trygvis.rules.dba.Container; -import io.trygvis.rules.machine.Machine; -import io.trygvis.rules.dns.DnsEntry; diff --git a/module/ri-wireguard/src/main/resources/META-INF/kmodule.xml b/module/ri-wireguard/src/main/resources/META-INF/kmodule.xml index f046259..de617f7 100644 --- a/module/ri-wireguard/src/main/resources/META-INF/kmodule.xml +++ b/module/ri-wireguard/src/main/resources/META-INF/kmodule.xml @@ -4,6 +4,6 @@ xsi:schemaLocation="http://www.drools.org/xsd/kmodule https://www.drools.org/xsd/kmodule_7_1.xsd"> - + diff --git a/out/phase-1.yaml b/out/phase-1.yaml index 9ebaa02..91b0524 100644 --- a/out/phase-1.yaml +++ b/out/phase-1.yaml @@ -1,29 +1,29 @@ --- -type: "io.trygvis.rules.acme.AcmeMyApp" +type: "io.trygvis.acme.AcmeMyApp" data: environment: "ci" dockerTag: "development" --- -type: "io.trygvis.rules.acme.AcmeMyApp" +type: "io.trygvis.acme.AcmeMyApp" data: environment: "production" dockerTag: "master" --- -type: "io.trygvis.rules.acme.AcmeServer" +type: "io.trygvis.acme.AcmeServer" data: name: "acme-1" machine: name: "acme-1" fqdn: "acme-1.machine.acme.com" --- -type: "io.trygvis.rules.acme.AcmeServer" +type: "io.trygvis.acme.AcmeServer" data: name: "acme-2" machine: name: "acme-2" fqdn: "acme-2.machine.acme.com" --- -type: "io.trygvis.rules.acme.AcmeServer" +type: "io.trygvis.acme.AcmeServer" data: name: "acme-3" machine: diff --git a/pom.xml b/pom.xml index 70a06b2..244420f 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,12 @@ import + + commons-io + commons-io + 2.8.0 + + com.fasterxml.jackson.dataformat jackson-dataformat-yaml @@ -59,6 +65,7 @@ + module/acme module/ri-engine module/ri-wireguard -- cgit v1.2.3