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

Uptodate with core-0.0.7

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