commit 3c20ed2657086f970f3581317d76681e81b45561 Author: Julien Palard Date: Fri Nov 18 15:36:16 2022 +0100 Initial revision. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea1472e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +output/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0d9e147 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +SRCS := $(sort $(wildcard *.md)) +DEST := $(notdir $(PWD)) + +.PHONY: static +static: output/index.html + cp -a static/ output/ + +%.html: %.md + sed 's/#!//e;' $< | mdtoreveal /dev/stdin --output $@ + +output/index.md: $(SRCS) + mkdir -p output + cat $(SRCS) > output/index.md + +.PHONY: publish +publish: static + rsync -vah --delete output/ mdk@mdk.fr:/var/www/mdk.fr/$DEST/ + +.PHONY: clean +clean: + rm -fr output + +.PHONY: entr +entr: + ls -1 *.md | entr $(MAKE) static + +.PHONY: serve +serve: static + python3 -m http.server -d output/ + +.PHONY: test +test: + if [ -f test.py ]; then \ + python test.py *.md; \ + fi diff --git a/slides.md b/slides.md new file mode 100644 index 0000000..cf98dd1 --- /dev/null +++ b/slides.md @@ -0,0 +1,280 @@ +# HackInScience + + + +
+ +Julien Palard + +CPython core dev + + +# C'est historique. + +Tu ne peux pas dire qu'HackInScience n'est pas né en 2014, parce que c'est historique. + +## Enseigner le Python + +J'ai l'habitude. + +Mais à des groupes de ~6 pendant ~3 jours. + +## C'est green + +![Ruby Rhod](static/ruby-rhod.jpg) + +## Enseigner le Python + +Un jour on m'a proposé un groupe de 50 pendant 7 jours. + +## C'est pas green + +![Ruby Rhod étranglé](static/pas-green.jpg) + +## Mais on est devs + +Alors on a automatisé tout ce qui pouvait l'être. + +::: notes + +Pour passer du temps avec ceux qui en ont besoin. + + +# HackInScience.org + +C'est un petit Django, avec un peu de celery. + +::: notes + +Pour répartir les corrections sur des machines qui ne font que ça. + +## Démo en prod ! + +https://hackinscience.org + +::: notes + +Faire un tour côté teams, et un tour côté admin aussi ! + +## C'est moche ! + +J'ai dit que j'étais dev, pas dev front, toute aide est la bienvenue. + +::: notes c'est du bootstrap. + +## Je veux voir le code ! + +La première version fonctionnelle : 181 lignes de Python. + +Ça devrait loger dans quelques slides ;) + +::: notes + +Aujourd'hui c'est 2700 lignes de code… + + +## Django models + +```python +class Exercise(models.Model): + title = models.CharField(max_length=255) + check = models.TextField() + wording = models.TextField() +``` + +::: notes + +Si vous connaissez déjà Django, concentrez-vous sur le contenu. + + +## Django models + +Un modèle Django c'est pas just pour l'ORM, ça aide à générer : + +- des migrations de DB ; +- l'interface d'admin ; +- les formulaires ; +- les vues ; +- l'API ; +- l'autocomplétion dans l'IDE . +- les requêtes SQL (l'ORM). + +::: notes + +Un modèle permet au code de connaître de la structure de la base de donnée. Il n'est plus aveugle. C'est bien. + + +## Django view + +```python +class ExerciseListView(LoginRequiredMixin, ListView): + model = Exercise + template_name = "hkis/exercises.html" + +``` + +::: notes + +Vous saviez que la MRO de Python garanti un héritage de gauche à droite ? + +Ici il est garanti que les méthodes surchargées par `LoginRequiredMixin` +sont exécutées avant celles de `ListView`. + + +## Django view + +```python +class ExerciseView(LoginRequiredMixin, DetailView): + model = Exercise + template_name = "hkis/exercise.html" +``` + +## Une petite API + +```python +class ExerciseSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Exercise + fields = '__all__' + +class ExerciseViewSet(viewsets.ModelViewSet): + queryset = Exercise.objects.all() + serializer_class = ExerciseSerializer + +router = routers.DefaultRouter() +router.register('exercises', ExerciseViewSet) +``` + +::: notes + +Pourquoi un "Router" ? Parce que derrière cette ViewSet il y a plein +de vues ! + +Démo time ! + +## Une interface d'admin + +```python +from django.contrib import admin +from website.models import Answer, Exercise + +admin.site.register(Answer) +admin.site.register(Exercise) +``` + +::: notes + +Démo time ! + +# C'est utilisé ? + +Je n'ai pas de « pisteur », mais j'ai une DB. + +En octobre 2022 : 730 personnes ont résolu 10_780 exercices + +La moulinette a corrigé près de 50k rendus. + +::: notes + +Google Analytics c'est illégal. Mais je sais écrire du SQL. + +Aucun tracker, aucune pub, aucun asset externe. + +10k c'est peu ou beaucoup, je ne sais pas. + +## Ça tient la charge ? + +Les exercices sont corrigés en environ 200ms, + +Deux serveurs se répartissent le travail (et ils s'ennuient). + +Les boucles infinies sont interrompues après 20s. + +::: notes + +Il est très facile d'ajouter un serveur de correction au besoin. + +# Côté sécu + +Le code de chaque exercice est exécuté côté serveur, c'est un challenge niveau sécurité. + +::: notes + +Python est réputé pour ne pas être sandboxable, du moins pas depuis l'intérieur de l'interpréteur. + + +## Namespaces Linux + seccomp + rlimit + +Les exercices sont exécutés dans des environements très restreints. + +## seccomp + +`seccomp` (*secure computing*) c'est un outil du kernel Linux pour +limiter les appels systèmes que peuvent faire les programmes. + +## rlimit + +`rlimit` (*resource limit*) c'est un moyen de limiter les resources utilisées par un programme. + +On limite par exemple à 20s de CPU, 2000 threads, 100 fichiers ouverts, 1GB de RAM, …. + +## namespaces + +C'est aussi une fonctionalité du kernel Linux, elle permet de faire +croire à un processus qu'il a une ressource « juste pour lui ». + +## C'est compliqué + +Configurer setccomp, rlimit, les namespaces, la vie et le reste +correctement, c'est pas simple. + +Nous on utilise [firejail](https://github.com/netblue30/firejail). + +## C'est simple + +Un petit appercu de comment on lance firejail : + + +```python +FIREJAIL_OPTIONS = [ + "--net=none", + "--shell=none", + "--x11=none", + "--private-dev", + "--private-tmp", + "--caps.drop=all", + "--nonewprivs", + "--nosound", + "--no3d", + "--noroot", + "--seccomp", + ... +``` + +::: notes + +C'est rassurant écrit comme ça, mais on sait que rien n'est parfait… + +# La rédaction d'exercices + +## Via l'interface d'admin + +## Via un repo git + +# L'hébergement d'instances locales + +# L'API + +# L'AFPy + +La PyConFr + +# Gandi + +# Questions + +- Mastodon : [@mdk@mamot.fr](https://mamot.fr/@mdk) +- XMPP : mdk@chapril.org +- HTTP : https://mdk.fr +- SMTP : julien@python.org +- Whatsapp : HAHAHA jamais. diff --git a/static/background.jpg b/static/background.jpg new file mode 100644 index 0000000..714dbd0 Binary files /dev/null and b/static/background.jpg differ diff --git a/static/pas-green.jpg b/static/pas-green.jpg new file mode 100644 index 0000000..b240ddb Binary files /dev/null and b/static/pas-green.jpg differ diff --git a/static/ruby-rhod.jpg b/static/ruby-rhod.jpg new file mode 100644 index 0000000..a52fc05 Binary files /dev/null and b/static/ruby-rhod.jpg differ