Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project revamp and docker integration #251

Merged
merged 30 commits into from
May 10, 2024

Conversation

TR1VER
Copy link
Contributor

@TR1VER TR1VER commented May 6, 2024

In this pull request, the following were changed/added

  • Docker tests are integrated with the backend, creating a folder artifacts.zip in the process which will be in the submission directory.
  • A variable docker_finished is added, which becomes true after the tests have successfully run.
  • Project backend is revamped and no longer works with multipart files. Instead it works with text and strings, this is better since files were overkill for this purpose. Bringing with them additional resources, complexity and tests.
  • New functions were added for mananiging docker images, such as "image exists", "docker is used in any project".
  • Updated checks when creating a project, so students can see required files to displaly structure and docker template.
  • Added docker template check
  • File handler now has capabilites to copy a list of files to a zip in its structure

Triver1 added 7 commits April 27, 2024 15:37
…sts. New utility functions for managing Docker Images. Checks for templates. Added filehandler List<Files> -> Zip
# Conflicts:
#	backend/app/src/main/java/com/ugent/pidgeon/util/CommonDatabaseActions.java
@TR1VER TR1VER marked this pull request as draft May 6, 2024 08:16
Copy link
Contributor

@Aqua-sc Aqua-sc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ik heb een aantal dingen aangepast en een aantal comments geplaatsts. Al bij al moest er veel veranderd worden dus is niet makkelijk om te reviewen maar de grote lijnen zien er zeker oké uit.

