Skip to content
Snippets Groups Projects
Commit fd50a86a authored by shinedday's avatar shinedday
Browse files

Uptodate with core-0.0.7

parent 85bcab95
No related branches found
No related tags found
No related merge requests found
......@@ -10,3 +10,4 @@ db.sqlite3
uploads/tmp/*
uploads/media/*
uploads/current_experiment/*
dump.rdb
......@@ -87,8 +87,12 @@ CHANNEL_LAYERS = {
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'iotamak',
'USER': 'raspberry',
'PASSWORD': 'raspberry',
'HOST': "localhost",
'PORT': '5432'
}
}
......
......@@ -6,4 +6,5 @@ admin.site.register(Client)
admin.site.register(Agent)
admin.site.register(Experiment)
admin.site.register(Metrics)
admin.site.register(CurrentExperiment)
\ No newline at end of file
admin.site.register(CurrentExperiment)
admin.site.register(Network)
\ No newline at end of file
......@@ -22,6 +22,7 @@ class Agent(models.Model):
def __str__(self):
return self.command
class Experiment(models.Model):
name = models.CharField(max_length=60)
status = models.CharField(max_length=60, default="Not checked")
......@@ -34,6 +35,7 @@ class ExperimentForm(ModelForm):
model = Experiment
fields = ["name", "description", "media"]
class Metrics(models.Model):
cycle = models.PositiveIntegerField()
_metrics = models.BinaryField()
......@@ -48,11 +50,23 @@ class Metrics(models.Model):
class CurrentExperiment(models.Model):
name = models.CharField(max_length=60)
cycle = models.PositiveIntegerField(default=0)
nbr_agent = models.PositiveIntegerField(default=0)
amas_pid = models.PositiveIntegerField(default=0)
scheduler_pid = models.PositiveIntegerField(default=0)
env_pid = models.PositiveIntegerField(default=0)
\ No newline at end of file
env_pid = models.PositiveIntegerField(default=0)
seed = models.CharField(default="0", max_length=64)
scheduling = models.CharField(default="sync", max_length=10)
class Network(models.Model):
broker_ip = models.CharField(max_length=60)
broker_username = models.CharField(max_length=60)
broker_password = models.CharField(max_length=60)
iotamak_core_version = models.CharField(max_length=60)
path_to_iotamak = models.CharField(max_length=60)
......@@ -105,21 +105,25 @@
{% endif %}
<canvas id="myChart" width="500" height="500" style="border:1px solid #000000;"></canvas>
<canvas id="line-chart" width="800" height="450"></canvas>
<script>
var chart_data = {
labels: ["0", "1", "2", "3"],
type: 'line',
data: {
datasets: [{
data: [0,0,0,0]
}]
}
};
chart_data = {
labels: ["t-9","t-8","t-7","t-6","t-5","t-4","t-3","t-2","t-1","t"],
datasets: [{
data: [0,0,0,0,0,0,0,0,0,0],
label: "Colored agents",
borderColor: "#3e95cd",
fill: false
}
]
};
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, chart_data);
const myChart = new Chart(document.getElementById("line-chart"), {
type: 'line',
data: chart_data,
options: {}
});
const graphSocket = new WebSocket(
......@@ -130,14 +134,11 @@ const myChart = new Chart(ctx, chart_data);
graphSocket.onmessage = function (e) {
const metrics = JSON.parse(e.data).message;
console.log(metrics);
new_graph_data = chart_data.data.datasets[0].data;
new_graph_data = chart_data.datasets[0].data;
new_graph_data.shift();
new_graph_data.push(metrics[0]);
console.log(new_graph_data);
chart_data.data.datasets[0].data = new_graph_data;
console.log(new_graph_data);
chart_data.datasets[0].data = new_graph_data;
myChart.update();
......
import os
import zipfile
from django.conf import settings
......@@ -7,6 +6,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from django.urls import reverse
from .experiment_checker import unzip, contains_basic_files, check_config
from .tool import delete_folder
from ..models import Experiment, ExperimentForm
......@@ -27,33 +27,20 @@ def entry(request):
def check(request, experiment_id):
# get the path
exp = Experiment.objects.get(pk=experiment_id)
# check if it's a zip -> wrong format : not zip
if not zipfile.is_zipfile(str(settings.MEDIA_ROOT) + str(exp.media)):
exp.status = "Wrong format : zip file expected"
exp.save()
if not unzip(str(settings.MEDIA_ROOT) + str(exp.media), str(settings.MEDIA_ROOT) + "/tmp", exp):
return HttpResponseRedirect(reverse('ping:experiment'))
with zipfile.ZipFile(str(settings.MEDIA_ROOT) + str(exp.media), 'r') as zip_ref:
zip_ref.extractall(str(settings.MEDIA_ROOT) + "/tmp")
folder_path = str(settings.MEDIA_ROOT) + "/tmp/" + exp.name
if not os.path.isdir(folder_path):
exp.status = "Wrong format : zip should contain a folder"
exp.save()
if not contains_basic_files(folder_path, exp):
delete_folder(str(settings.MEDIA_ROOT) + "/tmp")
return HttpResponseRedirect(reverse('ping:experiment'))
required_files = ["amas.py", "agent.py", "env.py", "scheduler.py", "config.json"]
for required_file in required_files:
if not os.path.exists(folder_path + "/" + required_file):
exp.status = "Wrong format : " + required_file + " file is expected"
exp.save()
delete_folder(str(settings.MEDIA_ROOT) + "/tmp")
return HttpResponseRedirect(reverse('ping:experiment'))
if not check_config(folder_path, exp):
delete_folder(str(settings.MEDIA_ROOT) + "/tmp")
return HttpResponseRedirect(reverse('ping:experiment'))
exp.status = "Checked"
exp.save()
......
import json
import os
import zipfile
from ..models import Network
def unzip(src_path: str, dest_path: str, exp) -> bool:
if not zipfile.is_zipfile(src_path):
exp.status = "Wrong format : zip file expected"
exp.save()
return False
with zipfile.ZipFile(src_path, 'r') as zip_ref:
zip_ref.extractall(dest_path)
return True
def contains_basic_files(path: str, exp) -> bool:
if not os.path.isdir(path):
exp.status = "Wrong format : zip should contain a folder"
exp.save()
return False
required_files = ["amas.py", "env.py", "config.json"]
for required_file in required_files:
if not os.path.exists(path + "/" + required_file):
exp.status = "Wrong format : " + required_file + " file is expected"
exp.save()
return False
return True
def check_config(path: str, exp) -> bool:
with open(path + "/config.json") as json_file:
config = json.load(json_file)
required_keys = ["iotamak_version", "scheduling_type"]
for key in required_keys:
if key not in config:
exp.status = "Wrong config : " + key + " is expected in config.json"
exp.save()
return False
if config.get("scheduling_type") not in ["sync", "async"]:
exp.status = "Wrong config : scheduling_type is either sync or async"
exp.save()
return False
n = Network.objects.all()[0]
version = n.iotamak_core_version
if int(config.get("iotamak_version").replace(".", "00")) < int(version.replace(".", "00")):
exp.status = "Wrong version : experiment version is outdated"
exp.save()
return False
elif int(config.get("iotamak_version").replace(".", "00")) > int(version.replace(".", "00")):
exp.status = "Wrong version : experiment version is ahead of the server version"
exp.save()
return False
if config.get("scheduling_type") == "sync":
if not os.path.exists(path + "/scheduler.py"):
exp.status = "Wrong format : scheduler.py file is expected"
exp.save()
return False
else:
pass
return True
......@@ -8,25 +8,32 @@ from django.urls import reverse
from iotAmak.tool.ssh_client import Cmd
from .tool import get_ssh_client
from ..models import Client, Agent
from ..models import Client, Agent, Network
def update(request):
ssh = get_ssh_client()
version = "0.0.3"
n = Network.objects.all()[0]
version = n.iotamak_core_version
commands = [
Cmd(
cmd="cd Desktop/mqtt_goyon/iotamak-core"
cmd="cd "+n.path_to_iotamak+"iotamak-core"
),
Cmd(
cmd="git pull"
),
Cmd(
cmd="git checkout main"
cmd="git reset --hard origin/main"
),
Cmd(
cmd="git clean -f -d"
),
Cmd(
cmd="git pull"
),
Cmd(
cmd="git checkout main"
),
Cmd(
cmd="python3 -m pip install --force-reinstall dist/iotAmak-" + version + "-py3-none-any.whl"
)
......
import csv
import os
import random
import sys
import zipfile
import json
......@@ -16,7 +17,7 @@ from iotAmak.tool.ssh_client import Cmd
from paho.mqtt.client import Client as MQTTClient
from .tool import delete_folder, get_ssh_client, canvas_event_triger, graph_event_triger
from ..models import Experiment, CurrentExperiment, Metrics
from ..models import Experiment, CurrentExperiment, Metrics, Network
client = MQTTClient(client_id="django-ihm")
......@@ -63,6 +64,7 @@ def cycle_done(client, userdata, message) -> None:
def update_nbr_agent(client, userdata, message) -> None:
exp = CurrentExperiment.objects.all()[0]
subscribe(client, "agent/"+str(exp.nbr_agent)+"/log", agent_log)
exp.nbr_agent += 1
exp.save()
......@@ -81,13 +83,50 @@ def experiment_load(request):
# drop current experiment table and create new instance
CurrentExperiment.objects.all().delete()
cur_exp = CurrentExperiment(name=Experiment.objects.get(status="Selected").name)
with open(str(settings.MEDIA_ROOT) + "current_experiment/"+str(exp.name)+"/config.json") as json_file:
config = json.load(json_file)
if "seed" in config:
cur_exp.seed = str(config.get("seed"))
else:
random.seed()
cur_exp.seed = str(random.randint(0,9999999))
cur_exp.scheduling = config.get("scheduling_type")
cur_exp.save()
return HttpResponseRedirect(reverse('ping:play'))
def delete_nohup():
ssh = get_ssh_client()
commands = [
Cmd(
cmd="rm nohup.out"
)
]
for i_client in range(len(ssh.clients)):
print(" Ip : ", ssh.clients[i_client].hostname)
ssh.run_cmd(i_client, commands)
def get_nohup():
ssh = get_ssh_client()
commands = [
Cmd(
cmd="cat nohup.out"
)
]
for i_client in range(len(ssh.clients)):
print(" Ip : ", ssh.clients[i_client].hostname)
ssh.run_cmd(i_client, commands)
def experiment_start(request):
broker_ip = "192.168.193.209"
n = Network.objects.all()[0]
ssh = get_ssh_client()
experiment_path = str(settings.MEDIA_ROOT) + "current_experiment/" + Experiment.objects.get(status="Selected").name
......@@ -96,25 +135,47 @@ def experiment_start(request):
global client
client.disconnect()
client = MQTTClient(client_id="django-ihm")
client.username_pw_set(username="goyon", password="mosquitto")
client.connect(host=broker_ip)
client.username_pw_set(username=n.broker_username, password=n.broker_password)
client.connect(host=n.broker_ip)
client.loop_start()
subscribe(client, "amas/agent/new", update_nbr_agent)
subscribe(client, "scheduler/cycledone", cycle_done)
subscribe(client, "amas/all_metric", agent_metric)
# start subprocess scheduler
p1 = Popen([sys.executable, experiment_path + '/scheduler.py', broker_ip])
sleep(1)
delete_nohup()
exp = CurrentExperiment.objects.all()[0]
if exp.scheduling == "sync":
p1 = Popen(
[sys.executable, experiment_path + '/scheduler.py', n.broker_ip, n.broker_username, n.broker_password]
)
exp.scheduler_pid = p1.pid
sleep(1)
# start subprocess amas
send_client = [c.to_send() for c in ssh.clients]
p2 = Popen([sys.executable, experiment_path + '/amas.py', broker_ip, str(send_client)])
amas_dict = {
"broker_ip": n.broker_ip,
"clients": str([c.to_send() for c in ssh.clients]),
"seed": exp.seed,
"iot_path": n.path_to_iotamak+"example/",
"broker_username": n.broker_username,
"broker_password": n.broker_password
}
if not exp.scheduling == "sync":
amas_dict["wait_delay"] = str(5)
p2 = Popen([sys.executable, experiment_path + '/amas.py', json.dumps(amas_dict)])
# start subprocess env
p3 = Popen([sys.executable, experiment_path + '/env.py', broker_ip])
env_dict = {
"broker_ip": n.broker_ip,
"seed": exp.seed,
"broker_username": n.broker_username,
"broker_password": n.broker_password
}
if not exp.scheduling == "sync":
env_dict["wait_delay"] = str(5)
p3 = Popen([sys.executable, experiment_path + '/env.py', json.dumps(env_dict)])
exp = CurrentExperiment.objects.all()[0]
exp.amas_pid = p2.pid
exp.scheduler_pid = p1.pid
exp.env_pid = p3.pid
exp.save()
......@@ -174,6 +235,7 @@ def scheduler_start(request):
def experiment_share(request):
# get selected experiment
exp = Experiment.objects.get(status="Selected")
n = Network.objects.all()[0]
# open ssh connection
ssh = get_ssh_client()
......@@ -181,19 +243,21 @@ def experiment_share(request):
# file transfer
commands = [
Cmd(
cmd="rm -r Desktop/mqtt_goyon/example/" + exp.name
cmd="rm -r " + n.path_to_iotamak + "example/" + exp.name
)
]
for i_client in range(len(ssh.clients)):
print(" Ip : ", ssh.clients[i_client].hostname)
ssh.run_cmd(i_client, commands)
ssh.update(exp.name, str(settings.MEDIA_ROOT) + "current_experiment/" + exp.name)
ssh.update("example/" + exp.name, str(settings.MEDIA_ROOT) + "current_experiment/" + exp.name)
return HttpResponseRedirect(reverse('ping:play'))
def experiment_stop(request):
get_nohup()
client.publish("ihm/exit")
client.publish("ihm/step")
return HttpResponseRedirect(reverse('ping:play'))
......
......@@ -6,7 +6,7 @@ from channels.layers import get_channel_layer
from iotAmak.tool.remote_client import RemoteClient
from iotAmak.tool.ssh_client import SSHClient
from ping.models import Client
from ping.models import Client, Network
def delete_folder(folder_name):
......@@ -20,6 +20,7 @@ def delete_folder(folder_name):
except Exception as e:
print('Failed to delete %s. Reason: %s' % (file_path, e))
def get_remote_client():
res = []
for client in Client.objects.all():
......@@ -28,8 +29,10 @@ def get_remote_client():
return res
def get_ssh_client():
return SSHClient(get_remote_client())
n = Network.objects.all()[0]
return SSHClient(get_remote_client(), n.path_to_iotamak)
def canvas_event_triger(metrics):
......@@ -42,6 +45,7 @@ def canvas_event_triger(metrics):
}
)
def graph_event_triger(metrics):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
......
Django >= 4.0.4
channels >= 3.0.4
channels-redis >= 3.4.0
psycopg2 >= 2.9.3
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment