diff --git a/Main/migrations/0033_solution_docker_instances.py b/Main/migrations/0033_solution_docker_instances.py new file mode 100644 index 0000000..af642d4 --- /dev/null +++ b/Main/migrations/0033_solution_docker_instances.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.4 on 2022-05-08 12:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('Main', '0032_auto_20220408_0018'), + ] + + operations = [ + migrations.AddField( + model_name='solution', + name='docker_instances', + field=models.JSONField(blank=True, default=list, null=True), + ), + ] diff --git a/Main/models/solution.py b/Main/models/solution.py index 69ddd4d..2cfbb7e 100644 --- a/Main/models/solution.py +++ b/Main/models/solution.py @@ -21,6 +21,7 @@ class Solution(models.Model): test = models.IntegerField(default=None, null=True, blank=True) set = models.ForeignKey(Set, null=True, blank=True, on_delete=models.SET_NULL) extras = models.JSONField(default=dict) + docker_instances = models.JSONField(null=True, blank=True, default=list) _solutionfiles = None diff --git a/SprintLib/testers/BaseTester.py b/SprintLib/testers/BaseTester.py index 6962651..071ca38 100644 --- a/SprintLib/testers/BaseTester.py +++ b/SprintLib/testers/BaseTester.py @@ -92,11 +92,19 @@ class BaseTester: def _setup_networking(self): self.call(f"docker network create solution_network_{self.solution.id}") + self.solution.docker_instances.append({ + "type": "network", + "name": f"solution_network_{self.solution.id}" + }) for file in self.solution.task.dockerfiles: add_name = file.filename[11:] with open(join(self.path, "Dockerfile"), "w") as fs: fs.write(file.text) self.call(f"docker build -t solution_image_{self.solution.id}_{add_name} .") + self.solution.docker_instances.append({ + "type": "image", + "name": f"solution_image_{self.solution.id}_{add_name}" + }) run_command = ( f"docker run " f"--hostname {add_name} " @@ -104,6 +112,10 @@ class BaseTester: f"--name solution_container_{self.solution.id}_{add_name} " f"-t -d solution_image_{self.solution.id}_{add_name}" ) + self.solution.docker_instances.append({ + "type": "container", + "name": f"solution_container_{self.solution.id}_{add_name}" + }) print("run command", run_command) self.call(run_command) @@ -150,6 +162,10 @@ class BaseTester: print("Files copied") self._setup_networking() docker_command = f"docker run --network solution_network_{self.solution.id} --name solution_{self.solution.id} --volume={self.path}:/{self.working_directory} -t -d {self.solution.language.image}" + self.solution.docker_instances.append({ + "type": "container", + "name": f"solution_{self.solution.id}" + }) print(docker_command) call(docker_command, shell=True) checker = self.solution.task.checkerfile @@ -159,6 +175,11 @@ class BaseTester: f"docker run --network solution_network_{self.solution.id} --name solution_{self.solution.id}_checker --volume={self.path}:/app -t -d python:3.6", shell=True, ) + self.solution.docker_instances.append({ + "type": "container", + "name": f"solution_{self.solution.id}_checker" + }) + self.solution.save() print("Container created") try: self.before_test() diff --git a/daemons/management/commands/docker_cleaner.py b/daemons/management/commands/docker_cleaner.py index f08a677..64654ee 100644 --- a/daemons/management/commands/docker_cleaner.py +++ b/daemons/management/commands/docker_cleaner.py @@ -1,4 +1,6 @@ -from subprocess import call, PIPE, run +from subprocess import call + +from django.db.models import Q from Main.models import Solution from SprintLib.utils import LoopWorker @@ -8,51 +10,16 @@ class Command(LoopWorker): help = "starts docker cleaner" def go(self): - result = run("docker ps -a", universal_newlines=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True) - lines = result.stdout.split('\n')[1:] - solution_id = None - for line in lines: - line = [i for i in line.split() if i] - if line and line[-1].startswith('solution_'): - for el in line[-1].split('_'): - if el.isnumeric(): - solution_id = int(el) - break - if solution_id: - solution = Solution.objects.filter(id=solution_id).first() - if solution is not None and (solution.result == 'In queue' or solution.result.startswith('Testing')): - continue - call(f"docker rm --force {line[-1]}", shell=True) - solution_id = None - result = run("docker image ls", universal_newlines=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True) - lines = result.stdout.split('\n')[1:] - for line in lines: - line = [i for i in line.split() if i] - if line and line[0].startswith('solution_'): - for el in line[-1].split('_'): - if el.isnumeric(): - solution_id = int(el) - break - if solution_id: - solution = Solution.objects.filter(id=solution_id).first() - if solution is not None and (solution.result == 'In queue' or solution.result.startswith('Testing')): - continue - call("docker image rm " + line[0], shell=True) - solution_id = None - result = run("docker network ls", universal_newlines=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True) - lines = result.stdout.split('\n')[1:] - for line in lines: - line = [i for i in line.split() if i] - if line and line[1].startswith('solution_'): - for el in line[-1].split('_'): - if el.isnumeric(): - solution_id = int(el) - break - if solution_id: - solution = Solution.objects.filter(id=solution_id).first() - if solution is not None and (solution.result == 'In queue' or solution.result.startswith('Testing')): - continue - call("docker network rm " + line[0], shell=True) + for solution in Solution.objects.filter(Q(result="Testing") | Q(result="In queue"), docker_instances__isnull=False): + for instance in sorted(solution.docker_instances, key=lambda x: x['type']): + if instance['type'] == 'network': + call(f"docker network rm --force {instance['name']}") + elif instance['type'] == 'image': + call(f"docker image rm --force {instance['name']}") + elif instance['type'] == 'container': + call(f"docker rm --force {instance['name']}") + else: + raise ValueError(f"Unknown docker type {instance['type']}") def handle(self, *args, **options): call('docker image rm $(docker images -q mathwave/sprint-repo)', shell=True)