Momenteel heb ik vooral naar de code gekeken, ik zou vanavond nog eens wat situaties uitproberen ook om te zien of alles zeker werkt; Kan je me een idee geven van een script dat artifacts creëert zodat ik dat ook kan testen (er zal er vast één zijn bij de tests maar daar heb ik nog niet naar kunnen kijken

Comment on lines 102 to 106
// This docker test is configured in the simple mode (store test console logs)
return model.runSubmission(testScript);
}else{
// This docker test is configured in the template mode (store json with feedback)
return model.runSubmissionWithTemplate(testScript, testTemplate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ksnap nie helemaal hoe de artifacts gekopieërd worden voordat het script gelopen wordt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad dit is een logic error. Het kopieeren gebeurd 5 lines erboven maar mijn order of execution was verkeerd.

}
submission.setTestFinished(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dit is niet helemaal hoe ik het in gedachten had. Dit heeft nu vrij weinig nut want op het moment dat de frontend de response krijgt is de volledige dockertest dus al gerund en zal dit veld dus altijd true zijn. Tis eerder de bedoeling dat er een reponse wordt teruggegeven waar dit dus default op false staat en dat dan in de achtergrond de dockertesten gerunt worden & dit veld geupdate wordt. Op deze manier kan de user al feedback krijgen over de structure test terwijl de docker testen aan het runnen zijn.

Comment on lines 110 to 122
// delete test entry
if(httpMethod.equals(HttpMethod.DELETE)){
// first check if docker image is not used anywhere else
if(!testRepository.imageIsUsed(dockerImage)){
// image is no longer required for any tests
DockerSubmissionTestModel.removeDockerImage(dockerImage);
}

// Create/update test entity
TestEntity test = new TestEntity(dockerImage, dockertestFileEntityId, structuretestFileEntityId);
test = testRepository.save(test);
projectEntity.setTestId(test.getId());
// delete test
testRepository.deleteById(testEntity.getId());
projectEntity.setTestId(null);
projectRepository.save(projectEntity);
return ResponseEntity.ok(entityToJsonConverter.testEntityToTestJson(test, projectId));
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error while saving files: " + e.getMessage());
return ResponseEntity.ok().build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Volgens mij mag dit gewoon weg, dit heeft heeft een aparte route (helemaal onderaan dit bestand) die je correct hebt aangepast opt eerste gezicht dus dit hoeft hier niet denkik

if(!(dockerImage == null && dockerScript == null && dockerTemplate == null)){

// update/install image if possible.
DockerSubmissionTestModel.installImage(dockerImage);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is dit is wat mogelijks een tijdje kan duren? Het lijkt me niet handig dat er gewacht moet worden op een response indien dit installeren even duurt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inderdaad dit kan wel een tijdje duren. Ik zal dit in een apparte thread doen

DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost("tcp://10.5.0.4:2375").build();

DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kweet niet of dit de bedoeling was, was dit niet net aangepast om dind te werken? Of werkt het dan niet lokaal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dit was wel de bedoeling, deze code van arthur werkte niet meer en hij moest hier nog een mail voor sturen. Op deze manier werkt het lokaal nog.

@TR1VER
Copy link
Contributor Author

TR1VER commented May 7, 2024

Feedback commit gedaan.

@Aqua-sc
Copy link
Contributor

Aqua-sc commented May 9, 2024

Testen

Onderdelen van een test

  • dockerimage: docker image die gebruikt wordt om de testen uit te voeren
  • dockerscript: test script dat uitgevoerd wordt
  • dockertemplate: mogelijkse configuratie van testen om betere feedback te kunnen krijgen
  • structuretest: template voor de vereisten van het project

Aanpassen testen v/e project

De url voor volgende request is altijd /api/projects/{projectId}/tests
De velden zijn een multipartform met allemaal strings met de namen die hierboven beschreven zijn

Toevoegen test

  • POST voegt de test voor de eerste keer toe. Indien het project al een test heeft moet er verder PUT gebruikt worden
  • Vereisten:
    • Indien er een dockerimage of script is moet het andere ook aanwezig is
    • Indien er een dockertemplate is moet er ook een image (en dus ook script) aanwezig zijn
    • een lege string wordt gezien als niet aanwezig
    • op de template wordt een test gedaan of deze de juiste syntax heeft

Aanpassen v/e test

  • PUT moet aan dezelfde voorwaarden als hierboven beschreven voldoen
  • PATCH hier mogen bepaalde velden wel afwezig zijn en wordt enkel geupdate wat er meegegeven is, indien iets niet meegegeven is blijft behouden wat id databank staat

Verwijderen

  • DELETE verwijdert meteen alle tests v/e project
  • PUT overschrijft dus om bv. template te verwijderen kan een request gebeuren met enkel script, image, structure

Disclaimer:

Indien het de eerste keer is dat een dockerimage gebruikt wordt bij een test moet deze nog geinstalleerd worden. Een submission erna zal dus niet correct draaien en de testen falen (zie later). Misschien handig om dit ook ergens te vermelden

Opvragen van de testen

Een GET request naar /api/projects/{projectId}/tests geeft volgende response:

{
	"projectUrl": "/api/projects/1",
	"dockerImage": "fedora:latest",
	"dockerScript": "output=$(bash /shared/input/helloworld.sh); \nif [[ \"$output\" == 'Hello World' ]]; \n\tthen echo 'Test one is successful'; \n\techo 'PUSH ALLOWED' > /shared/output/testOutput; \nelse \n\techo 'PUSH DENIED'; > /shared/output/testOutput; \nfi",
	"dockerTemplate": "@helloworld\n>required\n>description=\"Helloworldtest\"\nHello World\n",
	"structureTest": "helloworld.sh"
}

Deze velden zijn null wanneer:

  • Een bepaalde test gewoon niet aanwezig is
  • Indien de user niet een course admin is zullen dockerScript en dockerImage beiden null zijn. De andere 2 zijn nodig om de structure of feedback te renderen in de frontend en worden dus wel teruggegeven

Voorbeeldtesten

Dockerimage:

  • Als dockerimage heb ik altijd fedora:latest gebruikt. Andere zijn ook mogelijk maar het moet Linux based zijn

Dockerscript:

Simple:
Er moet PUSH ALLOWED naar /shared/output/testOutput geschreven worden indien de testen slagen, anders worden ze als gefaald beschouwd. Alles wat gewoon wordt gelogd (ik denk alles naar stdin) wordt als feedback gegegeven aan de student, bv:

output=$(bash /shared/input/helloworld.sh); 
if [[ "$output" == 'Hello World' ]]; 
	then echo 'Test one is successful'; 
	echo 'PUSH ALLOWED' > /shared/output/testOutput; 
else 
	echo 'PUSH DENIED'; > /shared/output/testOutput; 
fi

Template:
De output van de uitvoering moet naar /shared/output/{testname} geschreven worden, bv:

output=$(bash /shared/input/helloworld.sh); 
echo "$output" > /shared/output/helloworld

Dockertemplate:

gebruikt volgende syntax, de 2 lijntjes met > zijn optioneel. Een test is default required:

@testname
>[required|optional] 
>description="Description van de test" 
Verwachte output

Bijvoorbeeld:

@helloworld
>required
>description="Helloworldtest"
Hello World

structuretest

  • dit maakt gebruik van regex. Het doel is om een .wel nog als echt punt te zien voor file extensions en dan een andere manier te hebben om regex punt te ondersteunen.
  • tabs of gelijk aantal spaties duiden mappen aan, een - voor een lijn betekent dat het verboden is, geen - maakt het verplicht, bv:
file1.txt
folder1/
    file2.txt
file2.txt

Submission feedback

Algemene response

{
	"submissionId": 32,
	"projectUrl": "/api/projects/1",
	"groupUrl": "/api/groups/1",
	"projectId": 1,
	"groupId": 1,
	"fileUrl": "/api/submissions/32/file",
	"structureAccepted": true,
	"dockerStatus": "finished",
	"submissionTime": "2024-05-09T18:52:49Z",
	"structureFeedback": "File structure is correct",
	"dockerFeedback": {
		"type": "TEMPLATE",
		"feedback": {
			"subtests": [
				{
					"testName": "helloworld",
					"testDescription": "Helloworldtest",
					"correct": "Hello World\n",
					"output": "Hello World\n",
					"required": true,
					"succes": true
				},
			],
			"allowed": true
		},
	"artifactUrl": "/api/submissions/32/artifacts"
}

Structure feedback:

  • structureAccepted: boolean die zegt of de structure voldoet aan de voorwaarden
  • sturctureFeedback: uitleg waarom het eventueel gefaald is (kan newlines bevatten)

Docker feedback:

  • dockerstatus: heeft 4 mogelijke waarden:
    • no_test: er was gewoon geen dockertest
    • running: de dockertest is nog aan het lopen. Op dit moment moet dockerFeedback dus genegeert worden
    • finished: de dockertest is klaar, resultaat te vinden in dockerFeedback
    • aborted: een foutje in het runnen van de test. Ik zou dan zoiets tonen
Error while running tests, possible causes:
* results don't get printed to the correct file
* docker image is still installing
  • dockerFeedback: bevat volgende 3 velden
    • type: heeft volgende 3 mogelijkheden
      • SIMPLE, het feedback-veld is gewoon 1 string, de logs van de dockerrun
      • TEMPLATE, het feedback-veld bevat volgende velden:
        • testName: naam van de test
        • testDescription: beschrijving van de test
        • correct: verwachte output
        • output: gegenereerde output
        • required: of de test verplicht is
        • succes: of de test verplicht is
      • NONE, er was geen test, het feedback veld is gewoon lege string
    • feedback: hangt af van het type, zie hierboven
    • allowed: vat samen of de test geslaagd is of niet

Artifacts:

  • artifactUrl: een GET request naar deze URL returned het artifact als zip (of een 404 indien er geen artifacts gegenereerd is)

@TR1VER
Copy link
Contributor Author

TR1VER commented May 9, 2024

@Aqua-sc Misschien is het ook belangrijk om bij beide test script en image toe te voegen dat de container altijd based op een linux distro moet zijn. En dat de test script in bash gebeurd. Het is wel mogelijk via bash python commandos etc te doen op een python container bvb

@usserwoutV2
Copy link
Contributor

Klopt het dat ik een POST request moet sturen naar /api/projects/{projectId}/tests indien dockerImage null is en anders een PUT / PATCH request?

tabs of gelijk aantal spaties duiden mappen aan

Betekend dit dat 1 tab == 4 spaties (zoals in het voorbeeld) of 8 spaties (in frontend is 1 tab == 8 spaties voor één of andere reden, )? Momenteel is 1 tab gelijk aan 1 spatie in mijn structure parser, dus dit moet ik nog aanpassen.
Zijn er verder andere manieren om een invalid structuur test te krijgen?

@Aqua-sc
Copy link
Contributor

Aqua-sc commented May 10, 2024

Klopt het dat ik een POST request moet sturen naar /api/projects/{projectId}/tests indien dockerImage null is en anders een PUT / PATCH request?

Niet noodzakelijk. Bij POST/PUT wordt alles wat je meestuurt in de databank toegevoegd/vervangen. Indien je dan dockerimage = null hebt maar bv. dockerscript != null zal dit geweigert worden aangezien je geen dockerscript kan runnen zonder image. Indien je een PATCH stuurt zullen gewoon enkel degene die aanwezig zijn aangepast worden.

tabs of gelijk aantal spaties duiden mappen aan

Betekend dit dat 1 tab == 4 spaties (zoals in het voorbeeld) of 8 spaties (in frontend is 1 tab == 8 spaties voor één of andere reden, )? Momenteel is 1 tab gelijk aan 1 spatie in mijn structure parser, dus dit moet ik nog aanpassen. Zijn er verder andere manieren om een invalid structuur test te krijgen?

Ik zal antwoorden hoe ik het momenteel begrijp maar mss kan @TR1VER dit nog bevestigen: zolang dat het aantal spaties consistent is maakt het niet uit hoeveel er zijn. (De eerste indent bepaalt dus hoeveel spaties er gebruikt worden). Ik weet niet of spaties en tabs door elkaar gebruikt kunnen worden.
Ik denk dat het vast mogelijk is dat een structuretest invalid is (vooral door bv. tekens die niet in een bestandsnaam mogen voorkomen of mss ook niet consistent gebruik van spaties) maar mss kan @TR1VER hier nog een check voor in de backend maken.

@tr1ver69
Copy link

@usserwoutV2 voor de structure test is het eigenlijk enkel belangrijk dat de spaties/tabs consistent zijn. Zolang dit zo is mag de user beide spaties of tabs gebruiken. Op het einde van een folder moet er ook een / staan.

@Aqua-sc Aqua-sc marked this pull request as ready for review May 10, 2024 09:12
@Aqua-sc Aqua-sc changed the title Project revamp and docker integration (DRAFT) Project revamp and docker integration May 10, 2024
Copy link
Contributor

@Aqua-sc Aqua-sc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ait dit is helemaal top

@Aqua-sc Aqua-sc merged commit c10b256 into development May 10, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants