diff options
| -rw-r--r-- | docs/README.md | 175 | ||||
| -rw-r--r-- | docs/images/think2t.png.svg | 145 | ||||
| -rw-r--r-- | mkdocs.yml | 34 | ||||
| -rw-r--r-- | overrides/partials/copyright.html | 17 | ||||
| -rw-r--r-- | whiskey/README.md | 16 | ||||
| -rw-r--r-- | whiskey/drink.py | 52 | ||||
| -rw-r--r-- | whiskey/files/bartender-nginx.conf | 29 | ||||
| -rw-r--r-- | whiskey/files/whiskey.service | 23 | ||||
| -rw-r--r-- | whiskey/logs/.gitignore | 3 | ||||
| -rw-r--r-- | whiskey/wsgi.py | 4 |
10 files changed, 498 insertions, 0 deletions
diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..293f652 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,175 @@ +# Bartender: a wsgi server + +This impliments a wsgi server that is called by a github webhook. When called it validates the request, schedules an at job, and returns a status. The at job pulls the "docs" off of github, builds the site, and moves it into place. + +## The Stack + +```mermaid +graph LR + B -- http(s)://127.0.0.1:8000 <--> C[nginx] -- http(s)://bartender/whisky/STYLE <--> I([Internet]) + A[flask] -- wsgi <--> B[gunicorn]; +``` + +The implimentation + +```mermaid +graph LR + A[bartender app] --> C[AT] + A -- 200 ok / 400 bad id / 404 --> N[NGinX] + N <-- bartender.digithink.com --> I([Internet]) + G[(github)] -- pull --> D + C --> D[pullandbuild.sh] + D -- mkdocks build --> O[(site)] -->N + N -- whiskey/STYLE --> A +``` + +## The source code and the results + +- [https://github.com/feurig/digithink/tree/main/whiskey](https://github.com/feurig/digithink/tree/main/whiskey) + The source code for the bartender service is in the same repository as the content it serves +- [https://www.digithink.com](https://www.digithink.com) is the target website. +- [https://bartender.digithink.com/](https://bartender.digithink.com/) contains this and the other documents for the service. + +### Installing the service + +```sh +apt install nginx +apt install certbot python3-certbot-nginx +apt install python3-flask +apt install python3-gunicorn +apt install at + +echo www-data |tee /etc/at.allow +nano /etc/systemd/system/whiskey.service +[Unit] +Description=Gunicorn instance to serve whiskey +After=network.target + +[Service] +User=www-data +Group=www-data +WorkingDirectory=/var/www/digithink/whiskey +#Environment="PATH=/home/sammy/myproject/myprojectenv/bin" +# --bind unix:/run/whiskey.sock \ + +ExecStart=/usr/bin/gunicorn \ + --workers 3 \ + --bind 127.0.0.1:5000 \ + --reload \ + --access-logfile /var/www/digithink/whiskey/logs/gunicorn_access.log \ + --error-logfile /var/www/digithink/whiskey/logs/gunicorn_error.log \ + -m 007 wsgi:app +ExecReload=/bin/kill -s HUP $MAINPID +ExecStop=/bin/kill -s TERM $MAINPID + +[Install] +WantedBy=multi-user.target +^X +systemctl enable whiskey +systemctl start whiskey +``` + +### nginx.conf + +```sh +# lots of hard coded foo here +server { + server_name bartender.digithink.com; + + listen 198.202.31.232:443 ssl; + server_name bartender.digithink.com; + ssl_certificate /etc/letsencrypt/live/bartender.digithink.com/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/bartender.digithink.com/privkey.pem; # managed by Certbot + + root /var/www/digithink/whiskey/bartender; + index index.html; + location /whiskey { + include proxy_params; + proxy_pass http://bartender/whiskey; + } + # point the error page to the one created by mkdocs + error_page 404 /404.html; + location /404.html { + internal; + } +} + +# redirect http to https +server { + root /var/www/digithink/whiskey/bartender; + index index.html; + if ($host = bartender.digithink.com) { + return 301 https://$host$request_uri; + } # managed by Certbot + + listen 198.202.31.232:80; + server_name bartender.digithink.com; + return 404; # managed by Certbot +} +``` + +### the WSGI app + +The actual app will grow into something with better feedback more general use (ie to make different static web sites) + +#### drink.py + +Minimum Viable Product + +```python +from flask import Flask +from markupsafe import escape +import subprocess + +app = Flask(__name__) + +@app.route("/whiskey/<style>",methods = ['POST']) +def whiskey(style): + # break this out by style. + subprocess.call(['at', 'now', '-f', '/var/www/digithink/whiskey/pullandbuild.sh']) + return f"One Whiskey, {escape(style)}!" +``` + +The actual [drink.py](https://github.com/suspect-devices/digithink/blob/main/whiskey/drink.py) is slightly more developed. + +#### wsgi.py, Turning the above into a WSGI app + +```python +from drink import app + +if __name__ == "__main__": + app.run() +``` + +## Converting the git content to a static html site. + +### mkdocs plus the extensions + +Ubuntu (... ok, debian really...) fracked up the packaging for mkdocs and mkdocs-material. I wound up removing the packages and pip3 installing most of it with --break-system-packages. + +```sh +apt remove mkdocs* +apt remove markdown +apt remove python3-markdown +apt install python3-regex +apt install libvips-dev +apt install python3-pip +pip3 install mkdocs-material --break-system-packages +``` + +#### pull dependencies based on the current mkdocs install and mkdocs.yml + +```sh +cd /var/www/digithink/&& git pull +mkdocs-get-deps > requirements.txt +pip3 install $(mkdocs-get-deps) --break-system-packages +mkdocs build && chown -R www-data:www-data site/ +``` + +## linkdump + +- <https://github.com/codingforentrepreneurs/Pi-Awesome/blob/main/how-tos/Create%20a%20Minimal%20Web%20Application%20with%20Nginx%2C%20Python%2C%20Flask%20%26%20Raspberry%20Pi.md> +- <https://www.stackovercloud.com/2020/05/27/how-to-serve-flask-applications-with-uwsgi-and-nginx-on-ubuntu-20-04/> +- <https://www.digitalocean.com/community/tutorials/how-to-set-up-uwsgi-and-nginx-to-serve-python-apps-on-ubuntu-14-04> +- <https://stackoverflow.com/questions/10748108/nginx-uwsgi-unavailable-modifier-requested-0#11055729> +- https://github.com/mkdocs/get-deps diff --git a/docs/images/think2t.png.svg b/docs/images/think2t.png.svg new file mode 100644 index 0000000..50f8b1e --- /dev/null +++ b/docs/images/think2t.png.svg @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + inkscape:version="1.0 (4035a4f, 2020-05-01)" + sodipodi:docname="think2t.png.svg" + viewBox="0 0 62 87" + height="87" + width="62" + id="svg10" + version="1.1"> + <metadata + id="metadata16"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs14" /> + <sodipodi:namedview + inkscape:current-layer="g18" + inkscape:window-maximized="0" + inkscape:window-y="23" + inkscape:window-x="0" + inkscape:cy="43.5" + inkscape:cx="31" + inkscape:zoom="8.4252874" + showgrid="false" + id="namedview12" + inkscape:window-height="940" + inkscape:window-width="1046" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <g + id="g18" + inkscape:label="Image" + inkscape:groupmode="layer"> + <image + id="image20" + xlink:href="data:image/png;base64,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 +l3PJ9Bl8tPkj2lpPM3K0Py4XRo4upLjIdq8KSZIYObqQrw5o28TzvjOb2374QxInqDcvnM77H1Sw +85PdtLc2U1jsvC+nqiob1r/Jv/3iMS69eBo1v1vNyNFlrrq7rs721x9zS9JRUHCOqe9IoG8JZYkj +aNNLBfMxsEldrPP8+VdVxPNraR6fj5KSElpb2wm3tjjI0PDqyy9y5133APDC6ueTkoYkxHds+1jf +A4tEIjQ3O20Lp4IEuT7y6unEwbWiP4MGRSxltPNx436aG9ramrnzrns477xhKMpp01zDDSmtx5/7 +9ZP88wM/SyGn9WYiBsWdVnCq/vQZI14mzQXfHbf/gPff3cr3Fi3kmV/+ho0b1yfNnxLxjo7j7Pxk +tz6jSxX61q/JAIb0uEcd0xJ75bEk/4kUR1GRzCOPPkVhsczjTzxLgd/Pj+/4+6St1JX4seOn6DwR +ob21mZrf/YEr51xBMCjR3HyAcGsLnZ0n6Og4TiQSQVVVVFXllBLjeEcEFYVDB5t0xaO0Q+wk++uP +oSin+WzfYVNdSqeXLxt7gPjS1kC4uUXhkx07MR4ogNb9Dh/aS2PDl1q51mZ9wlX52MMcbmvh5htv +1t/b4DRE1FRX6UNCYlyvrV2nbygax/pZM6eJ2tp1oqa6yrQ6k2VZzJo5TXy64yWxauVyU1piI7Fy +xTI9LTGOJ8rVVFeJVSuX62N5IJAnysvLxIKKeaK2dp1YUDFP1yOha+WKZaa5SOK90zzAccqaWCmt +ffOPAFQuepjLLpuNJEksf/BBACZNHEf9gSZOn+pkbGgUw4eP4Dbg1m5z5C0eWsjcKy/W5N46z5Q2 +efJfUTy0kFzfMLos5S6//HzgfAByfcMYnD9ET7voohkAnD5lvqo5aeI4Td/HHrZxOrd4mOl7Rn8V +JKpuwUNr/Jt9jpk4jvJwCKIfEvXcoqeZ77EmEI/u2d9I+d+jU0UGfwdGRVEK8FvOFBTFaUOyAL9/ +tCWt77N/UG+8j2uG6onl26+UnyEyRjwSUalvcJpguE86kqf1oSh4itDYAanlioz+8o/fX9h/pgEg +Jzft7f9+kTHikqSdZJ4NZGpL2SQzk8LaIkfpOt3/FDNdnBdKdpoyMGSMuKpCUXAonf5YpkTq0Dxu +3oU5Y5mZEiRJEvnnDAXDIV+mEAwWkEnSkOHhrPHgZ2elqefkZjNydGZ/iiFjxDtPqPj9hbZxPBPo +6Yo5HCedGTI2c9MWAgM7POwfUkZJQ4abuvXExIqG/fv56oD5RtTg/CFMmjgOf2CwSynttESSnLec +BooMBregfmLinqeA3Dzzzami4FDOHTU24x7tDxn+6cL/O/hvv63GaHIytUAAAAAASUVORK5CYII= +" + preserveAspectRatio="none" + height="87" + width="62" /> + </g> +</svg> diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..bebd094 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,34 @@ +site_name: Bartender, Whiskey is served here. + +theme: + name: material + palette: + primary: white + accent: red + font: +# text: Courier Prime + text: JetBrains Mono +# text: Share Tech Mono + logo: images/think2t.png.svg + favicon: images/favicon.png + features: + - navigation.expand + custom_dir: overrides + +extra: + homepage: https://www.digithink.com + generator: true +copyright: Copyright © 2016 - 2025 D. Delmar Davis + +plugins: + - search + - with-pdf + - mermaid2 + +markdown_extensions: + - pymdownx.superfences: + # make exceptions to highlighting of code: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:mermaid2.fence_mermaid_custom diff --git a/overrides/partials/copyright.html b/overrides/partials/copyright.html new file mode 100644 index 0000000..3694ae2 --- /dev/null +++ b/overrides/partials/copyright.html @@ -0,0 +1,17 @@ +{#- + Credit the bartender. +-#} + <div class="md-copyright"> + {% if config.copyright %} + <!-- div class="md-copyright__highlight" --> + {{ config.copyright }} + <!-- /div --> + {% endif %} + Made by + <a href=https://bartender.digithink.com/> + bartender.digithink.com + </a> with + <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener"> + Material for MkDocs. + </a> + </div>
\ No newline at end of file diff --git a/whiskey/README.md b/whiskey/README.md new file mode 100644 index 0000000..73d3def --- /dev/null +++ b/whiskey/README.md @@ -0,0 +1,16 @@ +# Bartender: a wsgi server. + +I wanted to do a simple git hook for a static website or two where the content was pulled down and converted from markdown with a little mermaid to static html. I have been doing this manually for a while but it gets to be a pain and besides all the kids are doing ci-cd and I thought it might help me actually write more. + +Once apon a time when apache was really the best way to serve http writing interactive sites in python was a matter of enableing mod_wsgi and throwing up 20 lines of python. + +Gone are those days. + +Three days of swimming through uwsgi, unit and 3 other overtly complicated half thought out python solutions all of which require a separate standalone service I settled on a flask and gunicorn. It's still a kludgy pile. Time to go queue TurboNegros "I hate the kids" and just make it work. + +This part of the digithink repo contains the wsgi app that is called whenever changes are pushed to digithink.com as well as the documentation and files needed to deploy it. The details and source code are found under [bartender/docs](bartender/docs/README.md). + +At some point I may make the bartender and the digithink.com separate repos. At that point I will probably serve more than whiskey/neat and start developing some of my other web sites. + + +```
\ No newline at end of file diff --git a/whiskey/drink.py b/whiskey/drink.py new file mode 100644 index 0000000..4a0ae0d --- /dev/null +++ b/whiskey/drink.py @@ -0,0 +1,52 @@ +# Bare Bones POC +# Signature code stolen directly from Lukas Pühringer +# https://gist.github.com/lukpueh/498ff3489321bdc7106c05a2fd5b941c +# NOTE: Rquires payload to be set to json +# https://blog.gitguardian.com/how-to-handle-secrets-in-python/ +from flask import Flask , request, abort +from markupsafe import escape +from dotenv import load_dotenv +import hmac +import hashlib +import os +import subprocess + +app = Flask(__name__) + +load_dotenv() + +GITHUB_SECRET = os.getenv("GITHUB_SECRET") + +@app.route("/whiskey/<style>",methods = ['POST', 'GET']) +def whiskey(style): + + # Extract signature header + signature = request.headers.get("X-Hub-Signature") + if not signature or not signature.startswith("sha1="): + abort(400, "X-Hub-Signature required") + + # Create local hash of payload + digest = hmac.new(GITHUB_SECRET.encode(), + request.data, hashlib.sha1).hexdigest() + + # Verify signature + if not hmac.compare_digest(signature, "sha1=" + digest): + #abort(400, signature+"<>sha1="+digest) + abort(400, "I am going to need to see some id.") + + # After we have detemined that this is legit. + match style: + case "neat": + subprocess.call(['at', 'now', '-f', '/var/www/digithink/repo/makesite.sh']) + case "sour": + subprocess.call(['at', 'now', '-f', '/var/www/3dangst/repo/makesite.sh']) + case _: abort(404,"We Don't Serve That Here!") + + return f"One Whiskey, {escape(style)}!" + +@app.route("/") +def root(): + return f"Not much here...." + +if __name__ == "__main__": + app.run(host='0.0.0.0') diff --git a/whiskey/files/bartender-nginx.conf b/whiskey/files/bartender-nginx.conf new file mode 100644 index 0000000..b0eebaa --- /dev/null +++ b/whiskey/files/bartender-nginx.conf @@ -0,0 +1,29 @@ +# lots of hard coded foo here +server { + server_name bartender.digithink.com; + + listen 198.202.31.232:443 ssl; + server_name bartender.digithink.com; + ssl_certificate /etc/letsencrypt/live/bartender.digithink.com/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/bartender.digithink.com/privkey.pem; # managed by Certbot + + root /var/www/digithink/whiskey/bartender; + index index.html; + location /whiskey { + include proxy_params; + proxy_pass http://bartender/whiskey; + } +} + +server { + root /var/www/digithink/whiskey/bartender; + index index.html; + if ($host = bartender.digithink.com) { + return 301 https://$host$request_uri; + } # managed by Certbot + + listen 198.202.31.232:80; + server_name bartender.digithink.com; + return 404; # managed by Certbot +} + diff --git a/whiskey/files/whiskey.service b/whiskey/files/whiskey.service new file mode 100644 index 0000000..d7e968e --- /dev/null +++ b/whiskey/files/whiskey.service @@ -0,0 +1,23 @@ +[Unit] +Description=Gunicorn instance to serve whiskey +After=network.target + +[Service] +User=www-data +Group=www-data +WorkingDirectory=/var/www/digithink/whiskey +#Environment="PATH=/home/sammy/myproject/myprojectenv/bin" +# --bind unix:/run/whiskey.sock \ + +ExecStart=/usr/bin/gunicorn \ + --workers 3 \ + --bind 127.0.0.1:5000 \ + --reload \ + --access-logfile /var/www/digithink/whiskey/logs/gunicorn_access.log \ + --error-logfile /var/www/digithink/whiskey/logs/gunicorn_error.log \ + -m 007 wsgi:app +ExecReload=/bin/kill -s HUP $MAINPID +ExecStop=/bin/kill -s TERM $MAINPID + +[Install] +WantedBy=multi-user.target diff --git a/whiskey/logs/.gitignore b/whiskey/logs/.gitignore new file mode 100644 index 0000000..e7a210e --- /dev/null +++ b/whiskey/logs/.gitignore @@ -0,0 +1,3 @@ +* +*/ +!.gitignore
\ No newline at end of file diff --git a/whiskey/wsgi.py b/whiskey/wsgi.py new file mode 100644 index 0000000..f9c8563 --- /dev/null +++ b/whiskey/wsgi.py @@ -0,0 +1,4 @@ +from drink import app + +if __name__ == "__main__": + app.run()
\ No newline at end of file |
