Hackathon SO

Hackathon-ul presupune rezolvarea unui exercițiu propus de către echipa de Sisteme de Operare, din materia parcursă în cadrul cursului si laboratoarelor de SO. Exercițiul este propus spre a fi rezolvat de către o echipă de 2 studenți înscriși la cursul de Sisteme de Operare. Primele 3 cele mai bune implementări vor fi recompensate cu premii. În timpul desfășurării hackathon-ului, echipele vor primi ajutor din partea echipei de SO.

Obiective

  • Colaborare, lucrul in echipa
  • Dezvoltare cu suport din partea echipei SO
  • Dezvoltare a unei aplicați portabile

Data

Sâmbătă, 20 mai 2023, în intervalul 9:00 - 17:00.

Locație

Hackathonul se desfășoară în format fizic în sala PR706.

Precondiții

  1. La acest hackathon vor putea participa studenții înscriși la cursul de SO în anul universitar 2022-2023;
  2. Participanții vor forma echipe de câte două persoane;
  3. Participanții vor lucra pe propriile sisteme.

Înscriere

Echipele participante se vor putea înscrie la hackathon prin completarea formularului de aici până pe data de 17 mai 2023, ora 20:00. Se vor alege maxim 20 de echipe.

Regulament

  1. Codul versionat trebuie să fie adăugat într-un repository privat folosind platforma GitLab a facultății. Faceți un repo privat în care adăugați asistenții supraveghetori și un README cu componența echipei.
  2. Codul trebuie să treacă un set de teste puse la dispoziție de către echipa de SO.

Submisie

Submisiile vor fi încărcate pe Moodle .

  • O submisie constă într-o arhivă .zip care conține directorul so/hackathon/lambda-loader (cu directoarele checker și skel).
  • Arhiva este încărcată doar de unul dintre membrii echipei.
  • În so/hackathon/lambda-loader/skel trebuie să existe un fișier README.md care să conțină:
    • componența echipei
    • link GitHub/GitLab
    • detalii legate de implementare; fiecare funcționalitate extra are nevoie de o descriere, mod de abordare și testare.

Premii

Fiecare membru al echipelor câștigătoare va fi premiat, în funcție de locul obținut:

  1. Premiul 1: voucher eMag în valoare de 900 lei
  2. Premiul 2: voucher eMag în valoare de 800 lei
  3. Premiul 3: voucher eMag în valoare de 700 lei

Echivalare

Toate echipele participante sunt eligibile de echivalarea unui punct din notele pentru temă în cadrul materiei Sisteme de Operare (în funcție de complexitatea implementării și stadiului proiectului dezvoltat în timpul hackathonului).

Anunțare câștigători

Echipele câștigătoare vor fi anunțate până joi, 25 mai 2023.

Dezvoltarea aplicației

Dezvoltarea trebuie făcută exclusiv pe mașinile virtuale SO.

Nu rulați testele local (pe calculatoarele voastre sau în mașinile voastre virtuale). Pot să apară diferențe între local și VM-uri, iar, pentru corectare, vom considera doar rezultatele obținute în mașina virtuală de la SO.

Loader de funcții lambda

Proiectul constă în realizarea unui sistem care permite încărcarea dinamică a unor biblioteci și executarea unor funcții din acestea. Proiectul implementează o arhitectură de tip client - server, unde serverul primește cereri de rulat funcții dintr-o anumită bibliotecă dinamică din sistem.

Funcționalitatea este primul pas spre implementarea unei funcționalități similare AWS Lambda, unde utilizatorul poate să încarce o funcție și să o execute pe diferite servere, la cerere; în cazul proiectului propus, funcțiile sunt deja implementare în biblioteci, iar clientul cere executarea anumitor funcții printr-o comandă trimisă serverului. Mai jos sunt detaliate cerințele principale ale temei, precum și posibile îmbunătățiri.

Detalii și observații implementare

