From 49fda3601248d939b0cfff1bff5a18800e498bdc Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Wed, 11 Oct 2017 19:39:04 -0400 Subject: The HTML is kind of jank --- .gitignore | 2 ++ LICENSE.md | 21 ++++++++++++++++ Procfile | 1 + app.py | 37 +++++++++++++++++++++++++++++ bin/web | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 18 ++++++++++++++ runtime.txt | 1 + templates/index.html | 37 +++++++++++++++++++++++++++++ tests.py | 10 ++++++++ things-to-check.yml | 35 +++++++++++++++++++++++++++ 10 files changed, 229 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 Procfile create mode 100644 app.py create mode 100755 bin/web create mode 100644 requirements.txt create mode 100644 runtime.txt create mode 100644 templates/index.html create mode 100644 tests.py create mode 100644 things-to-check.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4df23a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.venv/ +*.pyc diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7ac9dc8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +Copyright (c) 2017 the authors. Please see the Git history, or contact +agora-discussion@agoranomic.org for information about the authorship of this +project. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..bb58ffb --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: bin/web diff --git a/app.py b/app.py new file mode 100644 index 0000000..05a41bd --- /dev/null +++ b/app.py @@ -0,0 +1,37 @@ +from apistar import Include, Route, annotate, render_template +from apistar.frameworks.wsgi import WSGIApp as App +from apistar.handlers import docs_urls, static_urls +from apistar.renderers import HTMLRenderer +import random +import yaml + +with open('things-to-check.yml', 'r') as things_file: + things = yaml.safe_load(things_file) + +@annotate(renderers=[HTMLRenderer()]) +def random_thing(item: int = None): + if item is None: + item = random.randrange(len(things)) + return render_template('index.html', + item=item, + thing=things[item], + ) + + +routes = [ + Route('/', 'GET', random_thing), + Include('/docs', docs_urls), + Include('/static', static_urls), +] + +settings = { + 'TEMPLATES': { + 'ROOT_DIR': 'templates', # Include the 'templates/' directory. + 'PACKAGE_DIRS': ['apistar'] # Include the built-in apistar templates. + } +} + +app = App( + routes=routes, + settings=settings, +) diff --git a/bin/web b/bin/web new file mode 100755 index 0000000..3d96f71 --- /dev/null +++ b/bin/web @@ -0,0 +1,67 @@ +#!/bin/bash -e + +# See "Running in Production" in the API Star documentation at +# + +# In development, gunicorn can automatically reload code as you edit it. To +# enable this feature, export `GUNICORN_CMD_ARGS='--reload'` before running +# this script. +# +# See: +# * +# * + +# If the `PORT` environment variable is set, we're probably running on a +# platform like Heroku that expects the application to bind to it. Otherwise, +# default to port 5000. gunicorn will print the value on startup either way, +# allowing administrators and developers to determine the server's base URL. +# +# See: +# * +# * + +PORT=${PORT:-5000} + +# Run the application with gunicorn. Note that the API Star documentation +# recommends setting `--workers`. We omit this option: on our target platform, +# this is controlled automatically using the `WEB_CONCURRENCY` environment +# variable, which has a computed default based on the resources available at +# runtime. Falling back to gunicorn's default configuration is safe enough, as +# an administrator who discovers this is the wrong configuration can easily set +# `WEB_CONCURRENCY` to override it. +# +# See: +# * +# * +# +# The API Star documentation also recommends the Meinheld worker type. However, +# deploying Meinheld to Heroku causes the application to fail on startup: +# +# Error: class uri 'meinheld.gmeinheld.MeinheldWorker' invalid or not found: +# [Traceback (most recent call last): +# File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 134, in load_class +# File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module +# mod = import_module('.'.join(components)) +# return _bootstrap._gcd_import(name[level:], package, level) +# File "", line 978, in _gcd_import +# File "", line 936, in _find_and_load_unlocked +# File "", line 961, in _find_and_load +# File "", line 205, in _call_with_frames_removed +# File "", line 950, in _find_and_load_unlocked +# File "", line 655, in _load_unlocked +# File "", line 205, in _call_with_frames_removed +# File "", line 678, in exec_module +# File "/app/.heroku/python/lib/python3.6/site-packages/meinheld/__init__.py", line 1, in +# from meinheld.server import * +# File "", line 978, in _gcd_import +# File "", line 961, in _find_and_load +# ImportError: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory +# ] +# +# The `libpython3.6m.so` library does not appear to be present. As we don't need +# to squeeze every ounce of performance out of this application, I've removed +# the Meinheld worker and opened a support ticket to get an explanation from +# Heroku. + +exec gunicorn app:app \ + --bind="0.0.0.0:${PORT}" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ce5bb01 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,18 @@ +apistar==0.3.9 +certifi==2017.7.27.1 +chardet==3.0.4 +coreapi==2.3.3 +coreschema==0.0.4 +gunicorn==19.7.1 +idna==2.6 +itypes==1.1.0 +Jinja2==2.9.6 +MarkupSafe==1.0 +py==1.4.34 +pytest==3.2.3 +PyYAML==3.12 +requests==2.18.4 +uritemplate==3.0.0 +urllib3==1.22 +Werkzeug==0.12.2 +whitenoise==3.3.1 diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 0000000..cfa5aa5 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-3.6.2 diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..a827efe --- /dev/null +++ b/templates/index.html @@ -0,0 +1,37 @@ + + + + Have you checked {{ thing }}? + + + +
+

Have you checked {{ thing }}?

+

That wasn't it, suggest something else.

+

Share this troubleshooting suggestion.

+
+ + diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..9d52baa --- /dev/null +++ b/tests.py @@ -0,0 +1,10 @@ +from apistar.test import TestClient +from app import app, welcome + + +def test_welcome(): + """ + Testing a view directly. + """ + data = welcome() + assert data == {'message': 'Welcome to API Star!'} diff --git a/things-to-check.yml b/things-to-check.yml new file mode 100644 index 0000000..29ecb37 --- /dev/null +++ b/things-to-check.yml @@ -0,0 +1,35 @@ +--- +# Insert new items at the bottom. The index into this list is the item's +# permalink. +# +# Yes, this is HTML and no, I don't care about injection. +- permissions +- cabling +- for a full disk +- the cache +- for a version conflict +- for a duplex mismatch +- the firewall rules +- resolv.conf +- /etc/hosts +- DNS +- CR/LF +- setuid/setgid bits +- the default gateway +- for IP conflicts +- the logs +- the port number +- for a zonefile dot +- I/O dammit +- the mounts +- the power +- for the wrong whitespace +- if it reloaded into bad config +- IP forwarding +- the trailing slash +- the MAC address +- if the filesystem is out of inodes +- the line length +- if you're on the wrong wifi network +- if the vpn timed out +- if that's the wrong host -- cgit v1.2.3