commit 56784cfe4fc653ffe95d66c98b9c58f7f394847b Author: David Todd (c0de) Date: Mon Apr 16 19:57:29 2018 -0500 Initial Commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d0ab940 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +max_line_length = 120 + +[*.py] +quote_type = single + +[*.{css,html}] +quote_type = double + +[*.js] +quote_type = single diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44434b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv/* +*.pyc +backup/* +*.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..691e56d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:2.7 + +WORKDIR /src +ADD . /src + +RUN set -ex \ + && curl -L https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -o /usr/local/bin/wait-for-it.sh \ + && chmod +x /usr/local/bin/wait-for-it.sh \ + && pip install -r requirements.txt + +CMD python manage.py runserver 0.0.0.0:8000 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8348ddd --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 David Todd (c0de) + +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/README.docker.md b/README.docker.md new file mode 100644 index 0000000..d25c90d --- /dev/null +++ b/README.docker.md @@ -0,0 +1,124 @@ +# local development + +You'll need to have installed `docker-compose` and `docker`, and have a running +docker daemon. + +# starting services with docker-compose + +You should be inside the `django-cms` directory when running this command. + +```sh +docker-compose u +``` + +You'll see labeled output from each service. + +When you make changes on your local copy of django-cms, they will automatically propagate to the running container. + +## accessing the database (cli) + +There are cases where you may need access to the database (such as restoring a backup). +These commands will allow you access into the database over the command line. + +1. Have docker running. Eg. `docker-compose up -f docker-compose.yaml` +2. Locate your container. `docker ps`, select the CONTAINER ID for postgres +3. Establish a shell in the container. `docker exec -t -i (CONTAINER ID) bash` +4. Connect to the database. `su postgres -c psql` + +Now that you are connected to the database CLI, you can perform queries as the root postgres user. +For remote access to this database, you may create a role for yourself with the following query. +`create role your-name with superuser createdb login password 'your-password';` + +To restore a database backup from the command line: +1. Find a way to copy the database into the container (or access it externally) +2. Become the postgres root user. `su postgres -c bash` +3. Stop the portal docker container (this can be accomplished with `docker stop (CONTAINER ID)`) +4. Verify that there are no other connections to the DB and enter psql +5. Rename or drop the imagehost_db database so it is out of the way +6. create the database and public schema +7. set permissions for the imagehost user +8. leave psql and run `pg_restore -F -c imagehost_db.custom` on newly created imagehost_db db + +## accessing the database (GUI) + +GUI access to the database can be established with PGAdmin (3 or 4) connected to localhost. +This assumes that you created a user for yourself in the previous section +(if you haven't, you can use the imagehost user at limited permissions) + +1. Open PGAdmin and add a new server with an identifying name +2. Under the connection tab + * Hostname/address should be localhost + * Username should be what you added in the previous section + * Password should be what you added in the previous section +3. Save and connect, you should now be able to run queries with administrative privileges. + +To restore a database backup inside PGAdmin: +1. Copy the imagehost_db.custom to your desktop (or somewhere easy) and + rename to imagehost_db.backup +2. Connect to the database server +3. Stop the portal docker container (this can be accomplished with `docker stop (CONTIANER ID)`) +4. Verify that there are no other connections to the db and either rename or drop the database +5. Create a new database with the owner set to imagehost +6. Right-click the newly created database and click restore +7. Navigate to your .backup file and select that +8. Let the restore run + +Some errors are expected from the above, such as a non-existant usagereports role. +These can safely be ignored for development use (the role requires read-only access in prod) + +## applying migrations + +After you have made changes to the database or models, migrations need +to be made and then applied. To accomplish that in the docker env: + +1. Have docker running. Eg. `docker-compose up -f docker-compose.yaml` +2. Locate your container. `docker ps`, select the CONTAINER ID for the portal +3. Establish a shell in the container. `docker exec -t -i (CONTIANER ID) bash` +4. CD to the portal directory (in docker-compose.yaml, this is defined as /portal) +5. Make your migrations. `python manage.py makemigrations` +6. Apply the migrations. `python manage.py migrate` +7. Optionally exit the shell. It is no longer needed. + +You may get errors on your last step if you are restoring from a database +backup. Before making the migrations, first run `python manage.py --fake-initial` + +If your database has migrations applied, it should be able to continue from +whichever the last applied migration was. + +# staging/testing + +You'll need to have `docker-machine` installed. You can create a fully +provisioned VM on ESXi using this command: + +```sh +docker-machine create \ + --driver vmwarevsphere \ + --vmwarevsphere-username root \ + --vmwarevsphere-password password \ + --vmwarevsphere-vcenter 500.500.500.500 \ + my-docker +``` + +You should replace `my-docker` with whatever you want to uniquely reference this +VM by. + +Note: If you get an error similar to "ServerFaultCode: Current license or ESXi version prohibits execution of the requested operation." +you must first put the vmserver in "Evaluation Mode" as the Free tier license does not support remote management of VMs. +This can be accomplished by logging into the esxi interface, navigating to configuration and changing the license config. + +## remote environment + +First, you'll set up your local docker client to connect to the remote docker host: + +```sh +eval $(docker-machine env my-docker) +``` + +You can see the containers running on the remote host using regular docker +commands like `docker ps`. + +## create a production environment + +```sh +docker-compose -f docker-compose.yaml -f docker-compose.production.yaml up +``` diff --git a/README.md b/README.md new file mode 100644 index 0000000..150e743 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Django-CMS + +This is a minimalistic microservice to run a Content Management System (CMS). +Normally, a CMS is used to run blogging platforms, and will be the end result for what will happen here. +Does not provide the proxy to connect to the services. + +Automatic unit testing is done by CircleCI + +Refer to the docker README for docker info + +License: MIT +Copyright 2018 David Todd (c0de) c0de@c0defox.es +Check the LICENSE file for further details diff --git a/cms/cms/__init__.py b/cms/cms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cms/cms/settings.py b/cms/cms/settings.py new file mode 100644 index 0000000..20753d3 --- /dev/null +++ b/cms/cms/settings.py @@ -0,0 +1,120 @@ +""" +Django settings for cms project. + +Generated by 'django-admin startproject' using Django 1.11.4. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = ')ry_&w-pg5o1%h$6@aqf369-0)=)k@x#9z*0oe2c5!!nya#pu(' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'cms.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'cms.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/cms/cms/urls.py b/cms/cms/urls.py new file mode 100644 index 0000000..0c3a418 --- /dev/null +++ b/cms/cms/urls.py @@ -0,0 +1,21 @@ +"""cms URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.11/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import url +from django.contrib import admin + +urlpatterns = [ + url(r'^admin/', admin.site.urls), +] diff --git a/cms/cms/wsgi.py b/cms/cms/wsgi.py new file mode 100644 index 0000000..0bd8415 --- /dev/null +++ b/cms/cms/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for cms project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings") + +application = get_wsgi_application() diff --git a/cms/manage.py b/cms/manage.py new file mode 100755 index 0000000..c6c5bbb --- /dev/null +++ b/cms/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..3f34e7d --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,34 @@ +version: '3' + +services: + postgres: + image: postgres + environment: + POSTGRES_PASSWORD: totallyHacked1337 + POSTGRES_USER: django_cms + POSTGRES_DB: cms_db + volumes: + - ./backup:/backup + ports: + - '5432:5432' + + imagehost_portal: + build: . + environment: + PORTAL_DEBUG: 'true' + POSTGRES_PASSWORD: totallyHacked1337 + POSTGRES_USER: django_cms + POSTGRES_DB: cms_db + POSTGRES_HOST: postgres + volumes: + - .:/portal + ports: + - '8000:8000' + depends_on: + - postgres + + working_dir: /portal + + command: | + /usr/local/bin/wait-for-it.sh -t 60 postgres:5432 -- + sh /portal/run.sh diff --git a/newdb.sh b/newdb.sh new file mode 100755 index 0000000..bb03c66 --- /dev/null +++ b/newdb.sh @@ -0,0 +1,2 @@ +#!/bin/bash +su postgres -c "psql < newdb.sql" \ No newline at end of file diff --git a/newdb.sql b/newdb.sql new file mode 100644 index 0000000..11672d0 --- /dev/null +++ b/newdb.sql @@ -0,0 +1,2 @@ +CREATE USER django_cms WITH LOGIN PASSWORD 'totallyHacked1337'; +CREATE DATABASE cms_db OWNER django_cms; diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4a145fe --- /dev/null +++ b/requirements.txt @@ -0,0 +1,20 @@ +asn1crypto==0.22.0 +cffi==1.10.0 +cryptography==2.0.3 +Django==1.11.4 +django-debug-panel==0.8.3 +django-debug-toolbar==1.8 +django-inline-actions==1.1.0 +djangorestframework==3.6.3 +enum34==1.1.6 +idna==2.6 +ipaddress==1.0.18 +psycopg2==2.7.3 +pycparser==2.18 +pycrypto==2.6.1 +pyOpenSSL==17.2.0 +pytz==2017.2 +six==1.10.0 +sqlparse==0.2.3 +uWSGI==2.0.15 +zipstream==1.1.4 diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..23224a8 --- /dev/null +++ b/run.sh @@ -0,0 +1,6 @@ +#!/bin/sh +cd /portal +sleep 1 # Hopefully enough for the database to start accepting connections +python manage.py makemigrations +python manage.py migrate +python manage.py runserver 0.0.0.0:8000