diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2021-02-03 16:35:48 +0100 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2021-02-03 16:35:48 +0100 |
commit | bafe762ac01d16904c18404283027e426e19bc73 (patch) | |
tree | c22688ad186f5ce635f525704c5035f91b983b68 /src/ri-planner | |
parent | 91abd0b04320a9c9d932df195aca38c1cacfcc5a (diff) | |
download | rules-sandbox-bafe762ac01d16904c18404283027e426e19bc73.tar.gz rules-sandbox-bafe762ac01d16904c18404283027e426e19bc73.tar.bz2 rules-sandbox-bafe762ac01d16904c18404283027e426e19bc73.tar.xz rules-sandbox-bafe762ac01d16904c18404283027e426e19bc73.zip |
Code reorganization.
Moving main code to src, keeping modules in modules/
Diffstat (limited to 'src/ri-planner')
11 files changed, 417 insertions, 0 deletions
diff --git a/src/ri-planner/classpath.txt b/src/ri-planner/classpath.txt new file mode 100644 index 0000000..411ee43 --- /dev/null +++ b/src/ri-planner/classpath.txt @@ -0,0 +1,90 @@ +io.trygvis.rules-sandbox:acme-planner:1.0-SNAPSHOT:jar +ch.obermuhlner:big-math:2.0.0: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.javaparser:javaparser-core:3.13.10: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.sun.activation:jakarta.activation:1.2.2:jar +com.sun.istack:istack-commons-runtime:3.0.8:jar +com.thoughtworks.xstream:xstream:1.4.14:jar +com.zaxxer:SparseBitSet:1.2:jar +commons-codec:commons-codec:1.14:jar +commons-io:commons-io:2.8.0:jar +commons-net:commons-net:3.3:jar +info.picocli:picocli:4.6.1:jar +io.trygvis.rules-sandbox:ri-engine:1.0-SNAPSHOT:jar +io.trygvis.rules-sandbox.module:ri-module-api:1.0-SNAPSHOT:jar +jakarta.activation:jakarta.activation-api:1.2.2:jar +jakarta.xml.bind:jakarta.xml.bind-api:2.3.3: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.10: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-canonical-model:7.48.0.Final:jar +org.drools:drools-compiler:7.48.0.Final:jar +org.drools:drools-core:7.48.0.Final:jar +org.drools:drools-core-dynamic:7.48.0.Final:jar +org.drools:drools-core-reflective:7.48.0.Final:jar +org.drools:drools-decisiontables:7.48.0.Final:jar +org.drools:drools-ecj:7.48.0.Final:jar +org.drools:drools-model-compiler:7.48.0.Final:jar +org.drools:drools-mvel:7.48.0.Final:jar +org.drools:drools-mvel-compiler:7.48.0.Final:jar +org.drools:drools-mvel-parser:7.48.0.Final:jar +org.drools:drools-templates:7.48.0.Final:jar +org.glassfish.jaxb:jaxb-runtime:2.3.3:jar +org.glassfish.jaxb:txw2:2.3.3:jar +org.javassist:javassist:3.24.1-GA:jar +org.jsoup:jsoup:1.10.3:jar +org.kie:kie-api:7.48.0.Final:jar +org.kie:kie-internal:7.48.0.Final:jar +org.kie:kie-memory-compiler:7.48.0.Final:jar +org.kie.kogito:drools-compiler:1.1.0.Final:jar +org.kie.kogito:drools-core:1.1.0.Final:jar +org.kie.kogito:drools-core-dynamic:1.1.0.Final:jar +org.kie.kogito:drools-core-static:1.1.0.Final:jar +org.kie.kogito:kogito-api:1.1.0.Final:jar +org.kie.kogito:kogito-drools-model:1.1.0.Final:jar +org.kie.kogito:kogito-internal:1.1.0.Final:jar +org.kie.kogito:kogito-services:1.1.0.Final:jar +org.kie.soup:kie-soup-commons:7.48.0.Final:jar +org.kie.soup:kie-soup-maven-support:7.48.0.Final:jar +org.kie.soup:kie-soup-project-datamodel-api:7.48.0.Final:jar +org.kie.soup:kie-soup-project-datamodel-commons:7.48.0.Final:jar +org.kie.soup:kie-soup-xstream:7.48.0.Final:jar +org.mvel:mvel2:2.4.11.Final:jar +org.optaplanner:optaplanner-core:8.1.0.Final:jar +org.optaplanner:optaplanner-persistence-common:8.1.0.Final:jar +org.optaplanner:optaplanner-persistence-jackson:8.1.0.Final:jar +org.optaplanner:optaplanner-spring-boot-autoconfigure:8.1.0.Final:jar +org.optaplanner:optaplanner-spring-boot-starter:8.1.0.Final:jar +org.slf4j:slf4j-api:1.7.30:jar +org.springframework:spring-aop:5.2.7.RELEASE:jar +org.springframework:spring-beans:5.2.7.RELEASE:jar +org.springframework:spring-context:5.2.7.RELEASE:jar +org.springframework:spring-core:5.2.7.RELEASE:jar +org.springframework:spring-expression:5.2.7.RELEASE:jar +org.springframework:spring-jcl:5.2.7.RELEASE:jar +org.springframework.boot:spring-boot:2.3.1.RELEASE:jar +org.springframework.boot:spring-boot-autoconfigure:2.3.1.RELEASE:jar +org.yaml:snakeyaml:1.26:jar +xmlpull:xmlpull:1.1.3.1:jar +xpp3:xpp3_min:1.1.4c:jar diff --git a/src/ri-planner/pom.xml b/src/ri-planner/pom.xml new file mode 100644 index 0000000..ed8699d --- /dev/null +++ b/src/ri-planner/pom.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>io.trygvis.rules-sandbox</groupId> + <artifactId>rules-sandbox</artifactId> + <version>1.0-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> + </parent> + + <artifactId>acme-planner</artifactId> + + <dependencies> + <dependency> + <groupId>org.optaplanner</groupId> + <artifactId>optaplanner-spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>ri-engine</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.optaplanner</groupId> + <artifactId>optaplanner-spring-boot-starter</artifactId> + <version>8.1.0.Final</version> + </dependency> + </dependencies> + </dependencyManagement> + +</project> diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java new file mode 100644 index 0000000..7311918 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java @@ -0,0 +1,48 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty; +import org.optaplanner.core.api.domain.solution.PlanningScore; +import org.optaplanner.core.api.domain.solution.PlanningSolution; +import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty; +import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider; +import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; + +import java.util.List; + +@PlanningSolution +public class CloudBalance { + + private List<CloudComputer> computerList; + + private List<CloudProcess> processList; + + private HardSoftScore score; + + public CloudBalance(List<CloudComputer> computerList, List<CloudProcess> processList) { + this.computerList = computerList; + this.processList = processList; + } + + public CloudBalance() { + } + + @ValueRangeProvider(id = "computerRange") + @ProblemFactCollectionProperty + public List<CloudComputer> getComputerList() { + return computerList; + } + + @PlanningEntityCollectionProperty + public List<CloudProcess> getProcessList() { + return processList; + } + + @PlanningScore + public HardSoftScore getScore() { + return score; + } + + public void setScore(HardSoftScore score) { + this.score = score; + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java new file mode 100644 index 0000000..6a14372 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java @@ -0,0 +1,45 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; +import org.optaplanner.core.api.score.calculator.EasyScoreCalculator; + +public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance, HardSoftScore> { + + @Override + public HardSoftScore calculateScore(CloudBalance cloudBalance) { + int hardScore = 0; + int softScore = 0; + for (CloudComputer computer : cloudBalance.getComputerList()) { + int cpu = 0; + int memory = 0; + boolean used = false; + + // Calculate usage + for (CloudProcess process : cloudBalance.getProcessList()) { + if (computer.equals(process.computer)) { + cpu += process.requiredCpu; + memory += process.requiredMemory; + used = true; + } + } + + var instance = computer.instance; + + // Hard constraints + int cpuPowerAvailable = instance.cpu - cpu; + if (cpuPowerAvailable < 0) { + hardScore += cpuPowerAvailable; + } + int memoryAvailable = instance.memory - memory; + if (memoryAvailable < 0) { + hardScore += memoryAvailable; + } + + // Soft constraints + if (used) { + softScore -= instance.cost; + } + } + return HardSoftScore.of(hardScore, softScore); + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java new file mode 100644 index 0000000..aa2087d --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java @@ -0,0 +1,16 @@ +package io.trygvis.acme.planning.machine; + +public class CloudComputer { + public final String host; + public final ScalewayInstance instance; + + public CloudComputer(String host, ScalewayInstance instance) { + this.host = host; + this.instance = instance; + } + + @Override + public String toString() { + return host; + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java new file mode 100644 index 0000000..60b3fd3 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java @@ -0,0 +1,52 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.solver.SolverFactory; + +import java.util.ArrayList; + +public class CloudPlaningMain { + public static final ScalewayInstance Stardust1_s = new ScalewayInstance("Stardust1-s", 0.0025, 1000, 1000); + public static final ScalewayInstance DEV1_S = new ScalewayInstance("DEV1-S", 0.01, 2000, 2000); + public static final ScalewayInstance DEV1_M = new ScalewayInstance("DEV1-M", 0.02, 3000, 4000); + public static final ScalewayInstance DEV1_L = new ScalewayInstance("DEV1-L", 0.04, 4000, 8000); + public static final ScalewayInstance DEV1_XL = new ScalewayInstance("DEV1-XL", 0.06, 4000, 12000); + + public static void main(String[] args) { + var solverFactory = SolverFactory.<CloudBalance>createFromXmlResource("io/trygvis/acme/planning/machine/solver-config.xml"); + var solver = solverFactory.buildSolver(); + + var computers = new ArrayList<CloudComputer>(); + + computers.add(new CloudComputer("acme-1", DEV1_S)); + computers.add(new CloudComputer("acme-2", DEV1_M)); + computers.add(new CloudComputer("acme-3", DEV1_S)); + + var processes = new ArrayList<CloudProcess>(); + + processes.add(new CloudProcess("statera", 200, 1000)); + processes.add(new CloudProcess("statera-console", 100, 50)); + processes.add(new CloudProcess("4tune-web", 100, 50)); + processes.add(new CloudProcess("4tune-api", 200, 200)); + processes.add(new CloudProcess("pdb", 500, 500)); + processes.add(new CloudProcess("mdb", 500, 200)); + + var unsolvedCloudBalance = new CloudBalance(computers, processes); + + var solvedCloudBalance = solver.solve(unsolvedCloudBalance); + + System.out.println("solvedCloudBalance.getScore() = " + solvedCloudBalance.getScore()); + for (CloudProcess process : solvedCloudBalance.getProcessList()) { + System.out.println("process.id = " + process.id); + if (process.computer == null) { + System.out.println("COMPUTER IS NULL"); + } else { + System.out.println("process.computer.host = " + process.computer.host); + } + } + + System.out.println("------------------------------------------------------------------------"); + +// System.out.println("\nSolved cloudBalance with 400 computers and 1200 processes:\n" +// + toDisplayString(solvedCloudBalance)); + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java new file mode 100644 index 0000000..c629656 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java @@ -0,0 +1,22 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.domain.entity.PlanningEntity; +import org.optaplanner.core.api.domain.variable.PlanningVariable; + +@PlanningEntity() +public class CloudPlanner { + private int requiredCpuPower; + private int requiredMemory; + private int requiredNetworkBandwidth; + + private CloudComputer computer; + + @PlanningVariable(valueRangeProviderRefs = {"computerRange"}) + public CloudComputer getComputer() { + return computer; + } + + public void setComputer(CloudComputer computer) { + this.computer = computer; + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java new file mode 100644 index 0000000..2002903 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java @@ -0,0 +1,48 @@ +package io.trygvis.acme.planning.machine; + +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.optaplanner.core.api.domain.entity.PlanningEntity; +import org.optaplanner.core.api.domain.variable.PlanningVariable; + +import java.util.Comparator; + +@PlanningEntity(difficultyComparatorClass = CloudProcessDifficultyComparator.class) +public class CloudProcess { + public String id; + public int requiredCpu; + public int requiredMemory; + public int requiredMultiplicand; + + @PlanningVariable( + valueRangeProviderRefs = "computerRange", + strengthComparatorClass = CloudComputerStrengthComparator.class) + public CloudComputer computer; + + public CloudProcess(String id, int requiredCpu, int requiredMemory) { + this.id = id; + this.requiredCpu = requiredCpu; + this.requiredMemory = requiredMemory; + + this.requiredMultiplicand = requiredCpu * requiredMemory; + } + + @SuppressWarnings("unused") + public CloudProcess() { + } + + public String toString() { + return id; + } + + public static class CloudComputerStrengthComparator implements Comparator<CloudComputer> { + public int compare(CloudComputer a, CloudComputer b) { + var x = a.instance; + var y = b.instance; + return new CompareToBuilder() + .append(x.multiplicand, y.multiplicand) + .append(y.cost, x.cost) // Descending (but this is debatable) + .append(x.kind, y.kind) + .toComparison(); + } + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java new file mode 100644 index 0000000..658e826 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java @@ -0,0 +1,15 @@ +package io.trygvis.acme.planning.machine; + +import org.apache.commons.lang3.builder.CompareToBuilder; + +import java.util.Comparator; + +public class CloudProcessDifficultyComparator implements Comparator<CloudProcess> { + + public int compare(CloudProcess a, CloudProcess b) { + return new CompareToBuilder() + .append(a.requiredMultiplicand, b.requiredMultiplicand) + .append(a.id, b.id) + .toComparison(); + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java new file mode 100644 index 0000000..dfdc0e0 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java @@ -0,0 +1,25 @@ +package io.trygvis.acme.planning.machine; + +public class ScalewayInstance { + public final String kind; + // Euros / hour + public final double cost; + public final int cpu; + public final int memory; + + public int multiplicand; + + public ScalewayInstance(String kind, double cost, int cpu, int memory) { + this.kind = kind; + this.cost = cost; + this.cpu = cpu; + this.memory = memory; + + this.multiplicand = cpu * memory; + } + + @Override + public String toString() { + return kind; + } +} diff --git a/src/ri-planner/src/main/resources/io/trygvis/acme/planning/machine/solver-config.xml b/src/ri-planner/src/main/resources/io/trygvis/acme/planning/machine/solver-config.xml new file mode 100644 index 0000000..81ae8ed --- /dev/null +++ b/src/ri-planner/src/main/resources/io/trygvis/acme/planning/machine/solver-config.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd"> + <!-- Domain model configuration --> + <solutionClass>io.trygvis.acme.planning.machine.CloudBalance</solutionClass> + <entityClass>io.trygvis.acme.planning.machine.CloudProcess</entityClass> + + <!-- Score configuration --> + <scoreDirectorFactory> + <easyScoreCalculatorClass>io.trygvis.acme.planning.machine.CloudBalancingEasyScoreCalculator</easyScoreCalculatorClass> + <!--<scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingConstraints.drl</scoreDrl>--> + </scoreDirectorFactory> + + <!-- Optimization algorithms configuration --> + <termination> + <secondsSpentLimit>3</secondsSpentLimit> + </termination> +</solver> |