diff options
author | Mike Crute <mike@crute.us> | 2021-01-27 04:41:00 +0000 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2021-01-27 04:41:00 +0000 |
commit | 763b810ca1a9d755205e49b1246025b83abb5132 (patch) | |
tree | 923df4e956b36ef95e86ff9c51c5bbad26fd076f | |
parent | cd833bc2852ec204fbaecde7ada56798eba005da (diff) | |
download | dockerfiles-763b810ca1a9d755205e49b1246025b83abb5132.tar.bz2 dockerfiles-763b810ca1a9d755205e49b1246025b83abb5132.tar.xz dockerfiles-763b810ca1a9d755205e49b1246025b83abb5132.zip |
Add netbox
-rw-r--r-- | netbox/Dockerfile | 73 | ||||
-rw-r--r-- | netbox/Makefile | 24 | ||||
-rw-r--r-- | netbox/config-patch1.diff | 26 | ||||
-rw-r--r-- | netbox/config-patch2.diff | 89 | ||||
-rw-r--r-- | netbox/django-driver.py | 69 | ||||
-rw-r--r-- | netbox/django-vault-client.py | 84 | ||||
-rwxr-xr-x | netbox/entrypoint.sh | 22 | ||||
-rwxr-xr-x | netbox/etc/service/netbox-rq/log/run | 3 | ||||
-rwxr-xr-x | netbox/etc/service/netbox-rq/run | 23 | ||||
-rwxr-xr-x | netbox/etc/service/uwsgi/log/run | 3 | ||||
-rwxr-xr-x | netbox/etc/service/uwsgi/run | 23 | ||||
-rw-r--r-- | netbox/etc/uwsgi/netbox.ini | 15 | ||||
-rw-r--r-- | netbox/settings-patch.diff | 11 |
13 files changed, 465 insertions, 0 deletions
diff --git a/netbox/Dockerfile b/netbox/Dockerfile new file mode 100644 index 0000000..022aebf --- /dev/null +++ b/netbox/Dockerfile | |||
@@ -0,0 +1,73 @@ | |||
1 | FROM alpine:latest | ||
2 | LABEL maintainer="Mike Crute <mike@crute.us>" | ||
3 | |||
4 | ARG netbox_version | ||
5 | |||
6 | ADD config-patch1.diff /config-patch1.diff | ||
7 | ADD config-patch2.diff /config-patch2.diff | ||
8 | ADD settings-patch.diff /settings-patch.diff | ||
9 | |||
10 | RUN set -euxo pipefail; \ | ||
11 | \ | ||
12 | apk --no-cache add \ | ||
13 | build-base \ | ||
14 | dumb-init \ | ||
15 | jpeg-dev \ | ||
16 | libffi-dev \ | ||
17 | libxml2-dev \ | ||
18 | libxslt-dev \ | ||
19 | openssl-dev \ | ||
20 | postgresql-dev \ | ||
21 | py3-pip \ | ||
22 | python3-dev \ | ||
23 | runit \ | ||
24 | su-exec \ | ||
25 | uwsgi \ | ||
26 | uwsgi-python \ | ||
27 | zlib-dev \ | ||
28 | ; \ | ||
29 | cd /tmp; \ | ||
30 | wget "https://github.com/netbox-community/netbox/archive/v${netbox_version}.tar.gz"; \ | ||
31 | tar -xvf "v${netbox_version}.tar.gz" -C /opt; \ | ||
32 | rm "v${netbox_version}.tar.gz"; \ | ||
33 | mv /opt/netbox-${netbox_version}/ /opt/netbox/; \ | ||
34 | \ | ||
35 | cd /; \ | ||
36 | cp /opt/netbox/netbox/netbox/configuration.example.py /opt/netbox/netbox/netbox/configuration.py; \ | ||
37 | patch -p1 < /config-patch1.diff; \ | ||
38 | rm /config-patch1.diff; \ | ||
39 | \ | ||
40 | addgroup -S netbox; \ | ||
41 | adduser -S -G netbox netbox; \ | ||
42 | chown -R netbox:netbox /opt/netbox/netbox/media; \ | ||
43 | \ | ||
44 | cd /opt/netbox; \ | ||
45 | pip3 install wheel; \ | ||
46 | pip3 install -r requirements.txt; \ | ||
47 | \ | ||
48 | python3 netbox/manage.py collectstatic --no-input; \ | ||
49 | \ | ||
50 | cd /; \ | ||
51 | cp /opt/netbox/netbox/netbox/configuration.example.py /opt/netbox/netbox/netbox/configuration.py; \ | ||
52 | patch -p1 < /config-patch2.diff; \ | ||
53 | rm /config-patch2.diff; \ | ||
54 | \ | ||
55 | patch -p1 < /settings-patch.diff; \ | ||
56 | rm /settings-patch.diff; \ | ||
57 | \ | ||
58 | mkdir -p /usr/lib/python3.8/site-packages/django/db/backends/postgresqlvault; \ | ||
59 | touch /usr/lib/python3.8/site-packages/django/db/backends/postgresqlvault/__init__.py; \ | ||
60 | \ | ||
61 | rm -rf /root/.cache; \ | ||
62 | apk --no-cache del --purge \ | ||
63 | build-base \ | ||
64 | ; | ||
65 | |||
66 | ADD django-vault-client.py /usr/lib/python3.8/site-packages/django/contrib/vault_client.py | ||
67 | ADD django-driver.py /usr/lib/python3.8/site-packages/django/db/backends/postgresqlvault/base.py | ||
68 | ADD etc/ /etc/ | ||
69 | ADD entrypoint.sh /entrypoint.sh | ||
70 | |||
71 | STOPSIGNAL SIGHUP | ||
72 | ENTRYPOINT [ "/entrypoint.sh" ] | ||
73 | CMD [ "/usr/bin/dumb-init", "/sbin/runsvdir", "/etc/service" ] | ||
diff --git a/netbox/Makefile b/netbox/Makefile new file mode 100644 index 0000000..ffe7e64 --- /dev/null +++ b/netbox/Makefile | |||
@@ -0,0 +1,24 @@ | |||
1 | VERSION=2.10.3 | ||
2 | IMAGE=docker.crute.me/netbox:$(VERSION) | ||
3 | LATEST=$(subst :$(VERSION),,$(IMAGE)):latest | ||
4 | |||
5 | all: | ||
6 | #docker pull alpine:latest | ||
7 | docker build \ | ||
8 | --build-arg=netbox_version=$(VERSION) \ | ||
9 | -t $(IMAGE) . | ||
10 | |||
11 | all-no-cache: | ||
12 | docker build --no-cache -t $(IMAGE) . | ||
13 | |||
14 | run: | ||
15 | docker run -d \ | ||
16 | -p 9110:9000 \ | ||
17 | -p 9111:9001 \ | ||
18 | -v /srv/code:/srv/code \ | ||
19 | $(IMAGE) | ||
20 | |||
21 | publish: | ||
22 | docker push $(IMAGE) | ||
23 | docker tag $(IMAGE) $(LATEST) | ||
24 | docker push $(LATEST) | ||
diff --git a/netbox/config-patch1.diff b/netbox/config-patch1.diff new file mode 100644 index 0000000..be5b068 --- /dev/null +++ b/netbox/config-patch1.diff | |||
@@ -0,0 +1,26 @@ | |||
1 | --- a/opt/netbox/netbox/netbox/configuration.py | ||
2 | +++ b/opt/netbox/netbox/netbox/configuration.py | ||
3 | @@ -4,11 +4,13 @@ | ||
4 | # # | ||
5 | ######################### | ||
6 | |||
7 | +import urllib3; urllib3.disable_warnings() | ||
8 | + | ||
9 | # This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write | ||
10 | # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. | ||
11 | # | ||
12 | # Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] | ||
13 | -ALLOWED_HOSTS = [] | ||
14 | +ALLOWED_HOSTS = ['*'] | ||
15 | |||
16 | # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: | ||
17 | # https://docs.djangoproject.com/en/stable/ref/settings/#databases | ||
18 | @@ -51,7 +53,7 @@ | ||
19 | # For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and | ||
20 | # symbols. NetBox will not run without this defined. For more information, see | ||
21 | # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY | ||
22 | -SECRET_KEY = '' | ||
23 | +SECRET_KEY = 'dummy setup value will get cleared after setup run' | ||
24 | |||
25 | |||
26 | ######################### | ||
diff --git a/netbox/config-patch2.diff b/netbox/config-patch2.diff new file mode 100644 index 0000000..5983cc1 --- /dev/null +++ b/netbox/config-patch2.diff | |||
@@ -0,0 +1,89 @@ | |||
1 | --- a/opt/netbox/netbox/netbox/configuration.py | ||
2 | +++ b/opt/netbox/netbox/netbox/configuration.py | ||
3 | @@ -4,21 +4,35 @@ | ||
4 | # # | ||
5 | ######################### | ||
6 | |||
7 | +import os | ||
8 | +from django.contrib.vault_client import SimpleVaultClient | ||
9 | + | ||
10 | + | ||
11 | +def _is_affirmative(value): | ||
12 | + value = "" if not value else value | ||
13 | + return value.lower() in ["yes", "true", "on", "1"] | ||
14 | + | ||
15 | + | ||
16 | # This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write | ||
17 | # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. | ||
18 | # | ||
19 | # Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] | ||
20 | -ALLOWED_HOSTS = [] | ||
21 | +ALLOWED_HOSTS = ['*'] | ||
22 | |||
23 | # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: | ||
24 | # https://docs.djangoproject.com/en/stable/ref/settings/#databases | ||
25 | +port = os.getenv("NETBOX_DB_PORT") | ||
26 | DATABASE = { | ||
27 | - 'NAME': 'netbox', # Database name | ||
28 | - 'USER': '', # PostgreSQL username | ||
29 | - 'PASSWORD': '', # PostgreSQL password | ||
30 | - 'HOST': 'localhost', # Database server | ||
31 | - 'PORT': '', # Database port (leave blank for default) | ||
32 | - 'CONN_MAX_AGE': 300, # Max database connection age | ||
33 | + 'NAME': os.getenv("NETBOX_DB_NAME"), | ||
34 | + 'HOST': os.getenv("NETBOX_DB_HOST"), | ||
35 | + 'PORT': int(port) if port else "", | ||
36 | + 'CONN_MAX_AGE': 300, | ||
37 | + "VAULT_SKIP_VERIFY": os.getenv("VAULT_SKIP_VERIFY"), | ||
38 | + "VAULT_ADDR": os.getenv("VAULT_ADDR"), | ||
39 | + "VAULT_TOKEN": os.getenv("VAULT_TOKEN"), | ||
40 | + "VAULT_DB_ROLE_NAME": os.getenv("VAULT_DB_ROLE_NAME"), | ||
41 | + "VAULT_ROLE_ID": os.getenv("VAULT_ROLE_ID"), | ||
42 | + "VAULT_SECRET_ID": os.getenv("VAULT_SECRET_ID"), | ||
43 | } | ||
44 | |||
45 | # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate | ||
46 | @@ -26,23 +40,23 @@ | ||
47 | # to use two separate database IDs. | ||
48 | REDIS = { | ||
49 | 'tasks': { | ||
50 | - 'HOST': 'localhost', | ||
51 | + 'HOST': os.getenv("NETBOX_REDIS_HOST"), | ||
52 | 'PORT': 6379, | ||
53 | # Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel | ||
54 | # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], | ||
55 | # 'SENTINEL_SERVICE': 'netbox', | ||
56 | 'PASSWORD': '', | ||
57 | - 'DATABASE': 0, | ||
58 | + 'DATABASE': int(os.getenv("NETBOX_REDIS_TASK_DB")), | ||
59 | 'SSL': False, | ||
60 | }, | ||
61 | 'caching': { | ||
62 | - 'HOST': 'localhost', | ||
63 | + 'HOST': os.getenv("NETBOX_REDIS_HOST"), | ||
64 | 'PORT': 6379, | ||
65 | # Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel | ||
66 | # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], | ||
67 | # 'SENTINEL_SERVICE': 'netbox', | ||
68 | 'PASSWORD': '', | ||
69 | - 'DATABASE': 1, | ||
70 | + 'DATABASE': int(os.getenv("NETBOX_REDIS_CACHE_DB")), | ||
71 | 'SSL': False, | ||
72 | } | ||
73 | } | ||
74 | @@ -51,7 +65,14 @@ | ||
75 | # For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and | ||
76 | # symbols. NetBox will not run without this defined. For more information, see | ||
77 | # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY | ||
78 | -SECRET_KEY = '' | ||
79 | +vc = SimpleVaultClient( | ||
80 | + os.getenv("VAULT_ADDR"), | ||
81 | + os.getenv("VAULT_ROLE_ID"), | ||
82 | + os.getenv("VAULT_SECRET_ID"), | ||
83 | + ssl_verify=not _is_affirmative(os.getenv("VAULT_SKIP_VERIFY")) | ||
84 | +) | ||
85 | +SECRET_KEY = vc.get_kv_secret(os.getenv("NETBOX_VAULT_SECRET_NAME"), "key") | ||
86 | +del vc | ||
87 | |||
88 | |||
89 | ######################### | ||
diff --git a/netbox/django-driver.py b/netbox/django-driver.py new file mode 100644 index 0000000..65a9136 --- /dev/null +++ b/netbox/django-driver.py | |||
@@ -0,0 +1,69 @@ | |||
1 | import threading | ||
2 | from datetime import datetime, timedelta | ||
3 | |||
4 | from django.core.exceptions import ImproperlyConfigured | ||
5 | from django.contrib.vault_client import SimpleVaultClient, Credential | ||
6 | from django.db.backends.postgresql.base import DatabaseWrapper as OrigWrapper | ||
7 | |||
8 | |||
9 | def _is_affirmative(value): | ||
10 | value = "" if not value else value | ||
11 | return value.lower() in ["yes", "true", "on", "1"] | ||
12 | |||
13 | |||
14 | def _must_get(store, key): | ||
15 | value = store.get(key) | ||
16 | |||
17 | if not value: | ||
18 | raise ImproperlyConfigured( | ||
19 | f"Database parameter {key} is required but not set.") | ||
20 | |||
21 | return value | ||
22 | |||
23 | |||
24 | class DatabaseWrapper(OrigWrapper): | ||
25 | |||
26 | def __init__(self, *args, **kwargs): | ||
27 | super().__init__(*args, **kwargs) | ||
28 | self._vault_cache_lock = threading.Lock() | ||
29 | self._vault_cred_cache = Credential.empty() | ||
30 | |||
31 | def close_if_unusable_or_obsolete(self): | ||
32 | super().close_if_unusable_or_obsolete() | ||
33 | |||
34 | if self.connection is None: | ||
35 | return | ||
36 | |||
37 | with self._vault_cache_lock: | ||
38 | if not self._vault_cred_cache.is_valid: | ||
39 | self.close() | ||
40 | |||
41 | # All of this is done under lock | ||
42 | def _get_vault_cred(self): | ||
43 | print("Getting credentials from vault") | ||
44 | params = self.settings_dict | ||
45 | |||
46 | verify = not _is_affirmative(params.get("VAULT_SKIP_VERIFY")) | ||
47 | url = _must_get(params, "VAULT_ADDR") | ||
48 | token = params.get("VAULT_TOKEN") | ||
49 | db_role_name = _must_get(params, "VAULT_DB_ROLE_NAME") | ||
50 | role_id = _must_get(params, "VAULT_ROLE_ID") | ||
51 | role_secret = _must_get(params, "VAULT_SECRET_ID") | ||
52 | |||
53 | client = SimpleVaultClient(url, role_id, role_secret, verify) | ||
54 | |||
55 | self._vault_cred_cache = client.get_db_credential(db_role_name) | ||
56 | |||
57 | def get_connection_params(self): | ||
58 | conn_params = super().get_connection_params() | ||
59 | |||
60 | # Do the fetch under lock to prevent multiple threads from piling onto | ||
61 | # the vault server | ||
62 | with self._vault_cache_lock: | ||
63 | if not self._vault_cred_cache.is_valid: | ||
64 | self._get_vault_cred() | ||
65 | |||
66 | conn_params["user"] = self._vault_cred_cache.username | ||
67 | conn_params["password"] = self._vault_cred_cache.password | ||
68 | |||
69 | return conn_params | ||
diff --git a/netbox/django-vault-client.py b/netbox/django-vault-client.py new file mode 100644 index 0000000..e699db3 --- /dev/null +++ b/netbox/django-vault-client.py | |||
@@ -0,0 +1,84 @@ | |||
1 | import os | ||
2 | import ssl | ||
3 | import json | ||
4 | from urllib import request, parse | ||
5 | from datetime import datetime, timedelta | ||
6 | |||
7 | |||
8 | class Credential: | ||
9 | |||
10 | def __init__(self, data): | ||
11 | self.username = data["data"]["username"] | ||
12 | self.password = data["data"]["password"] | ||
13 | |||
14 | # Leave 2 minutes in case we encounter a failure | ||
15 | _duration = timedelta(seconds=data["lease_duration"] - 120) | ||
16 | self.expires = datetime.now() + _duration | ||
17 | |||
18 | @classmethod | ||
19 | def empty(cls): | ||
20 | return cls({ | ||
21 | "lease_duration": -1, | ||
22 | "data": { "username": "", "password": "" } | ||
23 | }) | ||
24 | |||
25 | @property | ||
26 | def is_valid(self): | ||
27 | return self.expires > datetime.now() | ||
28 | |||
29 | |||
30 | |||
31 | class SimpleVaultClient: | ||
32 | |||
33 | def __init__(self, base_url, role_id, role_secret, ssl_verify=True): | ||
34 | self.base_url = base_url | ||
35 | self.ssl_verify = ssl_verify | ||
36 | self.role_id = role_id | ||
37 | self.role_secret = role_secret | ||
38 | |||
39 | env_token = os.getenv("VAULT_TOKEN") | ||
40 | if env_token: | ||
41 | self._token = env_token | ||
42 | self._token_expires = None # Token is assumed to never expire | ||
43 | else: | ||
44 | self._token = None | ||
45 | self._token_expires = datetime.now() + timedelta(seconds=-1) | ||
46 | |||
47 | def _login_approle(self, role_id, secret): | ||
48 | res = self._make_request("auth/approle/login", auth=False, data={ | ||
49 | "role_id": role_id, | ||
50 | "secret_id": secret, | ||
51 | }) | ||
52 | |||
53 | self._token = res["auth"]["client_token"] | ||
54 | self._token_expires = datetime.now() + \ | ||
55 | timedelta(seconds=res["auth"]["lease_duration"]) | ||
56 | |||
57 | @property | ||
58 | def _token_is_expired(self): | ||
59 | return self._token_expires and \ | ||
60 | self._token_expires < (datetime.now() + timedelta(seconds=120)) | ||
61 | |||
62 | def _auth_as_needed(self): | ||
63 | if self._token_is_expired: | ||
64 | self._login_approle(self.role_id, self.role_secret) | ||
65 | |||
66 | def _make_request(self, url, data=None, auth=True): | ||
67 | context = ssl._create_unverified_context() \ | ||
68 | if not self.ssl_verify else None | ||
69 | |||
70 | data = json.dumps(data).encode("utf-8") if data else None | ||
71 | headers = { "X-Vault-Token": self._token } if auth else {} | ||
72 | |||
73 | url = parse.urljoin(self.base_url, parse.urljoin("/v1/", url)) | ||
74 | req = request.Request(url, headers=headers, data=data) | ||
75 | res = request.urlopen(req, context=context) | ||
76 | return json.load(res) | ||
77 | |||
78 | def get_kv_secret(self, path, key): | ||
79 | self._auth_as_needed() | ||
80 | return self._make_request(f"kv/data/{path}")["data"]["data"][key] | ||
81 | |||
82 | def get_db_credential(self, role): | ||
83 | self._auth_as_needed() | ||
84 | return Credential(self._make_request(f"database/creds/{role}")) | ||
diff --git a/netbox/entrypoint.sh b/netbox/entrypoint.sh new file mode 100755 index 0000000..a4f844c --- /dev/null +++ b/netbox/entrypoint.sh | |||
@@ -0,0 +1,22 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | set -e | ||
4 | |||
5 | cd "/opt/netbox" | ||
6 | |||
7 | # Apply any database migrations | ||
8 | /sbin/su-exec netbox python3 netbox/manage.py migrate | ||
9 | |||
10 | # Trace any missing cable paths (not typically needed) | ||
11 | /sbin/su-exec netbox python3 netbox/manage.py trace_paths --no-input | ||
12 | |||
13 | # Delete any stale content types | ||
14 | /sbin/su-exec netbox python3 netbox/manage.py remove_stale_contenttypes --no-input | ||
15 | |||
16 | # Delete any expired user sessions | ||
17 | /sbin/su-exec netbox python3 netbox/manage.py clearsessions | ||
18 | |||
19 | # Clear all cached data | ||
20 | /sbin/su-exec netbox python3 netbox/manage.py invalidate all | ||
21 | |||
22 | exec "$@" | ||
diff --git a/netbox/etc/service/netbox-rq/log/run b/netbox/etc/service/netbox-rq/log/run new file mode 100755 index 0000000..6193824 --- /dev/null +++ b/netbox/etc/service/netbox-rq/log/run | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | cat - | ||
diff --git a/netbox/etc/service/netbox-rq/run b/netbox/etc/service/netbox-rq/run new file mode 100755 index 0000000..aa4b675 --- /dev/null +++ b/netbox/etc/service/netbox-rq/run | |||
@@ -0,0 +1,23 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # runsv sends us a TERM but uwsgi will only shutdown cleanly | ||
4 | # if it receives an INT so we need to translate the signal | ||
5 | # properly for uwsgi | ||
6 | trap 'kill -INT $PID' TERM | ||
7 | |||
8 | /sbin/su-exec netbox /usr/bin/python3 /opt/netbox/netbox/manage.py rqworker & | ||
9 | |||
10 | PID=$! | ||
11 | |||
12 | # wait for uwsgi, will get cancelled when runsv TERMs us and | ||
13 | # the trap will get executed next, unless something goes wrong | ||
14 | # and uwsgi fails then this wait will run | ||
15 | wait $PID | ||
16 | |||
17 | # if something went wrong then unregister the trap because it | ||
18 | # won't have a target | ||
19 | trap - TERM | ||
20 | |||
21 | # waiting on a dead process will return the return code of the | ||
22 | # processes original exit | ||
23 | wait $PID | ||
diff --git a/netbox/etc/service/uwsgi/log/run b/netbox/etc/service/uwsgi/log/run new file mode 100755 index 0000000..6193824 --- /dev/null +++ b/netbox/etc/service/uwsgi/log/run | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | cat - | ||
diff --git a/netbox/etc/service/uwsgi/run b/netbox/etc/service/uwsgi/run new file mode 100755 index 0000000..e24ede7 --- /dev/null +++ b/netbox/etc/service/uwsgi/run | |||
@@ -0,0 +1,23 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # runsv sends us a TERM but uwsgi will only shutdown cleanly | ||
4 | # if it receives an INT so we need to translate the signal | ||
5 | # properly for uwsgi | ||
6 | trap 'kill -INT $PID' TERM | ||
7 | |||
8 | /usr/sbin/uwsgi --ini /etc/uwsgi/netbox.ini & | ||
9 | |||
10 | PID=$! | ||
11 | |||
12 | # wait for uwsgi, will get cancelled when runsv TERMs us and | ||
13 | # the trap will get executed next, unless something goes wrong | ||
14 | # and uwsgi fails then this wait will run | ||
15 | wait $PID | ||
16 | |||
17 | # if something went wrong then unregister the trap because it | ||
18 | # won't have a target | ||
19 | trap - TERM | ||
20 | |||
21 | # waiting on a dead process will return the return code of the | ||
22 | # processes original exit | ||
23 | wait $PID | ||
diff --git a/netbox/etc/uwsgi/netbox.ini b/netbox/etc/uwsgi/netbox.ini new file mode 100644 index 0000000..8431c6f --- /dev/null +++ b/netbox/etc/uwsgi/netbox.ini | |||
@@ -0,0 +1,15 @@ | |||
1 | [uwsgi] | ||
2 | plugin = python | ||
3 | master = true | ||
4 | no-orphans = true | ||
5 | socket = [::]:9000 | ||
6 | uid = netbox | ||
7 | gid = netbox | ||
8 | mime-file = /etc/mime.types | ||
9 | chdir = /opt/netbox/netbox | ||
10 | pythonpath = /opt/netbox/netbox | ||
11 | workers = 2 | ||
12 | wsgi-file = netbox/wsgi.py | ||
13 | harakiri = 300 | ||
14 | offload-threads = 4 | ||
15 | static-map = /static=/opt/netbox/netbox/static | ||
diff --git a/netbox/settings-patch.diff b/netbox/settings-patch.diff new file mode 100644 index 0000000..78510ad --- /dev/null +++ b/netbox/settings-patch.diff | |||
@@ -0,0 +1,11 @@ | |||
1 | --- /opt/netbox/netbox/netbox/settings.py | ||
2 | +++ /opt/netbox/netbox/netbox/settings.py | ||
3 | @@ -147,7 +147,7 @@ | ||
4 | }) | ||
5 | else: | ||
6 | DATABASE.update({ | ||
7 | - 'ENGINE': 'django.db.backends.postgresql' | ||
8 | + 'ENGINE': 'django.db.backends.postgresqlvault' | ||
9 | }) | ||
10 | |||
11 | DATABASES = { | ||