diff --git a/backend/amuman/settings_manager.py b/backend/amuman/settings_manager.py index 1cf9a9f..cd3b464 100644 --- a/backend/amuman/settings_manager.py +++ b/backend/amuman/settings_manager.py @@ -29,4 +29,5 @@ STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'manager/static'), -] \ No newline at end of file +] +URL_MODE_PREFIX = "manager" \ No newline at end of file diff --git a/backend/common_models/migrations/0001_initial.py b/backend/common_models/migrations/0001_initial.py index d6cf854..c730a20 100644 --- a/backend/common_models/migrations/0001_initial.py +++ b/backend/common_models/migrations/0001_initial.py @@ -1,6 +1,8 @@ -# Generated by Django 5.0 on 2024-01-24 11:45 +# Generated by Django 4.2.9 on 2024-01-28 20:32 from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone class Migration(migrations.Migration): @@ -9,26 +11,143 @@ class Migration(migrations.Migration): dependencies = [] operations = [ + migrations.CreateModel( + name="Nodes", + fields=[ + ("id", models.AutoField(primary_key=True, serialize=False)), + ("ip", models.CharField(max_length=15, unique=True)), + ( + "name", + models.CharField(blank=True, max_length=15, null=True, unique=True), + ), + ("port", models.IntegerField(blank=True, null=True)), + ( + "number_of_gpus", + models.CharField(blank=True, max_length=15, null=True), + ), + ("gpu_info", models.TextField(blank=True, null=True)), + ("status", models.CharField(default="free", max_length=10)), + ( + "last_seen", + models.DateTimeField( + blank=True, default=django.utils.timezone.now, null=True + ), + ), + ], + ), migrations.CreateModel( name="Task", fields=[ ( "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), + models.AutoField(primary_key=True, serialize=False, unique=True), ), - ("path", models.CharField(max_length=500)), + ("user", models.CharField(blank=True, max_length=100, null=True)), + ("path", models.TextField()), ("node_name", models.CharField(blank=True, max_length=100, null=True)), ("port", models.IntegerField(blank=True, null=True)), + ("submit_time", models.DateTimeField(blank=True, null=True)), ("start_time", models.DateTimeField(blank=True, null=True)), ("end_time", models.DateTimeField(blank=True, null=True)), ("error_time", models.DateTimeField(blank=True, null=True)), - ("priority", models.IntegerField(default=0)), - ("status", models.CharField(default="waiting", max_length=50)), + ( + "priority", + models.CharField( + choices=[ + ("slow", "Slow"), + ("normal", "Normal"), + ("fast", "Fast"), + ], + default="normal", + max_length=6, + ), + ), + ( + "gpu_partition", + models.CharField( + choices=[ + ("slow", "Slow"), + ("normal", "Normal"), + ("fast", "Fast"), + ], + default="normal", + max_length=6, + ), + ), + ("est", models.DurationField(blank=True, null=True)), + ( + "status", + models.CharField( + choices=[ + ("Waiting", "Waiting"), + ("Pending", "Pending"), + ("Running", "Running"), + ("Finished", "Finished"), + ("Interrupted", "Interrupted"), + ], + default="Free", + max_length=50, + ), + ), + ( + "assigned_node_id", + models.CharField(blank=True, max_length=10, null=True), + ), + ( + "assigned_gpu_id", + models.CharField(blank=True, max_length=10, null=True), + ), + ], + ), + migrations.CreateModel( + name="Gpus", + fields=[ + ( + "id", + models.AutoField(primary_key=True, serialize=False, unique=True), + ), + ("gpu_uuid", models.TextField(blank=True, null=True, unique=True)), + ("brand_name", models.TextField(blank=True, null=True)), + ("gpu_speed", models.TextField(blank=True, null=True)), + ("gpu_util", models.TextField(blank=True, null=True)), + ("is_running_amumax", models.TextField(blank=True, null=True)), + ("gpu_info", models.TextField(blank=True, null=True)), + ( + "status", + models.CharField( + choices=[ + ("Free", "Free"), + ("Running", "Running"), + ("Reserved", "Reserved"), + ("Unavailable", "Unavailable"), + ], + default="Free", + max_length=50, + ), + ), + ( + "last_update", + models.DateTimeField( + blank=True, default=django.utils.timezone.now, null=True + ), + ), + ( + "node_id", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="common_models.nodes", + ), + ), + ( + "task_id", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="gpu_tasks", + to="common_models.task", + ), + ), ], ), ] diff --git a/backend/common_models/migrations/0002_alter_gpus_status_alter_nodes_status_and_more.py b/backend/common_models/migrations/0002_alter_gpus_status_alter_nodes_status_and_more.py new file mode 100644 index 0000000..dca4e82 --- /dev/null +++ b/backend/common_models/migrations/0002_alter_gpus_status_alter_nodes_status_and_more.py @@ -0,0 +1,55 @@ +# Generated by Django 4.2.9 on 2024-01-28 21:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("common_models", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="gpus", + name="status", + field=models.CharField( + choices=[ + ("Waiting", "Waiting"), + ("Running", "Running"), + ("Reserved", "Reserved"), + ("Unavailable", "Unavailable"), + ], + default="Waiting", + max_length=50, + ), + ), + migrations.AlterField( + model_name="nodes", + name="status", + field=models.CharField( + choices=[ + ("Waiting", "Waiting"), + ("Running", "Running"), + ("Reserved", "Reserved"), + ("Unavailable", "Unavailable"), + ], + default="Waiting", + max_length=50, + ), + ), + migrations.AlterField( + model_name="task", + name="status", + field=models.CharField( + choices=[ + ("Waiting", "Waiting"), + ("Pending", "Pending"), + ("Running", "Running"), + ("Finished", "Finished"), + ("Interrupted", "Interrupted"), + ], + default="Waiting", + max_length=50, + ), + ), + ] diff --git a/backend/common_models/migrations/0002_task_submit_time_task_user.py b/backend/common_models/migrations/0002_task_submit_time_task_user.py deleted file mode 100644 index 1764657..0000000 --- a/backend/common_models/migrations/0002_task_submit_time_task_user.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 5.0 on 2024-01-24 21:41 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0001_initial"), - ] - - operations = [ - migrations.AddField( - model_name="task", - name="submit_time", - field=models.DateTimeField(blank=True, null=True), - ), - migrations.AddField( - model_name="task", - name="user", - field=models.CharField(blank=True, max_length=100, null=True), - ), - ] diff --git a/backend/common_models/migrations/0010_alter_task_est.py b/backend/common_models/migrations/0003_alter_task_est.py similarity index 53% rename from backend/common_models/migrations/0010_alter_task_est.py rename to backend/common_models/migrations/0003_alter_task_est.py index dc833bd..406417e 100644 --- a/backend/common_models/migrations/0010_alter_task_est.py +++ b/backend/common_models/migrations/0003_alter_task_est.py @@ -1,17 +1,17 @@ -# Generated by Django 4.2.9 on 2024-01-27 14:44 +# Generated by Django 4.2.9 on 2024-01-28 22:34 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("common_models", "0009_task_est_task_gpu_partition_alter_task_id"), + ("common_models", "0002_alter_gpus_status_alter_nodes_status_and_more"), ] operations = [ migrations.AlterField( model_name="task", name="est", - field=models.DurationField(blank=True, null=True), + field=models.CharField(blank=True, max_length=100, null=True), ), ] diff --git a/backend/common_models/migrations/0003_nodes_gpus.py b/backend/common_models/migrations/0003_nodes_gpus.py deleted file mode 100644 index eaceb96..0000000 --- a/backend/common_models/migrations/0003_nodes_gpus.py +++ /dev/null @@ -1,51 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 11:41 - -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0002_task_submit_time_task_user"), - ] - - operations = [ - migrations.CreateModel( - name="Nodes", - fields=[ - ("id", models.AutoField(primary_key=True, serialize=False)), - ("ip", models.CharField(max_length=15, unique=True)), - ( - "name", - models.CharField(blank=True, max_length=15, null=True, unique=True), - ), - ("port", models.IntegerField(blank=True, null=True)), - ("gpu_info", models.TextField(blank=True, null=True)), - ("status", models.CharField(default="free", max_length=10)), - ( - "last_seen", - models.DateTimeField( - blank=True, default=django.utils.timezone.now, null=True - ), - ), - ], - ), - migrations.CreateModel( - name="Gpus", - fields=[ - ("id", models.AutoField(primary_key=True, serialize=False)), - ("brand_name", models.TextField(blank=True, null=True)), - ("gpu_speed", models.TextField(blank=True, null=True)), - ("gpu_info", models.TextField(blank=True, null=True)), - ("status", models.CharField(default="free", max_length=10)), - ( - "nodeid", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - to="common_models.nodes", - ), - ), - ], - ), - ] diff --git a/backend/common_models/migrations/0004_gpus_no_alter_task_gpu_partition_alter_task_priority.py b/backend/common_models/migrations/0004_gpus_no_alter_task_gpu_partition_alter_task_priority.py new file mode 100644 index 0000000..4de880d --- /dev/null +++ b/backend/common_models/migrations/0004_gpus_no_alter_task_gpu_partition_alter_task_priority.py @@ -0,0 +1,35 @@ +# Generated by Django 4.2.9 on 2024-01-29 10:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("common_models", "0003_alter_task_est"), + ] + + operations = [ + migrations.AddField( + model_name="gpus", + name="no", + field=models.IntegerField(blank=True, default=0, null=True), + ), + migrations.AlterField( + model_name="task", + name="gpu_partition", + field=models.CharField( + choices=[("Slow", "Slow"), ("Normal", "Normal"), ("Fast", "Fast")], + default="normal", + max_length=6, + ), + ), + migrations.AlterField( + model_name="task", + name="priority", + field=models.CharField( + choices=[("Slow", "Slow"), ("Normal", "Normal"), ("Fast", "Fast")], + default="normal", + max_length=6, + ), + ), + ] diff --git a/backend/common_models/migrations/0004_nodes_number_of_gpus.py b/backend/common_models/migrations/0004_nodes_number_of_gpus.py deleted file mode 100644 index 638b863..0000000 --- a/backend/common_models/migrations/0004_nodes_number_of_gpus.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 11:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0003_nodes_gpus"), - ] - - operations = [ - migrations.AddField( - model_name="nodes", - name="number_of_gpus", - field=models.CharField(blank=True, max_length=15, null=True), - ), - ] diff --git a/backend/common_models/migrations/0005_gpus_last_update.py b/backend/common_models/migrations/0005_gpus_last_update.py deleted file mode 100644 index fd4fe40..0000000 --- a/backend/common_models/migrations/0005_gpus_last_update.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 13:20 - -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0004_nodes_number_of_gpus"), - ] - - operations = [ - migrations.AddField( - model_name="gpus", - name="last_update", - field=models.DateTimeField( - blank=True, default=django.utils.timezone.now, null=True - ), - ), - ] diff --git a/backend/common_models/migrations/0006_gpus_gpu_util_gpus_is_running_amumax.py b/backend/common_models/migrations/0006_gpus_gpu_util_gpus_is_running_amumax.py deleted file mode 100644 index ef965cb..0000000 --- a/backend/common_models/migrations/0006_gpus_gpu_util_gpus_is_running_amumax.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 13:29 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0005_gpus_last_update"), - ] - - operations = [ - migrations.AddField( - model_name="gpus", - name="gpu_util", - field=models.TextField(blank=True, null=True), - ), - migrations.AddField( - model_name="gpus", - name="is_running_amumax", - field=models.TextField(blank=True, null=True), - ), - ] diff --git a/backend/common_models/migrations/0007_gpus_gpu_id.py b/backend/common_models/migrations/0007_gpus_gpu_id.py deleted file mode 100644 index 72000b3..0000000 --- a/backend/common_models/migrations/0007_gpus_gpu_id.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 13:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0006_gpus_gpu_util_gpus_is_running_amumax"), - ] - - operations = [ - migrations.AddField( - model_name="gpus", - name="gpu_id", - field=models.CharField(default=0, max_length=2, unique=True), - ), - ] diff --git a/backend/common_models/migrations/0008_rename_nodeid_gpus_node_id.py b/backend/common_models/migrations/0008_rename_nodeid_gpus_node_id.py deleted file mode 100644 index f88be18..0000000 --- a/backend/common_models/migrations/0008_rename_nodeid_gpus_node_id.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 16:12 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0007_gpus_gpu_id"), - ] - - operations = [ - migrations.RenameField( - model_name="gpus", - old_name="nodeid", - new_name="node_id", - ), - ] diff --git a/backend/common_models/migrations/0009_task_est_task_gpu_partition_alter_task_id.py b/backend/common_models/migrations/0009_task_est_task_gpu_partition_alter_task_id.py deleted file mode 100644 index 2e55564..0000000 --- a/backend/common_models/migrations/0009_task_est_task_gpu_partition_alter_task_id.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 14:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0008_rename_nodeid_gpus_node_id"), - ] - - operations = [ - migrations.AddField( - model_name="task", - name="est", - field=models.CharField(blank=True, max_length=15, null=True), - ), - migrations.AddField( - model_name="task", - name="gpu_partition", - field=models.CharField( - blank=True, default="normal", max_length=15, null=True, unique=True - ), - ), - migrations.AlterField( - model_name="task", - name="id", - field=models.AutoField(primary_key=True, serialize=False), - ), - ] diff --git a/backend/common_models/migrations/0011_task_assigned_gpu_task_assigned_node.py b/backend/common_models/migrations/0011_task_assigned_gpu_task_assigned_node.py deleted file mode 100644 index f6bbf3c..0000000 --- a/backend/common_models/migrations/0011_task_assigned_gpu_task_assigned_node.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 15:02 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0010_alter_task_est"), - ] - - operations = [ - migrations.AddField( - model_name="task", - name="assigned_gpu", - field=models.CharField(blank=True, max_length=10, null=True), - ), - migrations.AddField( - model_name="task", - name="assigned_node", - field=models.CharField(blank=True, max_length=10, null=True), - ), - ] diff --git a/backend/common_models/migrations/0012_gpus_task_id_alter_gpus_gpu_id.py b/backend/common_models/migrations/0012_gpus_task_id_alter_gpus_gpu_id.py deleted file mode 100644 index 43dbebf..0000000 --- a/backend/common_models/migrations/0012_gpus_task_id_alter_gpus_gpu_id.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 15:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0011_task_assigned_gpu_task_assigned_node"), - ] - - operations = [ - migrations.AddField( - model_name="gpus", - name="task_id", - field=models.CharField(blank=True, max_length=10, null=True), - ), - migrations.AlterField( - model_name="gpus", - name="gpu_id", - field=models.CharField(default="", max_length=2, unique=True), - ), - ] diff --git a/backend/common_models/migrations/0013_task_gpu_id.py b/backend/common_models/migrations/0013_task_gpu_id.py deleted file mode 100644 index a410762..0000000 --- a/backend/common_models/migrations/0013_task_gpu_id.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 15:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0012_gpus_task_id_alter_gpus_gpu_id"), - ] - - operations = [ - migrations.AddField( - model_name="task", - name="gpu_id", - field=models.CharField(blank=True, max_length=10, null=True), - ), - ] diff --git a/backend/common_models/migrations/0014_remove_gpus_gpu_id_remove_task_gpu_id_alter_gpus_id_and_more.py b/backend/common_models/migrations/0014_remove_gpus_gpu_id_remove_task_gpu_id_alter_gpus_id_and_more.py deleted file mode 100644 index e466ec1..0000000 --- a/backend/common_models/migrations/0014_remove_gpus_gpu_id_remove_task_gpu_id_alter_gpus_id_and_more.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 17:17 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0013_task_gpu_id"), - ] - - operations = [ - migrations.RemoveField( - model_name="gpus", - name="gpu_id", - ), - migrations.RemoveField( - model_name="task", - name="gpu_id", - ), - migrations.AlterField( - model_name="gpus", - name="id", - field=models.AutoField(primary_key=True, serialize=False, unique=True), - ), - migrations.AlterField( - model_name="task", - name="id", - field=models.AutoField(primary_key=True, serialize=False, unique=True), - ), - ] diff --git a/backend/common_models/migrations/0015_gpus_gpu_uuid.py b/backend/common_models/migrations/0015_gpus_gpu_uuid.py deleted file mode 100644 index 6d72d41..0000000 --- a/backend/common_models/migrations/0015_gpus_gpu_uuid.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 21:08 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ( - "common_models", - "0014_remove_gpus_gpu_id_remove_task_gpu_id_alter_gpus_id_and_more", - ), - ] - - operations = [ - migrations.AddField( - model_name="gpus", - name="gpu_uuid", - field=models.TextField(blank=True, null=True, unique=True), - ), - ] diff --git a/backend/common_models/migrations/0016_alter_task_gpu_partition_alter_task_priority.py b/backend/common_models/migrations/0016_alter_task_gpu_partition_alter_task_priority.py deleted file mode 100644 index 25603c1..0000000 --- a/backend/common_models/migrations/0016_alter_task_gpu_partition_alter_task_priority.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-28 11:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0015_gpus_gpu_uuid"), - ] - - operations = [ - migrations.AlterField( - model_name="task", - name="gpu_partition", - field=models.CharField( - blank=True, default="normal", max_length=15, null=True - ), - ), - migrations.AlterField( - model_name="task", - name="priority", - field=models.IntegerField(blank=True, default=0, null=True), - ), - ] diff --git a/backend/common_models/migrations/0017_alter_task_path.py b/backend/common_models/migrations/0017_alter_task_path.py deleted file mode 100644 index e115cef..0000000 --- a/backend/common_models/migrations/0017_alter_task_path.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-28 11:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0016_alter_task_gpu_partition_alter_task_priority"), - ] - - operations = [ - migrations.AlterField( - model_name="task", - name="path", - field=models.TextField(), - ), - ] diff --git a/backend/common_models/migrations/0018_alter_task_priority.py b/backend/common_models/migrations/0018_alter_task_priority.py deleted file mode 100644 index 97c84f3..0000000 --- a/backend/common_models/migrations/0018_alter_task_priority.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-28 11:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0017_alter_task_path"), - ] - - operations = [ - migrations.AlterField( - model_name="task", - name="priority", - field=models.CharField( - choices=[("slow", "Slow"), ("normal", "Normal"), ("fast", "Fast")], - default="normal", - max_length=6, - ), - ), - ] diff --git a/backend/common_models/migrations/0019_alter_task_gpu_partition.py b/backend/common_models/migrations/0019_alter_task_gpu_partition.py deleted file mode 100644 index 3063be3..0000000 --- a/backend/common_models/migrations/0019_alter_task_gpu_partition.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-28 11:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("common_models", "0018_alter_task_priority"), - ] - - operations = [ - migrations.AlterField( - model_name="task", - name="gpu_partition", - field=models.CharField( - choices=[("slow", "Slow"), ("normal", "Normal"), ("fast", "Fast")], - default="normal", - max_length=6, - ), - ), - ] diff --git a/backend/common_models/models.py b/backend/common_models/models.py index 3076d40..2b8f543 100644 --- a/backend/common_models/models.py +++ b/backend/common_models/models.py @@ -1,3 +1,4 @@ + from django.db import models from django.utils import timezone @@ -14,34 +15,27 @@ class Task(models.Model): start_time = models.DateTimeField(null=True, blank=True) end_time = models.DateTimeField(null=True, blank=True) error_time = models.DateTimeField(null=True, blank=True) - - PRIORITY_CHOICES = [ - ('slow', 'Slow'), - ('normal', 'Normal'), - ('fast', 'Fast') - ] + + PRIORITY_CHOICES = [("Slow", "Slow"), ("Normal", "Normal"), ("Fast", "Fast")] priority = models.CharField( - max_length=6, - choices=PRIORITY_CHOICES, - default='normal' + max_length=6, choices=PRIORITY_CHOICES, default="normal" ) - - GPU_PARTITION_CHOICES = [ - ('slow', 'Slow'), - ('normal', 'Normal'), - ('fast', 'Fast') - ] + + GPU_PARTITION_CHOICES = [("Slow", "Slow"), ("Normal", "Normal"), ("Fast", "Fast")] gpu_partition = models.CharField( - max_length=6, - choices=GPU_PARTITION_CHOICES, - default='normal' + max_length=6, choices=GPU_PARTITION_CHOICES, default="normal" ) - est = models.DurationField(null=True, blank=True) - status = models.CharField( - max_length=50, default="waiting" - ) # ['waiting', 'running', 'finished'] - assigned_node = models.CharField(max_length=10, null=True, blank=True) - assigned_gpu = models.CharField(max_length=10, null=True, blank=True) + est = models.CharField(max_length=100, null=True, blank=True) + STATUS_CHOICES = [ + ("Waiting", "Waiting"), + ("Pending", "Pending"), + ("Running", "Running"), + ("Finished", "Finished"), + ("Interrupted", "Interrupted"), + ] + status = models.CharField(max_length=50, choices=STATUS_CHOICES, default="Waiting") + assigned_node_id = models.CharField(max_length=10, null=True, blank=True) + assigned_gpu_id = models.CharField(max_length=10, null=True, blank=True) class Nodes(models.Model): @@ -53,9 +47,13 @@ class Nodes(models.Model): port = models.IntegerField(null=True, blank=True) number_of_gpus = models.CharField(max_length=15, null=True, blank=True) gpu_info = models.TextField(null=True, blank=True) - status = models.CharField( - max_length=10, default="free" - ) # np. 'active', 'disconnected' + STATUS_CHOICES = [ + ("Waiting", "Waiting"), + ("Running", "Running"), + ("Reserved", "Reserved"), + ("Unavailable", "Unavailable"), + ] + status = models.CharField(max_length=50, choices=STATUS_CHOICES, default="Waiting") last_seen = models.DateTimeField(default=timezone.now, null=True, blank=True) def __str__(self): @@ -63,19 +61,29 @@ def __str__(self): class Gpus(models.Model): - id = models.AutoField( - primary_key=True, unique=True - ) - gpu_uuid=models.TextField(unique=True,null=True, blank=True) + id = models.AutoField(primary_key=True, unique=True) + no = models.IntegerField(null=True, blank=True, default=0) + gpu_uuid = models.TextField(unique=True, null=True, blank=True) node_id = models.ForeignKey(Nodes, on_delete=models.CASCADE) brand_name = models.TextField(null=True, blank=True) gpu_speed = models.TextField(null=True, blank=True) gpu_util = models.TextField(null=True, blank=True) is_running_amumax = models.TextField(null=True, blank=True) gpu_info = models.TextField(null=True, blank=True) - status = models.CharField(max_length=10, default="free") + STATUS_CHOICES = [ + ("Waiting", "Waiting"), + ("Running", "Running"), + ("Reserved", "Reserved"), + ("Unavailable", "Unavailable"), + ] + status = models.CharField(max_length=50, choices=STATUS_CHOICES, default="Waiting") last_update = models.DateTimeField(default=timezone.now, null=True, blank=True) - task_id = models.CharField(max_length=10, null=True, blank=True) - + task_id = models.ForeignKey( + Task, + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="gpu_tasks" # Changed related_name to avoid conflict + ) def __str__(self): return f"GPU-{self.id}, {self.node_id}/{self.id}" diff --git a/backend/manager/__init__.py b/backend/manager/__init__.py index 481c2d0..e69de29 100644 --- a/backend/manager/__init__.py +++ b/backend/manager/__init__.py @@ -1,3 +0,0 @@ -from manager.scheduler import start_scheduler - -# start_scheduler() diff --git a/backend/manager/components/forms.py b/backend/manager/components/forms.py index 0153a73..049d0ee 100644 --- a/backend/manager/components/forms.py +++ b/backend/manager/components/forms.py @@ -8,7 +8,7 @@ class EditTaskForm(forms.ModelForm): pass class Meta: model = Task - fields = ['path', 'node_name', 'port', 'start_time', 'end_time', 'error_time', 'priority', 'status'] + fields = ['path', 'node_name', 'port', 'priority', 'status'] widgets = { 'path': forms.TextInput(attrs={'class': 'form-control'}), 'node_name': forms.TextInput(attrs={'class': 'form-control'}), @@ -16,17 +16,13 @@ class Meta: 'start_time': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}), 'end_time': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}), 'error_time': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}), - 'priority': forms.NumberInput(attrs={'class': 'form-control'}), + 'priority': forms.Select(attrs={'class': 'form-control'}), 'status': forms.Select(attrs={'class': 'form-control'}), } def __init__(self, *args, **kwargs): super(EditTaskForm, self).__init__(*args, **kwargs) for field in self.fields: self.fields[field].required = False - self.fields['status'].disabled = True - self.fields['end_time'].disabled = True - self.fields['error_time'].disabled = True - self.fields['start_time'].disabled = True self.fields['node_name'].disabled = True self.fields['port'].disabled = True @@ -47,18 +43,4 @@ class Meta: def __init__(self, *args, **kwargs): super(AddTaskForm, self).__init__(*args, **kwargs) for field in self.fields: - self.fields[field].required = False - - - # def clean_est(self): - # est = self.cleaned_data['est'] - # # Sprawdź, czy est jest już obiektem timedelta - # if isinstance(est, timedelta): - # return est - # # Jeśli est jest ciągiem znaków, przetwórz go - # try: - # hours, minutes, seconds = [int(part) for part in est.split(':')] - # return timedelta(hours=hours, minutes=minutes, seconds=seconds) - # except ValueError: - # # Możesz tu dodać jakąś logikę obsługi błędów lub po prostu zwrócić None - # return None + self.fields[field].required = False \ No newline at end of file diff --git a/backend/manager/components/job_queue.py b/backend/manager/components/job_queue.py index b52845c..2292cc6 100644 --- a/backend/manager/components/job_queue.py +++ b/backend/manager/components/job_queue.py @@ -31,9 +31,9 @@ def assign_tasks_to_gpus(): # for gpu in free_gpus: # for task in waiting_tasks: - # task.assigned_gpu = gpu.id + # task.assigned_gpu_id = gpu.id # task.status = "running" - # task.assigned_node = gpu.node_id + # task.assigned_node_id = gpu.node_id # task.save() # gpu.task_id = task.id diff --git a/backend/manager/migrations/0001_initial.py b/backend/manager/migrations/0001_initial.py deleted file mode 100644 index 48564e0..0000000 --- a/backend/manager/migrations/0001_initial.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 5.0 on 2024-01-23 20:39 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name="Task", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("path", models.CharField(max_length=500)), - ("node_name", models.CharField(blank=True, max_length=100, null=True)), - ("port", models.IntegerField(blank=True, null=True)), - ("start_time", models.DateTimeField(blank=True, null=True)), - ("end_time", models.DateTimeField(blank=True, null=True)), - ("error_time", models.DateTimeField(blank=True, null=True)), - ("priority", models.IntegerField(default=0)), - ("status", models.CharField(default="waiting", max_length=50)), - ], - ), - ] diff --git a/backend/manager/migrations/0002_nodes.py b/backend/manager/migrations/0002_nodes.py deleted file mode 100644 index 2f6716d..0000000 --- a/backend/manager/migrations/0002_nodes.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.0 on 2024-01-23 22:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("manager", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="Nodes", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("ip", models.CharField(max_length=15)), - ("port", models.CharField(max_length=5)), - ("gpu_info", models.TextField()), - ("is_active", models.BooleanField(default=True)), - ], - ), - ] diff --git a/backend/manager/migrations/0003_delete_task.py b/backend/manager/migrations/0003_delete_task.py deleted file mode 100644 index 9f290ff..0000000 --- a/backend/manager/migrations/0003_delete_task.py +++ /dev/null @@ -1,15 +0,0 @@ -# Generated by Django 5.0 on 2024-01-24 18:59 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("manager", "0002_nodes"), - ] - - operations = [ - migrations.DeleteModel( - name="Task", - ), - ] diff --git a/backend/manager/migrations/0004_remove_nodes_is_active_nodes_last_seen_nodes_status_and_more.py b/backend/manager/migrations/0004_remove_nodes_is_active_nodes_last_seen_nodes_status_and_more.py deleted file mode 100644 index 7d13c7d..0000000 --- a/backend/manager/migrations/0004_remove_nodes_is_active_nodes_last_seen_nodes_status_and_more.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.0 on 2024-01-25 09:36 - -import django.utils.timezone -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("manager", "0003_delete_task"), - ] - - operations = [ - migrations.RemoveField( - model_name="nodes", - name="is_active", - ), - migrations.AddField( - model_name="nodes", - name="last_seen", - field=models.DateTimeField( - blank=True, default=django.utils.timezone.now, null=True - ), - ), - migrations.AddField( - model_name="nodes", - name="status", - field=models.CharField(default="free", max_length=10), - ), - migrations.AlterField( - model_name="nodes", - name="gpu_info", - field=models.TextField(blank=True, null=True), - ), - migrations.AlterField( - model_name="nodes", - name="ip", - field=models.CharField(max_length=15, unique=True), - ), - migrations.AlterField( - model_name="nodes", - name="port", - field=models.IntegerField(blank=True, null=True), - ), - ] diff --git a/backend/manager/migrations/0005_nodes_name.py b/backend/manager/migrations/0005_nodes_name.py deleted file mode 100644 index e37699a..0000000 --- a/backend/manager/migrations/0005_nodes_name.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.0 on 2024-01-25 10:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("manager", "0004_remove_nodes_is_active_nodes_last_seen_nodes_status_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="nodes", - name="name", - field=models.CharField(blank=True, max_length=15, null=True, unique=True), - ), - ] diff --git a/backend/manager/migrations/0006_delete_nodes.py b/backend/manager/migrations/0006_delete_nodes.py deleted file mode 100644 index ccc63c8..0000000 --- a/backend/manager/migrations/0006_delete_nodes.py +++ /dev/null @@ -1,15 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 11:41 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("manager", "0005_nodes_name"), - ] - - operations = [ - migrations.DeleteModel( - name="Nodes", - ), - ] diff --git a/backend/manager/templates/manager/base.html b/backend/manager/templates/manager/base.html index 4b1a8ad..91f42b7 100644 --- a/backend/manager/templates/manager/base.html +++ b/backend/manager/templates/manager/base.html @@ -17,9 +17,7 @@ integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"> - + diff --git a/backend/manager/tests/__init__.py b/backend/manager/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/manager/tests/test_views.py b/backend/manager/tests/test_views.py new file mode 100644 index 0000000..08116fc --- /dev/null +++ b/backend/manager/tests/test_views.py @@ -0,0 +1,39 @@ +from django.test import TestCase, Client +from django.urls import reverse +from common_models.models import Task # Załóżmy, że mamy model Task + +class AddTaskFormTest(TestCase): + + def setUp(self): + # Ustawienie klienta testowego + self.client = Client() + # self.add_task_url = reverse('/manager/task/add_task/') # Nazwa URL powiązana z widokiem add_task_form + self.add_task_url = '/manager/task/add_task/' + def test_add_task_form_get(self): + # Testowanie odpowiedzi na żądanie GET + response = self.client.get(self.add_task_url) + self.assertEqual(response.status_code, 200) + + def test_add_task_form_post(self): + post_data = { + 'path': 'ścieżka/do/pliku.mx3', + 'priority': 'normal', + 'gpu_partition': 'normal', + 'est': '1', # Przesyłanie liczby godzin jako ciąg znaków + } + + response = self.client.post(self.add_task_url, post_data) + self.assertEqual(response.status_code, 302) # Przekierowanie po pomyślnym dodaniu + + self.assertEqual(Task.objects.count(), 1) + task = Task.objects.first() + self.assertEqual(task.path, post_data['path']) + self.assertEqual(task.priority, post_data['priority']) + self.assertEqual(task.gpu_partition, post_data['gpu_partition']) + + # Sprawdzenie, czy 'est' jest ustawione i porównanie wartości + if task.est is not None: + self.assertEqual(task.est, post_data['est']) + else: + # Jeśli 'est' jest None, upewnij się, że przesłane 'est' było puste + self.assertEqual(post_data['est'], '') \ No newline at end of file diff --git a/backend/manager/urls.py b/backend/manager/urls.py index edba760..5857216 100644 --- a/backend/manager/urls.py +++ b/backend/manager/urls.py @@ -7,24 +7,10 @@ router.register(r'tasks', TaskViewSet) urlpatterns = [ - - #OLD LINK TO FIX: - path('get_task/', views.get_task, name='get_task'), - path('finish_task/', views.finish_task, name='finish_task'), - # path('send_command/', views.send_command, name='send_command'), - - path('tasks/', task_list, name='task_list'), - path('task/add_new_task/', TaskManagerView.as_view(), name='add_task_form'), - path('task/edit//', TaskManagerView.as_view(), name='edit_task'), - path('task/delete//', TaskManagerView.as_view(), name='delete_task'), - - - path('task//pause/', views.pause_task, name='pause_task'), - path('task//resume/', views.resume_task, name='resume_task'), - # path('task//priority//', views.update_priority, name='update_priority'), - - - + + path('task/', TaskListView.as_view(), name='task_list'), + path('task///', TaskManagerView.as_view(), name='task_action_id'), + path('task//', TaskManagerView.as_view(), name='task_action'), # path('', include(router.urls)), # path('', views.index, name='index'), @@ -41,8 +27,6 @@ ####NODE-MANAGEMENT#### path('node-management/', NodeManagementView.as_view(), name='node_management'), - ####TASK-RUN#### - path('task//', TaskRunView.as_view(), name='task_action'), ] \ No newline at end of file diff --git a/backend/manager/views.py b/backend/manager/views.py index ef2a5e8..21842cb 100644 --- a/backend/manager/views.py +++ b/backend/manager/views.py @@ -6,27 +6,24 @@ from django.shortcuts import get_object_or_404, redirect from django.http import HttpResponse from django.db.models import Q - -from rest_framework import viewsets -from common_models.models import * -from .serializers import TaskSerializer -from .components.nodes_monitor import NodesMonitor -# Tymczasowe wyłączenie tokenów from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator +from django.contrib import messages +from django.urls import reverse +from rest_framework.renderers import TemplateHTMLRenderer, JSONRenderer +from rest_framework.parsers import JSONParser +from rest_framework import viewsets from rest_framework.views import APIView from rest_framework.response import Response -# from .s import Nodes +from common_models.models import * +from .components.forms import EditTaskForm, AddTaskForm +from .serializers import TaskSerializer +from .components.nodes_monitor import NodesMonitor from channels.layers import get_channel_layer from asgiref.sync import async_to_sync -from .components.forms import EditTaskForm, AddTaskForm - -from django.urls import reverse -# @csrf_exempt - from datetime import timedelta @csrf_exempt @@ -50,9 +47,9 @@ def add_task(request): @csrf_exempt def get_task(request): if request.method == "GET": - task = Task.objects.filter(status="waiting").order_by("id").first() + task = Task.objects.filter(status="Waiting").order_by("id").first() if task: - task.status = "running" + task.status = "Running" task.start_time = timezone.now() # Ustaw czas rozpoczęcia zadania task.save() return JsonResponse( @@ -72,8 +69,8 @@ def finish_task(request): task_id = request.POST.get("task_id") if task_id: try: - task = Task.objects.get(id=task_id, status="running") - task.status = "finished" + task = Task.objects.get(id=task_id, status="Running") + task.status = "Finished" task.end_time = timezone.now() # Ustaw czas zakończenia zadania task.save() return JsonResponse({"status": "success", "message": "Task finished"}) @@ -87,56 +84,11 @@ def finish_task(request): return JsonResponse( {"status": "error", "message": "Only POST method is allowed"} ) - - -def index(request): - tasks = Task.objects.all() - return render(request, "scheduler/index.html", {"tasks": tasks}) - - -@csrf_exempt -def pause_task(request, task_id): - task = get_object_or_404(Task, id=task_id) - task.status = "paused" - task.save() - return redirect("index") # Powrót do strony głównej - - -@csrf_exempt -def resume_task(request, task_id): - task = get_object_or_404(Task, id=task_id) - if task.status == "paused": - task.status = "waiting" - task.save() - return redirect("index") - - class TaskViewSet(viewsets.ModelViewSet): queryset = Task.objects.all() serializer_class = TaskSerializer -def task_list(request): - - waiting_tasks = Task.objects.filter(status='waiting') - active_tasks = Task.objects.filter(status='pending') - finished_tasks = Task.objects.filter(status='finished') - - tasks = Task.objects.all() - for task in tasks: - task.est = format_timedelta(task.est) if task.est else None - - return render(request, "manager/task_list.html", {"tasks": waiting_tasks,"active_tasks": active_tasks}) - -def format_timedelta(td): - total_seconds = int(td.total_seconds()) - hours = total_seconds // 3600 - minutes = (total_seconds % 3600) // 60 - seconds = total_seconds % 60 - return f"{hours:02d}:{minutes:02d}:{seconds:02d}" - - - # @csrf_exempt # async def send_command(request): @@ -388,124 +340,185 @@ def get(self, request, *args, **kwargs): gpus = Gpus.objects.all() return render(request, "manager/gpus_list.html", {"gpus": gpus}) - class TaskManagerView(APIView): + renderer_classes = [TemplateHTMLRenderer, JSONRenderer] - def get(self, request, *args, **kwargs): - path = request.path_info.split("/")[-3] + def get(self, request, action, *args, **kwargs): task_id = kwargs.get("task_id") - if path == "edit": - # Return the response from the edit_task method - return self.edit_task(request, task_id=task_id) - elif path == "delete": - # Return the response from the edit_task method - return self.delete_task(request, task_id=task_id) + methods = { + "edit": self.edit_task, + "delete": self.delete_task, + "run": self.run_task, + "cancel": self.cancel_task, + "redo": self.redo_task, + "add_task": self.add_task_form + } + + if action in methods: + return methods[action](request, task_id=task_id) else: - form = AddTaskForm() - return render(request, 'manager/task_form.html', {'form': form}) + # Redirect or return JSON response for invalid action + if request.accepted_renderer.format == 'json': + return Response({"error": "Invalid action"}, status=400) + else: + return redirect("task_list") + def post(self, request, *args, **kwargs): - form = AddTaskForm(request.POST) - if form.is_valid(): - form.save() - return redirect("task_list") + action = kwargs.get("action") + if action == "add_task": + return self.add_task_form(request) + elif action == "edit_task": + return self.edit_task(request, task_id=kwargs.get("task_id")) else: - return render(request, 'manager/task_form.html', {'form': form}) + if request.accepted_renderer.format == 'json': + return Response({"error": "Invalid action"}, status=400) + else: + return redirect("task_list") @csrf_exempt - def edit_task(self, request, task_id): + def edit_task(self, request, task_id=None): task = get_object_or_404(Task, pk=task_id) if request.method == "POST": form = EditTaskForm(request.POST, instance=task) if form.is_valid(): form.save() - return redirect("task_list") + if request.accepted_renderer.format == 'json': + return Response({"message": "Task updated successfully!"}) + elif request.accepted_renderer.format == 'html': + messages.success(request, "Task updated successfully!",extra_tags='primary') + return redirect("task_list") + else: + return redirect("task_list") else: form = EditTaskForm(instance=task) - - return render(request, "manager/edit_task.html", {"form": form}) + + if request.accepted_renderer.format == 'json': + return Response(form.errors, status=400) + else: + return render(request, "manager/edit_task.html", {"form": form, "task": task}) @csrf_exempt - def delete_task(self, request, task_id): + def delete_task(self, request, task_id=None): task = get_object_or_404(Task, pk=task_id) task.delete() - return redirect("task_list") - - -class TaskRunView(APIView): - def get(self, request, task_id,action): - # Wybór odpowiedniej akcji na podstawie ścieżki - if action == 'run': - return self.run_task(task_id,request) - elif action == 'cancel': - return self.cancel_task(task_id,request) - elif action == 'redo': - return self.redo_task(task_id,request) + if request.accepted_renderer.format == 'json': + return Response({"message": "Task deleted successfully"}) + elif request.accepted_renderer.format == 'html': + messages.success(request, "Task canceled successfully!",extra_tags='primary') + return redirect("task_list") else: - return HttpResponse("Invalid action", status=400) - def get_task_list(self,request): - waiting_tasks = Task.objects.filter(status='waiting') - pending_tasks = Task.objects.filter( - Q(status='pending') | Q(status='running') - ) - # finished_tasks = Task.objects.filter(status='finished') - - tasks = Task.objects.all() - for task in tasks: - task.est = format_timedelta(task.est) if task.est else None - - return render(request, "manager/task_list.html", {"tasks": waiting_tasks,"active_tasks": pending_tasks}) + return redirect("task_list") def select_gpu_for_task(self): - # Przykładowa funkcja do wyboru GPU na podstawie wymagań zadania - # Tutaj można dodać bardziej złożoną logikę dopasowania GPU do zadania return Gpus.objects.filter(status=0).first() def get_priority_task(self): - # Przykładowa funkcja do wyboru najwyższego priorytetu zadania return Task.objects.filter(status='waiting').order_by('-priority').first() - - def run_task(self, task_id, request = None): - task = self.get_priority_task() if task_id is None else Task.objects.get(id=task_id) - if not task: - return HttpResponse("No task available or specified task does not exist.", status=404) - + + def run_task(self, request, task_id=None): + task = self.get_priority_task() if task_id is None else get_object_or_404(Task, id=task_id) gpu = self.select_gpu_for_task() if not gpu: - return HttpResponse("No available GPUs.", status=503) + message = "No available GPUs." + if request.accepted_renderer.format == 'json': + return Response({"error": message}, status=400) + elif request.accepted_renderer.format == 'html': + messages.success(request, message ,extra_tags='danger') + return redirect("task_list") + else: + return redirect("task_list") ############ PROPABLY IT's the same as above - # Przydzielenie GPU do zadania i aktualizacja statusów - task.assigned_gpu = f"N{gpu.node_id.id}/G{gpu.id}" - task.assigned_node = f"{gpu.node_id.ip}" # Convert gpu.node_id to a string - task.status = 'pending' + task.assigned_gpu_id = f"N{gpu.node_id.id}/G{gpu.id}" + task.assigned_node_id = f"{gpu.node_id.ip}" + task.status = 'Pending' task.save() - gpu.status = 'Bussy' - gpu.task_id = str(task.id) # Convert task.id to a string + gpu.status = 'Running' + gpu.task_id = task gpu.save() - # Logika uruchomienia zadania na GPU - redirect("task_list") - # return self.get_task_list(request) - def cancel_task(self,task_id, request=None): - task = Task.objects.get(id=task_id) - task.assigned_gpu = None - task.assigned_node = None - task.status = 'waiting' + if request.accepted_renderer.format == 'json': + return Response({"message": "Task is running"}) + else: + return redirect("task_list") + + def cancel_task(self, request, task_id=None): + task = get_object_or_404(Task, id=task_id) + task.assigned_gpu_id = None + task.assigned_node_id = None + task.status = "Waiting" task.save() gpu = Gpus.objects.get(id=task_id) - gpu.status = 0 + gpu.status = "Waiting" gpu.task_id = None + gpu.last_update = timezone.now() gpu.save() + + if request.accepted_renderer.format == 'json': + return Response({"message": "Task cancelled"}) + else: + return redirect("task_list") + + def redo_task(self, request, task_id=None): + # Logic to redo the task + # ... + + if request.accepted_renderer.format == 'json': + return Response({"message": f"Task {task_id} redo initiated"}) + else: + return HttpResponse(f"Task {task_id} redo initiated") - if request: - return self.get_task_list(request) - else: - return HttpResponse(f"Task {task_id} canceled.") + def add_task_form(self, request,task_id=None): + if request.method == 'GET': + form = AddTaskForm() + if request.accepted_renderer.format == 'json': + # W przypadku odpowiedzi JSON, zwracamy pustą strukturę formularza + serializer = TaskSerializer(data=request.data) + return Response(serializer.data) + else: + # W przypadku odpowiedzi HTML, renderujemy formularz HTML + return render(request, 'manager/task_form.html', {'form': form}) + + elif request.method == 'POST': + # Obsługa żądania POST dla tworzenia nowego zadania + if request.accepted_renderer.format == 'json': + data = JSONParser().parse(request) + serializer = TaskSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=201) + return Response(serializer.errors, status=400) + else: + form = AddTaskForm(request.POST) + if form.is_valid(): + form.save() + return redirect("task_list") + else: + return render(request, 'manager/task_form.html', {'form': form}) + +class TaskListView(APIView): + renderer_classes = [TemplateHTMLRenderer, JSONRenderer] + def get(self, request): + waiting_tasks = Task.objects.filter( + Q(status='Waiting') | Q(status='Waiting') | Q(status='Interrupted') | Q(status=None) + ) + pending_tasks = Task.objects.filter( + Q(status='Pending') | Q(status='Running') | Q(status=None) + ) + + tasks = Task.objects.all() + data = { + "tasks": waiting_tasks, + # "tasks": tasks, + "active_tasks": pending_tasks + } + # Return a JSON response if the request is for API + if request.accepted_renderer.format == 'json': + return Response(data) - def redo_task(self, task_id,request=None): - # Logika ponownego uruchamiania zadania - return HttpResponse(f"Task {task_id} redo initiated.") \ No newline at end of file + # Otherwise, render the HTML template + return Response(data, template_name="manager/task_list.html") \ No newline at end of file diff --git a/backend/node/functions/gpu_monitor.py b/backend/node/functions/gpu_monitor.py index 13b7ca4..ae2a8a7 100644 --- a/backend/node/functions/gpu_monitor.py +++ b/backend/node/functions/gpu_monitor.py @@ -140,6 +140,7 @@ def assign_gpus(self, node_id): for gpu_key, gpu in self.gpus_status.items(): data = { "action": "assign_node_gpu", + "no": gpu_key, "brand_name": gpu["name"], "gpu_util": gpu["gpu_util"], "status": gpu["status"], @@ -177,6 +178,7 @@ def submit_update_gpu_status(self,node_id): for gpu_key, gpu in self.gpus_status.items(): data = { "action": "update_node_gpu_status", + "no": gpu_key, "brand_name": gpu["name"], "gpu_util": gpu["gpu_util"], "status": gpu["status"], diff --git a/backend/node/migrations/0001_initial.py b/backend/node/migrations/0001_initial.py index a357a29..61a8ca5 100644 --- a/backend/node/migrations/0001_initial.py +++ b/backend/node/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.9 on 2024-01-25 22:43 +# Generated by Django 4.2.9 on 2024-01-28 20:39 from django.db import migrations, models @@ -12,16 +12,21 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Local", fields=[ + ("id", models.IntegerField(primary_key=True, serialize=False)), + ("node_id", models.CharField(max_length=15, unique=True)), ( - "id", - models.BigAutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", + "managerNmUrl", + models.CharField( + default="http://localhost:8000/manager/node-management/", + max_length=15, + ), + ), + ( + "managerWsUrl", + models.CharField( + default="ws://localhost:8000/ws/node/", max_length=15 ), ), - ("node_id", models.CharField(max_length=15, unique=True)), ], ), ] diff --git a/backend/node/migrations/0002_alter_local_id.py b/backend/node/migrations/0002_alter_local_id.py deleted file mode 100644 index 7603ab4..0000000 --- a/backend/node/migrations/0002_alter_local_id.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-25 22:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("node", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="local", - name="id", - field=models.IntegerField(primary_key=True, serialize=False), - ), - ] diff --git a/backend/node/migrations/0003_local_url.py b/backend/node/migrations/0003_local_url.py deleted file mode 100644 index 89bd002..0000000 --- a/backend/node/migrations/0003_local_url.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-26 11:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("node", "0002_alter_local_id"), - ] - - operations = [ - migrations.AddField( - model_name="local", - name="url", - field=models.CharField( - default="http://localhost:8000/manager/node-management/", max_length=15 - ), - ), - ] diff --git a/backend/node/migrations/0004_rename_url_local_managernmurl_local_managerwsurl.py b/backend/node/migrations/0004_rename_url_local_managernmurl_local_managerwsurl.py deleted file mode 100644 index fc2a9c2..0000000 --- a/backend/node/migrations/0004_rename_url_local_managernmurl_local_managerwsurl.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2.9 on 2024-01-27 09:28 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("node", "0003_local_url"), - ] - - operations = [ - migrations.RenameField( - model_name="local", - old_name="url", - new_name="managerNmUrl", - ), - migrations.AddField( - model_name="local", - name="managerWsUrl", - field=models.CharField( - default="ws://localhost:8000/ws/node/", max_length=15 - ), - ), - ] diff --git a/backend/node/node_websocket_client.py b/backend/node/node_websocket_client.py index 30dc185..95c8df0 100644 --- a/backend/node/node_websocket_client.py +++ b/backend/node/node_websocket_client.py @@ -2,6 +2,7 @@ import websockets import json from asgiref.sync import sync_to_async +import logging async def get_node_id(): from node.models import Local @@ -10,7 +11,7 @@ async def get_node_id(): return node_id.id async def connect_to_manager(): - uri = "ws://manager:8000/ws/node/" + uri = "ws://localhost:8000/ws/node/" while True: try: async with websockets.connect(uri) as websocket: diff --git a/backend/node/views.py b/backend/node/views.py index ef467d2..d334a7b 100644 --- a/backend/node/views.py +++ b/backend/node/views.py @@ -103,6 +103,7 @@ def get(self, request, task_id=None,action=None): return self.redo_task(task_id,request) else: return self.get_task_list(request) + async def get_task_list(self,request): node_id = await sync_to_async(Local.objects.get, thread_sensitive=True)(id=1) waiting_tasks = Task.objects.filter(status='pending',node_id=node_id) @@ -133,9 +134,9 @@ def run_task(self, task_id, request = None): return HttpResponse("No available GPUs.", status=503) # Przydzielenie GPU do zadania i aktualizacja statusów - task.assigned_gpu = f"N{gpu.node_id.id}/G{gpu.id}" - task.assigned_node = f"{gpu.node_id.ip}" # Convert gpu.node_id to a string - task.status = 'running' + task.assigned_gpu_id = f"N{gpu.node_id.id}/G{gpu.id}" + task.assigned_node_id = f"{gpu.node_id.ip}" # Convert gpu.node_id to a string + task.status = 'Running' task.save() gpu.status = 'Bussy' @@ -148,8 +149,8 @@ def run_task(self, task_id, request = None): def cancel_task(self,task_id, request=None): task = Task.objects.get(id=task_id) - task.assigned_gpu = None - task.assigned_node = None + task.assigned_gpu_id = None + task.assigned_node_id = None task.status = 'waiting' task.save()