Pentru implementare se pune la dispoziție funcționalitatea de primire de comenzi (folosind UNIX sockets), care conțin numele unei biblioteci (calea către fișierul cu biblioteca) și opțional numele unei funcții. O comandă trimisă de la client către server are următorul format: <libname> [<funcname> [<filename>]] unde:

  • libname - calea spre biblioteca ce se dorește a fi utilizată
  • funcname - parametru opțional; numele funcției din cadrul bibliotecii; în mod implicit, funcția folosită este numită run.
  • filename - parametru opțional; numele unui fișier cu date de intrare dat ca argument funcției funcname.

Datele rezultate în urma execuției vor fi scrise într-un fișier al cărui nume este întors ca răspuns clientului. Fișierul returnat va conține doar mesajele afișate la standard output de către funcția de bibliotecă apelată.

Comunicarea între client și server este următoarea:

Client						    Server
						    listen()
connect()					    accept()
send()     -—---libname [funcname [filename]]-----> recv()
recv()     <--------------outputfile--------------- send()

După primirea și parsarea unui mesaj din partea unui client, serverul apelează secvențial o serie de funcții care au următoarele scopuri:

  • Prepare / pre-hooks - operații pregătitoare de care nu depinde încărcarea bibliotecii sau executarea funcțiilor din bibliotecă;
  • Încărcare bibliotecă - încărcarea bibliotecii și alte operații asociate gestiunii bibliotecii
  • Execuție funcționalitate cerută - rularea funcției din bibliotecă. Dacă funcname lipsește, atunci se apelează funcția run. Parametrul filename poate să apară doar atunci când este specificat funcname.
  • Descărcare bibliotecă - realizarea de operații asociate descărcării bibliotecii din memorie
  • Post-hooks - operații ulterioare execuției care nu depind de prezența bibliotecii în memorie.

Cele 5 funcții au caracter orientativ. În funcție de implementare, unele funcții pot să nu fie implementate. În acest caz, funcțiile vor rămâne ca stub-uri.

Implementarea serverului trebuie paralelizată astfel încât cererile clienților să fie tratate cât mai rapid. Fiecare echipă trebuie să decidă modelul de paralelizare (prin procese, prin threaduri, hibrid, folosirea unui work pool etc.) luând în considerare scopul proiectului.

Funcționalitatea de bază presupune implementarea în C, pentru sistemul de operare Linux, folosind API-ul POSIX:

  • conexiunii între client și server.
    • Conexiunea client-server se va face folosind UNIX Sockets, prin intermediul bibliotecii libipc.so.
    • Veți adăuga funcțiile necesare pentru creare, conectare, trimitere/primire de date în această bibliotecă (libipc.so).
    • Puteți modifica biblioteca în orice mod doriți atât timp cât clientul de test (checker/client.c) compilează și se poate conecta la server.
    • Clientul de test (checker/client.c) nu poate fi modificat. Dacă aveți nevoie să modificați clientul de test pentru funcționalități adiționale, creați un client nou de test.
  • comunicației dintre client și server: clientul trimite o cerere respectând formatul de mai sus și așteaptă ca răspuns calea către un fișier din sistem în care se află rezultatele; serverul primește cererea din partea unui client și o tratează.
  • tratării unei cereri de către server: serverul parsează comanda primită, încarcă biblioteca și apelează funcția cerută din bibliotecă.
    • În caz de eroare, se va scrie următorul mesaj în fișierul de output Error: <command> could not be executed. urmat de mesaje de eroare sugestive (Hint: folosiți strerror()).
    • Fișierul de output trebuie creat cu nume aleator folosind functia mkstemp(). Folosiți OUTPUTFILE_TEMPLATE ca template pentru numele fișierului.
  • trimiterii unui răspuns înapoi către client. Răspunsul este numele fișierului creat la pasul anterior pe baza OUTPUTFILE_TEMPLATE.
  • paralelizării modului de tratare a clienților.
    • Aveți în vedere ca sincronizarea datelor de ieșire și încărcarea și descărcarea bibliotecilor nu trebuie să afecteze funcționalitatea celorlalte thread-uri / procese.

