diff --git a/babybuddy/settings/nanobox.py b/babybuddy/settings/nanobox.py new file mode 100644 index 00000000..dabd2eee --- /dev/null +++ b/babybuddy/settings/nanobox.py @@ -0,0 +1,26 @@ +import os + +from .base import * # noqa: F401,F403 + + +DEBUG = os.environ.get('DEBUG', False) + + +# SECURITY WARNING: keep the secret key used in production secret! + +SECRET_KEY = os.environ['SECRET_KEY'] + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'gonano', + 'USER': os.environ.get('DATA_DB_USER'), + 'PASSWORD': os.environ.get('DATA_DB_PASS'), + 'HOST': os.environ.get('DATA_DB_HOST'), + 'PORT': '', + } +} diff --git a/boxfile.yml b/boxfile.yml new file mode 100644 index 00000000..67eb52b5 --- /dev/null +++ b/boxfile.yml @@ -0,0 +1,32 @@ +run.config: + engine: python + + cache_dirs: + - node_modules + + extra_packages: + - nodejs + - nginx + + extra_path_dirs: + - node_modules/.bin + + extra_steps: + - npm install + +deploy.config: + extra_steps: + - gulp build + - python manage.py collectstatic --no-input --clear + + before_live: + web.main: + - python manage.py migrate --fake-initial + +web.main: + start: + nginx: nginx -c /app/etc/nginx.conf + django: gunicorn -c /app/etc/gunicorn.py babybuddy.wsgi + +data.db: + image: nanobox/postgresql:9.5 \ No newline at end of file diff --git a/etc/gunicorn.py b/etc/gunicorn.py new file mode 100644 index 00000000..dea734c5 --- /dev/null +++ b/etc/gunicorn.py @@ -0,0 +1,129 @@ +# Server mechanics +bind = '0.0.0.0:8000' +backlog = 2048 +daemon = False +pidfile = None +umask = 0 +user = None +group = None +tmp_upload_dir = None +proc_name = None + +# Logging +errorlog = '-' +loglevel = 'info' +accesslog = '-' +access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' + +# +# Worker processes +# +# workers - The number of worker processes that this server +# should keep alive for handling requests. +# +# A positive integer generally in the 2-4 x $(NUM_CORES) +# range. You'll want to vary this a bit to find the best +# for your particular application's work load. +# +# worker_class - The type of workers to use. The default +# sync class should handle most 'normal' types of work +# loads. You'll want to read +# http://docs.gunicorn.org/en/latest/design.html#choosing-a-worker-type +# for information on when you might want to choose one +# of the other worker classes. +# +# An string referring to a 'gunicorn.workers' entry point +# or a python path to a subclass of +# gunicorn.workers.base.Worker. The default provided values +# are: +# +# egg:gunicorn#sync +# egg:gunicorn#eventlet - Requires eventlet >= 0.9.7 +# egg:gunicorn#gevent - Requires gevent >= 0.12.2 (?) +# egg:gunicorn#tornado - Requires tornado >= 0.2 +# +# worker_connections - For the eventlet and gevent worker classes +# this limits the maximum number of simultaneous clients that +# a single process can handle. +# +# A positive integer generally set to around 1000. +# +# timeout - If a worker does not notify the master process in this +# number of seconds it is killed and a new worker is spawned +# to replace it. +# +# Generally set to thirty seconds. Only set this noticeably +# higher if you're sure of the repercussions for sync workers. +# For the non sync workers it just means that the worker +# process is still communicating and is not tied to the length +# of time required to handle a single request. +# +# keepalive - The number of seconds to wait for the next request +# on a Keep-Alive HTTP connection. +# +# A positive integer. Generally set in the 1-5 seconds range. +# + +workers = 1 +worker_class = 'sync' +worker_connections = 1000 +timeout = 30 +keepalive = 2 + +spew = False + +# +# Server hooks +# +# post_fork - Called just after a worker has been forked. +# +# A callable that takes a server and worker instance +# as arguments. +# +# pre_fork - Called just prior to forking the worker subprocess. +# +# A callable that accepts the same arguments as after_fork +# +# pre_exec - Called just prior to forking off a secondary +# master process during things like config reloading. +# +# A callable that takes a server instance as the sole argument. +# + + +def post_fork(server, worker): + server.log.info("Worker spawned (pid: %s)", worker.pid) + + +def pre_fork(server, worker): + pass + + +def pre_exec(server): + server.log.info("Forked child, re-executing.") + + +def when_ready(server): + server.log.info("Server is ready. Spawning workers") + + +def worker_int(worker): + worker.log.info("worker received INT or QUIT signal") + + # get traceback info + import threading, sys, traceback + id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) + code = [] + for threadId, stack in sys._current_frames().items(): + code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), + threadId)) + for filename, lineno, name, line in traceback.extract_stack(stack): + code.append('File: "%s", line %d, in %s' % (filename, + lineno, name)) + if line: + code.append(" %s" % (line.strip())) + worker.log.debug("\n".join(code)) + + +def worker_abort(worker): + worker.log.info("worker received SIGABRT signal") diff --git a/etc/nginx.conf b/etc/nginx.conf new file mode 100644 index 00000000..fa9704aa --- /dev/null +++ b/etc/nginx.conf @@ -0,0 +1,52 @@ +worker_processes 1; +daemon off; + +events { + worker_connections 1024; +} + +http { + include /data/etc/nginx/mime.types; + sendfile on; + + gzip on; + gzip_http_version 1.0; + gzip_proxied any; + gzip_min_length 500; + gzip_disable "MSIE [1-6]\."; + gzip_types text/plain text/xml text/css + text/comma-separated-values + text/javascript + application/x-javascript + application/atom+xml; + + # Proxy upstream to the gunicorn process + upstream django { + server 127.0.0.1:8000; + } + + # Configuration for Nginx + server { + + # Listen on port 8080 + listen 8080; + + # Settings to serve static files + location ^~ /static/ { + root /app/; + } + + # Serve a static file (ex. favico) + # outside /static directory + location = /favico.ico { + root /app/favico.ico; + } + + # Proxy connections to django + location / { + proxy_pass http://django; + proxy_redirect off; + proxy_set_header Host $host; + } + } +} diff --git a/package-lock.json b/package-lock.json index aca832db..4bd2f819 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,16 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@plotly/d3-sankey": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@plotly/d3-sankey/-/d3-sankey-0.5.0.tgz", + "integrity": "sha1-si+up0LlglEzXuXZ+6JIdyYHgA8=", + "requires": { + "d3-array": "1.2.1", + "d3-collection": "1.0.4", + "d3-interpolate": "1.1.5" + } + }, "3d-view": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/3d-view/-/3d-view-2.0.0.tgz", @@ -26,21 +36,6 @@ "right-now": "1.0.0" } }, - "@plotly/d3-sankey": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@plotly/d3-sankey/-/d3-sankey-0.5.0.tgz", - "integrity": "sha1-si+up0LlglEzXuXZ+6JIdyYHgA8=", - "requires": { - "d3-array": "1.2.1", - "d3-collection": "1.0.4", - "d3-interpolate": "1.1.5" - } - }, - "JSV": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", - "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" - }, "a-big-triangle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/a-big-triangle/-/a-big-triangle-1.0.3.tgz", @@ -4846,6 +4841,11 @@ } } }, + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, "kdbush": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-1.0.1.tgz", @@ -6228,8 +6228,8 @@ "resolved": "https://registry.npmjs.org/plotly.js/-/plotly.js-1.31.1.tgz", "integrity": "sha1-z+ie2xunjG8Nwt/k6njs+Pb2/50=", "requires": { - "3d-view": "2.0.0", "@plotly/d3-sankey": "0.5.0", + "3d-view": "2.0.0", "alpha-shape": "1.0.0", "color-rgba": "1.1.1", "convex-hull": "1.0.3", @@ -7366,6 +7366,11 @@ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -7386,11 +7391,6 @@ "function-bind": "1.1.1" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..e32ee5ce Binary files /dev/null and b/requirements.txt differ