From fcf90f9f8118ee0d69acafb85ad759c3d8b3aa16 Mon Sep 17 00:00:00 2001 From: Adrian Amaglio Date: Mon, 15 Feb 2021 10:37:35 +0100 Subject: [PATCH] url args working --- test-python-ssh/Dockerfile | 21 ++++--- test-python-ssh/docker-compose.yml | 7 +++ test-python-ssh/entrypoint.sh | 26 ++++++--- test-python-ssh/nginx/nginx.conf | 20 ++++--- test-python-ssh/python_app/main.py | 67 +++++++++++++--------- test-python-ssh/python_app/modules/main.py | 3 + test-python-ssh/python_app/modules/mod1.py | 5 -- test-python-ssh/{python_app => }/users.txt | 0 8 files changed, 94 insertions(+), 55 deletions(-) create mode 100644 test-python-ssh/docker-compose.yml create mode 100644 test-python-ssh/python_app/modules/main.py delete mode 100644 test-python-ssh/python_app/modules/mod1.py rename test-python-ssh/{python_app => }/users.txt (100%) diff --git a/test-python-ssh/Dockerfile b/test-python-ssh/Dockerfile index 87438ba..86a961b 100644 --- a/test-python-ssh/Dockerfile +++ b/test-python-ssh/Dockerfile @@ -1,25 +1,30 @@ -FROM python:3-alpine -#TODO as an educational env, we sould use debian or centos. more like debian ? A dockerfile each ? +FROM python:3 +#TODO as an educational env, we sould use debian or centos. more like debian? A dockerfile each? -RUN apk update && apk add gcc linux-headers build-base nginx openssh -RUN pip install uwsgi +RUN apt update && apt install -y gcc nginx openssh-server +RUN pip3 install uwsgi WORKDIR /usr/share/app +RUN addgroup eleve # Python app -COPY python_app/* ./ +COPY python_app/ ./python_app ENV UID=33 ENV MOUNT=/ +ENV TZ=Europe/Paris -RUN MKDIR /tmp/uwsgi -CMD ["uwsgi", "--chown-socket", "$UID", "-s", "/tmp/uwsgi/uwsgi.sock", "--manage-script-name", "--mount", "$MOUNT=main:prod_app", "--http-timeout", "10", "--master", "--hook-master-start", "unix_signal:15gracefully_kill_them_all", "--need-app", "--die-on-term", "--show-config", "--log-master", "--strict", "--vacuum", "--single-interpreter"] +RUN mkdir /tmp/uwsgi +CMD ["uwsgi", "-s", "/tmp/uwsgi/uwsgi.sock", "--chown-socket", "${UID}", "--manage-script-name", "--mount", "${MOUNT}=python_app.main:application", "--http-timeout", "10", "--master", "--hook-master-start", "'unix_signal:15 gracefully_kill_them_all'", "--need-app", "--die-on-term", "--show-config", "--log-master", "--strict", "--vacuum", "--single-interpreter"] +#CMD ["sh", "-c", "echo lol"] # SSH server +RUN mkdir /run/sshd # Nginx server -COPY ./nginx.conf /etc/nginx/nginx.conf +COPY ./nginx/nginx.conf /etc/nginx/nginx.conf +COPY ./nginx/favicon.ico ./ # Entrypoint COPY ./entrypoint.sh ./entrypoint.sh diff --git a/test-python-ssh/docker-compose.yml b/test-python-ssh/docker-compose.yml new file mode 100644 index 0000000..acdd2c3 --- /dev/null +++ b/test-python-ssh/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3' +services: + app: + build: . + volumes: + - ./users.txt:/usr/share/app/users.txt + network_mode: "host" diff --git a/test-python-ssh/entrypoint.sh b/test-python-ssh/entrypoint.sh index 99c7bd8..82afa80 100755 --- a/test-python-ssh/entrypoint.sh +++ b/test-python-ssh/entrypoint.sh @@ -1,29 +1,39 @@ #!/bin/sh + +HOME_BASE="/usr/share/app/python_app/modules" + # Check we got users if [ ! -f 'users.txt' ] ; then echo "Missing file users.txt" - exit -1 + exit 1 fi +# Must be ascii for cut +separator="=" # Generate passwords if not done yet -function genPassowrd () { +genPassowrd () { tr -dc A-Za-z0-9 > passwords.txt + echo "$user$separator$(genPassowrd 10)" >> passwords.txt done fi +# Create users +for line in $(cat passwords.txt) ; do + name="$(echo "$line" | cut -d "$separator" -f 1)" + pass="$(echo "$line" | cut -d "$separator" -f 2)" + echo "$pass\n$pass" | useradd --home-dir "$HOME_BASE/$name" --create-home --no-user-group -G eleve "$name" +done + # Nginx -nginx -c '/etc/nginx/nginx.conf' & +nginx -c '/etc/nginx/nginx.conf' # SSH server -#TODO +/usr/sbin/sshd # Start watever the container should be doing -# TODO start it as www-data -$@ +/bin/sh -c "$*" diff --git a/test-python-ssh/nginx/nginx.conf b/test-python-ssh/nginx/nginx.conf index e81cdc2..989c43f 100644 --- a/test-python-ssh/nginx/nginx.conf +++ b/test-python-ssh/nginx/nginx.conf @@ -16,8 +16,8 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; - types_hash_max_size 2048; - types_hash_bucket_size 128; + types_hash_max_size 2048; + types_hash_bucket_size 128; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; @@ -30,13 +30,17 @@ server { listen 80; listen [::]:80; - root /usr/share/app/modules/ - location / { - index index.html main.py; - try_files $uri $uri/ =404; - } + root /usr/share/app/python_app/modules/; + location ~ favicon.ico { + root /usr/share/app/; + } - location ~ \.py { + location / { +# index index.html main.py; +# try_files $uri $uri/ =404; +# } + + #location ~ \.py { include uwsgi_params; #uwsgi_param PATH_INFO "$1"; #uwsgi_param SCRIPT_NAME /; diff --git a/test-python-ssh/python_app/main.py b/test-python-ssh/python_app/main.py index 6515801..01b200a 100644 --- a/test-python-ssh/python_app/main.py +++ b/test-python-ssh/python_app/main.py @@ -6,22 +6,29 @@ import inspect # The directory where student work will be # not a real path, do not use ./ or stuff like this -BASE_MODULE_PATH = 'modules' +BASE_MODULE_PATH = 'python_app/modules' if BASE_MODULE_PATH != '': BASE_MODULE_PATH += '/' -def application(env, start_response): - # Some hard-coded paths - if env['PATH_INFO'] == '/favicon.ico': - return file_content('favicon.ico') - if env['PATH_INFO'] == '/': - return index() +def application(env, start_response): + """ Cette fonction est appellée à chaque requête HTTP et doit exécuter le bon code python. """ # Find which python module and function will be called - elements = env['PATH_INFO'].split('/')[1:] # Removing the first empty element + # And remove empty elements + elements = tuple(e for e in env['PATH_INFO'].split('/') if e != '') + print(env) + + #m = importlib.import_module('python_app.modules.main') + #f = getattr(m,'index') + #if env['REQUEST_URI'] == '/': + # return htmlresp(200, f(), start_response) + + # Defaults path = '' module = 'main' function = 'index' + + # Get from url path if len(elements) == 1: module = elements[0] elif len(elements) == 2: @@ -31,8 +38,12 @@ def application(env, start_response): path = '/'.join(elements[0:-2]) module = elements[-2] function = elements[-1] + + # slash stuff if path != '': path += '/' + + # Module full path module_path = BASE_MODULE_PATH + path + module module_path = module_path.replace('/', '.') @@ -40,34 +51,38 @@ def application(env, start_response): try: m = importlib.import_module(module_path) except ModuleNotFoundError: - print('Le fichier {} n’a pas été trouvé.'.format(module_path)) - return htmlresp(404, 'Le fichier {} n’a pas été trouvé'.format(path + module), start_response) + print('Le fichier {} n’a pas été trouvé. {}'.format(module_path, str(elements))) + return htmlresp(404, 'Le fichier {} n’a pas été trouvé.'.format(path + module), start_response) # Find which parameters the function needs - params = {} try: f = getattr(m,function) - # TODO get http parameters and give them to the function - #print(inspect.signature(f)) + # Call the function with the rigth attributes except AttributeError: - return htmlresp(404, 'La fonction {} n’a pas été trouvée'.format(function), start_response) + return htmlresp(404, 'La fonction {} n’a pas été trouvée.'.format(function), start_response) - # Call the function with the rigth attributes - return [bytes(str(f(*params)), 'utf8')] + # Pass url parameters to the function + try: + params = {p:'' for p in list(inspect.getargspec(f).args)} + for item in env['QUERY_STRING'].split('&'): + k,v = tuple(item.split('=')) + if k in params: + params[k] = v + except Exception: + return htmlresp(400, 'La fonction {} demande les arguments suivants : {}. On a uniquement {}.'.format(function, params, ), start_response) + + try: + return htmlresp(200, str(f(**params)), start_response, False) + except Exception: + return htmlresp(400, 'Erreur à l’exécution de la fonction {}.'.format(function), start_response) -def index (): - return file_content('passwords.txt') - -def htmlresp(code, message, start_response): +def htmlresp(code, message, start_response, squelette=True): + """ Cette fonction crée le squelette HTML minimal """ html = '{}' - return resp(code, [('Content-Type','text/html')], html.format(message), start_response) + return resp(code, [('Content-Type','text/html')], html.format(message) if squelette else message, start_response) def resp(code, headers, message, start_response): + """ Cette fonction permet de faire une réponse HTTP """ start_response(str(code), headers) return bytes(message, 'utf8') - -def file_content (filename): - with open(filename, mode='rb') as file: - return file.read() - diff --git a/test-python-ssh/python_app/modules/main.py b/test-python-ssh/python_app/modules/main.py new file mode 100644 index 0000000..40692bc --- /dev/null +++ b/test-python-ssh/python_app/modules/main.py @@ -0,0 +1,3 @@ +def index(lol, mdr=True): + """ Main entrypoint """ + return 'Bienvenue ! lol:{} mdr:{} '.format(lol,mdr) diff --git a/test-python-ssh/python_app/modules/mod1.py b/test-python-ssh/python_app/modules/mod1.py deleted file mode 100644 index d4e83bc..0000000 --- a/test-python-ssh/python_app/modules/mod1.py +++ /dev/null @@ -1,5 +0,0 @@ -def func1_1(): - return "Bonjour de func1_1" - -def func1_2(): - return "Bonjour de func1_2" diff --git a/test-python-ssh/python_app/users.txt b/test-python-ssh/users.txt similarity index 100% rename from test-python-ssh/python_app/users.txt rename to test-python-ssh/users.txt