Add files from GitHub.
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
load_balancer/__pycache__
|
||||
credentials.py
|
||||
__pycache__
|
||||
sqlitedb.db
|
||||
14
README.md
Normal file
14
README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Uebersicht
|
||||
|
||||
## Kleine Boinc Projekte / Tasks
|
||||
|
||||
> LHC@home Sixtrack: https://lhcathome.cern.ch
|
||||
|
||||
> World Community Grid: https://worldcommunitygrid.org
|
||||
|
||||
> climateprediction.net: https://climateprediction.net/
|
||||
|
||||
> Rosetta@home: https://boinc.bakerlab.org/rosetta/
|
||||
|
||||
## Required Dependencies
|
||||
|
||||
10
demo.md
Normal file
10
demo.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Anleitung fuer Demo in presentation
|
||||
|
||||
AddInstance 192.52.32.182 ubuntu /Users/theresaherr/.ssh/id_rsa
|
||||
AddInstance 192.52.32.236 ubuntu /Users/theresaherr/.ssh/id_rsa
|
||||
AddInstance 192.52.34.222 ubuntu /Users/theresaherr/.ssh/id_rsa
|
||||
|
||||
StartSimulation Daily 01.03.2018 03.03.2018
|
||||
|
||||
DisplayOutcome
|
||||
StopSimulation
|
||||
BIN
docs/Project2_LoadBalancer.odp
Normal file
BIN
docs/Project2_LoadBalancer.odp
Normal file
Binary file not shown.
BIN
docs/Projekt_2_Outline_A5.odt
Normal file
BIN
docs/Projekt_2_Outline_A5.odt
Normal file
Binary file not shown.
BIN
docs/Projekt_2_Outline_A5.pdf
Normal file
BIN
docs/Projekt_2_Outline_A5.pdf
Normal file
Binary file not shown.
42
docs/database/database_description.md
Normal file
42
docs/database/database_description.md
Normal file
@@ -0,0 +1,42 @@
|
||||
Table instances:
|
||||
|
||||
A. id - Python int - SQLite INTEGER - ID der Instanz
|
||||
B. owner - Python str - SQLite TEXT - wer besitzt die Instanz?
|
||||
C. calculated_demand - Python bytes (UTF-8 encoding) - SQLite BLOB - die vorberechnete Liste ueber
|
||||
den Energiebedarf jeder Instanz
|
||||
im json Format
|
||||
Beispiel:
|
||||
{
|
||||
"energy_demands":[
|
||||
{
|
||||
"date": "01.01.2024",
|
||||
"energy_demand_in_watts": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
D. number_of_persons_in_household - Python int - SQLite INTEGER - Anzahl Personen in Haushalt
|
||||
E. fulfilled_demand - Python bytes (UTF-8 encoding) - SQLite BLOB - der tatsaechlich gedeckte Energiebedarf
|
||||
am jeweiligen Datum im json Format
|
||||
Beispiel:
|
||||
{
|
||||
"scored_demand":[
|
||||
{
|
||||
"date": "01.01.2024",
|
||||
"scored_energy_demand_in_watts": 3,
|
||||
"busy_method_used":[
|
||||
"hpc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
F. status - Python str - SQLite TEXT - Status der Instanz, "offline", "online", "error"
|
||||
G. heater_busy_methods - Python bytes (UTF-8 encoding) - SQLite BLOB - Methoden, welche die Instanz ausfuehrt im json Format
|
||||
Beispiel:
|
||||
{
|
||||
"busy_methods_active":[
|
||||
"hpc"
|
||||
]
|
||||
}
|
||||
|
||||
Table application:
|
||||
A. state - Python constants.State - SQLite TEXT - Zustand der Anwendung, Running oder Stopped
|
||||
7
docs/demod/demod_use.md
Normal file
7
docs/demod/demod_use.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Demod installieren
|
||||
|
||||
> pip install demod
|
||||
|
||||
> pip install openpyxl
|
||||
|
||||
> pip install odfpy
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
### Load Balancer Funktionalitaet
|
||||
|
||||
Der Load Balancer wird gestartet. Er prueft ob in der SQLite-DB bereits Daten ueber Instanzen liegen.
|
||||
|
||||
Check out [Database columns](../../database/database_description.md)
|
||||
|
||||
Pro Eintrag (Zeile) werden A, B, C geholt und ein Instanz - Objekt mit den entsprechenden Daten erzeugt. Die Load - Balancer Klasse kommuniziert ueber die Klasse DBInterface mit der Datenbank. Die Klasse DBInterface implementiert die Funktionalitaeten, die notwendig sind, um mit der Datenbank zu kommunizieren.
|
||||
|
||||
[Python SQLite Bibliothek](https://docs.python.org/3/library/sqlite3.html#)
|
||||
[JSON Validator](https://jsonlint.com/)
|
||||
90
docs/load_balancer/diagrams/.$data_control_flow.drawio.bkp
Normal file
90
docs/load_balancer/diagrams/.$data_control_flow.drawio.bkp
Normal file
@@ -0,0 +1,90 @@
|
||||
<mxfile host="Electron" modified="2024-05-28T06:53:56.903Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="tYrShgPT8Ox6WKzFjUai" version="24.2.5" type="device">
|
||||
<diagram name="Page-1" id="qy58Fjep3ziJMWIOLXcW">
|
||||
<mxGraphModel dx="1114" dy="663" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-1" target="7EknwZf3zE2kvBgCffaO-2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-1" value="<font style="font-size: 14px;">LoadBalancer</font>" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="525" y="40" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-2" target="7EknwZf3zE2kvBgCffaO-3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-2" target="7EknwZf3zE2kvBgCffaO-10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-2" target="7EknwZf3zE2kvBgCffaO-11">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-2">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="780" y="290" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-2" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><font face="Helvetica">HeaterInstanceWorkerThreadPoolOrchestrator</font></div>" style="rounded=0;whiteSpace=wrap;html=1;fontColor=default;" vertex="1" parent="1">
|
||||
<mxGeometry x="525" y="160" width="320" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-3" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><div style="line-height: 19px;"><font face="Helvetica">HeaterInstancesOrchestrator</font></div></div>" style="rounded=0;whiteSpace=wrap;html=1;fontColor=default;" vertex="1" parent="1">
|
||||
<mxGeometry x="690" y="40" width="320" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-7" value="Fetch Data about Instances" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="860" y="110" width="110" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-9" value="<font style="font-size: 14px;">Starts</font>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="525" y="110" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-10" target="7EknwZf3zE2kvBgCffaO-16">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-10" target="7EknwZf3zE2kvBgCffaO-17">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-10" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><span style="font-size: 14px;"><font style="" face="Helvetica">HeaterInstanceWorkerThread A</font></span></div>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontColor=default;" vertex="1" parent="1">
|
||||
<mxGeometry x="520" y="290" width="210" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-11" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><span style="font-size: 14px;"><font style="" face="Helvetica">HeaterInstanceWorkerThread n</font></span></div>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontColor=default;" vertex="1" parent="1">
|
||||
<mxGeometry x="830" y="290" width="210" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-12" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="740" y="320" as="sourcePoint" />
|
||||
<mxPoint x="820" y="320" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-16" target="7EknwZf3zE2kvBgCffaO-26">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-16" value="daily_task()" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="520" y="414" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-17" value="realtime_task()" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=14;" vertex="1" parent="1">
|
||||
<mxGeometry x="670" y="414" width="130" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-22" value="<div style="font-size: 14px; line-height: 19px; white-space-collapse: preserve;"><font face="Helvetica">HeaterInstanceInterface</font></div>" style="shape=message;html=1;html=1;outlineConnect=0;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="480" y="360" width="35" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-24" value="<div style="font-size: 14px; line-height: 19px; white-space-collapse: preserve;"><font face="Helvetica">HeaterInstanceInterface</font></div>" style="shape=message;html=1;html=1;outlineConnect=0;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="975" y="140" width="35" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-25" value="<div style="font-size: 14px; line-height: 19px; white-space-collapse: preserve;"><font face="Helvetica">HeaterInstanceInterface</font></div>" style="shape=message;html=1;html=1;outlineConnect=0;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="525" y="230" width="35" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="7EknwZf3zE2kvBgCffaO-26" target="7EknwZf3zE2kvBgCffaO-16">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-26" value="<font style="font-size: 14px;">HeaterInstanceInterface.run()</font>" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="520" y="520" width="260" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-32" value="<font style="font-size: 14px;">HeaterInstance</font><span style="font-size: 14px; background-color: initial;">.run()</span>" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="520" y="580" width="260" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-33" value="Threadcount" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="690" y="225" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
201
docs/load_balancer/diagrams/.$load_balancer.drawio.bkp
Normal file
201
docs/load_balancer/diagrams/.$load_balancer.drawio.bkp
Normal file
@@ -0,0 +1,201 @@
|
||||
<mxfile host="Electron" modified="2024-05-07T09:33:55.233Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="PlsJbYsQtKTGQ-h2Sm5Q" version="24.2.5" type="device">
|
||||
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
||||
<mxGraphModel dx="1061" dy="1458" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-23" value="<span style="white-space: pre;">	</span>Package: load_balancer" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="10" y="-820" width="1120" height="790" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-25" value="<span style="white-space: pre;">	</span>Package: heater_interface" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="797" y="-720" width="263" height="670" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-24" value="<span style="white-space: pre;">	</span>Package: db_interface" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="20" y="-720" width="360" height="370" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-22" value="<span style="white-space: pre;">	</span>Package: heater" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="1180" y="-820" width="375" height="525" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--0" value="LoadBalancer" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="440" y="-690" width="290" height="170" as="geometry">
|
||||
<mxRectangle x="230" y="140" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--1" value="heater_instances : HeaterInstance []" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="26" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--2" value="db_interface : DBInterface" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="52" width="290" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--3" value="foo" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="82" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--4" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="108" width="290" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--5" value="add_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="116" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-29" value="remove_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="142" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--17" value="HeaterInstance" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="835" y="-440" width="160" height="216" as="geometry">
|
||||
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--18" value="host : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--19" value="user : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--20" value="ssh_key : ssh_key" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="78" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--22" value="owner : Owner" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="104" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--23" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="130" width="160" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-31" value="foo" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="138" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-0" value="Instance" style="swimlane;fontStyle=2;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="830" y="-690" width="170" height="160" as="geometry">
|
||||
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-5" value="ssh_session : undefined" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="26" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-7" value="demand : undefined" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="56" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-8" value="outcome : undefined" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="86" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-9" value="status : bool" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="116" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-2" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="146" width="170" height="14" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-3" value="" style="endArrow=block;endSize=10;endFill=1;shadow=0;strokeWidth=1;rounded=0;curved=0;edgeStyle=elbowEdgeStyle;elbow=vertical;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--17" target="5vzdqylje9so0Pf0NUx3-0" edge="1">
|
||||
<mxGeometry width="160" relative="1" as="geometry">
|
||||
<mxPoint x="917" y="-418" as="sourcePoint" />
|
||||
<mxPoint x="807" y="-520" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--2" target="zkfFHV4jXpPFQw0GAbJ--18" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="760" y="-390" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="760" y="-625" />
|
||||
<mxPoint x="760" y="-401" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-16" value="0..n" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="730" y="-650" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-17" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="760" y="-430" width="37" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-18" value="orchestrates" style="text;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="690" y="-510" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-19" value="Owner" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="835" y="-160" width="160" height="90" as="geometry">
|
||||
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-20" value="first_name : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-19" vertex="1">
|
||||
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-21" value="last_name : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="5vzdqylje9so0Pf0NUx3-19" vertex="1">
|
||||
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-22" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-19" vertex="1">
|
||||
<mxGeometry y="78" width="160" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=open;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" target="5vzdqylje9so0Pf0NUx3-19" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="690" y="-310" as="targetPoint" />
|
||||
<mxPoint x="915" y="-222" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-26" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="912" y="-190" width="36" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-27" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="910" y="-224" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-28" value="owned by" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="850" y="-210" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-32" value="DBSettings" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="30" y="-690" width="270" height="70" as="geometry">
|
||||
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-33" value="file_path : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-32" vertex="1">
|
||||
<mxGeometry y="26" width="270" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-35" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-32" vertex="1">
|
||||
<mxGeometry y="52" width="270" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=open;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5vzdqylje9so0Pf0NUx3-36" target="5vzdqylje9so0Pf0NUx3-32" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-36" value="DBInterface" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="30" y="-590" width="280" height="220" as="geometry">
|
||||
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-37" value="settings : DBSettings" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="26" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-38" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="52" width="280" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-46" value="add_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="60" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-47" value="update_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="86" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-51" value="remove_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="112" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-40" value="1<div>1</div>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="150" y="-620" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--2" target="5vzdqylje9so0Pf0NUx3-37" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="390" y="-623" />
|
||||
<mxPoint x="390" y="-551" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-44" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="300" y="-580" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-45" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="400" y="-650" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-48" value="uses" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="380" y="-560" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-49" value="has" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="130" y="-620" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-26" value="get_instances() : HeaterInstance []" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="30" y="-450" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
37
docs/load_balancer/diagrams/.$overview.drawio.bkp
Normal file
37
docs/load_balancer/diagrams/.$overview.drawio.bkp
Normal file
@@ -0,0 +1,37 @@
|
||||
<mxfile host="Electron" modified="2024-06-09T23:20:32.162Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="i5KB9fsT4zV48CXnobgm" version="24.2.5" type="device">
|
||||
<diagram name="Page-1" id="Ah_-kuApFwH53ASNQh7D">
|
||||
<mxGraphModel dx="1114" dy="663" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-15" value="LoadBalancer" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="20" y="20" width="670" height="390" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-16" value="<div style="line-height: 19px; white-space: pre;"><font style="font-size: 12px;" face="Helvetica">HeaterInstanceWorkerThread</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="140" width="630" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-17" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">HeaterInstanceInterfaceManager</font></div>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="50" width="500" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-18" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">HeaterInstanceInterface</font></div>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||
<mxGeometry x="225" y="60" width="300" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-19" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">Simulation</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="550" y="50" width="120" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-20" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">GlobalOutcome</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="320" width="630" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-21" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">TaskOutcome</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="230" width="630" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-22" value="<div style="line-height: 19px; white-space: pre;"><font style="font-size: 12px;">HeaterInstance</font></div>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||
<mxGeometry x="365" y="70" width="150" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-23" value="<div style="line-height: 19px; white-space: pre;"><font style="font-size: 12px;" face="Helvetica">Host</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="455" y="80" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
84
docs/load_balancer/diagrams/data_control_flow.drawio
Normal file
84
docs/load_balancer/diagrams/data_control_flow.drawio
Normal file
@@ -0,0 +1,84 @@
|
||||
<mxfile host="Electron" modified="2024-05-31T12:12:03.617Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="Hc0sJxNv_TmvKQj58595" version="24.2.5" type="device">
|
||||
<diagram name="Page-1" id="qy58Fjep3ziJMWIOLXcW">
|
||||
<mxGraphModel dx="1114" dy="663" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-1" target="7EknwZf3zE2kvBgCffaO-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-1" value="<font style="font-size: 14px;">LoadBalancer</font>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="525" y="40" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-2" target="7EknwZf3zE2kvBgCffaO-3" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-2" target="7EknwZf3zE2kvBgCffaO-10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-2" target="7EknwZf3zE2kvBgCffaO-11" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="780" y="290" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-2" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><font face="Helvetica">HeaterInstanceWorkerThreadPoolOrchestrator</font></div>" style="rounded=0;whiteSpace=wrap;html=1;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="525" y="160" width="320" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-3" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><div style="line-height: 19px;"><font face="Helvetica">HeaterInstancesOrchestrator</font></div></div>" style="rounded=0;whiteSpace=wrap;html=1;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="690" y="40" width="320" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-7" value="Fetch Data about Instances" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;" parent="1" vertex="1">
|
||||
<mxGeometry x="860" y="110" width="110" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-9" value="<font style="font-size: 14px;">Starts</font>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="525" y="110" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" parent="1" source="7EknwZf3zE2kvBgCffaO-10" target="7EknwZf3zE2kvBgCffaO-16" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" parent="1" source="7EknwZf3zE2kvBgCffaO-10" target="7EknwZf3zE2kvBgCffaO-17" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-10" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><span style="font-size: 14px;"><font style="" face="Helvetica">HeaterInstanceWorkerThread A</font></span></div>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="520" y="290" width="210" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-11" value="<div style="font-size: 14px; line-height: 19px; white-space: pre;"><span style="font-size: 14px;"><font style="" face="Helvetica">HeaterInstanceWorkerThread n</font></span></div>" style="rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontColor=default;" parent="1" vertex="1">
|
||||
<mxGeometry x="830" y="290" width="210" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-12" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="740" y="320" as="sourcePoint" />
|
||||
<mxPoint x="820" y="320" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-16" target="7EknwZf3zE2kvBgCffaO-26" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-16" value="daily_task()" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=14;" parent="1" vertex="1">
|
||||
<mxGeometry x="520" y="414" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-17" value="realtime_task()" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=14;" parent="1" vertex="1">
|
||||
<mxGeometry x="670" y="414" width="130" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-22" value="<div style="font-size: 14px; line-height: 19px; white-space-collapse: preserve;"><font face="Helvetica">HeaterInstanceInterface</font></div>" style="shape=message;html=1;html=1;outlineConnect=0;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="480" y="360" width="35" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-24" value="<div style="font-size: 14px; line-height: 19px; white-space-collapse: preserve;"><font face="Helvetica">HeaterInstanceInterface</font></div>" style="shape=message;html=1;html=1;outlineConnect=0;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="975" y="140" width="35" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-25" value="<div style="font-size: 14px; line-height: 19px; white-space-collapse: preserve;"><font face="Helvetica">HeaterInstanceInterface</font></div>" style="shape=message;html=1;html=1;outlineConnect=0;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="525" y="230" width="35" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" parent="1" source="7EknwZf3zE2kvBgCffaO-26" target="7EknwZf3zE2kvBgCffaO-16" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="7EknwZf3zE2kvBgCffaO-26" value="<font style="font-size: 14px;">HeaterInstance.run()</font>" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="510" y="520" width="180" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
201
docs/load_balancer/diagrams/load_balancer.drawio
Normal file
201
docs/load_balancer/diagrams/load_balancer.drawio
Normal file
@@ -0,0 +1,201 @@
|
||||
<mxfile host="Electron" modified="2024-05-07T09:35:52.261Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="DmmaRJrs2XHzGILdNXqB" version="24.2.5" type="device">
|
||||
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
||||
<mxGraphModel dx="1061" dy="1458" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-23" value="<span style="white-space: pre;">	</span>Package: load_balancer" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="10" y="-820" width="1120" height="790" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-25" value="<span style="white-space: pre;">	</span>Package: heater_interface" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="797" y="-720" width="263" height="670" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-24" value="<span style="white-space: pre;">	</span>Package: db_interface" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="20" y="-720" width="360" height="370" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-22" value="<span style="white-space: pre;">	</span>Package: heater" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.document;align=left;verticalAlign=top;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="1180" y="-820" width="375" height="525" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--0" value="LoadBalancer" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="440" y="-690" width="290" height="240" as="geometry">
|
||||
<mxRectangle x="230" y="140" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--1" value="heater_instances : HeaterInstance []" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="26" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--2" value="db_interface : DBInterface" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="52" width="290" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--3" value="foo" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="82" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--4" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="108" width="290" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--5" value="bar" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--0" vertex="1">
|
||||
<mxGeometry y="116" width="290" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--17" value="HeaterInstance" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="835" y="-440" width="160" height="216" as="geometry">
|
||||
<mxRectangle x="550" y="140" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--18" value="host : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--19" value="user : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--20" value="ssh_key : ssh_key" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="78" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--22" value="owner : Owner" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="104" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="zkfFHV4jXpPFQw0GAbJ--23" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="130" width="160" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-31" value="foo" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="zkfFHV4jXpPFQw0GAbJ--17" vertex="1">
|
||||
<mxGeometry y="138" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-0" value="Instance" style="swimlane;fontStyle=2;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="830" y="-690" width="170" height="160" as="geometry">
|
||||
<mxRectangle x="340" y="380" width="170" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-5" value="ssh_session : undefined" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="26" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-7" value="demand : undefined" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="56" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-8" value="outcome : undefined" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="86" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-9" value="status : bool" style="text;html=1;align=left;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="116" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-2" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-0" vertex="1">
|
||||
<mxGeometry y="146" width="170" height="14" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-3" value="" style="endArrow=block;endSize=10;endFill=1;shadow=0;strokeWidth=1;rounded=0;curved=0;edgeStyle=elbowEdgeStyle;elbow=vertical;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--17" target="5vzdqylje9so0Pf0NUx3-0" edge="1">
|
||||
<mxGeometry width="160" relative="1" as="geometry">
|
||||
<mxPoint x="917" y="-418" as="sourcePoint" />
|
||||
<mxPoint x="807" y="-520" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;endArrow=open;endFill=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--2" target="zkfFHV4jXpPFQw0GAbJ--18" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="760" y="-390" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="760" y="-625" />
|
||||
<mxPoint x="760" y="-401" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-16" value="0..n" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="730" y="-650" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-17" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="760" y="-430" width="37" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-18" value="orchestrates" style="text;html=1;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="730" y="-400" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-19" value="Owner" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="835" y="-160" width="160" height="90" as="geometry">
|
||||
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-20" value="first_name : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-19" vertex="1">
|
||||
<mxGeometry y="26" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-21" value="last_name : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;" parent="5vzdqylje9so0Pf0NUx3-19" vertex="1">
|
||||
<mxGeometry y="52" width="160" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-22" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-19" vertex="1">
|
||||
<mxGeometry y="78" width="160" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=open;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" target="5vzdqylje9so0Pf0NUx3-19" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="690" y="-310" as="targetPoint" />
|
||||
<mxPoint x="915" y="-222" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-26" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="912" y="-190" width="36" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-27" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="910" y="-224" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-28" value="owned by" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="850" y="-210" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-32" value="DBSettings" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="30" y="-690" width="270" height="70" as="geometry">
|
||||
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-33" value="file_path : str" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-32" vertex="1">
|
||||
<mxGeometry y="26" width="270" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-35" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-32" vertex="1">
|
||||
<mxGeometry y="52" width="270" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=open;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5vzdqylje9so0Pf0NUx3-36" target="5vzdqylje9so0Pf0NUx3-32" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-36" value="DBInterface" style="swimlane;fontStyle=0;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="30" y="-590" width="280" height="220" as="geometry">
|
||||
<mxRectangle x="130" y="380" width="160" height="26" as="alternateBounds" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-37" value="settings : DBSettings" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="26" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-38" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="52" width="280" height="8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-46" value="add_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="60" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-47" value="update_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="86" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-51" value="remove_instance(instance : HeaterInstance) : void" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="5vzdqylje9so0Pf0NUx3-36" vertex="1">
|
||||
<mxGeometry y="112" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-40" value="1<div>1</div>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="150" y="-620" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;endArrow=open;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--2" target="5vzdqylje9so0Pf0NUx3-37" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="390" y="-623" />
|
||||
<mxPoint x="390" y="-551" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-44" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="300" y="-580" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-45" value="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="400" y="-650" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-48" value="uses" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="380" y="-560" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="5vzdqylje9so0Pf0NUx3-49" value="has" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||
<mxGeometry x="130" y="-620" width="40" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-26" value="get_instances() : HeaterInstance []" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||
<mxGeometry x="30" y="-450" width="280" height="26" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k0BLKvAXlocCeE4DJ_wN-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5vzdqylje9so0Pf0NUx3-18" target="5vzdqylje9so0Pf0NUx3-18">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
37
docs/load_balancer/diagrams/overview.drawio
Normal file
37
docs/load_balancer/diagrams/overview.drawio
Normal file
@@ -0,0 +1,37 @@
|
||||
<mxfile host="Electron" modified="2024-06-09T23:20:50.047Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="oc_10AI9Czrxgo6AxFQL" version="24.2.5" type="device">
|
||||
<diagram name="Page-1" id="Ah_-kuApFwH53ASNQh7D">
|
||||
<mxGraphModel dx="1086" dy="663" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-15" value="LoadBalancer" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="210" y="140" width="670" height="390" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-16" value="<div style="line-height: 19px; white-space: pre;"><font style="font-size: 12px;" face="Helvetica">HeaterInstanceWorkerThread</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="230" y="260" width="630" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-17" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">HeaterInstanceInterfaceManager</font></div>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||
<mxGeometry x="230" y="170" width="500" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-18" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">HeaterInstanceInterface</font></div>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||
<mxGeometry x="415" y="180" width="300" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-19" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">Simulation</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="740" y="170" width="120" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-20" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">GlobalOutcome</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="230" y="440" width="630" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-21" value="<div style="line-height: 19px; white-space: pre;"><font face="Helvetica" style="font-size: 12px;">TaskOutcome</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="230" y="350" width="630" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-22" value="<div style="line-height: 19px; white-space: pre;"><font style="font-size: 12px;">HeaterInstance</font></div>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||
<mxGeometry x="555" y="190" width="150" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="8_F79eOSLjp0VsFUqVzp-23" value="<div style="line-height: 19px; white-space: pre;"><font style="font-size: 12px;" face="Helvetica">Host</font></div>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="645" y="200" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
17
docs/meetings/16_04_2024_Meeting.md
Normal file
17
docs/meetings/16_04_2024_Meeting.md
Normal file
@@ -0,0 +1,17 @@
|
||||
Load Balancer lowers Power Consumption in summer
|
||||
modifizieren des Heaters erlaubt, die Instanz ist der Heater
|
||||
0.72h
|
||||
Skalierbarkeit: Aufgabe des Load Balancers
|
||||
Seed in Zufallsgenerator um Gebaeude auszuwaehlen
|
||||
min. 4 Personen
|
||||
Starten und Stoppen von Tasks Kommandozeilenbefehle
|
||||
Klasse mit hostname, passwort, die eine Instanz repraesentieren
|
||||
Status abfragen
|
||||
auf objekt start tasks aufrufen
|
||||
Parser von Status um Informationen rauszulesen
|
||||
In 14 Tagen
|
||||
GUI: An welchen Tagen wurde wie viel gearbeitet, Dashboard, stats von Boinc Instanzen darstellen
|
||||
Treffen 15 Uhr 23.04.24
|
||||
Mockup der UI
|
||||
5 Wochen
|
||||
GUI
|
||||
18
docs/meetings/30_04_2024_Meeting.md
Normal file
18
docs/meetings/30_04_2024_Meeting.md
Normal file
@@ -0,0 +1,18 @@
|
||||
Von Ziel aus anfangen zu planen
|
||||
HPC Aufgabe, mit SSH aufschalten, Programm starten, C++
|
||||
Idee: Falls kein Task verfuegbar, dann HPC Aufgabe, ansonsten Tasks
|
||||
CPUh zu Waerme 1 CPUh == 4kW Waerme
|
||||
CPU Zeit muss nicht genau gemessen werden, sondern nur Gesamtlaufzeit des Programms
|
||||
Demod ein Mal aufrufen um Daten fuer Zeitraum zu generieren
|
||||
Daten in sqlight DB schreiben
|
||||
Project Outline (max 1 Din A4 Seite) auf Moodle hochladen, verwendete Progsprachen, Aufgaben pro Teammember
|
||||
|
||||
Aaron: Demod, Load Balancer, Definieren, was Load Balancer als Rueckgabewert haben will, ssh session von allen Heatern uebergeben an, Session in Objekt speichern und an Davids Programm uebergeben, Rueckgabe wann wurde es ausgefuehrt, wie lange lief es, Ergebnis soll im Load balancer landen, Verteilung der Aufgabe in Prozent auf die Instanzen an Davids Middleware schicken.
|
||||
Python Funktion, Load Balancer soll selbstheilend sein, wenn Heater aussteigt
|
||||
|
||||
ssh -> Paramiko, pip install paramiko
|
||||
|
||||
Array mit Objekten, ein Objekt enthaelt ssh session und Prozentzahl, wie viel Bedarf, Feld fuer Ergebnis, in das Funktion von David Ergebnis schreibt, Statuswert ob Heater erreichbar war oder nicht
|
||||
|
||||
David: HPC Aufgabe, dominik.giel dgiel auf GitHub hinzufuegen.
|
||||
|
||||
7
docs/public_keys/README.md
Normal file
7
docs/public_keys/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
In Instanz anmelden
|
||||
|
||||
nano ./.ssh/authorized_keys
|
||||
Schluessel einfuegen
|
||||
Strg x zum Speichern
|
||||
|
||||
Fertig
|
||||
1
docs/public_keys/id_rsa.pub
Normal file
1
docs/public_keys/id_rsa.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCz9n3pJLtqT4p6zYvirbGh+9jTIfPjslK59NUvomnNczwh7Xw80I9bmeykygJNIvsOvwbYkRbTn66712x9pnzlj98kVgUrr2/IgsPHvhTRYF+7m00uaYZWbp24x6AQ4HggeIASKeBx5AVmT+JYLUb/vN2uaF6NnLTYVSn3OgKW65HRkwL+6qIitG18uj1a4G3wfSxQ1neU9gWrg+pf9oLkS3BxZHWhXqgQYuhR6hn4IsqjCRuav+Bv6y4RjoRbqrhOAwaRqysDufwavPGV12Xt0t2YqnqXSc8x9lUfJIvMzYLkWgkYr5pqhSoi3ZJwRaVDLPtZT1ZlVoFEI5hIQ0Zuh4l8bUkmgd1m+O7EzO9A3s1aGfM+LDFmS0xpYrgW84E9w1KIGX/mjXaE/wK1VLg/jTjM1wJ5C9F3G5cyj+spD2GQKD5i671HnYA7lW7Vclw4k2uuyMym9lDguhFWTiOj2EodCex5SwVoSypM1Bc6cEhB3V4YWYRlGedgVRDMBIz4gSL8shKPg8Fw5+czYiIm+lb3d97o51t8RNpeGdsfDuSqKGKPNtl1isGZgUnmZNu+djqlM1ziYmrGqHpZidDwg66y9VFLiWLCxgpNuNjUgvnKoZATVGP18GNfAAMzG8pT4TL3uFPqZ2iaT7o9/jzQjfQIQMDAkfC3a4KKw9turQ== theresaherr@Theresas-MacBook-Pro-9.fritz.box
|
||||
1
docs/public_keys/key_bwcloud_project2.pub
Normal file
1
docs/public_keys/key_bwcloud_project2.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC6mVWkB/4QlXtq40UjgsYZoE6hEs/vv/aUyJ7bxPtJnHu/S7SnPovWS1UjI8sMhuwXQ+XK/SOwjxosuLfozdrDHisWWmBmKvjrWwmhJPl51K7GRAZNXK/DWyrXhJeuVoYnA2fxzXFUnpBkl3hxtJNTh0kz1beCxATbh4uprJotgh0rrsRCJwivgkgrcrKBUZI3Op6L+VeYdqcxbcpothh3w7FLEmloCn40JRxowQqMozr1Ph5uujCyNk2+imgxnxnzvYBJLyVLr24XV2jzl7FEnGa5knRd9zV0icG2N0Y2gTY1wgCrKqfnsV99WsscPZ+jGG2cntKeaaCrtxLLlwY4JCvHqfJlsi0i724f80Q5BRIiSiaAqa7Sk3VdL7E9A3bd3HeuAuw7YOMKE05DzJ+K+2FZrZT00R1+bYsgpIfHkHSND08cO13gkF4mgPvD+lG0b2ZBn1/9A90gAwP0YqK7ZuQ7YX+uu03ginnZAGkdF9BvNvnvouCb/8EKAsjMrAs= student@student
|
||||
11
docs/questions/30_04_2024_Fragenkatalog.md
Normal file
11
docs/questions/30_04_2024_Fragenkatalog.md
Normal file
@@ -0,0 +1,11 @@
|
||||
1. Muss die GUI schoen aussehen? -> Duerfen wir Graphana verwenden?
|
||||
|
||||
> Graphana Beispiel: https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.lionbloggertech.com%2Fwp-content%2Fuploads%2F2020%2F08%2Fgrafana_visualize.jpg&f=1&nofb=1&ipt=600c75674993907aa247a68c66bcff6b88265e5d0e1b1d36351a67d43a1cc4b8&ipo=images
|
||||
|
||||
> Graphana Website: https://grafana.com/
|
||||
|
||||
Antwort: Ist erlaubt
|
||||
|
||||
2. Was tun wenn dauerhafte Ausnutzung der Instanz nicht moeglich ist, da nicht durchgehend Tasks verfuegbar sind?
|
||||
|
||||
Antwort: HPC Problem loesen
|
||||
0
docs/teammeetings/07_05_2024_Teammeeting.md
Normal file
0
docs/teammeetings/07_05_2024_Teammeeting.md
Normal file
23
docs/teammeetings/23_04_2024_Teammeeting.md
Normal file
23
docs/teammeetings/23_04_2024_Teammeeting.md
Normal file
@@ -0,0 +1,23 @@
|
||||
Datenbank? Dateien?
|
||||
|
||||
sqlight, sehr einfache DB, Daten werden dort rein geschrieben
|
||||
David: Graphana baut Dashboards aus Datenbank, sql abfragen bauen (naechstes Mal fragen ob graphana oder React? Schoenheit?)
|
||||
|
||||
UI holt sich Daten
|
||||
Load Balancer kommuniziert mit den Heater Instanzen und Heat requirement system und schreibt die Daten in sqlight db.
|
||||
|
||||
An welchen Tagen wurde wie viel gearbeitet: Histogram
|
||||
Hitzebedarf ueber Zeit: Zeitgraph x Zeit y Hitzebedarf
|
||||
|
||||
Auf naechsten Dienstag:
|
||||
|
||||
Theresa:
|
||||
kleines GUI Mockup vorbereiten
|
||||
|
||||
David:
|
||||
Load Balancer, demod einlesen, kann erst ab 03.05 wg. Bachelorarbeit
|
||||
Instanz zum laufen bringen
|
||||
|
||||
Aaron:
|
||||
Anderes Projekt mit einfachen Tasks researchen, Iterationsschritt immer gleich lang, Zuverlaessigkeit der Tasks gegeben? CPU soll was zu tun haben
|
||||
Parsen des Outputs
|
||||
12
load_balancer/boinc/boinc_components/boinc_application.py
Normal file
12
load_balancer/boinc/boinc_components/boinc_application.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# ======== Applications ========
|
||||
# 1) -----------
|
||||
# name: Theory
|
||||
# Project: LHC@home
|
||||
# 2) -----------
|
||||
# name: sixtrack
|
||||
# Project: LHC@home
|
||||
|
||||
class BoincApplication:
|
||||
def __init__(self, name, project):
|
||||
self.name = name
|
||||
self.project = project
|
||||
@@ -0,0 +1,35 @@
|
||||
# ======== Application versions ========
|
||||
# 1) -----------
|
||||
# project: LHC@home
|
||||
# application: Theory
|
||||
# platform: x86_64-pc-linux-gnu
|
||||
# plan class: native_theory
|
||||
# version: 300.08
|
||||
# estimated GFLOPS: 0.08
|
||||
# filename: wrapper_2019_03_02_x86_64-linux
|
||||
# 2) -----------
|
||||
# project: LHC@home
|
||||
# application: sixtrack
|
||||
# platform: x86_64-pc-linux-gnu
|
||||
# plan class: avx
|
||||
# version: 502.05
|
||||
# estimated GFLOPS: 1.28
|
||||
# filename: sixtrack_lin64_50205_avx.linux
|
||||
# 3) -----------
|
||||
# project: LHC@home
|
||||
# application: sixtrack
|
||||
# platform: x86_64-pc-linux-gnu
|
||||
# plan class: sse2
|
||||
# version: 502.05
|
||||
# estimated GFLOPS: 1.44
|
||||
# filename: sixtrack_lin64_50205_sse2.linux
|
||||
|
||||
class BoincApplicationVersion:
|
||||
def __init__(self, project, application, platform, plan_class, version, estimated, filename):
|
||||
self.project = project # string
|
||||
self.application = application # string
|
||||
self.platform = platform # string
|
||||
self.plan_class = plan_class # string
|
||||
self.version = version # string
|
||||
self.estimated = estimated # string
|
||||
self.filename = filename # string
|
||||
56
load_balancer/boinc/boinc_components/boinc_commands.py
Normal file
56
load_balancer/boinc/boinc_components/boinc_commands.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# Commands:
|
||||
|
||||
# --acct_mgr attach URL name passwd attach to account manager
|
||||
ACCOUNT_MANAGER_INFO = "--acct_mgr info" # show current account manager info
|
||||
ACCOUNT_MANAGER_SYNCHRONIZE = "--acct_mgr sync" # synchronize with acct mgr
|
||||
ACCOUNT_MANAGER_DETACH = "--acct_mgr detach" # detach from acct mgr
|
||||
|
||||
CLIENT_VERSION = "--client_version" # show client version
|
||||
|
||||
# --create_account URL email passwd name
|
||||
|
||||
# --file_transfer URL filename op file transfer operation
|
||||
# op = retry | abort
|
||||
|
||||
# --get_app_config URL show app config for given project
|
||||
GET_CC_STATUS = "--get_cc_status"
|
||||
GET_NETWORK_TRAFFIC_HISTORY = "--get_daily_xfer_history" # show network traffic history
|
||||
GET_DISK_USAGE = "--get_disk_usage" # show disk usage
|
||||
GET_FILE_TRANSFER = "--get_file_transfers" # show file transfers
|
||||
GET_HOST_INFO = "--get_host_info"
|
||||
GET_MESSAGE_COUNT = "--get_message_count" # show largest message seqno
|
||||
# --get_messages [ seqno ] show messages > seqno
|
||||
# --get_notices [ seqno ] show notices > seqno
|
||||
# --get_project_config URL
|
||||
GET_PROJECTS_STATUS = "--get_project_status" # show status of all attached projects
|
||||
GET_PROXY_SETTINGS = "--get_proxy_settings"
|
||||
GET_SIMPLE_GUI_INFO = "--get_simple_gui_info" # show status of projects and active tasks
|
||||
GET_STATE = "--get_state" # show entire state
|
||||
GET_TASKS = "--get_tasks" # show tasks
|
||||
# --get_old_tasks show reported tasks from last 1 hour
|
||||
# --join_acct_mgr URL name passwd same as --acct_mgr attach
|
||||
# --lookup_account URL email passwd
|
||||
# --network_available retry deferred network communication
|
||||
# --project URL op project operation
|
||||
# op = reset | detach | update | suspend | resume | nomorework | allowmorework | detach_when_done | dont_detach_when_done
|
||||
# --project_attach URL auth attach to project
|
||||
# --quit tell client to exit
|
||||
# --quit_acct_mgr same as --acct_mgr detach
|
||||
# --read_cc_config
|
||||
# --read_global_prefs_override
|
||||
# --reset_host_info have client get mem size, #CPUs etc. again
|
||||
# --run_benchmarks
|
||||
# --run_graphics_app id op (Macintosh only) run, test or stop graphics app
|
||||
# op = run | runfullscreen | stop | test
|
||||
# id = slot # for run or runfullscreen, process ID for stop or test
|
||||
# id = -1 for default screensaver (boincscr)
|
||||
# --set_gpu_mode mode duration set GPU run mode for given duration
|
||||
# mode = always | auto | never
|
||||
# --set_host_info product_name
|
||||
# --set_network_mode mode duration set network mode for given duration
|
||||
# mode = always | auto | never
|
||||
# --set_proxy_settings
|
||||
# --set_run_mode mode duration set run mode for given duration
|
||||
# mode = always | auto | never
|
||||
# --task url task_name op task operation
|
||||
# op = suspend | resume | abort
|
||||
18
load_balancer/boinc/boinc_components/boinc_host.py
Normal file
18
load_balancer/boinc/boinc_components/boinc_host.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from boinc_components.boinc_project import BoincProject
|
||||
from boinc_components.boinc_project_gui_url import BoincProjectGuiUrl
|
||||
from boinc_components.boinc_application import BoincApplication
|
||||
from boinc_components.boinc_application_version import BoincApplicationVersion
|
||||
from boinc_components.boinc_workunit import BoincWorkunit
|
||||
from boinc_components.boinc_task import BoincTask
|
||||
from boinc_components.boinc_time_stats import BoincTimeStats
|
||||
|
||||
class BoincHost:
|
||||
def __init__(self, address, password, projects=None, applications=None, application_versions=None, workunits=None, tasks=None, time_stats=None):
|
||||
self.address = address # string
|
||||
self.password = password # string
|
||||
self.projects = projects # list of BoincProject
|
||||
self.applications = applications # list of BoincApplication
|
||||
self.application_versions = application_versions # list of BoincApplicationVersion
|
||||
self.workunits = workunits # list of BoincWorkunit
|
||||
self.tasks = tasks # list of BoincTask
|
||||
self.time_stats = time_stats # TimeStats
|
||||
74
load_balancer/boinc/boinc_components/boinc_project.py
Normal file
74
load_balancer/boinc/boinc_components/boinc_project.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# ======== Projects ========
|
||||
# 1) -----------
|
||||
# name: LHC@home
|
||||
# master URL: https://lhcathome.cern.ch/lhcathome/
|
||||
# user_name: WickedJack
|
||||
# team_name:
|
||||
# resource share: 100.000000
|
||||
# user_total_credit: 412.990429
|
||||
# user_expavg_credit: 22.766969
|
||||
# host_total_credit: 412.990429
|
||||
# host_expavg_credit: 25.140667
|
||||
# nrpc_failures: 0
|
||||
# master_fetch_failures: 0
|
||||
# master fetch pending: no
|
||||
# scheduler RPC pending: no
|
||||
# trickle upload pending: no
|
||||
# attached via Account Manager: no
|
||||
# ended: no
|
||||
# suspended via GUI: no
|
||||
# don't request more work: no
|
||||
# disk usage: 42.67MB
|
||||
# last RPC: Tue Apr 23 11:23:53 2024
|
||||
# project files downloaded: 0.000000
|
||||
|
||||
from boinc_components.boinc_project_gui_url import BoincProjectGuiUrl
|
||||
|
||||
class BoincProject:
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
master_url,
|
||||
user_name,
|
||||
team_name,
|
||||
resource_share,
|
||||
user_total_credit,
|
||||
user_exponential_average_credit,
|
||||
host_total_credit,
|
||||
host_exponential_average_credit,
|
||||
nrpc_failures,
|
||||
master_fetch_failures,
|
||||
master_fetch_pending,
|
||||
scheduler_rpc_pending,
|
||||
trickle_upload_pending,
|
||||
attached_via_account_manager,
|
||||
ended,
|
||||
suspended_via_gui,
|
||||
dont_request_more_work,
|
||||
disk_usage,
|
||||
last_rpc,
|
||||
project_files_downloaded,
|
||||
gui_urls
|
||||
):
|
||||
self.name = name
|
||||
self.master_url = master_url
|
||||
self.user_name = user_name
|
||||
self.team_name = team_name
|
||||
self.resource_share = resource_share
|
||||
self.user_total_credit = user_total_credit
|
||||
self.user_exponential_average_credit = user_exponential_average_credit
|
||||
self.host_total_credit = host_total_credit
|
||||
self.host_exponential_average_credit = host_exponential_average_credit
|
||||
self.nrpc_failures = nrpc_failures
|
||||
self.master_fetch_failures = master_fetch_failures
|
||||
self.master_fetch_pending = master_fetch_pending
|
||||
self.scheduler_rpc_pending = scheduler_rpc_pending
|
||||
self.trickle_upload_pending = trickle_upload_pending
|
||||
self.attached_via_account_manager = attached_via_account_manager
|
||||
self.ended = ended
|
||||
self.suspended_via_gui = suspended_via_gui
|
||||
self.dont_request_more_work = dont_request_more_work
|
||||
self.disk_usage = disk_usage
|
||||
self.last_rpc = last_rpc
|
||||
self.project_files_downloaded = project_files_downloaded
|
||||
self.gui_urls = gui_urls
|
||||
@@ -0,0 +1,30 @@
|
||||
# GUI URL:
|
||||
# name: Message boards
|
||||
# description: Correspond with other users on the LHC@home message boards
|
||||
# URL: https://lhcathome.cern.ch/lhcathome/forum_index.php
|
||||
# GUI URL:
|
||||
# name: Your account
|
||||
# description: View your account information
|
||||
# URL: https://lhcathome.cern.ch/lhcathome/home.php
|
||||
# GUI URL:
|
||||
# name: Your tasks
|
||||
# description: View the last week or so of computational work
|
||||
# URL: https://lhcathome.cern.ch/lhcathome/results.php?userid=1062754
|
||||
# GUI URL:
|
||||
# name: FAQ
|
||||
# description: Frequently Asked Questions on LHC@home
|
||||
# URL: http://lhcathome.web.cern.ch/faq
|
||||
# jobs succeeded: 39
|
||||
# jobs failed: 492
|
||||
# elapsed time: 430959.162318
|
||||
# cross-project ID: 773913b4ca09b7fae8533c9c9c859d07
|
||||
|
||||
class BoincProjectGuiUrl:
|
||||
def __init__(self, name, description, url, jobs_succeeded, jobs_failed, elapsed_time, cross_project_id):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.url = url
|
||||
self.jobs_succeeded = jobs_succeeded
|
||||
self.jobs_failed = jobs_failed
|
||||
self.elapsed_time = elapsed_time
|
||||
self.cross_project_id = cross_project_id
|
||||
32
load_balancer/boinc/boinc_components/boinc_task.py
Normal file
32
load_balancer/boinc/boinc_components/boinc_task.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# ======== Tasks ========
|
||||
|
||||
# TODO find out if this information one task has is up to date.
|
||||
|
||||
class BoincTask:
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
workunit_name,
|
||||
project_url,
|
||||
received,
|
||||
report_deadline,
|
||||
ready_to_report,
|
||||
state,
|
||||
scheduler_state,
|
||||
active_task_state,
|
||||
app_version_num,
|
||||
resources,
|
||||
estimated_cpu_time_remaining
|
||||
):
|
||||
self.name = name
|
||||
self.workunit_name = workunit_name
|
||||
self.project_url = project_url
|
||||
self.received = received
|
||||
self.report_deadline = report_deadline
|
||||
self.ready_to_report = ready_to_report
|
||||
self.state = state
|
||||
self.scheduler_state = scheduler_state
|
||||
self.active_task_state = active_task_state
|
||||
self.app_version_num = app_version_num
|
||||
self.resources = resources
|
||||
self.estimated_cpu_time_remaining = estimated_cpu_time_remaining
|
||||
50
load_balancer/boinc/boinc_components/boinc_time_stats.py
Normal file
50
load_balancer/boinc/boinc_components/boinc_time_stats.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# ======== Time stats ========
|
||||
# now: 1713866392.601657
|
||||
# on_frac: 0.999491
|
||||
# connected_frac: -1.000000
|
||||
# cpu_and_network_available_frac: 0.999992
|
||||
# active_frac: 0.999992
|
||||
# gpu_active_frac: 0.999992
|
||||
# client_start_time: Tue Apr 16 14:45:29 2024
|
||||
|
||||
# previous_uptime: 3884.003729
|
||||
# session_active_duration: 594842.232585
|
||||
# session_gpu_active_duration: 594842.232585
|
||||
# total_start_time: Mon Apr 15 22:52:40 2024
|
||||
|
||||
# total_duration: 651143.128246
|
||||
# total_active_duration: 651133.088290
|
||||
# total_gpu_active_duration: 651133.088290
|
||||
|
||||
class BoincTimeStats:
|
||||
def __init__(
|
||||
self,
|
||||
now,
|
||||
on_frac,
|
||||
connected_frac,
|
||||
cpu_and_network_available_frac,
|
||||
active_frac,
|
||||
gpu_active_frac,
|
||||
client_start_time,
|
||||
previous_uptime,
|
||||
session_active_duration,
|
||||
session_gpu_active_duration,
|
||||
total_start_time,
|
||||
total_duration,
|
||||
total_active_duration,
|
||||
total_gpu_active_duration
|
||||
):
|
||||
self.now = now
|
||||
self.on_frac = on_frac
|
||||
self.connected_frac = connected_frac
|
||||
self.cpu_and_network_available_frac = cpu_and_network_available_frac
|
||||
self.active_frac = active_frac
|
||||
self.gpu_active_frac = gpu_active_frac
|
||||
self.client_start_time = client_start_time
|
||||
self.previous_uptime = previous_uptime
|
||||
self.session_active_duration = session_active_duration
|
||||
self.session_gpu_active_duration = session_gpu_active_duration
|
||||
self.total_start_time = total_start_time
|
||||
self.total_duration = total_duration
|
||||
self.total_active_duration = total_active_duration
|
||||
self.total_gpu_active_duration = total_gpu_active_duration
|
||||
6
load_balancer/boinc/boinc_components/boinc_workunit.py
Normal file
6
load_balancer/boinc/boinc_components/boinc_workunit.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# ======== Workunits ========
|
||||
|
||||
class BoincWorkunit:
|
||||
def __init__(self):
|
||||
self
|
||||
# TODO find out which information is contained in a workunit
|
||||
26
load_balancer/boinc/boinc_output_parser.py
Normal file
26
load_balancer/boinc/boinc_output_parser.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from boinc_components.boinc_project import BoincProject
|
||||
from boinc_components.boinc_project_gui_url import BoincProjectGuiUrl
|
||||
from boinc_components.boinc_application import BoincApplication
|
||||
from boinc_components.boinc_application_version import BoincApplicationVersion
|
||||
from boinc_components.boinc_workunit import BoincWorkunit
|
||||
from boinc_components.boinc_task import BoincTask
|
||||
from boinc_components.boinc_time_stats import BoincTimeStats
|
||||
from boinc_components.boinc_host import BoincHost
|
||||
|
||||
# TODO parse data from received output to host object
|
||||
# Create subfunctions for each param of BoincHost except address and password
|
||||
def parseOutputToHost(output, old_host):
|
||||
address = old_host.address
|
||||
password = old_host.password
|
||||
|
||||
projects = []
|
||||
applications = []
|
||||
application_versions = []
|
||||
workunits = []
|
||||
tasks = []
|
||||
time_stats = parseOutputToBoincTimeStats(output)
|
||||
|
||||
return BoincHost(address, password, projects, applications, application_versions, workunits, tasks, time_stats)
|
||||
|
||||
def parseOutputToBoincTimeStats(output):
|
||||
return BoincTimeStats()
|
||||
15
load_balancer/boinc/heater_instance.py
Normal file
15
load_balancer/boinc/heater_instance.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import subprocess
|
||||
|
||||
class HeaterInstance:
|
||||
def __init__(self, host):
|
||||
self.host = host
|
||||
|
||||
def execute_command_and_return_output(self, command):
|
||||
# Define the command to execute
|
||||
command = "boinccmd --host " + self.host.address + " --passwd '" + self.host.password + "' " + command
|
||||
# Execute the command and capture the output
|
||||
output = subprocess.check_output(command, shell=True)
|
||||
# Decode the output if needed (for Python 3)
|
||||
output = output.decode("utf-8")
|
||||
# Print or process the output
|
||||
return output
|
||||
20
load_balancer/boinc/load_balancer_a5.py
Normal file
20
load_balancer/boinc/load_balancer_a5.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import boinc_components.boinc_commands as BOINC_COMMAND
|
||||
|
||||
from load_balancer.boinc.heater_instance import HeaterInstance
|
||||
from boinc_components.boinc_host import BoincHost
|
||||
|
||||
def main():
|
||||
print("-------------------------------")
|
||||
print("Load Balancer has been started.")
|
||||
print("-------------------------------")
|
||||
|
||||
address = "494216f3-d1df-4ec0-ae1c-51f6643adc4a.fr.bw-cloud-instance.org"
|
||||
password = "&!dBgncRmwnjurJXyhK>#G%PTy$H]kt0"
|
||||
host = BoincHost(address, password)
|
||||
instance = HeaterInstance(host)
|
||||
output = instance.execute_command_and_return_output(BOINC_COMMAND.GET_STATE)
|
||||
|
||||
print(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
62
load_balancer/constants.py
Normal file
62
load_balancer/constants.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# author Aaron Moser
|
||||
|
||||
from enum import Enum
|
||||
|
||||
# Comstants
|
||||
|
||||
# 96 kWh maximale Arbeit, die von einer Instanz verrichtet werden kann
|
||||
# 4kW volle Leistungslast, welche in einer Stunde moeglich ist
|
||||
# 4kW / 100 = 0.04kW = 1 Prozent
|
||||
MAX_WORKLOAD_IN_KW:int = 4
|
||||
MAX_WORKLOAD_IN_KW_ONE_PERCENT:float = MAX_WORKLOAD_IN_KW / 100
|
||||
|
||||
# 24h/d * 60min/h * 60s/min = 86400s/d = Anzahl Sekunden am Tag
|
||||
# Ein Tag um Faktor 1000 gekuerzt = 86400s/d / 1000 = 86.4s/d
|
||||
# 86,4s/d / 1440min/d = 0.06s/min
|
||||
# Ratio how many seconds simulate one minute of a day
|
||||
DAILY_MODE_MILLISECONDS_MINUTE_RATIO:int = 60
|
||||
|
||||
MINIMUM_NUMBER_CLIENTS = 1
|
||||
MAXIMUM_NUMBER_CLIENTS = 20
|
||||
|
||||
# Error code enums
|
||||
class ConnectErrorCode(Enum):
|
||||
CONNECTED = 1
|
||||
ALREADY_CONNECTED = 2
|
||||
UNVERIFIED_KEY = 3
|
||||
AUTHENTICATION_FAILED = 4
|
||||
SOCKET_ERROR = 5
|
||||
ALL_CONNECTION_ATTEMPTS_FAILED = 6
|
||||
SSH_EXCEPTION = 7
|
||||
|
||||
class State(Enum):
|
||||
Stopped = 1
|
||||
Running = 2
|
||||
|
||||
# Commands
|
||||
START_SIMULATION_COMMAND = "startsimulation"
|
||||
STOP_SIMULATION_COMMAND = "stopsimulation"
|
||||
SET_SIMULATION_MODE_COMMAND = "setsimulationmode"
|
||||
ADD_INSTANCE_COMMAND = "addinstance"
|
||||
REMOVE_INSTANCE_COMMAND = "removeinstance"
|
||||
SHOW_INSTANCES_COMMAND = "showinstances"
|
||||
DISPLAY_OUTCOME_COMMAND = "displayoutcome"
|
||||
HELP_COMMAND = "help"
|
||||
EXIT_COMMAND = "exit"
|
||||
|
||||
SET_SIMULATION_MODE_COMMAND_REALTIME = "realtime"
|
||||
SET_SIMULATION_MODE_COMMAND_DAILY = "daily"
|
||||
|
||||
COMMANDS_HELP = [
|
||||
"StartSimulation [daily, realtime] [start date] [end date] // Starts simulation with default mode or optionally with given mode, start and end date.",
|
||||
"StopSimulation // Stops running simulation by stopping threads of instances.",
|
||||
"SetSimulationMode // 'daily' or 'realtime', sets simulation mode depending on second argument.",
|
||||
"AddInstance <hostname> <username> <ssh_key_filename> <passphrase> // Adds new instance to load balancer.",
|
||||
"RemoveInstance <hostname> <username> // Removes existing instance.",
|
||||
"ShowInstances // Lists all existsing instances and their state.",
|
||||
"DisplayOutcome // Shows global outcome which consists of: count, tries and PI",
|
||||
"Help // Shows commands and descriptions.",
|
||||
"Exit // Stops load balancer and exits application."]
|
||||
|
||||
# Messages
|
||||
START_MESSAGE = "-------------------------------\nLoad Balancer has been started."
|
||||
252
load_balancer/database_interface.py
Normal file
252
load_balancer/database_interface.py
Normal file
@@ -0,0 +1,252 @@
|
||||
# author Aaron Moser, Theresa Herr
|
||||
|
||||
import sqlite3
|
||||
import json
|
||||
import threading
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
from heater.host import Host
|
||||
from heater_instance_interface import HeaterInstanceInterface
|
||||
from tasks.task_outcome import TaskOutcome
|
||||
|
||||
db_lock = threading.Lock()
|
||||
|
||||
class DatabaseOperation(Enum):
|
||||
GET_INSTANCE = 1
|
||||
GET_INSTANCES = 2
|
||||
UPDATE_INSTANCE = 3
|
||||
REMOVE_INSTANCE = 4
|
||||
REMOVE_ALL_INSTANCES = 5
|
||||
|
||||
class DatabaseInterface:
|
||||
def __init__(self, db_path):
|
||||
self.__db_path = db_path
|
||||
self.__init_database()
|
||||
|
||||
def access_db(self, operation: DatabaseOperation, args) -> List[Host]:
|
||||
db_lock.acquire()
|
||||
try:
|
||||
if operation == DatabaseOperation.GET_INSTANCE:
|
||||
return self.__get_instance(args)
|
||||
elif operation == DatabaseOperation.GET_INSTANCES:
|
||||
return self.__get_all_instances()
|
||||
elif operation == DatabaseOperation.UPDATE_INSTANCE:
|
||||
self.__update_instance(args)
|
||||
elif operation == DatabaseOperation.REMOVE_INSTANCE:
|
||||
self.__remove_instance(args)
|
||||
elif operation == DatabaseOperation.REMOVE_ALL_INSTANCES:
|
||||
self.__remove_all_instances()
|
||||
else:
|
||||
print("Unknown database operation: " + operation)
|
||||
finally:
|
||||
db_lock.release()
|
||||
|
||||
def __init_database(self):
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
self.__init_table_instances(conn)
|
||||
self.__init_table_task_outcomes(conn)
|
||||
conn.close()
|
||||
|
||||
def __init_table_instances(self, conn: sqlite3.Connection):
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
SELECT name FROM sqlite_master WHERE type='table' AND name='instances';
|
||||
''')
|
||||
table_exists = cursor.fetchone()
|
||||
|
||||
if table_exists:
|
||||
print("SQLiteDB table 'instances' already exists, skipped initialization of table.")
|
||||
else:
|
||||
cursor.execute('''
|
||||
CREATE TABLE instances (
|
||||
id INTEGER PRIMARY KEY,
|
||||
owner TEXT,
|
||||
calculated_demand BLOB,
|
||||
number_of_persons_in_household INTEGER,
|
||||
fulfilled_demand BLOB,
|
||||
status TEXT,
|
||||
heater_busy_methods BLOB
|
||||
)
|
||||
''')
|
||||
conn.commit()
|
||||
|
||||
def __init_table_task_outcomes(self, conn: sqlite3.Connection):
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
SELECT name FROM sqlite_master WHERE type='table' AND name='task_outcomes';
|
||||
''')
|
||||
table_exists = cursor.fetchone()
|
||||
|
||||
if table_exists:
|
||||
print("SQLiteDB table 'task_outcomes' already exists, skipped initialization of table.")
|
||||
else:
|
||||
cursor.execute('''
|
||||
CREATE TABLE task_outcomes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
required_workload_in_percent REAL,
|
||||
runtime INTEGER,
|
||||
tries INTEGER,
|
||||
count INTEGER,
|
||||
diff REAL,
|
||||
diff_factor REAL,
|
||||
actual_date TEXT,
|
||||
heat_demand_per_minute REAL,
|
||||
actual_heat_generated REAL,
|
||||
hostname TEXT,
|
||||
username TEXT
|
||||
)
|
||||
''')
|
||||
conn.commit()
|
||||
|
||||
def __get_instance(self, args) -> List[Host]:
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM instances WHERE id=?", (args,))
|
||||
result = cursor.fetchone()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return result
|
||||
|
||||
def __get_all_instances(self) -> List[Host]:
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM instances")
|
||||
result = cursor.fetchall()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return result
|
||||
|
||||
def __update_instance(self, args):
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
UPDATE instances
|
||||
SET owner=?, calculated_demand=?, number_of_persons_in_household=?, fulfilled_demand=?, status=?, heater_busy_methods=?
|
||||
WHERE id=?
|
||||
''', (args['owner'], args['calculated_demand'], args['number_of_persons_in_household'], args['fulfilled_demand'], args['status'], args['heater_busy_methods'], args['id']))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def __remove_instance(self, args):
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM instances WHERE id=?", (args,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def __remove_all_instances(self):
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM instances")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def _get_instances(self) -> List[HeaterInstanceInterface]:
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM instances")
|
||||
potential_instances = cursor.fetchall()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# Transform potential instances to objects which application can communicate with
|
||||
instance_objects = []
|
||||
for instance in potential_instances:
|
||||
id, owner, calculated_demand, number_of_persons_in_household, fulfilled_demand, status, heater_busy_methods = instance
|
||||
calculated_demand_json = json.loads(calculated_demand)
|
||||
fulfilled_demand_json = json.loads(fulfilled_demand)
|
||||
heater_busy_methods_json = json.loads(heater_busy_methods)
|
||||
host = Host(hostname=id, username=owner, ssh_key_filename="", passphrase="")
|
||||
heater_instance_interface = HeaterInstanceInterface(host)
|
||||
instance_objects.append(heater_instance_interface)
|
||||
|
||||
return instance_objects
|
||||
|
||||
def insert_task_outcome_into_instances_table(self, heater_instance_interface: HeaterInstanceInterface, outcome_list: List[TaskOutcome]):
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
energy_demands = []
|
||||
fulfilled_demands = []
|
||||
|
||||
for outcome in outcome_list:
|
||||
energy_demands.append({
|
||||
"date": outcome.get_actual_date().strftime("%d.%m.%Y"),
|
||||
"energy_demand_in_watts": outcome.get_heat_demand_per_minute() * 60 # assuming demand per minute
|
||||
})
|
||||
fulfilled_demands.append({
|
||||
"date": outcome.get_actual_date().strftime("%d.%m.%Y"),
|
||||
"scored_energy_demand_in_watts": outcome.get_actual_heat_generated() * 60, # assuming generated heat per minute
|
||||
"busy_method_used": ["hpc"] # example method used
|
||||
})
|
||||
|
||||
calculated_demand_json = {"energy_demands": energy_demands}
|
||||
fulfilled_demand_json = {"scored_demand": fulfilled_demands}
|
||||
calculated_demand_blob = json.dumps(calculated_demand_json).encode('utf-8')
|
||||
fulfilled_demand_blob = json.dumps(fulfilled_demand_json).encode('utf-8')
|
||||
heater_busy_methods_blob = json.dumps({"busy_methods_active": ["hpc"]}).encode('utf-8')
|
||||
|
||||
cursor.execute('''
|
||||
INSERT INTO instances (
|
||||
owner, calculated_demand, number_of_persons_in_household,
|
||||
fulfilled_demand, status, heater_busy_methods
|
||||
) VALUES (?, ?, ?, ?, ?, ?)
|
||||
''', (
|
||||
heater_instance_interface.get_host().username,
|
||||
calculated_demand_blob,
|
||||
3, # assuming a default value, should be dynamic
|
||||
fulfilled_demand_blob,
|
||||
'online',
|
||||
heater_busy_methods_blob
|
||||
))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def insert_task_outcome(self, outcome: TaskOutcome):
|
||||
conn = sqlite3.connect(self.__db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
INSERT INTO task_outcomes (
|
||||
required_workload_in_percent, runtime, tries, count, diff, diff_factor, actual_date, heat_demand_per_minute, actual_heat_generated, hostname, username
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (
|
||||
outcome.get_required_workload_in_percent(),
|
||||
outcome.get_runtime(),
|
||||
outcome.get_tries(),
|
||||
outcome.get_count(),
|
||||
outcome.get_diff(),
|
||||
outcome.get_diff_factor(),
|
||||
outcome.get_actual_date().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
outcome.get_heat_demand_per_minute(),
|
||||
outcome.get_actual_heat_generated(),
|
||||
outcome.get_hostname(),
|
||||
outcome.get_username()
|
||||
))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# def insert_data(self, owner: str, calculated_demand: List[dict], number_of_persons_in_household: int, fulfilled_demand: List[dict], status: str, heater_busy_methods: List[str]):
|
||||
# conn = sqlite3.connect(self.__db_path)
|
||||
# cursor = conn.cursor()
|
||||
|
||||
# calculated_demand_blob = json.dumps({"energy_demands": calculated_demand}).encode('utf-8')
|
||||
# fulfilled_demand_blob = json.dumps({"scored_demand": fulfilled_demand}).encode('utf-8')
|
||||
# heater_busy_methods_blob = json.dumps({"busy_methods_active": heater_busy_methods}).encode('utf-8')
|
||||
|
||||
# cursor.execute('''
|
||||
# INSERT INTO instances (
|
||||
# owner, calculated_demand, number_of_persons_in_household,
|
||||
# fulfilled_demand, status, heater_busy_methods
|
||||
# ) VALUES (?, ?, ?, ?, ?, ?)
|
||||
# ''', (
|
||||
# owner,
|
||||
# calculated_demand_blob,
|
||||
# number_of_persons_in_household,
|
||||
# fulfilled_demand_blob,
|
||||
# status,
|
||||
# heater_busy_methods_blob
|
||||
# ))
|
||||
|
||||
# conn.commit()
|
||||
# conn.close()
|
||||
24
load_balancer/global_outcome.py
Normal file
24
load_balancer/global_outcome.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# author Aaron Moser
|
||||
|
||||
import threading
|
||||
|
||||
class GlobalOutcome:
|
||||
|
||||
def __init__(self):
|
||||
self.tries_count_lock = threading.Lock()
|
||||
self.tries = 0
|
||||
self.count = 0
|
||||
|
||||
def update_tries_count(self, new_tries:int, new_count:int):
|
||||
with self.tries_count_lock:
|
||||
self.tries += new_tries
|
||||
self.count += new_count
|
||||
|
||||
def get_tries_count(self):
|
||||
with self.tries_count_lock:
|
||||
return self.tries, self.count
|
||||
|
||||
def reset_tries_count(self):
|
||||
with self.tries_count_lock:
|
||||
tries = 0
|
||||
count = 0
|
||||
148
load_balancer/heat_demand_simulator.py
Normal file
148
load_balancer/heat_demand_simulator.py
Normal file
@@ -0,0 +1,148 @@
|
||||
"""
|
||||
HEATING DEMAND EXAMPLE
|
||||
"""
|
||||
|
||||
|
||||
import datetime
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.dates as mdates
|
||||
|
||||
# comment it if you dowloaded demod from GitHub
|
||||
import demod
|
||||
|
||||
from demod.simulators.base_simulators import SimLogger
|
||||
from demod.datasets.GermanTOU.loader import GTOU
|
||||
from demod.datasets.OpenPowerSystems.loader import OpenPowerSystemClimate
|
||||
from demod.datasets.Germany.loader import GermanDataHerus
|
||||
|
||||
from demod.simulators.sparse_simulators import SparseTransitStatesSimulator
|
||||
from demod.simulators.weather_simulators import RealClimate
|
||||
from demod.simulators.lighting_simulators import CrestLightingSimulator
|
||||
from demod.simulators.heating_simulators import FiveModulesHeatingSimulator
|
||||
from demod.simulators.appliance_simulators import SubgroupApplianceSimulator
|
||||
from demod.simulators.weather_simulators import RealInterpolatedClimate
|
||||
|
||||
|
||||
#%% INITIALIZATION
|
||||
|
||||
def heat_demand(seed, date):
|
||||
np.random.seed(seed)
|
||||
data = GermanDataHerus(version='v0.1')
|
||||
# time_ = datetime.datetime(2018, 1, 1, 0, 0, 0) # starting time of simulation
|
||||
time_ = date
|
||||
days = 1 # number of days to be simulated
|
||||
n_households = 1 # number of households to be simulated
|
||||
subgroup = {
|
||||
'n_residents': 2,
|
||||
'household_type': 2,
|
||||
} # n° residents should be consisten with the household type
|
||||
# Here the available household types:
|
||||
# 1 = One person household
|
||||
# 2 = Couple without kids
|
||||
# 3 = Single Parent with at least one kid under 18 and the other under 27
|
||||
# 4 = Couple with at least one kid under 18 and the other under 27
|
||||
# 5 = Others
|
||||
|
||||
# Occupancy
|
||||
occ_sim = SparseTransitStatesSimulator(
|
||||
n_households, subgroup, data,
|
||||
logger=SimLogger('get_active_occupancy', 'get_occupancy'),
|
||||
start_datetime=time_
|
||||
)
|
||||
|
||||
|
||||
# Climate
|
||||
climate_sim = RealInterpolatedClimate(
|
||||
data,
|
||||
start_datetime=time_,
|
||||
logger=SimLogger(
|
||||
'get_irradiance', 'get_outside_temperature'
|
||||
),
|
||||
# choose the one minute step size
|
||||
step_size = datetime.timedelta(minutes=1),
|
||||
)
|
||||
|
||||
|
||||
# Heating system
|
||||
# It integrates (1) heating demand, (2) thermostat, (3) building thermal
|
||||
# dynamics, (4) heating system control and (5) operation
|
||||
heating_sim = FiveModulesHeatingSimulator(
|
||||
n_households=n_households,
|
||||
initial_outside_temperature=climate_sim.get_outside_temperature(),
|
||||
# The algo that computes the heat demand like in CREST
|
||||
heatdemand_algo='heat_max_emmiters',
|
||||
logger=SimLogger(
|
||||
'get_temperatures',
|
||||
'get_dhw_heat_demand',
|
||||
'get_sh_heat_demand',
|
||||
'get_heat_outputs',
|
||||
'get_power_demand',
|
||||
)
|
||||
)
|
||||
|
||||
# Appliances, water fixtures
|
||||
app_sim = SubgroupApplianceSimulator(
|
||||
[subgroup], [n_households], data=data,
|
||||
initial_active_occupancy=occ_sim.get_active_occupancy(),
|
||||
start_datetime=time_,
|
||||
logger=SimLogger(
|
||||
'get_power_demand', 'get_dhw_heating_demand',
|
||||
'get_current_power_consumptions', aggregated=False )
|
||||
)
|
||||
|
||||
# Lighting
|
||||
lighting_sim = CrestLightingSimulator(
|
||||
n_households=n_households,
|
||||
data=data,
|
||||
logger=SimLogger('get_power_demand'),
|
||||
bulbs_sampling_algo='randn'
|
||||
)
|
||||
|
||||
#%% SIMULATION
|
||||
|
||||
appliance_usage = []
|
||||
|
||||
for _ in range(24*days*6):
|
||||
# every 10 minutes
|
||||
occ_sim.step()
|
||||
|
||||
for __ in range(10):
|
||||
# every 1 minute
|
||||
climate_sim.step()
|
||||
|
||||
app_sim.step(
|
||||
occ_sim.get_active_occupancy()
|
||||
)
|
||||
lighting_sim.step(
|
||||
occ_sim.get_active_occupancy(),
|
||||
climate_sim.get_irradiance()
|
||||
)
|
||||
heating_sim.step(
|
||||
climate_sim.get_outside_temperature(),
|
||||
climate_sim.get_irradiance(),
|
||||
app_sim.get_dhw_heating_demand(),
|
||||
occ_sim.get_thermal_gains(),
|
||||
lighting_sim.get_thermal_gains(),
|
||||
app_sim.get_thermal_gains(),
|
||||
external_target_temperature={'space_heating':20},
|
||||
)
|
||||
# you can pass different target temperature profiles
|
||||
# here it is considered a constant temperature of 20°C
|
||||
|
||||
# store appliance usage
|
||||
appliance_usage.append(app_sim.get_current_usage())
|
||||
# Wattzahlen in 1 Minuten Schritten: Summe in kWh
|
||||
power_demand_1_minute_steps = heating_sim.logger.get('get_power_demand')
|
||||
return power_demand_1_minute_steps
|
||||
|
||||
# Returns power demand in kWh as array where each element represents demand of 10 minutes
|
||||
def heat_demand_per_minute_in_kW(power_demand_1_minute_steps):
|
||||
# Maps array of elements to function, that divides each element by 1000
|
||||
# By dividing by 1000, W is transformed to kW
|
||||
return np.array(power_demand_1_minute_steps) / 1000
|
||||
|
||||
# date = datetime.datetime(2018,4,13)
|
||||
# seed =100005
|
||||
# bedarf = heat_requirement_daily(heat_requirement(seed, date))
|
||||
# print(f"Der Tageswärmebedarf am {date.day}. {date.month}. ist {bedarf:.2f} kWh")
|
||||
11
load_balancer/heater/README.md
Normal file
11
load_balancer/heater/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Heater
|
||||
|
||||
## Kompilieren
|
||||
|
||||
### Ohne Multithreading
|
||||
|
||||
`g++ ./monteCarloPi.cpp -O3 -o monteCarloPi`
|
||||
|
||||
### Mit Multithreading
|
||||
|
||||
`g++ ./monteCarloPi.cpp -O3 -o monteCarloPi -fopenmp`
|
||||
112
load_balancer/heater/heater_instance.py
Normal file
112
load_balancer/heater/heater_instance.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import paramiko
|
||||
import weakref
|
||||
import math
|
||||
import json
|
||||
|
||||
from heater.host import Host
|
||||
|
||||
|
||||
class HeaterInstance:
|
||||
def __init__(self, host: Host, iter=1000):
|
||||
"""Creates a heater instance
|
||||
|
||||
Args:
|
||||
host (Host): host to connect to
|
||||
iter (int, optional): Number of iterations to compute in one go. Defaults to 1000.
|
||||
|
||||
Raises:
|
||||
IOError: if there was an error reading the file
|
||||
paramiko.ssh_exception.PasswordRequiredException: if the private key file is encrypted, and password is None
|
||||
paramiko.ssh_exception.SSHException: if the key file is invalid
|
||||
"""
|
||||
self.host = host
|
||||
self.iter = iter
|
||||
self.__ssh = paramiko.SSHClient()
|
||||
self.__ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
if host.passphrase:
|
||||
self.__key = paramiko.RSAKey.from_private_key_file(host.ssh_key_filename, host.passphrase)
|
||||
else:
|
||||
self.__key = paramiko.RSAKey.from_private_key_file(host.ssh_key_filename)
|
||||
self.__finalizer = weakref.finalize(self, self.close)
|
||||
|
||||
def run(self, percent: float, milliseconds: int) -> tuple[int, int, float, float]:
|
||||
"""Runs heater for a time dependend on given parameters.
|
||||
Returns number of tries, number of hits, difference between wanted runtime and executed runtime, difference as a factor.
|
||||
Differnce is negative when was shorter than expected or positive when longer than expected.
|
||||
Difference factor is the percent of the expected time the program ran.
|
||||
|
||||
Args:
|
||||
percent (float): cpu usage percentage
|
||||
milliseconds (int): time to run
|
||||
|
||||
Returns:
|
||||
tuple[int, int, float, float]: tries, count, difference, difference as factor
|
||||
"""
|
||||
runtime = percent * milliseconds
|
||||
cmd = f'./monteCarloPi -d {math.floor(runtime)} -i {self.iter}'
|
||||
duration = 0.
|
||||
tries = 0
|
||||
count = 0
|
||||
|
||||
try:
|
||||
_, stdout, stderr = self.__ssh.exec_command(cmd)
|
||||
if stderr.readlines() == []:
|
||||
try:
|
||||
result_json = json.loads(stdout.read().decode().strip("\n"))
|
||||
tries = result_json["tries"]
|
||||
count = result_json["count"]
|
||||
duration = result_json["durationMilli"]
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
except paramiko.SSHException:
|
||||
pass
|
||||
diff = (duration - runtime) * (1 / percent)
|
||||
diffFactor = duration / runtime
|
||||
return tries, count, diff, diffFactor
|
||||
|
||||
def connect(self):
|
||||
"""Connect to heater per ssh.
|
||||
|
||||
Raises:
|
||||
paramiko.ssh_exception.BadHostKeyException: if the server's host key could not be verified.
|
||||
paramiko.ssh_exception.AuthenticationException: if authentication failed.
|
||||
paramiko.ssh_exception.UnableToAuthenticate: if authentication failed (when auth_strategy is non-None; and note that this is a subclass of AuthenticationException).
|
||||
socket.error: if a socket error (other than connection-refused or host-unreachable) occurred while connecting.
|
||||
paramiko.ssh_exception.NoValidConnectionsError: if all valid connection targets for the requested hostname (eg IPv4 and IPv6) yielded connection-refused or host-unreachable socket errors.
|
||||
paramiko.ssh_exception.SSHException: if there was any other error connecting or establishing an SSH session.
|
||||
"""
|
||||
self.__ssh.connect(hostname=self.host.hostname, username=self.host.username, pkey=self.__key)
|
||||
|
||||
@property
|
||||
def open(self) -> bool:
|
||||
"""Returns if ssh connection is open.
|
||||
|
||||
Returns:
|
||||
bool: is ssh connection open
|
||||
"""
|
||||
if self.__ssh.get_transport() is not None:
|
||||
return self.__ssh.get_transport().is_active()
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
"""Closes ssh connection.
|
||||
"""
|
||||
if self.open:
|
||||
self.__ssh.close()
|
||||
|
||||
def cleanup(self):
|
||||
"""cleans heater instance up.
|
||||
Only call once.
|
||||
Don't use instance after cleanup.
|
||||
Is called automatically by garbage collection.
|
||||
"""
|
||||
self.__finalizer()
|
||||
|
||||
@property
|
||||
def cleandup(self) -> bool:
|
||||
"""Returns if object was alreade cleand up.
|
||||
|
||||
Returns:
|
||||
bool: was object cleand up
|
||||
"""
|
||||
return not self.__finalizer.alive
|
||||
17
load_balancer/heater/host.py
Normal file
17
load_balancer/heater/host.py
Normal file
@@ -0,0 +1,17 @@
|
||||
class Host:
|
||||
def __init__(self, hostname: str, username: str, ssh_key_filename: str, passphrase: str):
|
||||
"""Create host to connect to.
|
||||
|
||||
Args:
|
||||
hostname (str): hostname to connect to
|
||||
username (str): user to use for connection
|
||||
ssh_key_filename (str): path to ssh key file
|
||||
passphrase (str): passphrase for ssh key
|
||||
"""
|
||||
self.hostname = hostname
|
||||
self.username = username
|
||||
self.ssh_key_filename = ssh_key_filename
|
||||
self.passphrase = passphrase
|
||||
|
||||
def equals(self, other):
|
||||
return (self.hostname == other.hostname) and (self.username == other.username)
|
||||
146
load_balancer/heater/monteCarloPi.cpp
Normal file
146
load_balancer/heater/monteCarloPi.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#if defined(_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
class InputParser
|
||||
{
|
||||
public:
|
||||
InputParser(int &argc, char **argv)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
this->tokens.push_back(std::string(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &getCmdOption(const std::string &option) const
|
||||
{
|
||||
std::vector<std::string>::const_iterator itr;
|
||||
itr = std::find(this->tokens.begin(), this->tokens.end(), option);
|
||||
if (itr != this->tokens.end() && ++itr != this->tokens.end())
|
||||
{
|
||||
return *itr;
|
||||
}
|
||||
static const std::string empty_string("");
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
bool cmdOptionExists(const std::string &option) const
|
||||
{
|
||||
return std::find(this->tokens.begin(), this->tokens.end(), option) != this->tokens.end();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> tokens;
|
||||
};
|
||||
|
||||
struct MonteCarloResult
|
||||
{
|
||||
int64_t tries = 0;
|
||||
int64_t count = 0;
|
||||
double durationMilli = 0;
|
||||
};
|
||||
|
||||
const int defaultIterationsPerChunk = 1000;
|
||||
|
||||
MonteCarloResult computePI(int milliseconds, int iterationsPerChunk)
|
||||
{
|
||||
std::chrono::duration<double, std::milli> diff;
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
int64_t tries = 0;
|
||||
int64_t count = 0;
|
||||
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp parallel reduction(+ : count, tries)
|
||||
#endif
|
||||
{
|
||||
#if defined(_OPENMP)
|
||||
std::mt19937 rng(static_cast<unsigned>(omp_get_thread_num()));
|
||||
#else
|
||||
std::mt19937 rng(0);
|
||||
#endif
|
||||
std::uniform_real_distribution<double> dist(0., 1.);
|
||||
|
||||
do
|
||||
{
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp for nowait
|
||||
#endif
|
||||
for (int64_t i = 0; i < iterationsPerChunk; ++i)
|
||||
{
|
||||
double x = dist(rng);
|
||||
double y = dist(rng);
|
||||
if ((x * x + y * y) < 1)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
tries++;
|
||||
}
|
||||
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp master
|
||||
#endif
|
||||
{
|
||||
auto end = std::chrono::system_clock::now();
|
||||
diff = end - start;
|
||||
}
|
||||
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp barrier
|
||||
#endif
|
||||
} while (diff.count() < milliseconds);
|
||||
}
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
diff = end - start;
|
||||
MonteCarloResult result{tries, count, diff.count()};
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// parse parameters
|
||||
InputParser input(argc, argv);
|
||||
std::filesystem::path path(argv[0]);
|
||||
|
||||
// help
|
||||
if (input.cmdOptionExists("-h") || argc <= 1)
|
||||
{
|
||||
std::cout << "Usage: " << path.filename() << " -d <milliseconds>" << std::endl;
|
||||
std::cout << " Options:" << std::endl;
|
||||
std::cout << " -d <milliseconds>: Number of milliseconds to compute pi for" << std::endl;
|
||||
std::cout << " -i <iterations>: Number of iterations to compute in one go" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// error if -d parameter not set
|
||||
if (!input.cmdOptionExists("-d"))
|
||||
{
|
||||
std::cout << "Error: Option -d must be set" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check if -i parameter is set and set iterations
|
||||
int iterationsPerChunk = defaultIterationsPerChunk;
|
||||
if (input.cmdOptionExists("-i"))
|
||||
{
|
||||
iterationsPerChunk = std::stoi(input.getCmdOption("-i"));
|
||||
}
|
||||
|
||||
// get duration
|
||||
const int duration = std::stoi(input.getCmdOption("-d"));
|
||||
|
||||
// run Monte Carlo
|
||||
MonteCarloResult result = computePI(duration, iterationsPerChunk);
|
||||
|
||||
// format result
|
||||
std::cout << "{\"tries\":" << result.tries << ", \"count\":" << result.count << ", \"durationMilli\":" << result.durationMilli << "}" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
32
load_balancer/heater/test_remote_pi.py
Normal file
32
load_balancer/heater/test_remote_pi.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import paramiko
|
||||
from credentials import hostname, username, ssh_key_filename, passphrase
|
||||
from host import Host
|
||||
from heater_instance import HeaterInstance
|
||||
|
||||
|
||||
def test_ssh():
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
key = paramiko.RSAKey.from_private_key_file(ssh_key_filename, passphrase)
|
||||
ssh.connect(hostname, username, pkey=key)
|
||||
|
||||
stdin, stdout, stderr = ssh.exec_command("ls")
|
||||
print(stdout.readlines())
|
||||
print(stderr.readlines())
|
||||
|
||||
ssh.close()
|
||||
|
||||
|
||||
def test_heater():
|
||||
host = Host(hostname, username, ssh_key_filename, passphrase)
|
||||
heater = HeaterInstance(host)
|
||||
heater.connect()
|
||||
tries, count, diff = heater.run(0.5, 10)
|
||||
print("diff = %s" % diff)
|
||||
print("pi = %f" % ((count / tries) * 4))
|
||||
heater.close()
|
||||
|
||||
|
||||
test_heater()
|
||||
# test_ssh()
|
||||
96
load_balancer/heater_instance_interface.py
Normal file
96
load_balancer/heater_instance_interface.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# author Aaron Moser
|
||||
|
||||
import paramiko
|
||||
import socket
|
||||
import paramiko.ssh_exception
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from heater.heater_instance import HeaterInstance
|
||||
from heater.host import Host
|
||||
from constants import ConnectErrorCode
|
||||
|
||||
class HeaterInstanceState(Enum):
|
||||
INITIALIZED = 1
|
||||
RUNNING = 2
|
||||
ERROR = 3
|
||||
FINISHED = 4
|
||||
|
||||
# Interface to class HeaterInstance
|
||||
class HeaterInstanceInterface:
|
||||
def __init__(self, host: Host):
|
||||
self.host = host
|
||||
self._heater_instance = HeaterInstance(self.host)
|
||||
self._seed = (abs(hash(self.host.hostname + self.host.username)) % 4294967295)
|
||||
self._state: HeaterInstanceState = HeaterInstanceState.INITIALIZED
|
||||
|
||||
# Tries to connect to instance via ssh, returns an error code if failing
|
||||
def connect(self) -> ConnectErrorCode:
|
||||
try:
|
||||
if (not self._heater_instance.open):
|
||||
self._heater_instance.connect()
|
||||
#print("Connected to the SSH server successfully.")
|
||||
return ConnectErrorCode.CONNECTED
|
||||
|
||||
else:
|
||||
#print("Already connected to SSH server.")
|
||||
return ConnectErrorCode.ALREADY_CONNECTED
|
||||
|
||||
except paramiko.ssh_exception.BadHostKeyException as e:
|
||||
print(f"BadHostKeyException: The server's host key could not be verified. {e}")
|
||||
self._state = HeaterInstanceState.ERROR
|
||||
return ConnectErrorCode.UNVERIFIED_KEY
|
||||
|
||||
except paramiko.ssh_exception.AuthenticationException as e:
|
||||
print(f"AuthenticationException: Authentication failed. {e}")
|
||||
self._state = HeaterInstanceState.ERROR
|
||||
return ConnectErrorCode.AUTHENTICATION_FAILED
|
||||
|
||||
except paramiko.ssh_exception.UnableToAuthenticate as e:
|
||||
print(f"UnableToAuthenticate: Authentication failed with the provided strategy. {e}")
|
||||
self._state = HeaterInstanceState.ERROR
|
||||
return ConnectErrorCode.AUTHENTICATION_FAILED
|
||||
|
||||
except socket.error as e:
|
||||
print(f"SocketError: A socket error occurred while connecting. {e}")
|
||||
self._state = HeaterInstanceState.ERROR
|
||||
return ConnectErrorCode.SOCKET_ERROR
|
||||
|
||||
except paramiko.ssh_exception.NoValidConnectionsError as e:
|
||||
print(f"NoValidConnectionsError: All connection attempts failed. {e}")
|
||||
self._state = HeaterInstanceState.ERROR
|
||||
return ConnectErrorCode.ALL_CONNECTION_ATTEMPTS_FAILED
|
||||
|
||||
except paramiko.ssh_exception.SSHException as e:
|
||||
print(f"SSHException: An error occurred while connecting or establishing an SSH session. {e}")
|
||||
self._state = HeaterInstanceState.ERROR
|
||||
return ConnectErrorCode.SSH_EXCEPTION
|
||||
|
||||
# Closes ssh connection to instance
|
||||
def close(self) -> None:
|
||||
self._heater_instance.close()
|
||||
|
||||
# Sends a task to an instance to produce the required heat
|
||||
def run(self, percent: float, seconds: float) -> tuple[int, int, float, float]:
|
||||
if (not self._heater_instance.open):
|
||||
self.connect()
|
||||
result = 0,0,0
|
||||
if self._state != HeaterInstanceState.ERROR:
|
||||
self._state = HeaterInstanceState.RUNNING
|
||||
try:
|
||||
result = self._heater_instance.run(percent, seconds)
|
||||
except Exception as e:
|
||||
print("Connection closed.")
|
||||
if self._state == HeaterInstanceState.RUNNING:
|
||||
self._state = HeaterInstanceState.FINISHED
|
||||
return result
|
||||
|
||||
# Returns host of instance
|
||||
def get_host(self) -> Host:
|
||||
return self.host
|
||||
|
||||
def get_seed(self) -> int:
|
||||
return self._seed
|
||||
|
||||
def get_state(self) -> HeaterInstanceState:
|
||||
return self._state
|
||||
108
load_balancer/heater_instance_interface_manager.py
Normal file
108
load_balancer/heater_instance_interface_manager.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# author Aaron Moser
|
||||
|
||||
from typing import List
|
||||
from enum import Enum
|
||||
import constants
|
||||
|
||||
from heater_instance_interface import HeaterInstanceInterface
|
||||
from heater_instance_worker_thread import HeaterInstanceWorkerThread
|
||||
from database_interface import DatabaseInterface
|
||||
from global_outcome import GlobalOutcome
|
||||
from heater.host import Host
|
||||
from simulation import Simulation
|
||||
from datetime import datetime
|
||||
|
||||
class HeaterInstanceInterfaceManager:
|
||||
|
||||
class HeaterInstanceInterfaceManagerErrorCode(Enum):
|
||||
HEATER_INSTANCE_ALREADY_EXISTS = 1
|
||||
HEATER_INSTANCE_ADDED = 2
|
||||
HEATER_INSTANCE_ADDED_AND_STARTED = 3
|
||||
HEATER_INSTANCE_REMOVED = 4
|
||||
|
||||
def __init__(self, global_outcome: GlobalOutcome, mode: Simulation.Mode, start_date: datetime, end_date: datetime, database_interface: DatabaseInterface):
|
||||
self.global_outcome = global_outcome
|
||||
self.heater_instances: List[HeaterInstanceInterface] = []
|
||||
self.__worker_thread_pool: List[HeaterInstanceWorkerThread] = []
|
||||
self._mode: Simulation.Mode = mode
|
||||
self.database_interface = database_interface
|
||||
self.start_date = start_date
|
||||
self.end_date = end_date
|
||||
|
||||
# Instance management --------------------------------------------------------------------------------------
|
||||
|
||||
# Adds new heater instance to list of instances
|
||||
def add_heater_instance_and_start_thread_if_running(self, host: Host, simulation_state: constants.State) -> HeaterInstanceInterfaceManagerErrorCode:
|
||||
heater_instance_exists = False
|
||||
for heater_instance in self.heater_instances:
|
||||
if heater_instance.get_host().equals(host):
|
||||
heater_instance_exists = True
|
||||
return HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_ALREADY_EXISTS
|
||||
if not heater_instance_exists:
|
||||
new_heater_instance_interface = HeaterInstanceInterface(host)
|
||||
self.heater_instances.append(new_heater_instance_interface)
|
||||
if simulation_state == constants.State.Running:
|
||||
new_thread = HeaterInstanceWorkerThread(self.global_outcome, self._mode, new_heater_instance_interface, self.start_date, self.end_date, self.database_interface)
|
||||
self.__worker_thread_pool.append(new_thread)
|
||||
new_thread.run()
|
||||
return HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_ADDED_AND_STARTED
|
||||
else:
|
||||
return HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_ADDED
|
||||
|
||||
# Removes heater instance from list of instances
|
||||
def remove_heater_instance(self, host) -> HeaterInstanceInterfaceManagerErrorCode:
|
||||
heater_instance_exists = False
|
||||
for heater_instance in self.heater_instances:
|
||||
if heater_instance.get_host().equals(host):
|
||||
heater_instance_exists = True
|
||||
if heater_instance_exists:
|
||||
self.heater_instances.remove(HeaterInstanceInterface(host))
|
||||
for thread in self.__worker_thread_pool:
|
||||
if thread.get_instance_interface().get_host().equals(host):
|
||||
thread.stop()
|
||||
return HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_REMOVED
|
||||
|
||||
# Returns list of all heater instances
|
||||
def get_heater_instances(self):
|
||||
return self.heater_instances
|
||||
|
||||
def show_heater_instances(self):
|
||||
if len(self.heater_instances) == 0:
|
||||
print("No instances registered.")
|
||||
else:
|
||||
for heater_instance in self.heater_instances:
|
||||
print("Hostname: " + heater_instance.get_host().hostname + ", Username: " + heater_instance.get_host().username + ", Seed: " + str(heater_instance.get_seed()))
|
||||
|
||||
def get_heater_instances_count(self) -> int:
|
||||
return len(self.heater_instances)
|
||||
|
||||
def set_start_and_end_date(self, start_date: datetime, end_date: datetime):
|
||||
self.start_date = start_date
|
||||
self.end_date = end_date
|
||||
|
||||
# Threading-------------------------------------------------------------------------------------------------
|
||||
|
||||
# Changes simulation mode, by restarting all threads with new mode
|
||||
def change_simulation_mode(self, mode: Simulation.Mode):
|
||||
self._mode = mode
|
||||
self.stop_threads()
|
||||
self.instantiate_threads()
|
||||
self.start_threads()
|
||||
|
||||
# Stops all running threads
|
||||
def stop_threads(self):
|
||||
for worker_thread in self.__worker_thread_pool:
|
||||
if worker_thread.get_stop_event_state() == False:
|
||||
worker_thread.stop()
|
||||
|
||||
# Clears list of threads and creates new threads which are then appended to cleared list
|
||||
def instantiate_threads(self):
|
||||
self.__worker_thread_pool: List[HeaterInstanceWorkerThread] = []
|
||||
for heater_instance_interface in self.heater_instances:
|
||||
self.__worker_thread_pool.append(HeaterInstanceWorkerThread(self.global_outcome, self._mode, heater_instance_interface, self.start_date, self.end_date, self.database_interface))
|
||||
|
||||
# Starts threads in list of threads if state of instance is 'INITIALIZED'
|
||||
def start_threads(self):
|
||||
for worker_thread in self.__worker_thread_pool:
|
||||
if worker_thread.get_stop_event_state() == False:
|
||||
worker_thread.start()
|
||||
46
load_balancer/heater_instance_worker_thread.py
Normal file
46
load_balancer/heater_instance_worker_thread.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# author Aaron Moser, Theresa Herr
|
||||
|
||||
import datetime
|
||||
import threading
|
||||
from heater_instance_interface import HeaterInstanceInterface
|
||||
from database_interface import DatabaseInterface
|
||||
from global_outcome import GlobalOutcome
|
||||
from simulation import Simulation
|
||||
import tasks.daily_task
|
||||
import tasks.realtime_task
|
||||
|
||||
class HeaterInstanceWorkerThread(threading.Thread):
|
||||
|
||||
def __init__(self, global_outcome: GlobalOutcome, mode: Simulation.Mode, heater_instance_interface: HeaterInstanceInterface, start_date: datetime.datetime, end_date: datetime.datetime, database_interface: DatabaseInterface):
|
||||
super().__init__()
|
||||
self.global_outcome: GlobalOutcome = global_outcome
|
||||
self.__mode: Simulation.Mode = mode
|
||||
self._stop_event: threading.Event = threading.Event()
|
||||
self.heater_instance_interface: HeaterInstanceInterface = heater_instance_interface
|
||||
self.start_date: datetime.datetime = start_date
|
||||
self.end_date: datetime.datetime = end_date
|
||||
self.db_interface: DatabaseInterface = database_interface
|
||||
|
||||
def run(self):
|
||||
while not self._stop_event.is_set():
|
||||
match self.__mode:
|
||||
case Simulation.Mode.REALTIME:
|
||||
tasks.realtime_task.realtime_task(self.global_outcome, self.heater_instance_interface, self.start_date, self.end_date, self.save_outcome)
|
||||
case Simulation.Mode.DAILY:
|
||||
tasks.daily_task.daily_task(self.global_outcome, self.heater_instance_interface, self.start_date, self.end_date, self.save_outcome)
|
||||
case _:
|
||||
print("Error unknown mode.")
|
||||
|
||||
def get_instance_interface(self) -> HeaterInstanceInterface:
|
||||
return self.heater_instance_interface
|
||||
|
||||
def stop(self):
|
||||
self.heater_instance_interface.close()
|
||||
self._stop_event.set()
|
||||
|
||||
def get_stop_event_state(self) -> bool:
|
||||
return self._stop_event.is_set()
|
||||
|
||||
def save_outcome(self, outcome_list: list):
|
||||
for outcome in outcome_list:
|
||||
self.db_interface.insert_task_outcome(outcome)
|
||||
383
load_balancer/load_balancer_impl.py
Normal file
383
load_balancer/load_balancer_impl.py
Normal file
@@ -0,0 +1,383 @@
|
||||
# author Aaron Moser
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
import constants
|
||||
|
||||
from typing import List
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from heater_instance_interface_manager import HeaterInstanceInterfaceManager
|
||||
from global_outcome import GlobalOutcome
|
||||
from simulation import Simulation
|
||||
from heater.host import Host
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class LoadBalancer:
|
||||
"""Implementation of load balancer, allows to add instances and start the simulation.
|
||||
"""
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
global_outcome,
|
||||
db_interface,
|
||||
simulation_mode: Simulation.Mode,
|
||||
start_date: datetime,
|
||||
end_date: datetime
|
||||
):
|
||||
"""Instantiates a LoadBalancer object.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, which is instantiated.
|
||||
db_interface (DatabaseInterface): interface class to database.
|
||||
simulation_mode (Simulation.Mode): current mode of simulation.
|
||||
"""
|
||||
self.state: constants.State = constants.State.Stopped
|
||||
self.global_outcome: GlobalOutcome = global_outcome
|
||||
self.db_interface = db_interface
|
||||
self.simulation = Simulation()
|
||||
self.simulation.set_mode(simulation_mode)
|
||||
self.running = False
|
||||
self.start_date = start_date
|
||||
self.end_date = end_date
|
||||
self.heater_instance_interface_manager: HeaterInstanceInterfaceManager = HeaterInstanceInterfaceManager(global_outcome, simulation_mode, start_date, end_date, db_interface)
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def run(self) -> None:
|
||||
"""Loop of asking user for input and processing entered command.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
self.print_start_message()
|
||||
self.running = True
|
||||
while self.running:
|
||||
self._process_first_level_command(self._get_command_args())
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def print_start_message(self) -> None:
|
||||
"""Prints message, load balancer started
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
print(constants.START_MESSAGE)
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def _get_command_args(self) -> List[str]:
|
||||
"""Prompts user to enter command and returns command string array splitted by spaces
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
List[str]: Partstrings which are created by splitting the command entered by user at spaces.
|
||||
"""
|
||||
return input("-------------------------------\nPlease enter command (Enter 'help' to see all commands)\nCommand: ").lower().split(" ")
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def _process_first_level_command(self, command_args) -> None:
|
||||
"""Processes the first level (command_args[0]) command.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
command_args (List[str]): partstrings of command string split at spaces.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
match command_args[0]:
|
||||
|
||||
#
|
||||
case constants.START_SIMULATION_COMMAND:
|
||||
if self.heater_instance_interface_manager.get_heater_instances_count() >= constants.MINIMUM_NUMBER_CLIENTS:
|
||||
self.start_simulation(command_args)
|
||||
else:
|
||||
print("Please add more instances, before starting the simulation.")
|
||||
|
||||
case constants.STOP_SIMULATION_COMMAND:
|
||||
self.stop_simulation()
|
||||
|
||||
#
|
||||
case constants.SET_SIMULATION_MODE_COMMAND:
|
||||
if self.heater_instance_interface_manager.get_heater_instances_count() >= constants.MINIMUM_NUMBER_CLIENTS:
|
||||
self.set_simulation_mode(command_args)
|
||||
else:
|
||||
print("Please add more instances, before re-setting the simulation mode.")
|
||||
|
||||
#
|
||||
case constants.ADD_INSTANCE_COMMAND:
|
||||
if self.heater_instance_interface_manager.get_heater_instances_count() < constants.MAXIMUM_NUMBER_CLIENTS:
|
||||
self.add_instance(command_args)
|
||||
else:
|
||||
print("Maximum number of clients reached, you have to remove an instance before you can add another.")
|
||||
|
||||
#
|
||||
case constants.REMOVE_INSTANCE_COMMAND:
|
||||
self.remove_instance(command_args)
|
||||
|
||||
#
|
||||
case constants.SHOW_INSTANCES_COMMAND:
|
||||
self.show_instances()
|
||||
|
||||
case constants.DISPLAY_OUTCOME_COMMAND:
|
||||
self.display_outcome()
|
||||
|
||||
#
|
||||
case constants.HELP_COMMAND:
|
||||
self.print_help()
|
||||
|
||||
#
|
||||
case constants.EXIT_COMMAND:
|
||||
self.exit_application()
|
||||
|
||||
# If user enters command, which doesn't match any case above.
|
||||
case _:
|
||||
print("Unknown command: " + command_args[0])
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def start_simulation(self, command_args) -> None:
|
||||
"""Starts simulation.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
command_args (List[str]): partstrings of command string split at spaces.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
if len(command_args) > 1:
|
||||
match command_args[1]:
|
||||
case constants.SET_SIMULATION_MODE_COMMAND_REALTIME:
|
||||
if len(command_args) == 4:
|
||||
start_date = command_args[2]
|
||||
end_date = command_args[3]
|
||||
date_format = "%d.%m.%Y"
|
||||
self.start_date = datetime.strptime(start_date, date_format)
|
||||
self.end_date = datetime.strptime(end_date, date_format)
|
||||
self.start_simulation_in_mode(Simulation.Mode.REALTIME)
|
||||
|
||||
elif len(command_args) == 3:
|
||||
start_date = command_args[2]
|
||||
date_format = "%d.%m.%Y"
|
||||
self.start_date = datetime.strptime(start_date, date_format)
|
||||
one_day_difference = timedelta(days=1)
|
||||
self.end_date = start_date + one_day_difference
|
||||
self.start_simulation_in_mode(Simulation.Mode.REALTIME)
|
||||
|
||||
else:
|
||||
self.start_simulation_in_mode(Simulation.Mode.REALTIME)
|
||||
|
||||
case constants.SET_SIMULATION_MODE_COMMAND_DAILY:
|
||||
if len(command_args) == 4:
|
||||
start_date = command_args[2]
|
||||
end_date = command_args[3]
|
||||
date_format = "%d.%m.%Y"
|
||||
self.start_date = datetime.strptime(start_date, date_format)
|
||||
self.end_date = datetime.strptime(end_date, date_format)
|
||||
self.start_simulation_in_mode(Simulation.Mode.DAILY)
|
||||
|
||||
elif len(command_args) == 3:
|
||||
start_date = command_args[2]
|
||||
date_format = "%d.%m.%Y"
|
||||
self.start_date = datetime.strptime(start_date, date_format)
|
||||
one_day_difference = timedelta(days=1)
|
||||
self.end_date = start_date + one_day_difference
|
||||
self.start_simulation_in_mode(Simulation.Mode.DAILY)
|
||||
|
||||
else:
|
||||
self.start_simulation_in_mode(Simulation.Mode.DAILY)
|
||||
|
||||
case _:
|
||||
print("Unknown simulation command.")
|
||||
else:
|
||||
self.heater_instance_interface_manager.change_simulation_mode(self.simulation.get_mode())
|
||||
|
||||
def start_simulation_in_mode(self, simulation_mode: Simulation.Mode):
|
||||
self.heater_instance_interface_manager.set_start_and_end_date(self.start_date, self.end_date)
|
||||
self.heater_instance_interface_manager.change_simulation_mode(simulation_mode)
|
||||
self.simulation.set_mode(simulation_mode)
|
||||
self.state: constants.State = constants.State.Running
|
||||
match simulation_mode:
|
||||
case Simulation.Mode.DAILY:
|
||||
print("Simulation started in daily mode. With start date: " + str(self.start_date) + " and end date: " + str(self.end_date))
|
||||
case Simulation.Mode.REALTIME:
|
||||
print("Simulation started in realtime mode. With start date: " + str(self.start_date) + " and end date: " + str(self.end_date))
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def stop_simulation(self) -> None:
|
||||
if self.state == constants.State.Running:
|
||||
self.heater_instance_interface_manager.stop_threads()
|
||||
self.state = constants.State.Stopped
|
||||
print("Stopped simulation. To restart enter StartSimulation [mode] [start date] [end date].")
|
||||
else:
|
||||
print("Error: Simulation is not running. Can't stop if not running.")
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def set_simulation_mode(self, command_args) -> None:
|
||||
"""If simulation is running, a user has to use stop simulation and start again or just SetSimulationMode.
|
||||
Will stop currently running threads and restart them with new mode.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
if len(command_args) > 1:
|
||||
match command_args[1]:
|
||||
case constants.SET_SIMULATION_MODE_COMMAND_REALTIME:
|
||||
if self.get_approval():
|
||||
self.heater_instance_interface_manager.change_simulation_mode(Simulation.Mode.REALTIME)
|
||||
self.simulation.set_mode(Simulation.Mode.REALTIME)
|
||||
else:
|
||||
print("Continuing at current mode.")
|
||||
|
||||
case constants.SET_SIMULATION_MODE_COMMAND_DAILY:
|
||||
if self.get_approval():
|
||||
self.heater_instance_interface_manager.change_simulation_mode(Simulation.Mode.DAILY)
|
||||
self.simulation.set_mode(Simulation.Mode.DAILY)
|
||||
else:
|
||||
print("Continuing at current mode.")
|
||||
else:
|
||||
print("Error, simulation mode missing, please re-enter command.")
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def get_approval(self) -> bool:
|
||||
"""Prompts user if s/he really wants to stop the simulation.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
bool: True if user enters 'Y|y', False otherwise.
|
||||
"""
|
||||
return input("Warning, current simulation will stop. Do you really want to stop? (Y)es (N)o\nCommand: ").lower() == "y"
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def add_instance(self, command_args) -> None:
|
||||
"""Add instance to instance interface manager and start worker thread.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
command_args (List[str]): partstrings of command string split at spaces.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
hostname = command_args[1]
|
||||
username = command_args[2]
|
||||
ssh_key_filename = command_args[3]
|
||||
passphrase = ""
|
||||
if len(command_args) >= 5:
|
||||
passphrase = command_args[4]
|
||||
match self.heater_instance_interface_manager.add_heater_instance_and_start_thread_if_running(Host(hostname, username, ssh_key_filename, passphrase), self.state):
|
||||
case HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_ALREADY_EXISTS:
|
||||
print("Instance already exists.")
|
||||
case HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_ADDED:
|
||||
print("Instance added.")
|
||||
case HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_ADDED_AND_STARTED:
|
||||
print("Instance added and thread started.")
|
||||
case _:
|
||||
print("Unkown error code.")
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def remove_instance(self, command_args) -> None:
|
||||
"""Removes instance indicated by host- and username given in command_args and stops worker thread.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
command_args (List[str]): partstrings of command string split at spaces.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
"""
|
||||
hostname = command_args[1]
|
||||
username = command_args[2]
|
||||
match self.heater_instance_interface_manager.remove_heater_instance(Host(hostname, username, None, None)):
|
||||
case HeaterInstanceInterfaceManager.HeaterInstanceInterfaceManagerErrorCode.HEATER_INSTANCE_REMOVED:
|
||||
print("Instance removed successfully.")
|
||||
case _:
|
||||
print("Unknown error code at remove_instance received.")
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def show_instances(self) -> None:
|
||||
"""Shows instances by printing them to console.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
"""
|
||||
self.heater_instance_interface_manager.show_heater_instances()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def display_outcome(self) -> None:
|
||||
"""Displays global outcome stats by printing them to console.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
"""
|
||||
tries, count = self.global_outcome.get_tries_count()
|
||||
pi:float = 0.0
|
||||
if tries != 0:
|
||||
pi = float(count) / float(tries) * float(4)
|
||||
print("Count: " + str(count) + ", Tries: " + str(tries) + ", PI: " + str(pi))
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def print_help(self) -> None:
|
||||
"""Prints list of commands with description from constants.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
"""
|
||||
for command_description in constants.COMMANDS_HELP:
|
||||
print(command_description)
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def exit_application(self) -> None:
|
||||
"""Exits application by stopping all threads and sets own state to stopped,
|
||||
then stops while loop and terminates.
|
||||
|
||||
Args:
|
||||
self (LoadBalancer): this current object, on which method is called.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
"""
|
||||
self.heater_instance_interface_manager.stop_threads()
|
||||
self.simulation.set_state(Simulation.State.STOPPED)
|
||||
self.running = False
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------
|
||||
31
load_balancer/simulation.py
Normal file
31
load_balancer/simulation.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# author Aaron Moser
|
||||
|
||||
from enum import Enum
|
||||
|
||||
class Simulation:
|
||||
|
||||
class State(Enum):
|
||||
INITIALIZED = 1
|
||||
RUNNING = 2
|
||||
PAUSED = 3
|
||||
STOPPED = 4
|
||||
|
||||
class Mode(Enum):
|
||||
REALTIME = 1
|
||||
DAILY = 2
|
||||
|
||||
def __init__(self):
|
||||
self.state = Simulation.State.INITIALIZED
|
||||
self.mode = Simulation.Mode.REALTIME
|
||||
|
||||
def set_state(self, state):
|
||||
self.state = state
|
||||
|
||||
def get_state(self):
|
||||
return self.state
|
||||
|
||||
def set_mode(self, mode):
|
||||
self.mode = mode
|
||||
|
||||
def get_mode(self):
|
||||
return self.mode
|
||||
22
load_balancer/start_load_balancer.py
Normal file
22
load_balancer/start_load_balancer.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# author Aaron Moser
|
||||
|
||||
import datetime
|
||||
from database_interface import DatabaseInterface
|
||||
from global_outcome import GlobalOutcome
|
||||
from load_balancer_impl import LoadBalancer
|
||||
from simulation import Simulation
|
||||
|
||||
def main():
|
||||
# Establish connection to db, if not possible, print error
|
||||
# If error suggests, that db couldn't be found, prompt user to enter location of db
|
||||
# If error suggests, that user / pw were wrong, prompt user to reenter creds
|
||||
# Retry to connect to db
|
||||
# Create instance of DBInterface class
|
||||
db_path = "sqlitedb.db"
|
||||
db_interface = DatabaseInterface(db_path)
|
||||
global_outcome = GlobalOutcome()
|
||||
|
||||
LoadBalancer(global_outcome, db_interface, Simulation.Mode.DAILY, datetime.datetime(2018,4,1), datetime.datetime(2018,4,2)).run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
59
load_balancer/tasks/daily_task.py
Normal file
59
load_balancer/tasks/daily_task.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import time
|
||||
import constants
|
||||
import heat_demand_simulator
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List
|
||||
from heater_instance_interface import HeaterInstanceInterface
|
||||
from global_outcome import GlobalOutcome
|
||||
from tasks.task_outcome import TaskOutcome
|
||||
|
||||
def daily_task(global_outcome: GlobalOutcome, heater_instance_interface: HeaterInstanceInterface, start_date: datetime, end_date: datetime, store_db_function):
|
||||
|
||||
one_minute_difference = timedelta(minutes=1)
|
||||
actual_date: datetime = start_date
|
||||
# Get difference in days between start and end date.
|
||||
difference: timedelta = end_date - start_date
|
||||
stopped = False
|
||||
|
||||
for i in range(difference.days):
|
||||
|
||||
outcome_list:List[TaskOutcome] = []
|
||||
|
||||
seed:int = heater_instance_interface.get_seed()
|
||||
heat_demand_per_minute_in_kW_day = heat_demand_simulator.heat_demand_per_minute_in_kW(heat_demand_simulator.heat_demand(seed, actual_date))
|
||||
|
||||
for heat_demand_per_minute in heat_demand_per_minute_in_kW_day:
|
||||
|
||||
required_workload_in_percent = diff = diff_factor = 0.0
|
||||
tries = count = 0
|
||||
|
||||
if heat_demand_per_minute > 0.0:
|
||||
# Calculate percentage of workload for cpu while runtime.
|
||||
# example: 1.5 / 0.04 / 100 = 0.375 = 37.5%
|
||||
required_workload_in_percent = heat_demand_per_minute / constants.MAX_WORKLOAD_IN_KW_ONE_PERCENT / 100
|
||||
try:
|
||||
start_time = time.time()
|
||||
tries, count, diff, diff_factor = heater_instance_interface.run(required_workload_in_percent, constants.DAILY_MODE_MILLISECONDS_MINUTE_RATIO)
|
||||
end_time = time.time()
|
||||
runtime = end_time - start_time
|
||||
sleep_time = 0.06 - runtime
|
||||
if sleep_time > 0:
|
||||
time.sleep(sleep_time)
|
||||
except:
|
||||
print()
|
||||
stopped = True
|
||||
break
|
||||
global_outcome.update_tries_count(tries, count)
|
||||
|
||||
else:
|
||||
time.sleep(0.06)
|
||||
|
||||
actual_heat_generated = diff_factor * heat_demand_per_minute
|
||||
outcome_list.append(TaskOutcome(required_workload_in_percent, constants.DAILY_MODE_MILLISECONDS_MINUTE_RATIO, tries, count, diff / 1000, diff_factor, actual_date, heat_demand_per_minute, actual_heat_generated, heater_instance_interface.get_host().hostname, heater_instance_interface.get_host().username))
|
||||
actual_date += one_minute_difference
|
||||
|
||||
if stopped:
|
||||
break
|
||||
|
||||
store_db_function(outcome_list)
|
||||
55
load_balancer/tasks/realtime_task.py
Normal file
55
load_balancer/tasks/realtime_task.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import time
|
||||
import constants
|
||||
import heat_demand_simulator
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List
|
||||
from heater_instance_interface import HeaterInstanceInterface
|
||||
from global_outcome import GlobalOutcome
|
||||
from tasks.task_outcome import TaskOutcome
|
||||
|
||||
def realtime_task(global_outcome: GlobalOutcome, heater_instance_interface: HeaterInstanceInterface, start_date: datetime, end_date: datetime, store_db_function):
|
||||
|
||||
one_minute_difference = timedelta(minutes=1)
|
||||
actual_date: datetime = start_date
|
||||
# Get difference in days between start and end date.
|
||||
difference: timedelta = end_date - start_date
|
||||
stopped = False
|
||||
|
||||
for i in range(difference.days):
|
||||
|
||||
seed = heater_instance_interface.get_seed()
|
||||
heat_demand_per_minute_in_kW_day = heat_demand_simulator.heat_demand_per_minute_in_kW(heat_demand_simulator.heat_demand(seed, actual_date))
|
||||
|
||||
for heat_demand_per_minute in heat_demand_per_minute_in_kW_day:
|
||||
|
||||
required_workload_in_percent = diff = diff_factor = 0.0
|
||||
tries = count = 0
|
||||
|
||||
if heat_demand_per_minute > 0.0:
|
||||
# Calculate percentage of workload for cpu while runtime.
|
||||
# example: 1.5 / 0.04 / 100 = 0.375 = 37.5%
|
||||
required_workload_in_percent = heat_demand_per_minute / constants.MAX_WORKLOAD_IN_KW_ONE_PERCENT / 100
|
||||
try:
|
||||
start_time = time.time()
|
||||
tries, count, diff, diff_factor = heater_instance_interface.run(required_workload_in_percent, 60000)
|
||||
end_time = time.time()
|
||||
runtime = end_time - start_time
|
||||
sleep_time = 60 - runtime
|
||||
if sleep_time > 0:
|
||||
time.sleep(sleep_time)
|
||||
except:
|
||||
print()
|
||||
stopped = True
|
||||
break
|
||||
global_outcome.update_tries_count(tries, count)
|
||||
|
||||
else:
|
||||
# If heat demand is 0, just sleep 1 minute and put values of 0 into list, since no heating required
|
||||
time.sleep(60)
|
||||
actual_heat_generated = diff_factor * heat_demand_per_minute
|
||||
actual_date += one_minute_difference
|
||||
store_db_function([TaskOutcome(required_workload_in_percent * 100, 60000, tries, count, diff / 1000, diff_factor, actual_date, heat_demand_per_minute, actual_heat_generated, heater_instance_interface.get_host().hostname, heater_instance_interface.get_host().username)])
|
||||
|
||||
if stopped:
|
||||
break
|
||||
49
load_balancer/tasks/task_outcome.py
Normal file
49
load_balancer/tasks/task_outcome.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from datetime import datetime
|
||||
|
||||
class TaskOutcome:
|
||||
def __init__(self, required_workload_in_percent, runtime, tries, count, diff, diff_factor, actual_date, heat_demand_per_minute, actual_heat_generated, hostname: str, username: str):
|
||||
self.required_workload_in_percent:float = required_workload_in_percent
|
||||
self.runtime: float = runtime
|
||||
self.tries: int = tries
|
||||
self.count: int = count
|
||||
self.diff: float = diff
|
||||
self.diff_factor: float = diff_factor
|
||||
self.actual_date: datetime = actual_date
|
||||
self.heat_demand_per_minute: float = heat_demand_per_minute
|
||||
self.actual_heat_generated: float = actual_heat_generated
|
||||
self.hostname: str = hostname
|
||||
self.username: str = username
|
||||
|
||||
def get_required_workload_in_percent(self) -> float:
|
||||
return self.required_workload_in_percent
|
||||
|
||||
def get_runtime(self) -> float:
|
||||
return self.runtime
|
||||
|
||||
def get_tries(self) -> int:
|
||||
return self.tries
|
||||
|
||||
def get_count(self) -> int:
|
||||
return self.count
|
||||
|
||||
def get_diff(self) -> float:
|
||||
return self.diff
|
||||
|
||||
def get_diff_factor(self) -> float:
|
||||
return self. diff_factor
|
||||
|
||||
def get_actual_date(self) -> datetime:
|
||||
return self.actual_date
|
||||
|
||||
def get_heat_demand_per_minute(self) -> float:
|
||||
return self.heat_demand_per_minute
|
||||
|
||||
def get_actual_heat_generated(self) -> float:
|
||||
return self.actual_heat_generated
|
||||
|
||||
def get_hostname(self) -> str:
|
||||
return self.hostname
|
||||
|
||||
def get_username(self) -> str:
|
||||
return self.username
|
||||
|
||||
Reference in New Issue
Block a user