Initial revision.
This commit is contained in:
commit
3c20ed2657
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
output/
|
35
Makefile
Normal file
35
Makefile
Normal file
@ -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
|
280
slides.md
Normal file
280
slides.md
Normal file
@ -0,0 +1,280 @@
|
||||
# HackInScience
|
||||
|
||||
<!-- .slide: data-background="static/background.jpg" -->
|
||||
|
||||
<br/>
|
||||
|
||||
<b>Julien Palard</b>
|
||||
|
||||
<tt>CPython core dev</tt>
|
||||
|
||||
|
||||
# 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.
|
BIN
static/background.jpg
Normal file
BIN
static/background.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
BIN
static/pas-green.jpg
Normal file
BIN
static/pas-green.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
BIN
static/ruby-rhod.jpg
Normal file
BIN
static/ruby-rhod.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
Reference in New Issue
Block a user