Aveți în vedere faptul că în implementarea voastră trebuie să asigurați buna funcționare a serverului: executarea funcțiilor dintr-o bibliotecă cerută de utilizator poate avea comportament neașteptat (ex. accese invalide, închideri forțate etc.). Implementarea serverului trebuie să fie robustă, iar serverul trebuie să își continue execuția și în aceste cazuri.

Concepte teoretice necesare

De ce este nevoie pentru implementarea proiectului propus:

  • Înțelegerea comunicării inter-proces - folosirea Unix sockets și a operațiilor read/write sau send/receive:
  • Înțelegerea API-ului de încărcare / descărcare a bibliotecilor și executare de funcții din biblioteci dinamice:
    • Hint: man dlopen
  • Lucrul cu date partajate între procese sau thread-uri:
  • Lucrul cu memoria
  • Lucrul cu fișiere

Testare

Exemplu rulare
## pornirea serverului
so@so:~/skel$ ./server
 
## client
# se execută funcția "run" din libbasic.so
so@so:~/checker$ ./client $(realpath libbasic.so)
Output file: /home/so/checker/output/out-cfy0fl
so@so:~/checker$ cat /home/so/output/out-cfy0fl 
run
 
# se execută funcția "function" din libbasic.so
so@so:~/checker$ ./client $(realpath libbasic.so) function
Output file: /home/so/checker/output/out-vc7s03
so@so:~/checker$ cat /home/so/output/out-vc7s03 
function
 
# se execută funcția "cat" din libbasic.so cu argumentul "/home/so/checker/Makefile"
so@so:~/checker$ ./client $(realpath libbasic.so) cat $(realpath Makefile)
Output file: /home/so/checker/output/out-y732bN
so@so:~/checker$ cat /home/so/output/out-y732bN 
CC=gcc
[...]
Rulare Checker

Aveți la dispoziție un checker pentru verificarea parțială a implementării voastre.

so@so~$ cd checker
so@so~$ ./checker.sh

Task-uri adiționale / departajare

Funcționalitatea de bază este obligatorie pentru toate echipele participante. Pe lângă aceasta, pentru departajare, fiecare echipă poate aduce funcționalități adiționale aplicației. Fiecare funcționalitate extra va fi descrisă într-un fișier README (ce presupune și cum ați testat).

Câteva funcționalități extra pe care le puteți avea în vedere (puteți propune voi orice altceva vi se pare necesar):

  • interfață pentru conexiunea client - server: în funcție de parametrii dați la rulare, folosim sockeți de rețea sau sockeți UNIX.
  • extinderea modului de tratare a unui client: serverul primește comenzi multiple până la întâlnirea comenzii “exit”/“quit” .
  • securizarea serverului: cum previn leak-urile de date
  • optimizări de performanță
  • log-uri ale aplicației
  • fișiere/opțiuni de configurare: la pornire, serverul este configurat în funcție de anumite opțiuni/fișiere de configurare: număr maxim de clienți, ce tip de sockeți să folosească, etc.
  • inspectarea în timp real a serverului și extragerea de statistici (număr clienți, număr biblioteci încărcate, memorie consumată etc.)
  • portarea spre alt limbaj de programare (scheletul propus este scris în C, însă, fiind vorba de comunicare client-server, implementarea poate fi în orice alt limbaj, atât timp cât respectă cerințele temei).
  • trimiterea unui răspuns adecvat în care funcția cerută durează prea mult timp (peste un TIMEOUT) sau a executat o operație care ar duce la oprirea serverului (ex: acces invalid la memorie, apelează exit/abort/etc). Soluția poate avea diferite niveluri de complexitate, funcție de modul în care este tratată terminarea conexiunii cu clientul (dacă clientul primește, sau nu, un mesaj de eroare) și cum se determină cauza terminării execuției.
  • implementarea unui mecanism eficient de comunicare a rezultatelor în cazul folosirii network sockets (în acest caz, serverul poate întoarce un URL de unde clientul poate descărca rezultatele).
  • închidere controlată a serverului (ex. la primirea unui semnal, se poate adăuga o rutină de tratare a semnalului care eliberează resursele înainte de închiderea serverului.
so/teme/hackathon.txt · Last modified: 2023/05/20 07:38 by maria.mihailescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0