diff options
21 files changed, 213 insertions, 41 deletions
@@ -0,0 +1,11 @@ +#!/bin/bash + +set -euo pipefail + +basedir="$(dirname $0)" +jar="$(echo $basedir/module/ri-engine/target/ri-engine-*-fat.jar)" + +exec java \ + --enable-preview \ + -jar "$jar" \ + "${@}" diff --git a/module/acme/src/main/resources/META-INF/kmodule.xml b/module/acme/src/main/resources/META-INF/kmodule.xml index 6bcd1db..da435d6 100644 --- a/module/acme/src/main/resources/META-INF/kmodule.xml +++ b/module/acme/src/main/resources/META-INF/kmodule.xml @@ -11,7 +11,7 @@ <ksession name="acme-wireguard" default="true"/> </kbase> - <kbase packages="io.trygvis.acme" name="acme-shared"> + <kbase name="acme-shared" packages="io.trygvis.acme"> <ksession name="acme-shared" default="true"/> </kbase> </kmodule> diff --git a/module/ri-base/src/main/java/io/trygvis/rules/machine/MachineSpecification.java b/module/ri-base/src/main/java/io/trygvis/rules/machine/MachineSpecification.java index 2e17ae5..9d38b2d 100644 --- a/module/ri-base/src/main/java/io/trygvis/rules/machine/MachineSpecification.java +++ b/module/ri-base/src/main/java/io/trygvis/rules/machine/MachineSpecification.java @@ -1,8 +1,10 @@ package io.trygvis.rules.machine; public class MachineSpecification { - public final int cpu; - public final int memory; + public int cpu; + public int memory; + + protected MachineSpecification() {} public MachineSpecification(int cpu, int memory) { this.cpu = cpu; diff --git a/module/ri-base/src/main/resources/io/trygvis/rules/terraform/terraform.drl b/module/ri-base/src/main/resources/io/trygvis/rules/terraform/terraform.drl index 5ebd082..7313998 100644 --- a/module/ri-base/src/main/resources/io/trygvis/rules/terraform/terraform.drl +++ b/module/ri-base/src/main/resources/io/trygvis/rules/terraform/terraform.drl @@ -50,7 +50,7 @@ when $managedZones : ArrayList() from collect(GoogleManagedZoneTerraformExpression()) then String path = "terraform/main-scaleway-machine.tf"; - te.template("terraform-main-scaleway-machine", path, Map.of( + te.template("terraform/main-scaleway-machine", path, Map.of( "managedZones", $managedZones )); end @@ -62,7 +62,7 @@ when $scw: ScalewayMachine(machine == $m) then String path = "terraform/scaleway-machine-%s.tf".formatted($scw.getKey()); - te.template("terraform-machine", path, Map.of("m", $m, "scw", $scw)); + te.template("terraform/machine", path, Map.of("m", $m, "scw", $scw)); end rule "Terraform for DNS" @@ -73,7 +73,7 @@ when $managedZone : GoogleManagedZoneTerraformExpression() then String path = "terraform/dns-%s.tf".formatted($tf.key); - te.template("terraform-record-set", path, Map.of( + te.template("terraform/record-set", path, Map.of( "entry", $entry, "managedZone", $managedZone, "tf", $tf) diff --git a/j2/dba/cluster.j2 b/module/ri-base/src/main/resources/templates/dba/cluster.j2 index 045fbcd..045fbcd 100644 --- a/j2/dba/cluster.j2 +++ b/module/ri-base/src/main/resources/templates/dba/cluster.j2 diff --git a/j2/platform-ansible.j2 b/module/ri-base/src/main/resources/templates/platform-ansible.j2 index 72e3247..72e3247 100644 --- a/j2/platform-ansible.j2 +++ b/module/ri-base/src/main/resources/templates/platform-ansible.j2 diff --git a/j2/terraform-machine-outputs.j2 b/module/ri-base/src/main/resources/templates/terraform/machine-outputs.j2 index 438fac6..438fac6 100644 --- a/j2/terraform-machine-outputs.j2 +++ b/module/ri-base/src/main/resources/templates/terraform/machine-outputs.j2 diff --git a/j2/terraform-machine.j2 b/module/ri-base/src/main/resources/templates/terraform/machine.j2 index 0ac8b90..0ac8b90 100644 --- a/j2/terraform-machine.j2 +++ b/module/ri-base/src/main/resources/templates/terraform/machine.j2 diff --git a/j2/terraform-main-scaleway-machine.j2 b/module/ri-base/src/main/resources/templates/terraform/main-scaleway-machine.j2 index eab9fac..eab9fac 100644 --- a/j2/terraform-main-scaleway-machine.j2 +++ b/module/ri-base/src/main/resources/templates/terraform/main-scaleway-machine.j2 diff --git a/j2/terraform-record-set.j2 b/module/ri-base/src/main/resources/templates/terraform/record-set.j2 index b89ee00..b89ee00 100644 --- a/j2/terraform-record-set.j2 +++ b/module/ri-base/src/main/resources/templates/terraform/record-set.j2 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 index d3d309a..e2abd5a 100644 --- 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 @@ -14,9 +14,10 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import org.drools.core.common.DefaultFactHandle; import org.drools.core.factmodel.GeneratedFact; import org.kie.api.KieBase; -import org.kie.api.definition.type.FactType; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.rule.FactHandle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileWriter; @@ -27,6 +28,8 @@ import java.util.function.Function; @SuppressWarnings("unchecked") public class DbIo { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final ObjectMapper mapper; private static final List<String> prioritizedKeys = List.of("key", "name", "fqdn"); @@ -268,9 +271,9 @@ public class DbIo { } } - private static class DbClassLoader extends ClassLoader { - private final KieBase kieBase; + private class DbClassLoader extends ClassLoader { private final KieContainer container; + private final KieBase kieBase; public DbClassLoader(KieContainer container, KieBase kieBase) { this.container = container; @@ -279,35 +282,43 @@ public class DbIo { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { + logger.info("Loading class {}", name); try { - return super.loadClass(name); + var klass = super.loadClass(name); + logger.info("Found class in super classloader"); + return klass; } catch (ClassNotFoundException e) { var i = name.lastIndexOf('.'); - String pkg, klass; + String pkg, simpleName; if (i == -1) { pkg = null; - klass = name; + simpleName = name; } else { pkg = name.substring(0, i); - klass = name.substring(i + 1); + simpleName = name.substring(i + 1); } try { - return container.getClassLoader().loadClass(name); + var klass = container.getClassLoader().loadClass(name); + logger.info("Found class in container's classloader"); + return klass; } catch (ClassNotFoundException ignore) { } - FactType clazz = null; try { - clazz = kieBase.getFactType(pkg, klass); + logger.info("pkg = {}", pkg); + logger.info("simpleName = {}", simpleName); + var clazz = kieBase.getFactType(pkg, simpleName); + if (clazz != null) { + logger.info("Found class as a FactType"); + return clazz.getFactClass(); + } } catch (UnsupportedOperationException ignore) { - System.out.println("AcmeClassLoader.loadClass: " + name); - } - if (clazz == null) { - throw e; } - return clazz.getFactClass(); + logger.warn("Class not found: {}", name); + + throw e; } } } 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 index f73419a..4a49ca2 100644 --- 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 @@ -1,6 +1,7 @@ package io.trygvis.rules.engine; import org.drools.core.audit.WorkingMemoryConsoleLogger; +import org.drools.reflective.classloader.ProjectClassLoader; import org.kie.api.KieServices; import org.kie.api.event.rule.AgendaEventListener; import org.kie.api.event.rule.RuleRuntimeEventListener; @@ -12,10 +13,16 @@ import org.slf4j.LoggerFactory; import java.io.Closeable; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import static io.trygvis.rules.engine.TemplateEngine.TemplateLoader; + public class Engine implements Closeable { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -33,8 +40,10 @@ public class Engine implements Closeable { logger.info("kieRepository.getDefaultReleaseId() = {}", kieRepository.getDefaultReleaseId()); KieContainer container; + TemplateLoader templateLoader; if (modules != null && modules.length > 0) { List<Resource> resources = new ArrayList<>(); + List<URL> files = new ArrayList<>(); for (File path : modules) { if (!path.exists()) { logger.warn("Module path does not exist: {}", path.getAbsolutePath()); @@ -43,6 +52,10 @@ public class Engine implements Closeable { logger.info("New KieBuilder: {}, file={}, directory={}", path, path.isFile(), path.isDirectory()); + if (path.isFile()) { + files.add(path.toURI().toURL()); + } + var resource = services.getResources().newFileSystemResource(path); logger.info("resource.getResourceType() = {}", resource.getResourceType()); resources.add(resource); @@ -54,8 +67,12 @@ public class Engine implements Closeable { logger.info("Creating classpath container, releaseId=" + rId); container = services.newKieContainer(rId); + + templateLoader = new ClasspathTemplateLoader(new URLClassLoader(files.toArray(new URL[0]))); } else { - container = services.getKieClasspathContainer(); + var classLoader = ProjectClassLoader.findParentClassLoader(); + container = services.getKieClasspathContainer(classLoader); + templateLoader = new ClasspathTemplateLoader(classLoader); } logger.info("Creating KieBase \"{}\"", name); @@ -68,11 +85,17 @@ public class Engine implements Closeable { session.addEventListener((AgendaEventListener) l); session.addEventListener((RuleRuntimeEventListener) l); - session.setGlobal("te", new JinjavaTemplateEngine(output)); + session.setGlobal("te", new JinjavaTemplateEngine(templateLoader, output)); logger.info("Loading data"); io = new DbIo(container, kieBase); var objects = io.load(database); + + if (objects.isEmpty()) { + logger.warn("Did not load any objects, something is wrong"); + return; + } + logger.info("Loaded {} objects", objects.size()); for (var object : objects) { @@ -91,4 +114,25 @@ public class Engine implements Closeable { public void close() { session.dispose(); } + + private static class ClasspathTemplateLoader implements TemplateLoader { + private final ClassLoader classLoader; + + private ClasspathTemplateLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public String load(String name) throws IOException { + var resource = "templates/" + name + ".j2"; + + try (var inputStream = classLoader.getResourceAsStream(resource)) { + if (inputStream == null) { + throw new FileNotFoundException("Classpath resource: " + resource); + } + + return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } + } + } } diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java index 42b2127..286029e 100644 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java +++ b/module/ri-engine/src/main/java/io/trygvis/rules/engine/JinjavaTemplateEngine.java @@ -7,15 +7,19 @@ import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.util.Map; +/** + * TODO: cache templates. + */ public class JinjavaTemplateEngine implements TemplateEngine { private final Jinjava jinjava = new Jinjava(); + private final TemplateLoader loader; private final File basedir; - public JinjavaTemplateEngine(File basedir) { + public JinjavaTemplateEngine(TemplateLoader templateLoader, File basedir) { + this.loader = templateLoader; this.basedir = basedir; } @@ -31,7 +35,7 @@ public class JinjavaTemplateEngine implements TemplateEngine { @Override public void template(String name, String output, Map<String, Object> params) throws IOException { - var template = Files.readString(Path.of("j2", name + ".j2")); + var template = loader.load(name); String renderedTemplate = jinjava.render(template, params); var f = new File(basedir, output); FileUtil.createMissingParentDirectories(f); diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateEngine.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateEngine.java index eafa6e4..a2ae0c2 100644 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateEngine.java +++ b/module/ri-engine/src/main/java/io/trygvis/rules/engine/TemplateEngine.java @@ -1,5 +1,6 @@ package io.trygvis.rules.engine; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; @@ -7,4 +8,8 @@ public interface TemplateEngine { void clean(); void template(String name, String output, Map<String, Object> params) throws IOException; + + interface TemplateLoader { + String load(String name) throws IOException; + } } diff --git a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java b/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java index 2b016f2..203a9b0 100644 --- a/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java +++ b/module/ri-engine/src/main/java/io/trygvis/rules/engine/cli/RunCommand.java @@ -20,14 +20,18 @@ public class RunCommand implements Callable<Integer> { @Option(names = {"--output-state"}) public File outputState; + @Option(names = {"--include"}, split = ",", arity = "1..*") + public String[] includes; + @Option(names = {"--generated-output"}) public File generatedOutput; @Option(names = {"--agenda-groups"}) public String[] agendaGroups; - @Option(names = {"--modules"}, split = ",", arity = "1..*") - public File[] modules; + // TODO: Remove --modules + @Option(names = {"--modules", "--module"}, split = ",", arity = "1..*") + public File[] module; @Override public Integer call() throws Exception { @@ -36,13 +40,39 @@ public class RunCommand implements Callable<Integer> { agendaGroups = new String[]{"init", "generate"}; } - try (var engine = new Engine(name, input, generatedOutput, agendaGroups, modules)) { + try (var engine = new Engine(name, input, generatedOutput, agendaGroups, module)) { engine.io.dump(outputState, engine.session.getFactHandles(), (Object o) -> - o.getClass().getName().contains("Wg") || - o.getClass().getSimpleName().contains("Machine") || - o.getClass().getSimpleName().contains("DnsEntry") || - o.getClass().getSimpleName().contains("Ipv4Cidr") || - o.getClass().getSimpleName().contains("Ipv4Address") + { + if (includes == null || includes.length == 0) { + return true; + } + + var name = o.getClass().getName(); + var simpleName = o.getClass().getSimpleName(); + + for (var i : includes) { + var ok = false; + if (i.startsWith("*")) { + i = i.substring(1); + + if (i.endsWith("*")) { + i = i.substring(1, i.length() - 2); + ok = name.contains(i); + } else { + ok = name.startsWith(i) || simpleName.startsWith(i); + } + } else if (i.endsWith("*")) { + i = i.substring(0, i.length() - 2); + ok = name.startsWith(i) || simpleName.startsWith(i); + } + + if (ok) { + return true; + } + } + + return false; + } ); } diff --git a/module/ri-engine/src/test/java/io/trygvis/rules/engine/WireguardTestMain.java b/module/ri-engine/src/test/java/io/trygvis/rules/engine/AcmeAppsTestMain.java index 20aeffa..17b7950 100644 --- a/module/ri-engine/src/test/java/io/trygvis/rules/engine/WireguardTestMain.java +++ b/module/ri-engine/src/test/java/io/trygvis/rules/engine/AcmeAppsTestMain.java @@ -6,14 +6,14 @@ import java.io.File; import static org.junit.jupiter.api.Assertions.assertEquals; -class WireguardTestMain { +class AcmeAppsTestMain { public static void main(String[] args) throws Exception { var c = new RunCommand(); - c.name = "acme"; + c.name = "acme-apps"; c.input = new File("acme.yaml"); - c.outputState = new File("out/acme/wireguard.yaml"); + c.outputState = new File("out/acme/apps.yaml"); c.agendaGroups = new String[]{"init", "generate"}; - c.generatedOutput = new File("acme-wireguard"); + c.generatedOutput = new File("acme-apps"); assertEquals(0, c.call()); } } diff --git a/module/ri-engine/src/test/java/io/trygvis/rules/engine/AcmeWireguardTestMain.java b/module/ri-engine/src/test/java/io/trygvis/rules/engine/AcmeWireguardTestMain.java new file mode 100644 index 0000000..2bb5513 --- /dev/null +++ b/module/ri-engine/src/test/java/io/trygvis/rules/engine/AcmeWireguardTestMain.java @@ -0,0 +1,27 @@ +package io.trygvis.rules.engine; + +import io.trygvis.rules.engine.cli.RunCommand; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AcmeWireguardTestMain { + public static void main(String[] args) throws Exception { + var c = new RunCommand(); + c.name = "acme-wireguard"; + c.input = new File("acme.yaml"); + c.outputState = new File("out/acme/wireguard.yaml"); + c.agendaGroups = new String[]{"init", "generate"}; + c.generatedOutput = new File("acme-wireguard"); + c.includes = new String[]{ + "Wg*", + "Machine", + "DnsEntry", + "Ipv4Cidr", + "Ipv4Address", + }; + + assertEquals(0, c.call()); + } +} diff --git a/j2/wireguard/ansible-host.j2 b/module/ri-wireguard/src/main/resources/templates/wireguard/ansible-host.j2 index a3c8c40..a3c8c40 100644 --- a/j2/wireguard/ansible-host.j2 +++ b/module/ri-wireguard/src/main/resources/templates/wireguard/ansible-host.j2 diff --git a/j2/wireguard/ansible.j2 b/module/ri-wireguard/src/main/resources/templates/wireguard/ansible.j2 index 82c0ca0..82c0ca0 100644 --- a/j2/wireguard/ansible.j2 +++ b/module/ri-wireguard/src/main/resources/templates/wireguard/ansible.j2 diff --git a/j2/wireguard/inventory.j2 b/module/ri-wireguard/src/main/resources/templates/wireguard/inventory.j2 index 0924bb2..0924bb2 100644 --- a/j2/wireguard/inventory.j2 +++ b/module/ri-wireguard/src/main/resources/templates/wireguard/inventory.j2 diff --git a/out/acme/apps.yaml b/out/acme/apps.yaml index 0c69b8e..e0e9e88 100644 --- a/out/acme/apps.yaml +++ b/out/acme/apps.yaml @@ -76,6 +76,9 @@ image: "4tune-api" tag: "development" machine: *acme-1 + machineSpecification: + cpu: 200 + memory: 200 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-production-4tune-api" @@ -85,6 +88,9 @@ image: "4tune-api" tag: "master" machine: *acme-3 + machineSpecification: + cpu: 200 + memory: 200 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-ci-4tune-web" @@ -94,6 +100,9 @@ image: "4tune-web" tag: "development" machine: *acme-1 + machineSpecification: + cpu: 100 + memory: 50 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-production-4tune-web" @@ -103,6 +112,9 @@ image: "4tune-web" tag: "master" machine: *acme-3 + machineSpecification: + cpu: 100 + memory: 50 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-ci-mdb" @@ -112,6 +124,9 @@ image: "mongodb" tag: "3.2" machine: *acme-2 + machineSpecification: + cpu: 500 + memory: 200 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-production-mdb" @@ -121,6 +136,9 @@ image: "mongodb" tag: "3.2" machine: *acme-3 + machineSpecification: + cpu: 500 + memory: 200 - type: "io.trygvis.rules.dba.Container" data: id: "acme-ops-n8n" @@ -130,6 +148,7 @@ image: "n8n" tag: "0.84.1" machine: *acme-2 + machineSpecification: null - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-ci-pdb" @@ -139,6 +158,9 @@ image: "postgresql" tag: "13" machine: *acme-2 + machineSpecification: + cpu: 500 + memory: 500 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-production-pdb" @@ -148,6 +170,9 @@ image: "postgresql" tag: "13" machine: *acme-3 + machineSpecification: + cpu: 500 + memory: 500 - type: "io.trygvis.rules.dba.Container" data: id: "acme-ops-pdb" @@ -157,6 +182,7 @@ image: "postgresql" tag: "11" machine: *acme-2 + machineSpecification: null - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-ci-statera" @@ -166,6 +192,9 @@ image: "statera" tag: "development" machine: *acme-1 + machineSpecification: + cpu: 200 + memory: 1000 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-production-statera" @@ -175,6 +204,9 @@ image: "statera" tag: "master" machine: *acme-3 + machineSpecification: + cpu: 200 + memory: 1000 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-ci-statera-console" @@ -184,6 +216,9 @@ image: "statera-console" tag: "development" machine: *acme-1 + machineSpecification: + cpu: 100 + memory: 50 - type: "io.trygvis.rules.dba.Container" data: id: "acme-myapp-production-statera-console" @@ -193,20 +228,23 @@ image: "statera-console" tag: "master" machine: *acme-3 + machineSpecification: + cpu: 100 + memory: 50 - type: "io.trygvis.rules.dba.DbaMachineRole" data: - machine: "acme-1" + &1 machine: "acme-1" roles: - "ci-app" - type: "io.trygvis.rules.dba.DbaMachineRole" data: - machine: "acme-2" + &2 machine: "acme-2" roles: - "ops" - "ci-db" - type: "io.trygvis.rules.dba.DbaMachineRole" data: - machine: "acme-3" + &3 machine: "acme-3" roles: - "production-app" - "production-db" |