From d0cf32329072580a8a739c6c9218400738e0cfd9 Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 06:04:04 -0500 Subject: [PATCH 01/19] A new start --- ChangeLog | 21 -- MANIFEST.in | 5 - README.md | 139 --------- README.rst | 254 ---------------- README.txt | 4 - anouman/__init__.py | 0 anouman/bin/__init__.py | 0 anouman/bin/anouman | 44 --- anouman/bin/anouman-admin.py | 150 ---------- anouman/bin/templates/__init__.py | 0 anouman/bin/templates/gunicorn_start.template | 33 -- anouman/exceptions/__init__.py | 61 ---- anouman/project/__init__.py | 0 anouman/project/create_vm.py | 37 --- anouman/project/deploy.py | 239 --------------- anouman/project/setup.py | 45 --- anouman/templates/Vagrantfile | 33 -- anouman/templates/__init__.py | 122 -------- anouman/templates/clean.sh | 26 -- anouman/templates/gunicorn_start.sh | 27 -- anouman/templates/nginx.conf | 49 --- anouman/templates/shell_commands | 30 -- anouman/templates/test.py | 25 -- anouman/templates/test_expected_results.py | 32 -- anouman/templates/upstart.conf | 5 - anouman/templates/vagrant_bootstrap.sh | 26 -- anouman/utils/__init__.py | 0 anouman/utils/find_files.py | 172 ----------- build_and_deploy.sh | 12 - packages.txt | 1 - release_todo | 2 - run_tests.sh | 45 --- setup.cfg | 9 - setup.py | 134 --------- test.py | 281 ------------------ test/django/site1/manage.py | 10 - test/django/site1/site1/__init__.py | 0 test/django/site1/site1/settings.py | 158 ---------- test/django/site1/site1/urls.py | 17 -- test/django/site1/site1/views.py | 4 - test/django/site1/site1/wsgi.py | 32 -- test/django/site2/manage.py | 10 - test/django/site2/site2/__init__.py | 0 test/django/site2/site2/settings.py | 158 ---------- test/django/site2/site2/urls.py | 17 -- test/django/site2/site2/views.py | 4 - test/django/site2/site2/wsgi.py | 32 -- .../default/virtualbox/action_provision | 1 - .../default/virtualbox/action_set_name | 1 - .../.vagrant/machines/default/virtualbox/id | 1 - test/vm/site1/Vagrantfile | 33 -- test/vm/site1/bootstrap.sh | 13 - test/vm/site1/clean.sh | 26 -- test/vm/site1/install.sh | 5 - version.py | 3 - 55 files changed, 2588 deletions(-) delete mode 100644 ChangeLog delete mode 100644 MANIFEST.in delete mode 100644 README.md delete mode 100644 README.rst delete mode 100644 README.txt delete mode 100644 anouman/__init__.py delete mode 100644 anouman/bin/__init__.py delete mode 100644 anouman/bin/anouman delete mode 100755 anouman/bin/anouman-admin.py delete mode 100644 anouman/bin/templates/__init__.py delete mode 100755 anouman/bin/templates/gunicorn_start.template delete mode 100644 anouman/exceptions/__init__.py delete mode 100644 anouman/project/__init__.py delete mode 100644 anouman/project/create_vm.py delete mode 100644 anouman/project/deploy.py delete mode 100644 anouman/project/setup.py delete mode 100644 anouman/templates/Vagrantfile delete mode 100644 anouman/templates/__init__.py delete mode 100644 anouman/templates/clean.sh delete mode 100644 anouman/templates/gunicorn_start.sh delete mode 100644 anouman/templates/nginx.conf delete mode 100644 anouman/templates/shell_commands delete mode 100644 anouman/templates/test.py delete mode 100644 anouman/templates/test_expected_results.py delete mode 100644 anouman/templates/upstart.conf delete mode 100644 anouman/templates/vagrant_bootstrap.sh delete mode 100644 anouman/utils/__init__.py delete mode 100644 anouman/utils/find_files.py delete mode 100755 build_and_deploy.sh delete mode 100644 packages.txt delete mode 100644 release_todo delete mode 100755 run_tests.sh delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test.py delete mode 100644 test/django/site1/manage.py delete mode 100644 test/django/site1/site1/__init__.py delete mode 100644 test/django/site1/site1/settings.py delete mode 100644 test/django/site1/site1/urls.py delete mode 100644 test/django/site1/site1/views.py delete mode 100644 test/django/site1/site1/wsgi.py delete mode 100644 test/django/site2/manage.py delete mode 100644 test/django/site2/site2/__init__.py delete mode 100644 test/django/site2/site2/settings.py delete mode 100644 test/django/site2/site2/urls.py delete mode 100644 test/django/site2/site2/views.py delete mode 100644 test/django/site2/site2/wsgi.py delete mode 100644 test/vm/site1/.vagrant/machines/default/virtualbox/action_provision delete mode 100644 test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name delete mode 100644 test/vm/site1/.vagrant/machines/default/virtualbox/id delete mode 100644 test/vm/site1/Vagrantfile delete mode 100644 test/vm/site1/bootstrap.sh delete mode 100644 test/vm/site1/clean.sh delete mode 100644 test/vm/site1/install.sh delete mode 100644 version.py diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 7a154be..0000000 --- a/ChangeLog +++ /dev/null @@ -1,21 +0,0 @@ -0.0.4.0 - Features: - - Added many unit test - - Initial support for --vm option to autobuild virtual machine for testing - Bug fixes: - Users can now install anouman packages in other directorie. - -0.0.5.0 - Updates: - -Refactored the template code to be more extinsible - -Changed naming scheme of nginx conf from "nginx.domainname.conf" to "domainname" - -Automatic settings of STATIC_ROOT and MEDIA_ROOT - - - Features: - -Better support for multisite installs - -Finished --vm option for auto creation of virtual machines - -0.0.5.1 - Bugs: - -Fixed documentation errors diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 523fde2..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include *.txt -include *.md -include *.rst - -recursive-include anouman *.py * diff --git a/README.md b/README.md deleted file mode 100644 index e3c5594..0000000 --- a/README.md +++ /dev/null @@ -1,139 +0,0 @@ -Anouman Overview -================ - -Anouman is a django site deployment tool that is designed to greatly simplify the process of deploying [Django](https://www.djangoproject.com/) projects behind [gunicorn](http://gunicorn.org/)/[nginx](http://nginx.com/). In the spirit of reusing great open source software Anouman makes use of [virtualenv](https://pypi.python.org/pypi/virtualenv), [virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/), and of course [django](https://www.djangoproject.com/) to help manage the process of deploying your django projects. - -The easiest way to become familiar with Anouman is to dive in and use it by following along with the tutorial below. However, before you begin you will first need to install [vagrant](http://www.vagrantup.com/) and [virtualbox](https://www.virtualbox.org/). You will be using these tools to build a fresh Ubuntu VM to test your django deployment on. - -**Disclaimer:** *Anouman is still very much alpha stage software. As such it has only been tested on Ubuntu 12.04 using the BASH shell. I'd love to hear from others if they get this working in other OS/SHELL combinations.* - -Install Anouman --------------- - -Switch to the python virtualenv you use for development. You are using [virtualenv](http://www.virtualenv.org/en/latest/) for python development right? If not Anouman should still work with your python system packages. - - source /path/to/your/virtualenv/activate - pip install anouman - -Virtual Machine Creation and Provisioning ------------------------------------------ - -**Step 1:** VM Creation - - anouman --vm test1 - -This command uses vagrant to create and spin up a virtual machine in a directory called test1. -As part of this process anouman created an account with sudo privileges. Go ahead and login with user/password=*anouman/anouman*: - - ssh anouman@192.168.100.100 # Password *anouman* - -**Step 2:** Final provisioning - -If you are using sqlite as your database you may skip this step. - -If you are using MySQL or Postgres you will need to install them now. For MySQL: - - sudo apt-get install mysql-server - -You will then need to login to the mysql server and create/setup the appropriate database for your django project. - -If you are using [Postgres](http://www.postgresql.org/download/linux/ubuntu/) you will need to follow a similar [protocal](http://www.postgresql.org/download/linux/ubuntu/) to setup your Postgres database. - - -Assuming this worked then you are ready to walk through the Anouman tutorial and deploy your django project on a fresh virtual machine. - - - -Anouman Setup and Deployment Tutorial ------------------------------ - -### Section 1: Packaging - -This section will assume you have a django project called *example*. Most likely your project is not named *example* -so follow along with your own project by simply replacing *example* with your project's name. - -Before you begin make sure to open a new Terminal window. - -**Step 1:** Create Anouman Package - -In this step you will use Anouman to create a deployable package from your django project. Start by navigating to the directory containing your django project. This is the directory you originally ran *django-admin.py startproject* from. For instance if you ran *django-admin start-project example* from your home directory then you want to be in your home directory when you issue the following command: - - anouman --django-project=example --domainname=example.com - -Behind the scenes your django project was copied into a directory named example.com/src. Inside this directory is another file which contains a listing of python packages you are using for your django projects. This was determiend from the output of "pip freeze". Lastly this directory was tarred and gzipped. AKA an anouman package/bundle. - -### Section2: Deploying - -**Step 1:** Copy files to server - -Scp your Anouman bundle to the virtual machine we created above and then log in. - - scp example.com.tar.gz anouman@192.168.100.100:/home/anouman - -If you are using sqlite and it is not contained in your project directory then you will now need to copy it to the VM as well. *A future version will take care of copying your database to a default location and updating your setting file* - -Return to the terminal where you are logged into your vm or relogin with: - - ssh anouman@192.168.100.100 - -**Step 2:** Install Anouman into the servers system python repository. - - sudo pip install anouman - -**Step 3:** Setup Anouman and deploy your new project. - -*Anouman requires all projects to be installed as a non root user.* - -The first time you run Anouman it will install itself and in the process create a wrapped '*anouman*' virtualenv as well as a wrapped '*example.com*' virtualenv. - - anouman --deploy example.com.tar.gz - -Follow the intructions when this command finishes to update/source your .bash_profile. You should now have your web site deployed behind nginx/gunicorn. Your projects system packages are now located in the default virtualenv wrapper location */home/anouman/.virtualenvs/example.com*. If you are unfamiliar with the [virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/) I highly recommend taking a little time to become familiar with it. - -Anouman has also modified your STATIC_ROOT and MEDIA_ROOT variables in settings.py to point to *example.com/static* and *example.com/media* respectively. The goal here is to have each site completely contained in a single directory with nginx logs, gunicorn logs, static files, and your source code. *This makes it trivial to move your site to a new server using anouman.* - -Your site should now be running behind nginx/gunicon with static files properly being servered, however you still have a few steps remaining before everything will work correctly. - -**STep 4:** Ensure your database settings are correct. - -Your site should now be deployed into a directory called */home/anouman/example.com*. Your original django project can be found in *example.com/src*. Please update the DATABASE section of settings.py so that it points to your database. If it was a MySQL or Postgres DB running on localhost then you may only need to populate the database. If it was MySQL or Postgres on a remotely accessible database then you likely have nothing to do. - -If you are using an sqlite database then I recommend you create example.com/DB and copy your sqlite database into this directory. If you are following along with the tutorial then you would change the DATABASE NAME section in your settings.py file to /home/anouman/example.com/DB/{name_of_your_db} - -**Step 5** Explore Anouman Shell Commands - -Assuming you updated and sourced .bash_profile at the end of the deployment step you will now have a few shell commands that were appended to the end of your sites virtualenv activate script which is locate in . For instance to check the status of gunicorn/nginx type: - - site status - -Now let's bring it up.. - - site start - -Likewise you can stop your site with: - - site stop - -Go ahead and bring the site back up: - - site start - -You can force nginx to do a reload with: - - site reload - -These site management commands are specific to the site curently being worked on. If you install another django project Anouman will gladly set it up for you and ensure that nginx properly directs traffic to the appropriate django back end and it's all managed with virtualenv and virtualenvwrapper. To switch between sites deployed with Anouman is as simple as switching wrapped virtualenv's. For ex: workon example.com, workon site2.com, etc. - -**Step 6:** Adjust client */etc/hosts* file to simulate DNS for your web site. - -First make sure your site is running (see step 5). Next, add the following line to your */etc/hosts*. - - 192.168.100.100 www.example.com example.com - -If you setup another site, say site2.com, on the same server then you would add another line to /etc/hsots - - 192.168.100.100 www.site2.com site1.com - -NGINX will now properly direct traffic based on the URL to the correct gunicorn/django backend as well as server the correct static files for the given project. - -**Step 7:** Now point your browser to example.com and you should see your django website. Enjoy. diff --git a/README.rst b/README.rst deleted file mode 100644 index ee480e0..0000000 --- a/README.rst +++ /dev/null @@ -1,254 +0,0 @@ -Anouman Overview -================ - -Anouman is a django site deployment tool that is designed to greatly -simplify the process of deploying -`Django `__ projects behind -`gunicorn `__/`nginx `__. In -the spirit of reusing great open source software Anouman makes use of -`virtualenv `__, -`virtualenvwrapper `__, -and of course `django `__ to help manage -the process of deploying your django projects. - -The easiest way to become familiar with Anouman is to dive in and use it -by following along with the tutorial below. However, before you begin -you will first need to install `vagrant `__ -and `virtualbox `__. You will be using -these tools to build a fresh Ubuntu VM to test your django deployment -on. - -**Disclaimer:** *Anouman is still very much alpha stage software. As -such it has only been tested on Ubuntu 12.04 using the BASH shell. I'd -love to hear from others if they get this working in other OS/SHELL -combinations.* - -Install Anouman ---------------- - -Switch to the python virtualenv you use for development. You are using -`virtualenv `__ for python -development right? If not Anouman should still work with your python -system packages. - -:: - - source /path/to/your/virtualenv/activate - pip install anouman - -Virtual Machine Creation and Provisioning ------------------------------------------ - -**Step 1:** VM Creation - -:: - - anouman --vm test1 - -This command uses vagrant to create and spin up a virtual machine in a -directory called test1. As part of this process anouman created an -account with sudo privileges. Go ahead and login with -user/password=\ *anouman/anouman*: - -:: - - ssh anouman@192.168.100.100 # Password *anouman* - -**Step 2:** Final provisioning - -If you are using sqlite as your database you may skip this step. - -If you are using MySQL or Postgres you will need to install them now. -For MySQL: - -:: - - sudo apt-get install mysql-server - -You will then need to login to the mysql server and create/setup the -appropriate database for your django project. - -If you are using -`Postgres `__ you will -need to follow a similar -`protocal `__ to setup -your Postgres database. - -Assuming this worked then you are ready to walk through the Anouman -tutorial and deploy your django project on a fresh virtual machine. - -Anouman Setup and Deployment Tutorial -------------------------------------- - -Section 1: Packaging -~~~~~~~~~~~~~~~~~~~~ - -This section will assume you have a django project called *example*. -Most likely your project is not named *example* so follow along with -your own project by simply replacing *example* with your project's name. - -Before you begin make sure to open a new Terminal window. - -**Step 1:** Create Anouman Package - -In this step you will use Anouman to create a deployable package from -your django project. Start by navigating to the directory containing -your django project. This is the directory you originally ran -*django-admin.py startproject* from. For instance if you ran -*django-admin start-project example* from your home directory then you -want to be in your home directory when you issue the following command: - -:: - - anouman --django-project=example --domainname=example.com - -Behind the scenes your django project was copied into a directory named -example.com/src. Inside this directory is another file which contains a -listing of python packages you are using for your django projects. This -was determiend from the output of "pip freeze". Lastly this directory -was tarred and gzipped. AKA an anouman package/bundle. - -Section2: Deploying -~~~~~~~~~~~~~~~~~~~ - -**Step 1:** Copy files to server - -Scp your Anouman bundle to the virtual machine we created above and then -log in. - -:: - - scp example.com.tar.gz anouman@192.168.100.100:/home/anouman - - -If you are using sqlite and it is not contained in your project -directory then you will now need to copy it to the VM as well. *A future -version will take care of copying your database to a default location -and updating your setting file* - -Return to the terminal where you are logged into your vm or relogin -with: - -:: - - ssh anouman@192.168.100.100 - -**Step 2:** Install Anouman into the servers system python repository. - -:: - - sudo pip install anouman - -**Step 3:** Setup Anouman and deploy your new project. - -*Anouman requires all projects to be installed as a non root user.* - -The first time you run Anouman it will install itself and in the process -create a wrapped '*anouman*\ ' virtualenv as well as a wrapped -'*example.com*\ ' virtualenv. - -:: - - anouman --deploy example.com.tar.gz - -Follow the intructions when this command finishes to update/source your -.bash\_profile. You should now have your web site deployed behind -nginx/gunicorn. Your projects system packages are now located in the -default virtualenv wrapper location -*/home/anouman/.virtualenvs/example.com*. If you are unfamiliar with the -`virtualenvwrapper `__ -I highly recommend taking a little time to become familiar with it. - -Anouman has also modified your STATIC\_ROOT and MEDIA\_ROOT variables in -settings.py to point to *example.com/static* and *example.com/media* -respectively. The goal here is to have each site completely contained in -a single directory with nginx logs, gunicorn logs, static files, and -your source code. *This makes it trivial to move your site to a new -server using anouman.* - -Your site should now be running behind nginx/gunicon with static files -properly being servered, however you still have a few steps remaining -before everything will work correctly. - -**STep 4:** Ensure your database settings are correct. - -Your site should now be deployed into a directory called -*/home/anouman/example.com*. Your original django project can be found -in *example.com/src*. Please update the DATABASE section of settings.py -so that it points to your database. If it was a MySQL or Postgres DB -running on localhost then you may only need to populate the database. If -it was MySQL or Postgres on a remotely accessible database then you -likely have nothing to do. - -If you are using an sqlite database then I recommend you create -example.com/DB and copy your sqlite database into this directory. If you -are following along with the tutorial then you would change the DATABASE -NAME section in your settings.py file to -/home/anouman/example.com/DB/{name\_of\_your\_db} - -**Step 5** Explore Anouman Shell Commands - -Assuming you updated and sourced .bash\_profile at the end of the -deployment step you will now have a few shell commands that were -appended to the end of your sites virtualenv activate script which is -locate in . For instance to check the status of gunicorn/nginx type: - -:: - - site status - -Now let's bring it up.. - -:: - - site start - -Likewise you can stop your site with: - -:: - - site stop - -Go ahead and bring the site back up: - -:: - - site start - -You can force nginx to do a reload with: - -:: - - site reload - -These site management commands are specific to the site curently being -worked on. If you install another django project Anouman will gladly set -it up for you and ensure that nginx properly directs traffic to the -appropriate django back end and it's all managed with virtualenv and -virtualenvwrapper. To switch between sites deployed with Anouman is as -simple as switching wrapped virtualenv's. For ex: workon example.com, -workon site2.com, etc. - -**Step 6:** Adjust client */etc/hosts* file to simulate DNS for your web -site. - -First make sure your site is running (see step 5). Next, add the -following line to your */etc/hosts*. - -:: - - 192.168.100.100 www.example.com example.com - -If you setup another site, say site2.com, on the same server then you -would add another line to /etc/hsots - -:: - - 192.168.100.100 www.site2.com site1.com - -NGINX will now properly direct traffic based on the URL to the correct -gunicorn/django backend as well as server the correct static files for -the given project. - -**Step 7:** Now point your browser to example.com and you should see -your django website. Enjoy. diff --git a/README.txt b/README.txt deleted file mode 100644 index 751fc4e..0000000 --- a/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -anouman -====== - -A django wrapper designed to setup project so they are easily deployable with nginx diff --git a/anouman/__init__.py b/anouman/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/anouman/bin/__init__.py b/anouman/bin/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/anouman/bin/anouman b/anouman/bin/anouman deleted file mode 100644 index 5e0698b..0000000 --- a/anouman/bin/anouman +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# control whether we are working in test mode or not -TEST=false - -USER=`whoami` -if [ $USER == 'root' ]; -then - echo "You need to run this as a normal mode user" - exit -fi - -if [[ "$@" == *--deploy* ]] -then - if [ ! -d "~/.virtualenvs/anouman" ]; then - echo "Setting up anouman an server" - - echo "Install virtualwrapper" - sudo pip install virtualenvwrapper -q - source /usr/local/bin/virtualenvwrapper.sh; - - echo "Setting up anouman virtualenv" - mkvirtualenv anouman; - workon anouman; - - #echo "Installing django into anouman virtualenv" - pip install django -q - - if [ $TEST ]; then - ~/.virtualenvs/anouman/bin/pip install /vagrant/anouman-*.tar.gz --upgrade - else - pip install anouman --upgrade -q - fi - echo "anouman basic setup now finished" - fi -fi - -if [ $1 ]; -then - echo "calling anouman-admin.py $@" - anouman-admin.py $@ -else - echo "anouman" -fi diff --git a/anouman/bin/anouman-admin.py b/anouman/bin/anouman-admin.py deleted file mode 100755 index 7a289bc..0000000 --- a/anouman/bin/anouman-admin.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -import os -import argparse - -from anouman.project.setup import package_django_project -from anouman.project.create_vm import build_vm -from anouman.project.deploy import Deploy - -descr=""" - anouman is a django 1.4+ deployment simplifier. - - You provide anouman a django project and anouman provides - you a fully deployable anouman package (aka tarball) - - NOTE: anouman - Currently we can deploy project based on django 1.4 and up. -""" - -def get_args(): - parser = argparse.ArgumentParser( - description=descr - ) - - parser.add_argument('--vm', - help='Create a virtual machine. Pass it the VM name', - dest='vm', - default="", - ) - - parser.add_argument('--domainname', - help='Enter the domain name of your website', - dest='domainname', - default="www.example.com", - ) - - parser.add_argument('--startproject', - help='Start a new django project with default option nginx/gunicorn', - dest='project_name', - default=False, - ) - - parser.add_argument('--django-version', - help='Set the django version. Default to latest version pip repo. (ex: ==1.5.1) note the ==', - dest='django_version', - default='>=1.5, <=1.6', - ) - - parser.add_argument('--django-project', - help='Create deployment for django project. (Assumes one settings file and one wsgi file)', - dest='django_project', - default=False, - ) - - parser.add_argument('--settings', - help='Specify path to settings.py', - dest='settings', - default=False, - ) - - parser.add_argument('--wsgi', - help='Specify path to wsgi.py', - dest='wsgi', - default=False, - ) - - parser.add_argument('--manage', - help='Specify the path to your projects manage.py scrpt', - dest='manage', - default=False, - ) - - parser.add_argument('--virtualenv', - help='Set the virtualev directory.', - dest='virtualenv', - default='virtualenv', - ) - - parser.add_argument('--bind', - help='Set the virtualev directory.', - dest='bind', - default=False, #ex: 10.0.1.13:8001 - ) - - parser.add_argument('--gunicorn', - help='use gunicorn as the django server', - dest='gunicorn', - action='store_true', - default=True, - ) - - parser.add_argument('--deploy', - help='deploy the project', - dest='deploy', - default=False, - ) - - parser.add_argument('--setup', - help='setup anouman', - dest='setup', - action='store_true', - default=False, - ) - - parser.add_argument('--mysql', - help='setup for mysql backed database', - dest='mysql', - action='store_true', - default=True, - ) - - args = parser.parse_args() - - if args.django_project: - args.django_project = os.path.abspath(args.django_project) - - """ By default (neither --socket nor --bind is explicitly passed in) - we bind to --socket=unix:/var/run/your_project.sock - If the --bind={10.0.1.13:8000} option is used - the --socket default is overridden...Even if you pass - --socket yourself. If - """ - if args.bind: - args.socket=False - - return args - - - -if __name__ == '__main__': - print "anouman" - args = get_args() - - if args.vm: - build_vm(args) - - # Project Packaging - if args.django_project: - package_django_project(args) - - # Project Deploying - if args.deploy: - Deploy(args) - - # This is for creating a brand new django project - # TODO do we still want to go this route??? - if args.project_name: - setup.new_project( args ) - - - diff --git a/anouman/bin/templates/__init__.py b/anouman/bin/templates/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/anouman/bin/templates/gunicorn_start.template b/anouman/bin/templates/gunicorn_start.template deleted file mode 100755 index 96c49bf..0000000 --- a/anouman/bin/templates/gunicorn_start.template +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - - -############ YOU MIGHT BE ABLE TO SKIP THESE STEPS IF YOU USE ABSOLUTE PATHS ################################# -# Change to the DJANGODIR -cd {{DJANGODIR}} - -# source the virtualenv 'activate' file -source {{VIRTUALENVDIR}}/{{NAME}}/bin/activate # Assumes a symbolically linked virtualenv activate command -################################################################################################################ - -# Export your projects settings module -export DJANGO_SETTINGS_MODULE={{DJANGO_SETTINGS_MODULE}} # the settings file Django should use - -# Make sure your project is at the beggening of PYTHONPATH -export PYTHONPATH={{DJANGODIR}}:$PYTHONPATH - -# Create the run directory if it doesn't exist -RUNDIR=$(dirname {{SOCKFILE}}) -test -d $RUNDIR || mkdir -p $RUNDIR - -# Start gunicorn -exec {{VIRTUALENVDIR}}/{{NAME}}/bin/gunicorn {{DJANGO_WSGI_MODULE}}:application - --name {{NAME}} - --workers {{NUM_WORKERS}} - --user={{USER}} - --group={{GROUP}} - --log-level=debug - {% if SOCKFILE %}--bind=unix:{{SOCKFILE}} {% endif %} - {% if BIND %}--bind={{BIND}}{% endif %} - {% if DAEMON %} --daemon{% endif %} - -echo "gunicorn start for site: {{NAME}}" diff --git a/anouman/exceptions/__init__.py b/anouman/exceptions/__init__.py deleted file mode 100644 index 6fa4469..0000000 --- a/anouman/exceptions/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -""" - Defining some Error base classes -""" - -class MultipleError(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) - -class NotFoundError(Exception): - def __init__(self, msg=''): - self.msg = msg - - def __str__(self): - return repr(self.msg) - -""" - settings.py related exceptions -""" -class MultipleSettingError(MultipleError): - def __str__(self): - out = repr(self.value) - out = out + "\ntry running with --settings" - return out - -class NoSettingsError(NotFoundError): - def __str__(self): - if not self.msg: - return "settings.py not found" - -""" - wsgi.py related exceptions -""" -class MultipleWSGIError(MultipleError): - def __str__(self): - out = repr(self.value) - out = out + "\ntry running with --wsgi" - return out - -class NoWSGIError(NotFoundError): - def __str__(self): - if not self.msg: - return "wsgi.py not found" - -""" - manage.py related exceptions -""" -class MultipleMANAGEError(MultipleError): - def __str__(self): - out = repr(self.value) - out = out + "\ntry running with --manage" - return out - - -class NoMANAGEError(NotFoundError): - def __str__(self): - if not self.msg: - return "manage.py not found" - - diff --git a/anouman/project/__init__.py b/anouman/project/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/anouman/project/create_vm.py b/anouman/project/create_vm.py deleted file mode 100644 index 8a59aa6..0000000 --- a/anouman/project/create_vm.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, subprocess - -from anouman.templates import ( - VagrantTemplate, - VagrantBootstrapTemplate, - CleanTemplate, -) - -def build_vm(args): - if not args.vm: - raise Exception("build_vm must be callsed with args.mv=name") - - os.mkdir(args.vm) - os.chdir(args.vm) - # Write the Vagrantfile - VagrantTemplate.save("Vagrantfile", context={ - 'NAME':args.vm, - 'PUBLIC':True - }) - - # Write teh bootstrap file - VagrantBootstrapTemplate.save(path="./bootstrap.sh", context={ - 'NGINX':True, - 'MYSQL':True, - }) - - # Write the clean file - CleanTemplate.save(path="./clean.sh", context={'DOMAINNAME':'site3.com'}) - - subprocess.call(['vagrant', 'up']) - print "#########################################" - print "# #" - print "# Your VM is ready. #" - print "# To login use the collowing command #" - print "# ssh anouman@192.168.100.100 #" - print "# #" - print "#########################################" diff --git a/anouman/project/deploy.py b/anouman/project/deploy.py deleted file mode 100644 index af81984..0000000 --- a/anouman/project/deploy.py +++ /dev/null @@ -1,239 +0,0 @@ -import os, stat, shutil -from os.path import expanduser -import getpass -import subprocess - - -from anouman.templates import ( - GunicornTemplate, - UpstateTemplate, - NginxTemplate, - ShellCommandTemplate, -) - -from anouman.utils.find_files import ( - get_settings, - get_wsgi, - get_manage, - set_static_roots, -) - - -class Deploy(): - """ - To Deploy a site simply call Deploy(args) - """ - def __init__(self, args): - # Next we unpack the project - # subproces, tar returns zero on success... - if subprocess.call(["tar", "xvfz", args.deploy]): - raise Exception( "Call to subprocess failed on tar unpack" ) - - # Set both args.domainname AND args.django_project to the deploy basename - args.domainname = args.deploy.split(".tar.gz")[0] - args.django_project=args.domainname+"/src" - - home = expanduser("~") - # absolute path to the virtualenv - self.VIRTUALENV = home+"/.virtualenvs/%s"%(args.domainname) - - # absoluate path to virtualenv/bin/ - self.VIRTBIN=os.path.abspath("%s/bin"%(self.VIRTUALENV)) - - # absolute path to the virtualenv pip - self.PIP="%s/pip"%(self.VIRTBIN) - - # absolute path the virtualenv python interpretor - self.PYTHON="%s/python"%(self.VIRTBIN) - - # absolute path the vitualenv activate script - self.ACTIVATE="%s/activate"%(self.VIRTBIN) - - # absolute path to the project LOGDIR - self.LOG_DIR = os.getcwd() +"/%s/logs"%(args.domainname) - - # absolute path to the gunicorn_start.sh script - self.GUNICORN_START="%s/gunicorn_start"%(self.VIRTBIN) - - # SETTINGS project path: ex project.settings - # settings absolute path to the settings.py - [self.settings, self.SETTINGS] = get_settings(args) - - # absolute path to the project wsgi.py - self.WSGI = get_wsgi(args) - - # absolute path to manage.py - self.MANAGE = get_manage(args) #get abspath of manage.py - - # Create log directory if it doesn't exist - if not os.path.isdir(self.LOG_DIR): - os.makedirs(self.LOG_DIR) - - - self.deploy_django_project(args) - - - def deploy_django_project(self, args): - """ - This is the primary deploy method - """ - - # Create a virtualenv - subprocess.call(["virtualenv", self.VIRTUALENV]) - - # Append anouman shell command to activate script - ShellCommandTemplate.save(self.ACTIVATE, context={'DOMAINNAME':args.domainname}) - - # Create the gunicorn_start.sh file - self.Setup_Gunicorn_Start(args) - - # Create the upstart files in /etc/init - self.SetupUpstart(args) - - # Create the NGINX files - self.SetupNGINX(args) - - # Install the python packages - self.install_python_packages(args) - - # Run collectstatic command - #subprocess.call([self.PYTHON, self.MANAGE, "collectstatic"]) - print '''/bin/echo "yes" | %s %s collectstatic'''%(self.PYTHON, self.MANAGE) - os.system( '''/bin/echo "yes" | %s %s collectstatic'''%(self.PYTHON, self.MANAGE) ) - #subprocess.call(['''/bin/echo "yes" | %s %s collectstatic'''%(self.PYTHON, self.MANAGE)]) - - """ - Print output message - """ - print "#######################################################################" - print " " - print " SETUP COMPLETE " - print " " - print " Please add the following line(s) to your .bash_profile " - print " " - print " source /usr/local/bin/virtualenvwrapper.sh " - print " workon %s "%(args.domainname) - print " " - print " Then call source on .bash_profile " - print " $source ~/.bash_profile " - print " " - print "#######################################################################" - - - - def SetupNGINX(self, args): - """ - nginx script for the site. - place in: domainname/etc/nginx/sites-available - and in: /etc/nginx/sites-available - link to: /etc/nginx/sites-enabled - - Anouman should eventually be able to bring your sites on - and off line simple by removing the symlink - - Must pass an args with minimally: - args.domainname - args.django_project OR args.settings - """ - - # update STATIC_ROOT and MEDIA_ROOT in settings.py to reflect the install location - [self.STATIC_ROOT, self.MEDIA_ROOT] = set_static_roots(args) - - # Create the project etc/nginx/sites_available directory - if not os.path.exists( "%s/etc/nginx/sites-available/"%(args.domainname) ): - os.makedirs("%s/etc/nginx/sites-available/"%(args.domainname) ) - - # Save nginx config ot project/etc/nginx/sites-available - NGINX_CONF="%s/etc/nginx/sites-available/%s"%(args.domainname, args.domainname) - NginxTemplate.save(NGINX_CONF, context={ - 'UNIXBIND':'unix:/var/run/%s.sock' %(args.domainname), - 'DOMAINNAME':args.domainname, - 'DJANGO_STATIC':self.STATIC_ROOT, - 'DJANGO_MEDIA':self.MEDIA_ROOT, - 'ACCESS_LOG':"%s/nginx-access.log"%(self.LOG_DIR), - 'ERROR_LOG':"%s/nginx-error.log"%(self.LOG_DIR), - }) - - # Remove any prior installs - os.system("rm -f /etc/nginx/sites-available/%(dn)s /etc/nginx/sites-enabled/%(dn)s"% {'dn':args.domainname} ) - - # Copy the /etc/nginx files to /etc/nginx - os.system("sudo cp -r %s/etc/nginx/* /etc/nginx/" %(args.domainname)) - - # Symlink sites-available to sites enabled - os.system("sudo ln -s /etc/nginx/sites-available/%(dn)s /etc/nginx/sites-enabled/%(dn)s"% {'dn':args.domainname} ) - - - def SetupUpstart(self, args): - """ - Now we create the gunicorn upstart scripts - """ - NAME=args.domainname+".conf" - - UpstateTemplate.save(NAME, context={ - 'GUNICORN_START':self.GUNICORN_START, - 'DOMAINNAME':args.domainname, - }) - - os.system("sudo mv %s /etc/init/%s"%(NAME, NAME) ) - - - def Setup_Gunicorn_Start(self, args): - """ - Setup and install gunicorn_start.sh on the server - - default context located: anouman/templates/gunicorn_start.sh - install location {virtenv}/bin/gunicorn_start.sh - """ - - # set DJANGODIR env variable to abspath of project root. - NAME=os.path.basename(args.django_project) - DJANGODIR=os.path.abspath(args.domainname + "/" + NAME) - - GunicornTemplate.save(self.GUNICORN_START, context={ - 'NAME':args.domainname, - 'USER':getpass.getuser(), - 'GROUP':getpass.getuser(), - 'GUNICORN':"%s/gunicorn"%(self.VIRTBIN), - 'DJANGODIR':DJANGODIR, - 'DJANGO_SETTINGS_MODULE':self.SETTINGS, - 'DJANGO_WSGI_MODULE':self.WSGI, - 'ACCESS_LOG':"%s/gunicorn-access.log"%(self.LOG_DIR), - 'ERROR_LOG':"%s/gunicorn-error.log"%(self.LOG_DIR), - 'BIND':args.bind if args.bind else 'unix:/var/run/%s.sock' %(args.domainname), - }) - - # Set Permissions on the GUNICORN file - os.chmod(self.GUNICORN_START, stat.S_IRWXU|stat.S_IRWXG|stat.S_IXOTH) - - return self.GUNICORN_START - - def install_python_packages(self, args): - """ - This section installs the users python packages into their site virtualenv - TODO: This should have better reporting for failing packages - """ - pkg_success = [] - pgk_fails = [] - with open("%s/pip_packages.txt"%(args.domainname)) as f: - PACKAGES = f.readlines() - PACKAGES.append("gunicorn") - for package in PACKAGES: - try: - subprocess.call([self.PIP, "install", package]) - pkg_success.append(package) - except: - pgk_fails.append(package) - - subprocess.call([self.PIP, "install", "-r", "%s/pip_packages.txt"%(args.domainname)]) - print "Package Installation Results" - print "SUCCESS: %s" %(len(pkg_success)) - print "FAIL: %s" %(len(pgk_fails)) - for f in pgk_fails: - print "\t*\t%s"%(f) - - - -if __name__ == '__main__': - print "This does nothing" - pass diff --git a/anouman/project/setup.py b/anouman/project/setup.py deleted file mode 100644 index 1c74538..0000000 --- a/anouman/project/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -import os -import subprocess - - -from anouman.utils.find_files import ( - get_settings, - get_wsgi, -) - -def package_django_project(args): - # settings is the full path - # SETTINGS is the django projec path, exL finance.settings - [settings, SETTINGS] = get_settings(args) - - # TODO Should this all be done in deploy? - os.makedirs(args.domainname) - os.makedirs("%s/bin"%(args.domainname)) - os.makedirs("%s/etc/nginx/sites-available"%(args.domainname)) - os.makedirs("%s/etc/init"%(args.domainname)) - - """ - Install packages from project environment into the new virtualenv. - Also store the status for success/fail as we install them - """ - pip = subprocess.check_output(['which', 'pip']) - print "pip: ", pip - print "Saving pacakges to: ", "%s/pip_packages.txt"%(args.domainname) - os.system("pip freeze > %s/pip_packages.txt"%(args.domainname)) - - - """ - Now we copy your django project into the virtual env - """ - print "Copying your source tree into the virtual env" - print "args.django_project: ", args.django_project - print "args.domainname: ", args.domainname - subprocess.call(['cp', '-r', args.django_project, args.domainname+"/src"]) - subprocess.call(['tar', '-cf', args.domainname+".tar", args.domainname]) - subprocess.call(['gzip', args.domainname+".tar"]) - subprocess.call(["rm", "-rf", args.domainname]) - - -if __name__ == '__main__': - print "This does nothing" - pass diff --git a/anouman/templates/Vagrantfile b/anouman/templates/Vagrantfile deleted file mode 100644 index 92bea45..0000000 --- a/anouman/templates/Vagrantfile +++ /dev/null @@ -1,33 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = "{{NAME}}" - - # The url from where the 'config.vm.box' box will be fetched if it - # doesn't already exist on the user's system. - config.vm.box_url = "http://files.vagrantup.com/precise64.box" - - # Run bootstrap.sh provisioning script - config.vm.provision :shell, :path => "bootstrap.sh" - {% if PRIVATE %} - # Create a private network, which allows host-only access to the machine - # using a specific IP. - config.vm.network :private_network, ip: "{{PRIVATE}}" - {% else %} - # Create a public network, which will make the machine appear as another - #physical device on your network. - config.vm.network :public_network - {% endif %} - #config.vm.provider :virtualbox do |vb| - # # Don't boot with headless mode - # vb.gui = true - # - # # Use VBoxManage to customize the VM. For example to change memory: - # vb.customize ["modifyvm", :id, "--memory", "1024"] - #end -end diff --git a/anouman/templates/__init__.py b/anouman/templates/__init__.py deleted file mode 100644 index 315fab0..0000000 --- a/anouman/templates/__init__.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -import os -from django.template import Template, Context -from django.conf import settings - -settings.configure() - -class BaseTemplate: - """ - This is the base class for template rendering - Each template to render should extend from this class and - override minimalliy the context and template properties. - """ - - # absolute path to the template file - template = '' - - # The context that will be passed to the template - # Sublcasses should specify their own context parameters - context = {} - - @classmethod - def render(cls, c={}): - """ - Pass in a context our the defaults above will be used - """ - cls.context.update(c) - t = Template( open(cls.template).read() ) - c = Context( cls.context ) - return t.render( c ) - - @classmethod - def save(cls, path, **kwargs): - """ - path is the path to where the file will be saved - """ - c = kwargs.get('context', cls.context) - with open(path, 'w') as f: - f.write(cls.render(c) ) - -class VagrantTemplate(BaseTemplate): - template = os.path.dirname(os.path.realpath(__file__)) + "/Vagrantfile" - context = { - 'NAME':'site1', - 'PRIVATE':'192.168.100.100', #To use private network set to ip: 192.168.100.100 - } - -class GunicornTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/gunicorn_start.sh" - - context = { - 'NAME':'website', # Name of the application - 'DJANGODIR':'./', # Django project director - 'USER':'username', # user to run as - 'GROUP':'username', # group to run as - 'NUM_WORKERS':3, # Number of Gunicorn threads. 2(proc)+1 - 'VIRTUALENVDIR':'./virtualenv', # Directory containing your projects virtual env - 'DJANGO_SETTINGS_MODULE':'website.settings', # the django settings file - 'DJANGO_WSGI_MODULE':'website.wsgi', # your project wsgi module - 'GUNICORN':'virtualenv/bin/gunicorn', # location of gunicorn.py - 'ERROR_LOG':'/var/log/gunicorn-error.log', # recommend setting this to domain/logs/gunicorn-error.log - 'ACCESS_LOG':'/var/log/gunicorn-access.log', # recommend setting this to domain/logs/gunicorn-error.log - 'SOCKFILE':False, # ex: /var/run/gunicorn.sock - # You can bind your server to a unix socket or to a port - # But you should only bind it to one or the other - # unix socket example: /var/run/gunicorn.sock - # ip:port example: 10.0.2.13:8000 - 'BIND':False, # ex: 10.0.2.13:80 Use - } - -class NginxTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/nginx.conf" - context = { - 'UNIXBIND':'', - 'DOMAINNAME':'', - 'DJANGO_STATIC':'', - 'DJANGO_MEDIA':'', - 'ACCESS_LOG':'', # Project/Site based logs - 'ERROR_LOG':'' # Project/Site based logs - } - -class VagrantBootstrapTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/vagrant_bootstrap.sh" - - context = { - 'NGINX':True, - 'MYSQL':False, - } - -class UpstateTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/upstart.conf" - - context = { - 'GUNICORN_START':'', # The abspath to the gunicorn_start script - 'DOMAINNAME':'', # The domain name - } - - -class ShellCommandTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/shell_commands" - - context = { - 'DOMAINNAME':'', - } - - @classmethod - def save(cls, path="./site.conf", **kwargs): - """ - Overridden because we need to append and not write to the activate file - """ - c = kwargs.get('context', cls.context) - with open(path, 'a') as f: - f.write(cls.render(c) ) - - -class CleanTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/clean.sh" - - context = { - 'DOMAINNAME':'site1.com', - } - diff --git a/anouman/templates/clean.sh b/anouman/templates/clean.sh deleted file mode 100644 index d330698..0000000 --- a/anouman/templates/clean.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# This file cleans up a server for a fresh anouman install -# Set the domain name of the project here -DOMAINNAME={{DOMAINNAME}} - -# Echo Clean up NGINX sites enabled -# TODO Shouldn't we store these locally in our package directory and then just create the symbolic -# link back to the sites-enabled for nginx? If you are worried about conforming then just create a -# symlink in sites-available to. -sudo rm -rf /etc/nginx/sites-enabled/nginx.$DOMAINNAME.conf /etc/nginx/sites-available/nginx.$DOMAINNAME.conf - -# Remove anouman -/usr/bin/yes | sudo pip uninstall anouman - -# Remove all traces of virtualenv -sudo rm -rf /home/anouman/* -sudo rm -rf /home/anouman/.virtualenvs/ - -# Remove the .bash_profile -# Make sure this test never runs on the clients machine! -rm -rf /home/anouman/.bash_profile - - -# Remove the site upstart command -sudo rm -rf /etc/init/site1.com.conf diff --git a/anouman/templates/gunicorn_start.sh b/anouman/templates/gunicorn_start.sh deleted file mode 100644 index ab26669..0000000 --- a/anouman/templates/gunicorn_start.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Export your projects settings module -export DJANGO_SETTINGS_MODULE={{DJANGO_SETTINGS_MODULE}} - -# Make sure your project is at the beginning of PYTHONPATH -export PYTHONPATH={{DJANGODIR}}:$PYTHONPATH - -{# If using a unix socket then create the run directory #} -{% if SOCKFILE %} -# Make sure the directory for teh sockfile is created -RUNDIR=$(dirname {{SOCKFILE}}) -test -d $RUNDIR || mkdir -p $RUNDIR -{% endif %} - -# Start gunicorn -exec {{GUNICORN}} {{DJANGO_WSGI_MODULE}}:application \ - --bind={{BIND}} \ - --name {{NAME}} \ - --workers {{NUM_WORKERS}} \ - --user={{USER}} \ - --log-level=debug \ - --error-logfile {{ERROR_LOG}} \ - --access-logfile {{ACCESS_LOG}} \ - {% if DAEMON %} --daemon \{% endif %} - -echo "gunicorn start for site: {{NAME}}" diff --git a/anouman/templates/nginx.conf b/anouman/templates/nginx.conf deleted file mode 100644 index 4830bf2..0000000 --- a/anouman/templates/nginx.conf +++ /dev/null @@ -1,49 +0,0 @@ -upstream {{DOMAINNAME}} { - # bind to the upstream unix socket and continue to retry even if it failed - # to return a good HTTP response - server {{UNIXBIND}} fail_timeout=0; -} - -server { - - listen 80; - server_name {{DOMAINNAME}} www.{{DOMAINNAME}}; - - client_max_body_size 128M; - - access_log {{ACCESS_LOG}}; - error_log {{ERROR_LOG}}; - - location /static/ { - alias {{DJANGO_STATIC}}; - } - - location /media/ { - alias {{DJANGO_MEDIA}}; - } - - location / { - # set the HTTP header - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # pass the Host: header from the client right along so redirects - # can be set correctly in the Django application - proxy_set_header Host $http_host; - - # we don't want nginx trying to do something clever with - # redirects, we set the Host: header above already. - proxy_redirect off; - - # Let nginx server the static files while gunicorn focuses on the python/db content - if (!-f $request_filename) { - proxy_pass http://{{DOMAINNAME}}; - break; - } - } - - # Error pages - error_page 500 502 503 504 /500.html; - location = /500.html { - root {{DJANGO_STATIC}}; - } -} diff --git a/anouman/templates/shell_commands b/anouman/templates/shell_commands deleted file mode 100644 index 9b41793..0000000 --- a/anouman/templates/shell_commands +++ /dev/null @@ -1,30 +0,0 @@ - -#This section defines commands specified by Anouman - -NGINX=/etc/init.d/nginx -DOMAINNAME={{DOMAINNAME}} - -function site { - if [ $1 == 'status' ]; - then - sudo $NGINX status - sudo status $DOMAINNAME - fi - - if [ $1 == 'stop' ]; - then - sudo $NGINX stop - sudo stop $DOMAINNAME - fi - - if [ $1 == 'start' ]; - then - sudo $NGINX start - sudo start $DOMAINNAME - fi - - if [ $1 == 'reload' ]; - then - sudo nginx -s reload - fi -} diff --git a/anouman/templates/test.py b/anouman/templates/test.py deleted file mode 100644 index 022e054..0000000 --- a/anouman/templates/test.py +++ /dev/null @@ -1,25 +0,0 @@ -import random -import unittest - -from django.conf import settings -settings.configure() - -from anouman.templates import ShellCommandTemplate - -class TestSequenceFunctions(unittest.TestCase): - - def setUp(self): - self.seq = range(10) - - def test_shell_cmd_template(self): - from test_expected_results import shell_commands_expected - context = { - 'DOMAINNAME':'example.com', - } - - out = ShellCommandTemplate.render(context) - self.assertTrue(out == shell_commands_expected) - -if __name__ == '__main__': - suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/anouman/templates/test_expected_results.py b/anouman/templates/test_expected_results.py deleted file mode 100644 index ed3f727..0000000 --- a/anouman/templates/test_expected_results.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -shell_commands_expected=""" -#This section defines commands specified by Anouman - -NGINX=/etc/init.d/nginx -DOMAINNAME=example.com - -function site { - if [ $1 == 'status' ]; - then - sudo $NGINX status - sudo status $DOMAINNAME - fi - - if [ $1 == 'stop' ]; - then - sudo $NGINX stop - sudo stop $DOMAINNAME - fi - - if [ $1 == 'start' ]; - then - sudo $NGINX start - sudo start $DOMAINNAME - fi - - if [ $1 == 'reload' ]; - then - sudo nginx -s reload - fi -}""" diff --git a/anouman/templates/upstart.conf b/anouman/templates/upstart.conf deleted file mode 100644 index 2d7e819..0000000 --- a/anouman/templates/upstart.conf +++ /dev/null @@ -1,5 +0,0 @@ -description "Starting {{DOMAINNAME}}" - -start on startup -exec {{GUNICORN_START}} -respawn diff --git a/anouman/templates/vagrant_bootstrap.sh b/anouman/templates/vagrant_bootstrap.sh deleted file mode 100644 index 835c6de..0000000 --- a/anouman/templates/vagrant_bootstrap.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# Setup anouman user -sudo useradd --shell /bin/bash --home /home/anouman anouman -echo -e "anouman\\nanouman\\n" | sudo passwd anouman -sudo usermod --groups admin anouman -sudo mkdir /home/anouman -sudo chown -R anouman:anouman /home/anouman - -sudo apt-get update # Update apt-get -sudo apt-get install -yf vim # VIM because VI isn't as cool -sudo apt-get install -yf git # install git - -### PYTHON STUFF -sudo apt-get install -yf python-setuptools -sudo apt-get install -yf python-virtualenv -sudo apt-get install -yf python-dev -sudo apt-get install -yf build-essential - -{% if NGINX %} -sudo apt-get install -yf nginx # install nginx -{% endif %} - -{% if MYSQL %} -sudo apt-get install -yf mysql-client # only install mysql command line client -sudo apt-get install -yf libmysqlclient-dev # needed for django mysql integration -{% endif %} diff --git a/anouman/utils/__init__.py b/anouman/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/anouman/utils/find_files.py b/anouman/utils/find_files.py deleted file mode 100644 index 232210c..0000000 --- a/anouman/utils/find_files.py +++ /dev/null @@ -1,172 +0,0 @@ -import os, sys, re -import fnmatch - -from anouman.exceptions import ( - MultipleSettingError, - NoSettingsError, - MultipleWSGIError, - NoWSGIError, - MultipleMANAGEError, - NoMANAGEError, -) - -def find_file(root_dir, pattern): - """ - This is a generic recursive grep function - """ - matches = [] - for root, dirnames, filenames in os.walk(root_dir): - for filename in fnmatch.filter(filenames, pattern): - matches.append(os.path.join(root, filename)) - return matches - -def get_settings(args): - """ - This function checks for the existence of the settings file. - - If the --settings options is specified then we simply - check to see if the file exists and if so return the name of the - file. - - If no --settings option was given then we look for settings.py - recursivly in the directory defined by --django-project. - -- If multiple settings.py are found we throw an exception. - -- If not settings.py is found we throw an exception. - -- If one settings.py is found we return it's path. - """ - settings_path='' - if not args.settings: - matches = find_file(args.django_project, 'settings.py') - if len(matches) > 1: - raise MultipleSettingError(matches) - elif len(matches) == 0: - print "args.django_project: ", args.django_project - print "search path: %s"%(os.path.abspath(args.django_project)) - raise NoSettingsError() - settings_path= matches[0] - elif not os.path.isfile(args.settings): - raise NoSettingsError() - else: - settings_path = args.settings - - # We now have the path to the settings.py modules, but we need - # to convert it to python module format: settings.wsgi - tmp = settings_path.split(args.django_project) - if len(tmp) == 2: - return [ - os.path.abspath(settings_path), - tmp[1][1:].replace("/", ".").replace(".py", "") - ] - else: - raise NoSettingsError( str(tmp) ) - -def get_wsgi(args): - """ - This function checks for the existence of the wsgi.py file. - - If the --wsgi options is specified then we simply - check to see if the file exists and if so return the name of the - file. - - If no --wsgi option was given then we look for wsgi.py - recursivly in the directory defined by --django-project. - -- If multiple wsgi.py are found we throw an exception. - -- If not wsgi.py is found we throw an exception. - -- If one wsgi.py is found we return it's path. - """ - wsgi_path = '' - if not args.wsgi: - matches = find_file(args.django_project, 'wsgi.py') - if len(matches) > 1: - raise MultipleWSGIError(matches) - if len(matches) == 0: - raise NoWSGIError() - wsgi_path=os.path.abspath( matches[0] ) - elif not os.path.isfile(args.wsgi): - raise NoWSGIError() - else: - wsgi_path = os.path.abspath( args.wsgi ) - - # We now have the path to the wsgi.py modules, but we need - # to convert it to python module format: website.wsgi - tmp = wsgi_path.split( os.path.abspath(args.django_project) ) - if len(tmp) == 2: - return tmp[1][1:].replace("/", ".").replace(".py", "") - else: - raise NoWSGIError( str(tmp) ) - -def get_manage(args): - """ - This function checks for the existence of the manage.py file. - - If the --manage options is specified then we simply - check to see if the file exists and if so return the name of the - file. - - If no --manage option was given then we look for manage.py - recursivly in the directory defined by --django-project. - -- If multiple manage.py are found we throw an exception. - -- If not manage.py is found we throw an exception. - -- If one manage.py is found we return it's path. - """ - manage_path = '' - if not args.manage: - matches = find_file(args.django_project, 'manage.py') - if len(matches) > 1: - raise MultipleMANAGEError(matches) - if len(matches) == 0: - raise NoMANAGEError() - manage_path = matches[0] - elif not os.path.isfile(args.manage): - raise NoMANAGEError() - else: - manage_path = os.path.abspath( args.manage ) - - return os.path.abspath( manage_path ) - -def change_settings(settings_file, pattern, value): - with open(settings_file, 'r') as f: - contents = f.readlines() - - match_count = 0 - for line in contents: - if pattern in line and "#" not in line: - match_count = match_count + 1 - - - if match_count > 1: - print "WARNING: More than one %s line in settings file." %(pattern) - print "Anouman would prefer to have you set this value yourself or remove duplicate %s settings" %(pattern) - return False - - new_contents = [] - for line in contents: - if pattern in line and "#" not in line: - line = "#"+line - new_contents.append(line) - new_contents.append('%s="%s"'%(pattern, value) ) - else: - new_contents.append(line) - - with open(settings_file, 'w') as f: - f.writelines(new_contents) - - # Flush the stdout buffer and force write to disk - sys.stdout.flush() - - return True - -def set_static_roots(args): - """ - We need to change the STATIC_ROOT and MEDIA_ROOT variables - """ - [settings_path, SETTINGS] = get_settings(args) - sys.path.append(os.path.dirname(settings_path)) - import settings - - change_settings(settings_path, r'MEDIA_ROOT', "%s/"%(os.path.abspath("%s/media/" %(args.domainname))) ) - change_settings(settings_path, r'STATIC_ROOT', "%s/"%(os.path.abspath("%s/static/" %(args.domainname))) ) - - reload(settings) - - return [settings.STATIC_ROOT, settings.MEDIA_ROOT] diff --git a/build_and_deploy.sh b/build_and_deploy.sh deleted file mode 100755 index 95b2ca1..0000000 --- a/build_and_deploy.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -source buildenv/bin/activate -rm -rf buildenv/lib/python2.7/site-packages/Dnginx-0.1-py2.7.egg-info/ -rm -rf dist - -rm -rf B/anouman-admin.py A/Dnginx-0.1-py2.7.egg-info/ dist - -python setup.py sdist -pip install dist/anouman-0.1.tar.gz - -ls /Users/jfurr/blank/lib/python2.7/site-packages/anouman/templates/ diff --git a/packages.txt b/packages.txt deleted file mode 100644 index 7abea1e..0000000 --- a/packages.txt +++ /dev/null @@ -1 +0,0 @@ -Django>=1.5,<=1.6 diff --git a/release_todo b/release_todo deleted file mode 100644 index acca857..0000000 --- a/release_todo +++ /dev/null @@ -1,2 +0,0 @@ -* Make sure up change pip install path for anouman in the anouman/bin/anouman bash script. - diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index de44837..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -############################################# -# # -# Simple Test Driver # -# # -# ./run_tests -q (queit) -f (failfast) # -############################################# - -#QUEIT="" -#if [[ "$@" == *-q* ]]; then -# QUEIT=" > /dev/null" -#fi -# -#FAILFAST="" -#if [[ "$@" == *-f* ]]; then -# FAILFAST=" --failfast " -#fi -# -#VERBOSE="" -#if [[ "$@" == *-v* ]]; then -# VERBOSE=" -v " -#fi -# -#echo "/usr/bin/yes | python -m unittest discover $VERBOSE $FAILFAST $QUEIT" -#exec /usr/bin/yes | python -m unittest discover $VERBOSE $FAILFAST $QUEIT - - - -if [[ "$@" == *-q* ]]; -then - if [[ "$@" == *-f* ]]; - then - /usr/bin/yes | python -m unittest discover -v --failfast > /dev/null - else - /usr/bin/yes | python -m unittest discover -v > /dev/null - fi -else - if [[ "$@" == *-f* ]]; - then - /usr/bin/yes | python -m unittest discover -v --failfast - else - /usr/bin/yes | python -m unittest discover -v - fi -fi diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9e53a95..0000000 --- a/setup.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[bdist_rpm] -doc_files = docs extras AUTHORS INSTALL LICENSE -install-script = scripts/rpm-install.sh - -[metadata] -license-file = LICENSE - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 72d9d2b..0000000 --- a/setup.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import sys -from distutils.core import setup -from distutils.sysconfig import get_python_lib - -from setuptools import find_packages - -VERSION="0.0.5.1" - -# Make sure README.rst is in sync with README.md #*rst used by pypi and *md used by github -os.system("pandoc --from=markdown --to=rst --output=README.rst README.md") - -# Warn if we are installing over top of an existing installation. This can -# cause issues where files that were deleted from a more recent Dnginx are -# still present in site-packages. -overlay_warning = False -if "install" in sys.argv: - # We have to try also with an explicit prefix of /usr/local in order to - # catch Debian's custom user site-packages directory. - for lib_path in get_python_lib(), get_python_lib(prefix="/usr/local"): - existing_path = os.path.abspath(os.path.join(lib_path, "anouman")) - if os.path.exists(existing_path): - # We note the need for the warning here, but present it after the - # command is run, so it's more likely to be seen. - overlay_warning = True - break - - -def fullsplit(path, result=None): - """ - Split a pathname into components (the opposite of os.path.join) - in a platform-neutral way. - """ - if result is None: - result = [] - head, tail = os.path.split(path) - if head == '': - return [tail] + result - if head == path: - return result - return fullsplit(head, [tail] + result) - - -EXCLUDE_FROM_PACKAGES = [] - -def is_package(package_name): - for pkg in EXCLUDE_FROM_PACKAGES: - if package_name.startswith(pkg): - return False - return True - - -# Compile the list of packages available, because distutils doesn't have -# an easy way to do this. -packages, package_data = [], {} - -root_dir = os.path.dirname(__file__) -if root_dir != '': - os.chdir(root_dir) -anouman_dir = 'anouman' - -for dirpath, dirnames, filenames in os.walk(anouman_dir): - # Ignore PEP 3147 cache dirs and those whose names start with '.' - dirnames[:] = [d for d in dirnames if not d.startswith('.') and d != '__pycache__'] - parts = fullsplit(dirpath) - package_name = '.'.join(parts) - if '__init__.py' in filenames and is_package(package_name): - packages.append(package_name) - elif filenames: - relative_path = [] - while '.'.join(parts) not in packages: - relative_path.append(parts.pop()) - relative_path.reverse() - path = os.path.join(*relative_path) - package_files = package_data.setdefault('.'.join(parts), []) - package_files.extend([os.path.join(path, f) for f in filenames]) - - -with open('README.rst') as file: - long_description = file.read() - - -setup( - name='anouman', - version=VERSION, - author='John Furr', - author_email='anouman.dev@gmail.com', - url='https://github.com/gnulnx/anouman', - description=('Rapidly deploy your django project behind gunicorn and nginx'), - long_description=long_description, - download_url='https://github.com/gnulnx/anouman/tree/%s'%(VERSION), - license='BSD', - #packages=packages, - include_package_data = True, - packages=find_packages(), - package_data=package_data, - scripts=['anouman/bin/anouman-admin.py', 'anouman/bin/anouman'], - classifiers=[ - 'Environment :: Web Environment', - 'Development Status :: 2 - Pre-Alpha', - 'Intended Audience :: Developers', - 'Programming Language :: Python', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: WSGI', - ], - install_requires=[ - "virtualenvwrapper", - "django", - # Currently only the django template engine is being used - # but there are plans to have an anouman server monitoring - # protion of the website - #"Django >= 1.2", - ], -) - -if overlay_warning: - sys.stderr.write(""" - -===================== -Danger Will Robinson! -===================== - -You have just installed anouman over top of an existing -installation, without removing it first. Because of this, -your install may now include extraneous files from a -previous version that have since been removed from -Dnginx. This is known to cause a variety of problems. You -should manually remove the - -%(existing_path)s - -directory and re-install Dnginx. - -""" % {"existing_path": existing_path}) diff --git a/test.py b/test.py deleted file mode 100644 index d56a276..0000000 --- a/test.py +++ /dev/null @@ -1,281 +0,0 @@ -import os -import unittest -import time -import subprocess -import paramiko -import shutil -from anouman.templates import ( - vagrant, - vagrant_bootstrap, - clean -) - -for line in open("setup.py"): - if "VERSION" in line: - try: - VERSION = line.split("=")[1].strip().replace('"', '') - break - except: - pass - -try: VERSION -except Exception as e: - raise Exception("VERSION NUMBER NOT FOUND") - -VM1="10.0.1.21" - -class TestBuild(unittest.TestCase): - - def setUp(self): - """ - There were a lot of directory changes going on. - It was easier to alway's return to a common root directory - """ - # return to the rool level directory - os.chdir(os.path.dirname(__file__)) - - def test_1_remove_dist(self): - """Make sure the build directory is gone""" - subprocess.call(['rm', '-rf', 'dist']) - self.assertFalse( - os.path.isfile( - 'dist/anouman-%(version)s.tar.gz' % {'version':VERSION} - ) - ) - - def test_2_uninstall_anouman(self): - subprocess.call(['pip', '-q', 'uninstall', 'anouman']) - try: - anouman = subprocess.check_output(['which', 'anouman']) - except subprocess.CalledProcessError: - anouman = False - - self.assertFalse(anouman) - - def test_3_sdist(self): - subprocess.call(['python', 'setup.py', '--quiet', 'sdist']) - self.assertTrue( - os.path.isfile( - 'dist/anouman-%(version)s.tar.gz' % {'version':VERSION} - ) - ) - - - def test_4_install_anouman(self): - subprocess.call(['pip', 'install', 'dist/anouman-%(version)s.tar.gz' % {'version':VERSION}, '--upgrade']) - try: - anouman = subprocess.check_output(['which', 'anouman']) - except subprocess.CalledProcessError: - anouman = False - - self.assertTrue(anouman) - - - def test_5_create_anouman_package(self): - # Pre test cleanup - subprocess.call(['rm', '-rf', 'tmp/*']) - subprocess.call(['rm', '-rf', 'site1.com.tar.gz']) - - #create empty virtualenv - subprocess.call(['virtualenv', 'site1']) - os.system("source site1/bin/activate") - - # build anouman package - results = subprocess.check_output(['anouman', '--django-project', 'test/django/site1', '--domainname', 'site1.com']) - - # Mv package to tmp directory - subprocess.call(['mv', 'site1.com.tar.gz', 'tmp/']) - self.assertTrue(True) - # clean up and remove this virtualenv - - def test_6_check_package_contents(self): - os.chdir('tmp/') - # unpack the package and check basic directory structure. - subprocess.call(['tar', 'xvfz', 'site1.com.tar.gz']) - dir_contents = os.listdir("site1.com") - self.assertEqual( - ['pip_packages.txt', 'src'], - dir_contents - ) - - self.assertTrue( - os.path.isfile("site1.com/src/manage.py") - ) - - self.assertTrue( - os.path.isfile("site1.com/src/site1/settings.py") - ) - - self.assertTrue( - os.path.isfile("site1.com/src/site1/wsgi.py") - ) - - - -class TestVagrant(unittest.TestCase): - - def setUp(self): - """ - There were a lot of directory changes going on. - It was easier to alway's return to a common root directory - """ - # return to the rool level directory - try: - os.chdir(os.path.dirname(__file__)) - except: - os.chdir("/Users/jfurr/anouman/") - - - def connect_to_s1(self, transport=False): - """ - return a connection to server "s1" - This is a vagrant box. that expects to have already - had provisioning from bootstrap.sh done on it. - """ - client = paramiko.SSHClient() - client.load_system_host_keys() - client.connect( - hostname=VM1, - username='anouman', - password='anouman', - timeout=5 - ) - - stdin, stdout, stderr = client.exec_command('hostname') - return client - - def scp(self, remotepath, localpath): - """ - scp a file to remote server s1. - """ - #TODO: Remove the hard coded scp call. In fact why not move this - # out of the test suite and make it a general purpose call. - transport = paramiko.Transport((VM1, 22)) - transport.connect( - username='anouman', - password='anouman' - ) - - sftp = paramiko.SFTPClient.from_transport(transport) - try: - sftp.put(remotepath, localpath) - except Exception as e: - print os.listdir("./") - raise Exception("YOU FAIL: ", e) - sftp.close() - transport.close() - - def exec_s1(self, cmd): - ssh = self.connect_to_s1() - return self.exec_command(ssh, cmd) - - def exec_command(self, ssh, cmd): - stdin, stdout, stderr = ssh.exec_command(cmd) - - out='' - for line in stdout: - out = out + line - - return out - - def test_1_create_new_vagrant_box(self): - print "test_1_create_new_vagrant_box" - try: - shutil.rmtree("test/vm/site3") - print "REMOVED" - except OSError as e: - print "EXCEPTION: ", e - pass - - os.mkdir("test/vm/site3") - os.chdir("test/vm/site3") - - vagrant.save(path="./Vagrantfile", context={ - 'NAME':'site3', - 'PUBLIC':True - }) - - vagrant_bootstrap.save(path="./bootstrap.sh", context={ - 'NGINX':True, - 'MYSQL':True, - }) - - clean.save(path="./clean.sh", context={ - 'DOMAINNAME':'site3.com' - }) - - print "YOU NEED TO ACTUALLY CHECK SOMETHIGN FOR THIS TO BE ATEST" - - def test_2_bring_vagrant_up(self): - base_dir = os.path.dirname(__file__) - os.chdir(os.path.join(base_dir, "test/vm/site1")) - - """ - Frist we try to connect to see if the vm is already up. - If that fails we then call vagrant up and try to connect - again after that finishes. - """ - try: - ssh = self.connect_to_s1() - except Exception as e: - print "\nCONNECTION FAILED. \nTrying to bring vagrant up...." - subprocess.call(['vagrant', 'up']) - print "Now retrying ssh connect" - ssh = self.connect_to_s1() - - stdout = self.exec_command(ssh, 'hostname') - if 'precise64' not in stdout: - self.assertFalse("Incorrect hostname....so no this test fails") - - def test_3_clean_server(self): - out = self.exec_s1("/usr/bin/yes | sh /vagrant/clean.sh") - - # Confirm that the home directory has been cleaned out - out = self.exec_s1("cd /home/anouman; ls") - self.assertEqual(out.strip(), '') - - # Make sure anouman has been uninstalled - out = self.exec_s1("anouman") - self.assertEqual(out, '') - - # TODO There are probably several other checks could do here - - def test_4_scp_anouman_to_s1(self): - # copy anouman to server - self.scp( - "dist/anouman-%(version)s.tar.gz" % {'version':VERSION}, - "/home/anouman/anouman-0.0.4.0.tar.gz" - ) - - out = self.exec_s1("cd /home/anouman; ls") - self.assertEqual( - "anouman-%(version)s.tar.gz" % {'version':VERSION}, - out.strip() - ) - - - def test_5_install_anouman_with_pip(self): - out = self.exec_s1("sudo pip install /home/anouman/anouman-%(version)s.tar.gz --upgrade" % {'version':VERSION}) - - # Check that anouman is installed - out = self.exec_s1("anouman") - self.assertEqual(out.strip(), "anouman") - - def test_6_scp_package_to_s1(self): - - self.scp( - "tmp/site1.com.tar.gz", - "/home/anouman/site1.com.tar.gz" - ) - - out = self.exec_s1("cd /home/anouman; ls") - self.assertEqual( - "anouman-%(version)s.tar.gz\nsite1.com.tar.gz" % {'version':VERSION}, - out.strip() - ) - - def test_7_install_site1(self): - print "cd /home/anouman; /usr/bin/yes | anouman --deploy site1.com.tar.gz" - out = self.exec_s1("cd /home/anouman; /usr/bin/yes | anouman --deploy site1.com.tar.gz") - - print "out: ", out diff --git a/test/django/site1/manage.py b/test/django/site1/manage.py deleted file mode 100644 index 952e57a..0000000 --- a/test/django/site1/manage.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site1.settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff --git a/test/django/site1/site1/__init__.py b/test/django/site1/site1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/django/site1/site1/settings.py b/test/django/site1/site1/settings.py deleted file mode 100644 index 72dfd64..0000000 --- a/test/django/site1/site1/settings.py +++ /dev/null @@ -1,158 +0,0 @@ -# Django settings for site1 project. - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - # ('Your Name', 'your_email@example.com'), -) - -MANAGERS = ADMINS - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': '', # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': '', - 'PASSWORD': '', - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - } -} - -# Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'America/Chicago' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True - -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" -MEDIA_URL = '' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" -STATIC_ROOT = '' - -# URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" -STATIC_URL = '/static/' - -# Additional locations of static files -STATICFILES_DIRS = ( - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) - -# Make this unique, and don't share it with anybody. -SECRET_KEY = '_)@har^yqnqhw(nt!)5&_=)39%_+)6q%ee#0hy8h^^*&z^#&!4' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = 'site1.urls' - -# Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = 'site1.wsgi.application' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', -) - -SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer' - -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} diff --git a/test/django/site1/site1/urls.py b/test/django/site1/site1/urls.py deleted file mode 100644 index 21b4ff0..0000000 --- a/test/django/site1/site1/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.conf.urls import patterns, include, url - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('', - # Examples: - url(r'^$', 'site1.views.home', name='home'), - # url(r'^site1/', include('site1.foo.urls')), - - # Uncomment the admin/doc line below to enable admin documentation: - # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - # url(r'^admin/', include(admin.site.urls)), -) diff --git a/test/django/site1/site1/views.py b/test/django/site1/site1/views.py deleted file mode 100644 index 4fd6507..0000000 --- a/test/django/site1/site1/views.py +++ /dev/null @@ -1,4 +0,0 @@ -from django.http import HttpResponse - -def home(request): - return HttpResponse("Hello From Site1") diff --git a/test/django/site1/site1/wsgi.py b/test/django/site1/site1/wsgi.py deleted file mode 100644 index 40282b3..0000000 --- a/test/django/site1/site1/wsgi.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -WSGI config for site1 project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" -import os - -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "site1.settings" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site1.settings") - -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -from django.core.wsgi import get_wsgi_application -application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/test/django/site2/manage.py b/test/django/site2/manage.py deleted file mode 100644 index 2bcfd5a..0000000 --- a/test/django/site2/manage.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site2.settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff --git a/test/django/site2/site2/__init__.py b/test/django/site2/site2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/django/site2/site2/settings.py b/test/django/site2/site2/settings.py deleted file mode 100644 index d9b8703..0000000 --- a/test/django/site2/site2/settings.py +++ /dev/null @@ -1,158 +0,0 @@ -# Django settings for site2 project. - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - # ('Your Name', 'your_email@example.com'), -) - -MANAGERS = ADMINS - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': '', # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': '', - 'PASSWORD': '', - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - } -} - -# Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'America/Chicago' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True - -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" -MEDIA_URL = '' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" -STATIC_ROOT = '' - -# URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" -STATIC_URL = '/static/' - -# Additional locations of static files -STATICFILES_DIRS = ( - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) - -# Make this unique, and don't share it with anybody. -SECRET_KEY = 'l-4buq75*yn%&k5aps+s(%g@+=$-7ds1$dqleyh7imugm-yse%' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = 'site2.urls' - -# Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = 'site2.wsgi.application' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', -) - -SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer' - -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} diff --git a/test/django/site2/site2/urls.py b/test/django/site2/site2/urls.py deleted file mode 100644 index 9c67a80..0000000 --- a/test/django/site2/site2/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.conf.urls import patterns, include, url - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('', - # Examples: - url(r'^$', 'site2.views.home', name='home'), - # url(r'^site2/', include('site2.foo.urls')), - - # Uncomment the admin/doc line below to enable admin documentation: - # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - # url(r'^admin/', include(admin.site.urls)), -) diff --git a/test/django/site2/site2/views.py b/test/django/site2/site2/views.py deleted file mode 100644 index c8be81b..0000000 --- a/test/django/site2/site2/views.py +++ /dev/null @@ -1,4 +0,0 @@ -from django.http import HttpResponse - -def home(request): - return HttpResponse("Hello From Site2") diff --git a/test/django/site2/site2/wsgi.py b/test/django/site2/site2/wsgi.py deleted file mode 100644 index 7450849..0000000 --- a/test/django/site2/site2/wsgi.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -WSGI config for site2 project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" -import os - -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "site2.settings" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site2.settings") - -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -from django.core.wsgi import get_wsgi_application -application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/test/vm/site1/.vagrant/machines/default/virtualbox/action_provision b/test/vm/site1/.vagrant/machines/default/virtualbox/action_provision deleted file mode 100644 index 1c58a99..0000000 --- a/test/vm/site1/.vagrant/machines/default/virtualbox/action_provision +++ /dev/null @@ -1 +0,0 @@ -1379886284 \ No newline at end of file diff --git a/test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name b/test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name deleted file mode 100644 index 1c58a99..0000000 --- a/test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name +++ /dev/null @@ -1 +0,0 @@ -1379886284 \ No newline at end of file diff --git a/test/vm/site1/.vagrant/machines/default/virtualbox/id b/test/vm/site1/.vagrant/machines/default/virtualbox/id deleted file mode 100644 index 1d2b141..0000000 --- a/test/vm/site1/.vagrant/machines/default/virtualbox/id +++ /dev/null @@ -1 +0,0 @@ -b9bf713a-af78-4055-aba2-91f4b4abbf06 \ No newline at end of file diff --git a/test/vm/site1/Vagrantfile b/test/vm/site1/Vagrantfile deleted file mode 100644 index de106f9..0000000 --- a/test/vm/site1/Vagrantfile +++ /dev/null @@ -1,33 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = "m1" - - # The url from where the 'config.vm.box' box will be fetched if it - # doesn't already exist on the user's system. - config.vm.box_url = "http://files.vagrantup.com/precise64.box" - - # Run bootstrap.sh provisioning script - config.vm.provision :shell, :path => "bootstrap.sh" - - # Create a private network, which allows host-only access to the machine - # using a specific IP. - config.vm.network :private_network, ip: "192.168.100.100" - - # Create a public network, which will make the machine appear as another - #physical device on your network. - # config.vm.network :public_network - - #config.vm.provider :virtualbox do |vb| - # # Don't boot with headless mode - # vb.gui = true - # - # # Use VBoxManage to customize the VM. For example to change memory: - # vb.customize ["modifyvm", :id, "--memory", "1024"] - #end -end diff --git a/test/vm/site1/bootstrap.sh b/test/vm/site1/bootstrap.sh deleted file mode 100644 index e3615ca..0000000 --- a/test/vm/site1/bootstrap.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -sudo apt-get update # Update apt-get -sudo apt-get install -yf vim #VIM because VI isn't cool -sudo apt-get install -yf git # install git -sudo apt-get install -yf nginx # install nginx -sudo apt-get install -yf mysql-client #only install mysql command line client -sudo apt-get install -yf libmysqlclient-dev # needed for django mysql integration - -### PYTHON STUFF -sudo apt-get install -yf python-setuptools -sudo apt-get install -yf python-virtualenv -sudo apt-get install -yf python-dev -sudo apt-get install -yf build-essential diff --git a/test/vm/site1/clean.sh b/test/vm/site1/clean.sh deleted file mode 100644 index b9c5ae1..0000000 --- a/test/vm/site1/clean.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# This file cleans up a server for a fresh anouman install -# Set the domain name of the project here -DOMAINNAME=site1.com - -# Echo Clean up NGINX sites enabled -# TODO Shouldn't we store these locally in our package directory and then just create the symbolic -# link back to the sites-enabled for nginx? If you are worried about conforming then just create a -# symlink in sites-available to. -sudo rm -rf /etc/nginx/sites-enabled/nginx.$DOMAINNAME.conf /etc/nginx/sites-available/nginx.$DOMAINNAME.conf - -# Remove anouman -/usr/bin/yes | sudo pip uninstall anouman - -# Remove all traces of virtualenv -sudo rm -rf /home/anouman/* -sudo rm -rf /home/anouman/.virtualenvs/ - -# Remove the .bash_profile -# Make sure this test never runs on the clients machine! -rm -rf /home/anouman/.bash_profile - - -# Remove the site upstart command -sudo rm -rf /etc/init/site1.com.conf diff --git a/test/vm/site1/install.sh b/test/vm/site1/install.sh deleted file mode 100644 index 7b18040..0000000 --- a/test/vm/site1/install.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -# Install script for vagrant testing machine -ANOUMAN=/vagrant/anouman-0.0.4.0.tar.gz -sudo pip install $ANOUMAN --upgrade diff --git a/version.py b/version.py deleted file mode 100644 index a47295b..0000000 --- a/version.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python - -VERSION = "0.0.4.0" From 7e9bdb6cc4f04c9a1ae9ab592e8e5ec1c1809877 Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 07:14:29 -0500 Subject: [PATCH 02/19] Setting up some gitignore rules --- .gitignore | 3 + ChangeLog | 21 -- MANIFEST.in | 5 - README.md | 139 --------- README.rst | 254 ---------------- README.txt | 4 - anouman/bin/anouman | 44 --- anouman/bin/anouman-admin.py | 150 ---------- anouman/bin/templates/gunicorn_start.template | 33 -- anouman/exceptions/__init__.py | 61 ---- anouman/{bin => management}/__init__.py | 0 .../commands}/__init__.py | 0 anouman/management/commands/anouman.py | 47 +++ anouman/project/create_vm.py | 37 --- anouman/project/deploy.py | 239 --------------- anouman/project/setup.py | 45 --- anouman/settings.py | 122 ++++++++ anouman/templates/Vagrantfile | 33 -- anouman/templates/__init__.py | 122 -------- anouman/templates/clean.sh | 26 -- anouman/templates/gunicorn_start.sh | 27 -- anouman/templates/nginx.conf | 49 --- anouman/templates/shell_commands | 30 -- anouman/templates/test.py | 25 -- anouman/templates/test_expected_results.py | 32 -- anouman/templates/upstart.conf | 5 - anouman/templates/vagrant_bootstrap.sh | 26 -- anouman/urls.py | 21 ++ anouman/utils/find_files.py | 172 ----------- anouman/wsgi.py | 16 + build_and_deploy.sh | 12 - {anouman/project => cloudgroup}/__init__.py | 0 cloudgroup/admin.py | 6 + cloudgroup/apps.py | 8 + cloudgroup/migrations/0001_initial.py | 42 +++ .../migrations}/__init__.py | 0 cloudgroup/models.py | 27 ++ cloudgroup/tests.py | 6 + cloudgroup/views.py | 6 + manage.py | 22 ++ packages.txt | 1 - release_todo | 2 - requirements.txt | 3 + run_tests.sh | 45 --- setup.cfg | 9 - setup.py | 134 --------- test.py | 281 ------------------ test/django/site1/manage.py | 10 - test/django/site1/site1/__init__.py | 0 test/django/site1/site1/settings.py | 158 ---------- test/django/site1/site1/urls.py | 17 -- test/django/site1/site1/views.py | 4 - test/django/site1/site1/wsgi.py | 32 -- test/django/site2/manage.py | 10 - test/django/site2/site2/__init__.py | 0 test/django/site2/site2/settings.py | 158 ---------- test/django/site2/site2/urls.py | 17 -- test/django/site2/site2/views.py | 4 - test/django/site2/site2/wsgi.py | 32 -- .../default/virtualbox/action_provision | 1 - .../default/virtualbox/action_set_name | 1 - .../.vagrant/machines/default/virtualbox/id | 1 - test/vm/site1/Vagrantfile | 33 -- test/vm/site1/bootstrap.sh | 13 - test/vm/site1/clean.sh | 26 -- test/vm/site1/install.sh | 5 - version.py | 3 - 67 files changed, 329 insertions(+), 2588 deletions(-) delete mode 100644 ChangeLog delete mode 100644 MANIFEST.in delete mode 100644 README.md delete mode 100644 README.rst delete mode 100644 README.txt delete mode 100644 anouman/bin/anouman delete mode 100755 anouman/bin/anouman-admin.py delete mode 100755 anouman/bin/templates/gunicorn_start.template delete mode 100644 anouman/exceptions/__init__.py rename anouman/{bin => management}/__init__.py (100%) rename anouman/{bin/templates => management/commands}/__init__.py (100%) create mode 100644 anouman/management/commands/anouman.py delete mode 100644 anouman/project/create_vm.py delete mode 100644 anouman/project/deploy.py delete mode 100644 anouman/project/setup.py create mode 100644 anouman/settings.py delete mode 100644 anouman/templates/Vagrantfile delete mode 100644 anouman/templates/__init__.py delete mode 100644 anouman/templates/clean.sh delete mode 100644 anouman/templates/gunicorn_start.sh delete mode 100644 anouman/templates/nginx.conf delete mode 100644 anouman/templates/shell_commands delete mode 100644 anouman/templates/test.py delete mode 100644 anouman/templates/test_expected_results.py delete mode 100644 anouman/templates/upstart.conf delete mode 100644 anouman/templates/vagrant_bootstrap.sh create mode 100644 anouman/urls.py delete mode 100644 anouman/utils/find_files.py create mode 100644 anouman/wsgi.py delete mode 100755 build_and_deploy.sh rename {anouman/project => cloudgroup}/__init__.py (100%) create mode 100644 cloudgroup/admin.py create mode 100644 cloudgroup/apps.py create mode 100644 cloudgroup/migrations/0001_initial.py rename {anouman/utils => cloudgroup/migrations}/__init__.py (100%) create mode 100644 cloudgroup/models.py create mode 100644 cloudgroup/tests.py create mode 100644 cloudgroup/views.py create mode 100755 manage.py delete mode 100644 packages.txt delete mode 100644 release_todo create mode 100644 requirements.txt delete mode 100755 run_tests.sh delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test.py delete mode 100644 test/django/site1/manage.py delete mode 100644 test/django/site1/site1/__init__.py delete mode 100644 test/django/site1/site1/settings.py delete mode 100644 test/django/site1/site1/urls.py delete mode 100644 test/django/site1/site1/views.py delete mode 100644 test/django/site1/site1/wsgi.py delete mode 100644 test/django/site2/manage.py delete mode 100644 test/django/site2/site2/__init__.py delete mode 100644 test/django/site2/site2/settings.py delete mode 100644 test/django/site2/site2/urls.py delete mode 100644 test/django/site2/site2/views.py delete mode 100644 test/django/site2/site2/wsgi.py delete mode 100644 test/vm/site1/.vagrant/machines/default/virtualbox/action_provision delete mode 100644 test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name delete mode 100644 test/vm/site1/.vagrant/machines/default/virtualbox/id delete mode 100644 test/vm/site1/Vagrantfile delete mode 100644 test/vm/site1/bootstrap.sh delete mode 100644 test/vm/site1/clean.sh delete mode 100644 test/vm/site1/install.sh delete mode 100644 version.py diff --git a/.gitignore b/.gitignore index 920df90..e0f5d9a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ build/* buildenv/* buildenv/lib/python2.7/site-packages/easy-install.pth test/vm/site1/anouman-0.0.4.0.tar.gz + +local.py +db.sqlite3 diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 7a154be..0000000 --- a/ChangeLog +++ /dev/null @@ -1,21 +0,0 @@ -0.0.4.0 - Features: - - Added many unit test - - Initial support for --vm option to autobuild virtual machine for testing - Bug fixes: - Users can now install anouman packages in other directorie. - -0.0.5.0 - Updates: - -Refactored the template code to be more extinsible - -Changed naming scheme of nginx conf from "nginx.domainname.conf" to "domainname" - -Automatic settings of STATIC_ROOT and MEDIA_ROOT - - - Features: - -Better support for multisite installs - -Finished --vm option for auto creation of virtual machines - -0.0.5.1 - Bugs: - -Fixed documentation errors diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 523fde2..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include *.txt -include *.md -include *.rst - -recursive-include anouman *.py * diff --git a/README.md b/README.md deleted file mode 100644 index e3c5594..0000000 --- a/README.md +++ /dev/null @@ -1,139 +0,0 @@ -Anouman Overview -================ - -Anouman is a django site deployment tool that is designed to greatly simplify the process of deploying [Django](https://www.djangoproject.com/) projects behind [gunicorn](http://gunicorn.org/)/[nginx](http://nginx.com/). In the spirit of reusing great open source software Anouman makes use of [virtualenv](https://pypi.python.org/pypi/virtualenv), [virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/), and of course [django](https://www.djangoproject.com/) to help manage the process of deploying your django projects. - -The easiest way to become familiar with Anouman is to dive in and use it by following along with the tutorial below. However, before you begin you will first need to install [vagrant](http://www.vagrantup.com/) and [virtualbox](https://www.virtualbox.org/). You will be using these tools to build a fresh Ubuntu VM to test your django deployment on. - -**Disclaimer:** *Anouman is still very much alpha stage software. As such it has only been tested on Ubuntu 12.04 using the BASH shell. I'd love to hear from others if they get this working in other OS/SHELL combinations.* - -Install Anouman --------------- - -Switch to the python virtualenv you use for development. You are using [virtualenv](http://www.virtualenv.org/en/latest/) for python development right? If not Anouman should still work with your python system packages. - - source /path/to/your/virtualenv/activate - pip install anouman - -Virtual Machine Creation and Provisioning ------------------------------------------ - -**Step 1:** VM Creation - - anouman --vm test1 - -This command uses vagrant to create and spin up a virtual machine in a directory called test1. -As part of this process anouman created an account with sudo privileges. Go ahead and login with user/password=*anouman/anouman*: - - ssh anouman@192.168.100.100 # Password *anouman* - -**Step 2:** Final provisioning - -If you are using sqlite as your database you may skip this step. - -If you are using MySQL or Postgres you will need to install them now. For MySQL: - - sudo apt-get install mysql-server - -You will then need to login to the mysql server and create/setup the appropriate database for your django project. - -If you are using [Postgres](http://www.postgresql.org/download/linux/ubuntu/) you will need to follow a similar [protocal](http://www.postgresql.org/download/linux/ubuntu/) to setup your Postgres database. - - -Assuming this worked then you are ready to walk through the Anouman tutorial and deploy your django project on a fresh virtual machine. - - - -Anouman Setup and Deployment Tutorial ------------------------------ - -### Section 1: Packaging - -This section will assume you have a django project called *example*. Most likely your project is not named *example* -so follow along with your own project by simply replacing *example* with your project's name. - -Before you begin make sure to open a new Terminal window. - -**Step 1:** Create Anouman Package - -In this step you will use Anouman to create a deployable package from your django project. Start by navigating to the directory containing your django project. This is the directory you originally ran *django-admin.py startproject* from. For instance if you ran *django-admin start-project example* from your home directory then you want to be in your home directory when you issue the following command: - - anouman --django-project=example --domainname=example.com - -Behind the scenes your django project was copied into a directory named example.com/src. Inside this directory is another file which contains a listing of python packages you are using for your django projects. This was determiend from the output of "pip freeze". Lastly this directory was tarred and gzipped. AKA an anouman package/bundle. - -### Section2: Deploying - -**Step 1:** Copy files to server - -Scp your Anouman bundle to the virtual machine we created above and then log in. - - scp example.com.tar.gz anouman@192.168.100.100:/home/anouman - -If you are using sqlite and it is not contained in your project directory then you will now need to copy it to the VM as well. *A future version will take care of copying your database to a default location and updating your setting file* - -Return to the terminal where you are logged into your vm or relogin with: - - ssh anouman@192.168.100.100 - -**Step 2:** Install Anouman into the servers system python repository. - - sudo pip install anouman - -**Step 3:** Setup Anouman and deploy your new project. - -*Anouman requires all projects to be installed as a non root user.* - -The first time you run Anouman it will install itself and in the process create a wrapped '*anouman*' virtualenv as well as a wrapped '*example.com*' virtualenv. - - anouman --deploy example.com.tar.gz - -Follow the intructions when this command finishes to update/source your .bash_profile. You should now have your web site deployed behind nginx/gunicorn. Your projects system packages are now located in the default virtualenv wrapper location */home/anouman/.virtualenvs/example.com*. If you are unfamiliar with the [virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/) I highly recommend taking a little time to become familiar with it. - -Anouman has also modified your STATIC_ROOT and MEDIA_ROOT variables in settings.py to point to *example.com/static* and *example.com/media* respectively. The goal here is to have each site completely contained in a single directory with nginx logs, gunicorn logs, static files, and your source code. *This makes it trivial to move your site to a new server using anouman.* - -Your site should now be running behind nginx/gunicon with static files properly being servered, however you still have a few steps remaining before everything will work correctly. - -**STep 4:** Ensure your database settings are correct. - -Your site should now be deployed into a directory called */home/anouman/example.com*. Your original django project can be found in *example.com/src*. Please update the DATABASE section of settings.py so that it points to your database. If it was a MySQL or Postgres DB running on localhost then you may only need to populate the database. If it was MySQL or Postgres on a remotely accessible database then you likely have nothing to do. - -If you are using an sqlite database then I recommend you create example.com/DB and copy your sqlite database into this directory. If you are following along with the tutorial then you would change the DATABASE NAME section in your settings.py file to /home/anouman/example.com/DB/{name_of_your_db} - -**Step 5** Explore Anouman Shell Commands - -Assuming you updated and sourced .bash_profile at the end of the deployment step you will now have a few shell commands that were appended to the end of your sites virtualenv activate script which is locate in . For instance to check the status of gunicorn/nginx type: - - site status - -Now let's bring it up.. - - site start - -Likewise you can stop your site with: - - site stop - -Go ahead and bring the site back up: - - site start - -You can force nginx to do a reload with: - - site reload - -These site management commands are specific to the site curently being worked on. If you install another django project Anouman will gladly set it up for you and ensure that nginx properly directs traffic to the appropriate django back end and it's all managed with virtualenv and virtualenvwrapper. To switch between sites deployed with Anouman is as simple as switching wrapped virtualenv's. For ex: workon example.com, workon site2.com, etc. - -**Step 6:** Adjust client */etc/hosts* file to simulate DNS for your web site. - -First make sure your site is running (see step 5). Next, add the following line to your */etc/hosts*. - - 192.168.100.100 www.example.com example.com - -If you setup another site, say site2.com, on the same server then you would add another line to /etc/hsots - - 192.168.100.100 www.site2.com site1.com - -NGINX will now properly direct traffic based on the URL to the correct gunicorn/django backend as well as server the correct static files for the given project. - -**Step 7:** Now point your browser to example.com and you should see your django website. Enjoy. diff --git a/README.rst b/README.rst deleted file mode 100644 index ee480e0..0000000 --- a/README.rst +++ /dev/null @@ -1,254 +0,0 @@ -Anouman Overview -================ - -Anouman is a django site deployment tool that is designed to greatly -simplify the process of deploying -`Django `__ projects behind -`gunicorn `__/`nginx `__. In -the spirit of reusing great open source software Anouman makes use of -`virtualenv `__, -`virtualenvwrapper `__, -and of course `django `__ to help manage -the process of deploying your django projects. - -The easiest way to become familiar with Anouman is to dive in and use it -by following along with the tutorial below. However, before you begin -you will first need to install `vagrant `__ -and `virtualbox `__. You will be using -these tools to build a fresh Ubuntu VM to test your django deployment -on. - -**Disclaimer:** *Anouman is still very much alpha stage software. As -such it has only been tested on Ubuntu 12.04 using the BASH shell. I'd -love to hear from others if they get this working in other OS/SHELL -combinations.* - -Install Anouman ---------------- - -Switch to the python virtualenv you use for development. You are using -`virtualenv `__ for python -development right? If not Anouman should still work with your python -system packages. - -:: - - source /path/to/your/virtualenv/activate - pip install anouman - -Virtual Machine Creation and Provisioning ------------------------------------------ - -**Step 1:** VM Creation - -:: - - anouman --vm test1 - -This command uses vagrant to create and spin up a virtual machine in a -directory called test1. As part of this process anouman created an -account with sudo privileges. Go ahead and login with -user/password=\ *anouman/anouman*: - -:: - - ssh anouman@192.168.100.100 # Password *anouman* - -**Step 2:** Final provisioning - -If you are using sqlite as your database you may skip this step. - -If you are using MySQL or Postgres you will need to install them now. -For MySQL: - -:: - - sudo apt-get install mysql-server - -You will then need to login to the mysql server and create/setup the -appropriate database for your django project. - -If you are using -`Postgres `__ you will -need to follow a similar -`protocal `__ to setup -your Postgres database. - -Assuming this worked then you are ready to walk through the Anouman -tutorial and deploy your django project on a fresh virtual machine. - -Anouman Setup and Deployment Tutorial -------------------------------------- - -Section 1: Packaging -~~~~~~~~~~~~~~~~~~~~ - -This section will assume you have a django project called *example*. -Most likely your project is not named *example* so follow along with -your own project by simply replacing *example* with your project's name. - -Before you begin make sure to open a new Terminal window. - -**Step 1:** Create Anouman Package - -In this step you will use Anouman to create a deployable package from -your django project. Start by navigating to the directory containing -your django project. This is the directory you originally ran -*django-admin.py startproject* from. For instance if you ran -*django-admin start-project example* from your home directory then you -want to be in your home directory when you issue the following command: - -:: - - anouman --django-project=example --domainname=example.com - -Behind the scenes your django project was copied into a directory named -example.com/src. Inside this directory is another file which contains a -listing of python packages you are using for your django projects. This -was determiend from the output of "pip freeze". Lastly this directory -was tarred and gzipped. AKA an anouman package/bundle. - -Section2: Deploying -~~~~~~~~~~~~~~~~~~~ - -**Step 1:** Copy files to server - -Scp your Anouman bundle to the virtual machine we created above and then -log in. - -:: - - scp example.com.tar.gz anouman@192.168.100.100:/home/anouman - - -If you are using sqlite and it is not contained in your project -directory then you will now need to copy it to the VM as well. *A future -version will take care of copying your database to a default location -and updating your setting file* - -Return to the terminal where you are logged into your vm or relogin -with: - -:: - - ssh anouman@192.168.100.100 - -**Step 2:** Install Anouman into the servers system python repository. - -:: - - sudo pip install anouman - -**Step 3:** Setup Anouman and deploy your new project. - -*Anouman requires all projects to be installed as a non root user.* - -The first time you run Anouman it will install itself and in the process -create a wrapped '*anouman*\ ' virtualenv as well as a wrapped -'*example.com*\ ' virtualenv. - -:: - - anouman --deploy example.com.tar.gz - -Follow the intructions when this command finishes to update/source your -.bash\_profile. You should now have your web site deployed behind -nginx/gunicorn. Your projects system packages are now located in the -default virtualenv wrapper location -*/home/anouman/.virtualenvs/example.com*. If you are unfamiliar with the -`virtualenvwrapper `__ -I highly recommend taking a little time to become familiar with it. - -Anouman has also modified your STATIC\_ROOT and MEDIA\_ROOT variables in -settings.py to point to *example.com/static* and *example.com/media* -respectively. The goal here is to have each site completely contained in -a single directory with nginx logs, gunicorn logs, static files, and -your source code. *This makes it trivial to move your site to a new -server using anouman.* - -Your site should now be running behind nginx/gunicon with static files -properly being servered, however you still have a few steps remaining -before everything will work correctly. - -**STep 4:** Ensure your database settings are correct. - -Your site should now be deployed into a directory called -*/home/anouman/example.com*. Your original django project can be found -in *example.com/src*. Please update the DATABASE section of settings.py -so that it points to your database. If it was a MySQL or Postgres DB -running on localhost then you may only need to populate the database. If -it was MySQL or Postgres on a remotely accessible database then you -likely have nothing to do. - -If you are using an sqlite database then I recommend you create -example.com/DB and copy your sqlite database into this directory. If you -are following along with the tutorial then you would change the DATABASE -NAME section in your settings.py file to -/home/anouman/example.com/DB/{name\_of\_your\_db} - -**Step 5** Explore Anouman Shell Commands - -Assuming you updated and sourced .bash\_profile at the end of the -deployment step you will now have a few shell commands that were -appended to the end of your sites virtualenv activate script which is -locate in . For instance to check the status of gunicorn/nginx type: - -:: - - site status - -Now let's bring it up.. - -:: - - site start - -Likewise you can stop your site with: - -:: - - site stop - -Go ahead and bring the site back up: - -:: - - site start - -You can force nginx to do a reload with: - -:: - - site reload - -These site management commands are specific to the site curently being -worked on. If you install another django project Anouman will gladly set -it up for you and ensure that nginx properly directs traffic to the -appropriate django back end and it's all managed with virtualenv and -virtualenvwrapper. To switch between sites deployed with Anouman is as -simple as switching wrapped virtualenv's. For ex: workon example.com, -workon site2.com, etc. - -**Step 6:** Adjust client */etc/hosts* file to simulate DNS for your web -site. - -First make sure your site is running (see step 5). Next, add the -following line to your */etc/hosts*. - -:: - - 192.168.100.100 www.example.com example.com - -If you setup another site, say site2.com, on the same server then you -would add another line to /etc/hsots - -:: - - 192.168.100.100 www.site2.com site1.com - -NGINX will now properly direct traffic based on the URL to the correct -gunicorn/django backend as well as server the correct static files for -the given project. - -**Step 7:** Now point your browser to example.com and you should see -your django website. Enjoy. diff --git a/README.txt b/README.txt deleted file mode 100644 index 751fc4e..0000000 --- a/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -anouman -====== - -A django wrapper designed to setup project so they are easily deployable with nginx diff --git a/anouman/bin/anouman b/anouman/bin/anouman deleted file mode 100644 index 5e0698b..0000000 --- a/anouman/bin/anouman +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# control whether we are working in test mode or not -TEST=false - -USER=`whoami` -if [ $USER == 'root' ]; -then - echo "You need to run this as a normal mode user" - exit -fi - -if [[ "$@" == *--deploy* ]] -then - if [ ! -d "~/.virtualenvs/anouman" ]; then - echo "Setting up anouman an server" - - echo "Install virtualwrapper" - sudo pip install virtualenvwrapper -q - source /usr/local/bin/virtualenvwrapper.sh; - - echo "Setting up anouman virtualenv" - mkvirtualenv anouman; - workon anouman; - - #echo "Installing django into anouman virtualenv" - pip install django -q - - if [ $TEST ]; then - ~/.virtualenvs/anouman/bin/pip install /vagrant/anouman-*.tar.gz --upgrade - else - pip install anouman --upgrade -q - fi - echo "anouman basic setup now finished" - fi -fi - -if [ $1 ]; -then - echo "calling anouman-admin.py $@" - anouman-admin.py $@ -else - echo "anouman" -fi diff --git a/anouman/bin/anouman-admin.py b/anouman/bin/anouman-admin.py deleted file mode 100755 index 7a289bc..0000000 --- a/anouman/bin/anouman-admin.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -import os -import argparse - -from anouman.project.setup import package_django_project -from anouman.project.create_vm import build_vm -from anouman.project.deploy import Deploy - -descr=""" - anouman is a django 1.4+ deployment simplifier. - - You provide anouman a django project and anouman provides - you a fully deployable anouman package (aka tarball) - - NOTE: anouman - Currently we can deploy project based on django 1.4 and up. -""" - -def get_args(): - parser = argparse.ArgumentParser( - description=descr - ) - - parser.add_argument('--vm', - help='Create a virtual machine. Pass it the VM name', - dest='vm', - default="", - ) - - parser.add_argument('--domainname', - help='Enter the domain name of your website', - dest='domainname', - default="www.example.com", - ) - - parser.add_argument('--startproject', - help='Start a new django project with default option nginx/gunicorn', - dest='project_name', - default=False, - ) - - parser.add_argument('--django-version', - help='Set the django version. Default to latest version pip repo. (ex: ==1.5.1) note the ==', - dest='django_version', - default='>=1.5, <=1.6', - ) - - parser.add_argument('--django-project', - help='Create deployment for django project. (Assumes one settings file and one wsgi file)', - dest='django_project', - default=False, - ) - - parser.add_argument('--settings', - help='Specify path to settings.py', - dest='settings', - default=False, - ) - - parser.add_argument('--wsgi', - help='Specify path to wsgi.py', - dest='wsgi', - default=False, - ) - - parser.add_argument('--manage', - help='Specify the path to your projects manage.py scrpt', - dest='manage', - default=False, - ) - - parser.add_argument('--virtualenv', - help='Set the virtualev directory.', - dest='virtualenv', - default='virtualenv', - ) - - parser.add_argument('--bind', - help='Set the virtualev directory.', - dest='bind', - default=False, #ex: 10.0.1.13:8001 - ) - - parser.add_argument('--gunicorn', - help='use gunicorn as the django server', - dest='gunicorn', - action='store_true', - default=True, - ) - - parser.add_argument('--deploy', - help='deploy the project', - dest='deploy', - default=False, - ) - - parser.add_argument('--setup', - help='setup anouman', - dest='setup', - action='store_true', - default=False, - ) - - parser.add_argument('--mysql', - help='setup for mysql backed database', - dest='mysql', - action='store_true', - default=True, - ) - - args = parser.parse_args() - - if args.django_project: - args.django_project = os.path.abspath(args.django_project) - - """ By default (neither --socket nor --bind is explicitly passed in) - we bind to --socket=unix:/var/run/your_project.sock - If the --bind={10.0.1.13:8000} option is used - the --socket default is overridden...Even if you pass - --socket yourself. If - """ - if args.bind: - args.socket=False - - return args - - - -if __name__ == '__main__': - print "anouman" - args = get_args() - - if args.vm: - build_vm(args) - - # Project Packaging - if args.django_project: - package_django_project(args) - - # Project Deploying - if args.deploy: - Deploy(args) - - # This is for creating a brand new django project - # TODO do we still want to go this route??? - if args.project_name: - setup.new_project( args ) - - - diff --git a/anouman/bin/templates/gunicorn_start.template b/anouman/bin/templates/gunicorn_start.template deleted file mode 100755 index 96c49bf..0000000 --- a/anouman/bin/templates/gunicorn_start.template +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - - -############ YOU MIGHT BE ABLE TO SKIP THESE STEPS IF YOU USE ABSOLUTE PATHS ################################# -# Change to the DJANGODIR -cd {{DJANGODIR}} - -# source the virtualenv 'activate' file -source {{VIRTUALENVDIR}}/{{NAME}}/bin/activate # Assumes a symbolically linked virtualenv activate command -################################################################################################################ - -# Export your projects settings module -export DJANGO_SETTINGS_MODULE={{DJANGO_SETTINGS_MODULE}} # the settings file Django should use - -# Make sure your project is at the beggening of PYTHONPATH -export PYTHONPATH={{DJANGODIR}}:$PYTHONPATH - -# Create the run directory if it doesn't exist -RUNDIR=$(dirname {{SOCKFILE}}) -test -d $RUNDIR || mkdir -p $RUNDIR - -# Start gunicorn -exec {{VIRTUALENVDIR}}/{{NAME}}/bin/gunicorn {{DJANGO_WSGI_MODULE}}:application - --name {{NAME}} - --workers {{NUM_WORKERS}} - --user={{USER}} - --group={{GROUP}} - --log-level=debug - {% if SOCKFILE %}--bind=unix:{{SOCKFILE}} {% endif %} - {% if BIND %}--bind={{BIND}}{% endif %} - {% if DAEMON %} --daemon{% endif %} - -echo "gunicorn start for site: {{NAME}}" diff --git a/anouman/exceptions/__init__.py b/anouman/exceptions/__init__.py deleted file mode 100644 index 6fa4469..0000000 --- a/anouman/exceptions/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -""" - Defining some Error base classes -""" - -class MultipleError(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) - -class NotFoundError(Exception): - def __init__(self, msg=''): - self.msg = msg - - def __str__(self): - return repr(self.msg) - -""" - settings.py related exceptions -""" -class MultipleSettingError(MultipleError): - def __str__(self): - out = repr(self.value) - out = out + "\ntry running with --settings" - return out - -class NoSettingsError(NotFoundError): - def __str__(self): - if not self.msg: - return "settings.py not found" - -""" - wsgi.py related exceptions -""" -class MultipleWSGIError(MultipleError): - def __str__(self): - out = repr(self.value) - out = out + "\ntry running with --wsgi" - return out - -class NoWSGIError(NotFoundError): - def __str__(self): - if not self.msg: - return "wsgi.py not found" - -""" - manage.py related exceptions -""" -class MultipleMANAGEError(MultipleError): - def __str__(self): - out = repr(self.value) - out = out + "\ntry running with --manage" - return out - - -class NoMANAGEError(NotFoundError): - def __str__(self): - if not self.msg: - return "manage.py not found" - - diff --git a/anouman/bin/__init__.py b/anouman/management/__init__.py similarity index 100% rename from anouman/bin/__init__.py rename to anouman/management/__init__.py diff --git a/anouman/bin/templates/__init__.py b/anouman/management/commands/__init__.py similarity index 100% rename from anouman/bin/templates/__init__.py rename to anouman/management/commands/__init__.py diff --git a/anouman/management/commands/anouman.py b/anouman/management/commands/anouman.py new file mode 100644 index 0000000..e9d3694 --- /dev/null +++ b/anouman/management/commands/anouman.py @@ -0,0 +1,47 @@ +from django.core.management.base import BaseCommand, CommandError + +class Command(BaseCommand): + help = 'Manage your infrastructure' + + def add_arguments(self, parser): + parser.add_argument('--create', help="create a new digitial ocean droplet", type=bool) + parser.add_argument('--name', help="The name of the droplet") + parser.add_argument('--region', help="The digitial ocean region") + parser.add_argument('--size_slug', help="The droplet size") + parser.add_argument('--backups', help="Enable backups", type=bool, default=False) + parser.add_argument('--monitoring', help="Enable/Disable monitoring.", type=bool, default=False) + parser.add_argument('--private', help="Enable private networking", type=bool, default=False) + + + def get_keys(self): + for tries in range(11): + try: + manager = do.Manager(token=TOKEN) + return manager.get_all_sshkeys() + except do.baseapi.DataReadError: + if tries > 10: raise + else: pass + + def create_droplet(self, **kwargs): + print("CREATING DROPLET") + # Create Keys + #keys = self.get_keys() + + # Create Droplet + """ + droplet = do.Droplet( + token=TOKEN, + name=kwargs.get('name', 'qa.teaquinox.com'), + region=kwargs.get('region', 'nyc2'), # New York 2 + image=kwargs.get('image', 'ubuntu-16-04-x64'), # Ubuntu 16.04 x64 + size_slug=kwargs.get('size_slug', '512mb'), # 512MB + ssh_keys=keys, + backups=kwargs.get('backups', False), + monitoring=kwargs.get('monitoring', True), + private_networking=kwargs.get('private_networking', False) + ) + droplet.create() + """ + + def handle(self, *args, **options): + print(options) diff --git a/anouman/project/create_vm.py b/anouman/project/create_vm.py deleted file mode 100644 index 8a59aa6..0000000 --- a/anouman/project/create_vm.py +++ /dev/null @@ -1,37 +0,0 @@ -import os, subprocess - -from anouman.templates import ( - VagrantTemplate, - VagrantBootstrapTemplate, - CleanTemplate, -) - -def build_vm(args): - if not args.vm: - raise Exception("build_vm must be callsed with args.mv=name") - - os.mkdir(args.vm) - os.chdir(args.vm) - # Write the Vagrantfile - VagrantTemplate.save("Vagrantfile", context={ - 'NAME':args.vm, - 'PUBLIC':True - }) - - # Write teh bootstrap file - VagrantBootstrapTemplate.save(path="./bootstrap.sh", context={ - 'NGINX':True, - 'MYSQL':True, - }) - - # Write the clean file - CleanTemplate.save(path="./clean.sh", context={'DOMAINNAME':'site3.com'}) - - subprocess.call(['vagrant', 'up']) - print "#########################################" - print "# #" - print "# Your VM is ready. #" - print "# To login use the collowing command #" - print "# ssh anouman@192.168.100.100 #" - print "# #" - print "#########################################" diff --git a/anouman/project/deploy.py b/anouman/project/deploy.py deleted file mode 100644 index af81984..0000000 --- a/anouman/project/deploy.py +++ /dev/null @@ -1,239 +0,0 @@ -import os, stat, shutil -from os.path import expanduser -import getpass -import subprocess - - -from anouman.templates import ( - GunicornTemplate, - UpstateTemplate, - NginxTemplate, - ShellCommandTemplate, -) - -from anouman.utils.find_files import ( - get_settings, - get_wsgi, - get_manage, - set_static_roots, -) - - -class Deploy(): - """ - To Deploy a site simply call Deploy(args) - """ - def __init__(self, args): - # Next we unpack the project - # subproces, tar returns zero on success... - if subprocess.call(["tar", "xvfz", args.deploy]): - raise Exception( "Call to subprocess failed on tar unpack" ) - - # Set both args.domainname AND args.django_project to the deploy basename - args.domainname = args.deploy.split(".tar.gz")[0] - args.django_project=args.domainname+"/src" - - home = expanduser("~") - # absolute path to the virtualenv - self.VIRTUALENV = home+"/.virtualenvs/%s"%(args.domainname) - - # absoluate path to virtualenv/bin/ - self.VIRTBIN=os.path.abspath("%s/bin"%(self.VIRTUALENV)) - - # absolute path to the virtualenv pip - self.PIP="%s/pip"%(self.VIRTBIN) - - # absolute path the virtualenv python interpretor - self.PYTHON="%s/python"%(self.VIRTBIN) - - # absolute path the vitualenv activate script - self.ACTIVATE="%s/activate"%(self.VIRTBIN) - - # absolute path to the project LOGDIR - self.LOG_DIR = os.getcwd() +"/%s/logs"%(args.domainname) - - # absolute path to the gunicorn_start.sh script - self.GUNICORN_START="%s/gunicorn_start"%(self.VIRTBIN) - - # SETTINGS project path: ex project.settings - # settings absolute path to the settings.py - [self.settings, self.SETTINGS] = get_settings(args) - - # absolute path to the project wsgi.py - self.WSGI = get_wsgi(args) - - # absolute path to manage.py - self.MANAGE = get_manage(args) #get abspath of manage.py - - # Create log directory if it doesn't exist - if not os.path.isdir(self.LOG_DIR): - os.makedirs(self.LOG_DIR) - - - self.deploy_django_project(args) - - - def deploy_django_project(self, args): - """ - This is the primary deploy method - """ - - # Create a virtualenv - subprocess.call(["virtualenv", self.VIRTUALENV]) - - # Append anouman shell command to activate script - ShellCommandTemplate.save(self.ACTIVATE, context={'DOMAINNAME':args.domainname}) - - # Create the gunicorn_start.sh file - self.Setup_Gunicorn_Start(args) - - # Create the upstart files in /etc/init - self.SetupUpstart(args) - - # Create the NGINX files - self.SetupNGINX(args) - - # Install the python packages - self.install_python_packages(args) - - # Run collectstatic command - #subprocess.call([self.PYTHON, self.MANAGE, "collectstatic"]) - print '''/bin/echo "yes" | %s %s collectstatic'''%(self.PYTHON, self.MANAGE) - os.system( '''/bin/echo "yes" | %s %s collectstatic'''%(self.PYTHON, self.MANAGE) ) - #subprocess.call(['''/bin/echo "yes" | %s %s collectstatic'''%(self.PYTHON, self.MANAGE)]) - - """ - Print output message - """ - print "#######################################################################" - print " " - print " SETUP COMPLETE " - print " " - print " Please add the following line(s) to your .bash_profile " - print " " - print " source /usr/local/bin/virtualenvwrapper.sh " - print " workon %s "%(args.domainname) - print " " - print " Then call source on .bash_profile " - print " $source ~/.bash_profile " - print " " - print "#######################################################################" - - - - def SetupNGINX(self, args): - """ - nginx script for the site. - place in: domainname/etc/nginx/sites-available - and in: /etc/nginx/sites-available - link to: /etc/nginx/sites-enabled - - Anouman should eventually be able to bring your sites on - and off line simple by removing the symlink - - Must pass an args with minimally: - args.domainname - args.django_project OR args.settings - """ - - # update STATIC_ROOT and MEDIA_ROOT in settings.py to reflect the install location - [self.STATIC_ROOT, self.MEDIA_ROOT] = set_static_roots(args) - - # Create the project etc/nginx/sites_available directory - if not os.path.exists( "%s/etc/nginx/sites-available/"%(args.domainname) ): - os.makedirs("%s/etc/nginx/sites-available/"%(args.domainname) ) - - # Save nginx config ot project/etc/nginx/sites-available - NGINX_CONF="%s/etc/nginx/sites-available/%s"%(args.domainname, args.domainname) - NginxTemplate.save(NGINX_CONF, context={ - 'UNIXBIND':'unix:/var/run/%s.sock' %(args.domainname), - 'DOMAINNAME':args.domainname, - 'DJANGO_STATIC':self.STATIC_ROOT, - 'DJANGO_MEDIA':self.MEDIA_ROOT, - 'ACCESS_LOG':"%s/nginx-access.log"%(self.LOG_DIR), - 'ERROR_LOG':"%s/nginx-error.log"%(self.LOG_DIR), - }) - - # Remove any prior installs - os.system("rm -f /etc/nginx/sites-available/%(dn)s /etc/nginx/sites-enabled/%(dn)s"% {'dn':args.domainname} ) - - # Copy the /etc/nginx files to /etc/nginx - os.system("sudo cp -r %s/etc/nginx/* /etc/nginx/" %(args.domainname)) - - # Symlink sites-available to sites enabled - os.system("sudo ln -s /etc/nginx/sites-available/%(dn)s /etc/nginx/sites-enabled/%(dn)s"% {'dn':args.domainname} ) - - - def SetupUpstart(self, args): - """ - Now we create the gunicorn upstart scripts - """ - NAME=args.domainname+".conf" - - UpstateTemplate.save(NAME, context={ - 'GUNICORN_START':self.GUNICORN_START, - 'DOMAINNAME':args.domainname, - }) - - os.system("sudo mv %s /etc/init/%s"%(NAME, NAME) ) - - - def Setup_Gunicorn_Start(self, args): - """ - Setup and install gunicorn_start.sh on the server - - default context located: anouman/templates/gunicorn_start.sh - install location {virtenv}/bin/gunicorn_start.sh - """ - - # set DJANGODIR env variable to abspath of project root. - NAME=os.path.basename(args.django_project) - DJANGODIR=os.path.abspath(args.domainname + "/" + NAME) - - GunicornTemplate.save(self.GUNICORN_START, context={ - 'NAME':args.domainname, - 'USER':getpass.getuser(), - 'GROUP':getpass.getuser(), - 'GUNICORN':"%s/gunicorn"%(self.VIRTBIN), - 'DJANGODIR':DJANGODIR, - 'DJANGO_SETTINGS_MODULE':self.SETTINGS, - 'DJANGO_WSGI_MODULE':self.WSGI, - 'ACCESS_LOG':"%s/gunicorn-access.log"%(self.LOG_DIR), - 'ERROR_LOG':"%s/gunicorn-error.log"%(self.LOG_DIR), - 'BIND':args.bind if args.bind else 'unix:/var/run/%s.sock' %(args.domainname), - }) - - # Set Permissions on the GUNICORN file - os.chmod(self.GUNICORN_START, stat.S_IRWXU|stat.S_IRWXG|stat.S_IXOTH) - - return self.GUNICORN_START - - def install_python_packages(self, args): - """ - This section installs the users python packages into their site virtualenv - TODO: This should have better reporting for failing packages - """ - pkg_success = [] - pgk_fails = [] - with open("%s/pip_packages.txt"%(args.domainname)) as f: - PACKAGES = f.readlines() - PACKAGES.append("gunicorn") - for package in PACKAGES: - try: - subprocess.call([self.PIP, "install", package]) - pkg_success.append(package) - except: - pgk_fails.append(package) - - subprocess.call([self.PIP, "install", "-r", "%s/pip_packages.txt"%(args.domainname)]) - print "Package Installation Results" - print "SUCCESS: %s" %(len(pkg_success)) - print "FAIL: %s" %(len(pgk_fails)) - for f in pgk_fails: - print "\t*\t%s"%(f) - - - -if __name__ == '__main__': - print "This does nothing" - pass diff --git a/anouman/project/setup.py b/anouman/project/setup.py deleted file mode 100644 index 1c74538..0000000 --- a/anouman/project/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -import os -import subprocess - - -from anouman.utils.find_files import ( - get_settings, - get_wsgi, -) - -def package_django_project(args): - # settings is the full path - # SETTINGS is the django projec path, exL finance.settings - [settings, SETTINGS] = get_settings(args) - - # TODO Should this all be done in deploy? - os.makedirs(args.domainname) - os.makedirs("%s/bin"%(args.domainname)) - os.makedirs("%s/etc/nginx/sites-available"%(args.domainname)) - os.makedirs("%s/etc/init"%(args.domainname)) - - """ - Install packages from project environment into the new virtualenv. - Also store the status for success/fail as we install them - """ - pip = subprocess.check_output(['which', 'pip']) - print "pip: ", pip - print "Saving pacakges to: ", "%s/pip_packages.txt"%(args.domainname) - os.system("pip freeze > %s/pip_packages.txt"%(args.domainname)) - - - """ - Now we copy your django project into the virtual env - """ - print "Copying your source tree into the virtual env" - print "args.django_project: ", args.django_project - print "args.domainname: ", args.domainname - subprocess.call(['cp', '-r', args.django_project, args.domainname+"/src"]) - subprocess.call(['tar', '-cf', args.domainname+".tar", args.domainname]) - subprocess.call(['gzip', args.domainname+".tar"]) - subprocess.call(["rm", "-rf", args.domainname]) - - -if __name__ == '__main__': - print "This does nothing" - pass diff --git a/anouman/settings.py b/anouman/settings.py new file mode 100644 index 0000000..395441b --- /dev/null +++ b/anouman/settings.py @@ -0,0 +1,122 @@ +""" +Django settings for anouman project. + +Generated by 'django-admin startproject' using Django 1.11.10. + +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 = ')6cjz&2&@mk7@v+3v2bn%0_-r-kk-qk^io!0x@gi($(q8r4)@r' + +# 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', + 'anouman', + 'cloudgroup', +] + +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 = 'anouman.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 = 'anouman.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/anouman/templates/Vagrantfile b/anouman/templates/Vagrantfile deleted file mode 100644 index 92bea45..0000000 --- a/anouman/templates/Vagrantfile +++ /dev/null @@ -1,33 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = "{{NAME}}" - - # The url from where the 'config.vm.box' box will be fetched if it - # doesn't already exist on the user's system. - config.vm.box_url = "http://files.vagrantup.com/precise64.box" - - # Run bootstrap.sh provisioning script - config.vm.provision :shell, :path => "bootstrap.sh" - {% if PRIVATE %} - # Create a private network, which allows host-only access to the machine - # using a specific IP. - config.vm.network :private_network, ip: "{{PRIVATE}}" - {% else %} - # Create a public network, which will make the machine appear as another - #physical device on your network. - config.vm.network :public_network - {% endif %} - #config.vm.provider :virtualbox do |vb| - # # Don't boot with headless mode - # vb.gui = true - # - # # Use VBoxManage to customize the VM. For example to change memory: - # vb.customize ["modifyvm", :id, "--memory", "1024"] - #end -end diff --git a/anouman/templates/__init__.py b/anouman/templates/__init__.py deleted file mode 100644 index 315fab0..0000000 --- a/anouman/templates/__init__.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -import os -from django.template import Template, Context -from django.conf import settings - -settings.configure() - -class BaseTemplate: - """ - This is the base class for template rendering - Each template to render should extend from this class and - override minimalliy the context and template properties. - """ - - # absolute path to the template file - template = '' - - # The context that will be passed to the template - # Sublcasses should specify their own context parameters - context = {} - - @classmethod - def render(cls, c={}): - """ - Pass in a context our the defaults above will be used - """ - cls.context.update(c) - t = Template( open(cls.template).read() ) - c = Context( cls.context ) - return t.render( c ) - - @classmethod - def save(cls, path, **kwargs): - """ - path is the path to where the file will be saved - """ - c = kwargs.get('context', cls.context) - with open(path, 'w') as f: - f.write(cls.render(c) ) - -class VagrantTemplate(BaseTemplate): - template = os.path.dirname(os.path.realpath(__file__)) + "/Vagrantfile" - context = { - 'NAME':'site1', - 'PRIVATE':'192.168.100.100', #To use private network set to ip: 192.168.100.100 - } - -class GunicornTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/gunicorn_start.sh" - - context = { - 'NAME':'website', # Name of the application - 'DJANGODIR':'./', # Django project director - 'USER':'username', # user to run as - 'GROUP':'username', # group to run as - 'NUM_WORKERS':3, # Number of Gunicorn threads. 2(proc)+1 - 'VIRTUALENVDIR':'./virtualenv', # Directory containing your projects virtual env - 'DJANGO_SETTINGS_MODULE':'website.settings', # the django settings file - 'DJANGO_WSGI_MODULE':'website.wsgi', # your project wsgi module - 'GUNICORN':'virtualenv/bin/gunicorn', # location of gunicorn.py - 'ERROR_LOG':'/var/log/gunicorn-error.log', # recommend setting this to domain/logs/gunicorn-error.log - 'ACCESS_LOG':'/var/log/gunicorn-access.log', # recommend setting this to domain/logs/gunicorn-error.log - 'SOCKFILE':False, # ex: /var/run/gunicorn.sock - # You can bind your server to a unix socket or to a port - # But you should only bind it to one or the other - # unix socket example: /var/run/gunicorn.sock - # ip:port example: 10.0.2.13:8000 - 'BIND':False, # ex: 10.0.2.13:80 Use - } - -class NginxTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/nginx.conf" - context = { - 'UNIXBIND':'', - 'DOMAINNAME':'', - 'DJANGO_STATIC':'', - 'DJANGO_MEDIA':'', - 'ACCESS_LOG':'', # Project/Site based logs - 'ERROR_LOG':'' # Project/Site based logs - } - -class VagrantBootstrapTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/vagrant_bootstrap.sh" - - context = { - 'NGINX':True, - 'MYSQL':False, - } - -class UpstateTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/upstart.conf" - - context = { - 'GUNICORN_START':'', # The abspath to the gunicorn_start script - 'DOMAINNAME':'', # The domain name - } - - -class ShellCommandTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/shell_commands" - - context = { - 'DOMAINNAME':'', - } - - @classmethod - def save(cls, path="./site.conf", **kwargs): - """ - Overridden because we need to append and not write to the activate file - """ - c = kwargs.get('context', cls.context) - with open(path, 'a') as f: - f.write(cls.render(c) ) - - -class CleanTemplate(BaseTemplate): - template=os.path.dirname(os.path.realpath(__file__)) + "/clean.sh" - - context = { - 'DOMAINNAME':'site1.com', - } - diff --git a/anouman/templates/clean.sh b/anouman/templates/clean.sh deleted file mode 100644 index d330698..0000000 --- a/anouman/templates/clean.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# This file cleans up a server for a fresh anouman install -# Set the domain name of the project here -DOMAINNAME={{DOMAINNAME}} - -# Echo Clean up NGINX sites enabled -# TODO Shouldn't we store these locally in our package directory and then just create the symbolic -# link back to the sites-enabled for nginx? If you are worried about conforming then just create a -# symlink in sites-available to. -sudo rm -rf /etc/nginx/sites-enabled/nginx.$DOMAINNAME.conf /etc/nginx/sites-available/nginx.$DOMAINNAME.conf - -# Remove anouman -/usr/bin/yes | sudo pip uninstall anouman - -# Remove all traces of virtualenv -sudo rm -rf /home/anouman/* -sudo rm -rf /home/anouman/.virtualenvs/ - -# Remove the .bash_profile -# Make sure this test never runs on the clients machine! -rm -rf /home/anouman/.bash_profile - - -# Remove the site upstart command -sudo rm -rf /etc/init/site1.com.conf diff --git a/anouman/templates/gunicorn_start.sh b/anouman/templates/gunicorn_start.sh deleted file mode 100644 index ab26669..0000000 --- a/anouman/templates/gunicorn_start.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Export your projects settings module -export DJANGO_SETTINGS_MODULE={{DJANGO_SETTINGS_MODULE}} - -# Make sure your project is at the beginning of PYTHONPATH -export PYTHONPATH={{DJANGODIR}}:$PYTHONPATH - -{# If using a unix socket then create the run directory #} -{% if SOCKFILE %} -# Make sure the directory for teh sockfile is created -RUNDIR=$(dirname {{SOCKFILE}}) -test -d $RUNDIR || mkdir -p $RUNDIR -{% endif %} - -# Start gunicorn -exec {{GUNICORN}} {{DJANGO_WSGI_MODULE}}:application \ - --bind={{BIND}} \ - --name {{NAME}} \ - --workers {{NUM_WORKERS}} \ - --user={{USER}} \ - --log-level=debug \ - --error-logfile {{ERROR_LOG}} \ - --access-logfile {{ACCESS_LOG}} \ - {% if DAEMON %} --daemon \{% endif %} - -echo "gunicorn start for site: {{NAME}}" diff --git a/anouman/templates/nginx.conf b/anouman/templates/nginx.conf deleted file mode 100644 index 4830bf2..0000000 --- a/anouman/templates/nginx.conf +++ /dev/null @@ -1,49 +0,0 @@ -upstream {{DOMAINNAME}} { - # bind to the upstream unix socket and continue to retry even if it failed - # to return a good HTTP response - server {{UNIXBIND}} fail_timeout=0; -} - -server { - - listen 80; - server_name {{DOMAINNAME}} www.{{DOMAINNAME}}; - - client_max_body_size 128M; - - access_log {{ACCESS_LOG}}; - error_log {{ERROR_LOG}}; - - location /static/ { - alias {{DJANGO_STATIC}}; - } - - location /media/ { - alias {{DJANGO_MEDIA}}; - } - - location / { - # set the HTTP header - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # pass the Host: header from the client right along so redirects - # can be set correctly in the Django application - proxy_set_header Host $http_host; - - # we don't want nginx trying to do something clever with - # redirects, we set the Host: header above already. - proxy_redirect off; - - # Let nginx server the static files while gunicorn focuses on the python/db content - if (!-f $request_filename) { - proxy_pass http://{{DOMAINNAME}}; - break; - } - } - - # Error pages - error_page 500 502 503 504 /500.html; - location = /500.html { - root {{DJANGO_STATIC}}; - } -} diff --git a/anouman/templates/shell_commands b/anouman/templates/shell_commands deleted file mode 100644 index 9b41793..0000000 --- a/anouman/templates/shell_commands +++ /dev/null @@ -1,30 +0,0 @@ - -#This section defines commands specified by Anouman - -NGINX=/etc/init.d/nginx -DOMAINNAME={{DOMAINNAME}} - -function site { - if [ $1 == 'status' ]; - then - sudo $NGINX status - sudo status $DOMAINNAME - fi - - if [ $1 == 'stop' ]; - then - sudo $NGINX stop - sudo stop $DOMAINNAME - fi - - if [ $1 == 'start' ]; - then - sudo $NGINX start - sudo start $DOMAINNAME - fi - - if [ $1 == 'reload' ]; - then - sudo nginx -s reload - fi -} diff --git a/anouman/templates/test.py b/anouman/templates/test.py deleted file mode 100644 index 022e054..0000000 --- a/anouman/templates/test.py +++ /dev/null @@ -1,25 +0,0 @@ -import random -import unittest - -from django.conf import settings -settings.configure() - -from anouman.templates import ShellCommandTemplate - -class TestSequenceFunctions(unittest.TestCase): - - def setUp(self): - self.seq = range(10) - - def test_shell_cmd_template(self): - from test_expected_results import shell_commands_expected - context = { - 'DOMAINNAME':'example.com', - } - - out = ShellCommandTemplate.render(context) - self.assertTrue(out == shell_commands_expected) - -if __name__ == '__main__': - suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/anouman/templates/test_expected_results.py b/anouman/templates/test_expected_results.py deleted file mode 100644 index ed3f727..0000000 --- a/anouman/templates/test_expected_results.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -shell_commands_expected=""" -#This section defines commands specified by Anouman - -NGINX=/etc/init.d/nginx -DOMAINNAME=example.com - -function site { - if [ $1 == 'status' ]; - then - sudo $NGINX status - sudo status $DOMAINNAME - fi - - if [ $1 == 'stop' ]; - then - sudo $NGINX stop - sudo stop $DOMAINNAME - fi - - if [ $1 == 'start' ]; - then - sudo $NGINX start - sudo start $DOMAINNAME - fi - - if [ $1 == 'reload' ]; - then - sudo nginx -s reload - fi -}""" diff --git a/anouman/templates/upstart.conf b/anouman/templates/upstart.conf deleted file mode 100644 index 2d7e819..0000000 --- a/anouman/templates/upstart.conf +++ /dev/null @@ -1,5 +0,0 @@ -description "Starting {{DOMAINNAME}}" - -start on startup -exec {{GUNICORN_START}} -respawn diff --git a/anouman/templates/vagrant_bootstrap.sh b/anouman/templates/vagrant_bootstrap.sh deleted file mode 100644 index 835c6de..0000000 --- a/anouman/templates/vagrant_bootstrap.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# Setup anouman user -sudo useradd --shell /bin/bash --home /home/anouman anouman -echo -e "anouman\\nanouman\\n" | sudo passwd anouman -sudo usermod --groups admin anouman -sudo mkdir /home/anouman -sudo chown -R anouman:anouman /home/anouman - -sudo apt-get update # Update apt-get -sudo apt-get install -yf vim # VIM because VI isn't as cool -sudo apt-get install -yf git # install git - -### PYTHON STUFF -sudo apt-get install -yf python-setuptools -sudo apt-get install -yf python-virtualenv -sudo apt-get install -yf python-dev -sudo apt-get install -yf build-essential - -{% if NGINX %} -sudo apt-get install -yf nginx # install nginx -{% endif %} - -{% if MYSQL %} -sudo apt-get install -yf mysql-client # only install mysql command line client -sudo apt-get install -yf libmysqlclient-dev # needed for django mysql integration -{% endif %} diff --git a/anouman/urls.py b/anouman/urls.py new file mode 100644 index 0000000..1456981 --- /dev/null +++ b/anouman/urls.py @@ -0,0 +1,21 @@ +"""anouman 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/anouman/utils/find_files.py b/anouman/utils/find_files.py deleted file mode 100644 index 232210c..0000000 --- a/anouman/utils/find_files.py +++ /dev/null @@ -1,172 +0,0 @@ -import os, sys, re -import fnmatch - -from anouman.exceptions import ( - MultipleSettingError, - NoSettingsError, - MultipleWSGIError, - NoWSGIError, - MultipleMANAGEError, - NoMANAGEError, -) - -def find_file(root_dir, pattern): - """ - This is a generic recursive grep function - """ - matches = [] - for root, dirnames, filenames in os.walk(root_dir): - for filename in fnmatch.filter(filenames, pattern): - matches.append(os.path.join(root, filename)) - return matches - -def get_settings(args): - """ - This function checks for the existence of the settings file. - - If the --settings options is specified then we simply - check to see if the file exists and if so return the name of the - file. - - If no --settings option was given then we look for settings.py - recursivly in the directory defined by --django-project. - -- If multiple settings.py are found we throw an exception. - -- If not settings.py is found we throw an exception. - -- If one settings.py is found we return it's path. - """ - settings_path='' - if not args.settings: - matches = find_file(args.django_project, 'settings.py') - if len(matches) > 1: - raise MultipleSettingError(matches) - elif len(matches) == 0: - print "args.django_project: ", args.django_project - print "search path: %s"%(os.path.abspath(args.django_project)) - raise NoSettingsError() - settings_path= matches[0] - elif not os.path.isfile(args.settings): - raise NoSettingsError() - else: - settings_path = args.settings - - # We now have the path to the settings.py modules, but we need - # to convert it to python module format: settings.wsgi - tmp = settings_path.split(args.django_project) - if len(tmp) == 2: - return [ - os.path.abspath(settings_path), - tmp[1][1:].replace("/", ".").replace(".py", "") - ] - else: - raise NoSettingsError( str(tmp) ) - -def get_wsgi(args): - """ - This function checks for the existence of the wsgi.py file. - - If the --wsgi options is specified then we simply - check to see if the file exists and if so return the name of the - file. - - If no --wsgi option was given then we look for wsgi.py - recursivly in the directory defined by --django-project. - -- If multiple wsgi.py are found we throw an exception. - -- If not wsgi.py is found we throw an exception. - -- If one wsgi.py is found we return it's path. - """ - wsgi_path = '' - if not args.wsgi: - matches = find_file(args.django_project, 'wsgi.py') - if len(matches) > 1: - raise MultipleWSGIError(matches) - if len(matches) == 0: - raise NoWSGIError() - wsgi_path=os.path.abspath( matches[0] ) - elif not os.path.isfile(args.wsgi): - raise NoWSGIError() - else: - wsgi_path = os.path.abspath( args.wsgi ) - - # We now have the path to the wsgi.py modules, but we need - # to convert it to python module format: website.wsgi - tmp = wsgi_path.split( os.path.abspath(args.django_project) ) - if len(tmp) == 2: - return tmp[1][1:].replace("/", ".").replace(".py", "") - else: - raise NoWSGIError( str(tmp) ) - -def get_manage(args): - """ - This function checks for the existence of the manage.py file. - - If the --manage options is specified then we simply - check to see if the file exists and if so return the name of the - file. - - If no --manage option was given then we look for manage.py - recursivly in the directory defined by --django-project. - -- If multiple manage.py are found we throw an exception. - -- If not manage.py is found we throw an exception. - -- If one manage.py is found we return it's path. - """ - manage_path = '' - if not args.manage: - matches = find_file(args.django_project, 'manage.py') - if len(matches) > 1: - raise MultipleMANAGEError(matches) - if len(matches) == 0: - raise NoMANAGEError() - manage_path = matches[0] - elif not os.path.isfile(args.manage): - raise NoMANAGEError() - else: - manage_path = os.path.abspath( args.manage ) - - return os.path.abspath( manage_path ) - -def change_settings(settings_file, pattern, value): - with open(settings_file, 'r') as f: - contents = f.readlines() - - match_count = 0 - for line in contents: - if pattern in line and "#" not in line: - match_count = match_count + 1 - - - if match_count > 1: - print "WARNING: More than one %s line in settings file." %(pattern) - print "Anouman would prefer to have you set this value yourself or remove duplicate %s settings" %(pattern) - return False - - new_contents = [] - for line in contents: - if pattern in line and "#" not in line: - line = "#"+line - new_contents.append(line) - new_contents.append('%s="%s"'%(pattern, value) ) - else: - new_contents.append(line) - - with open(settings_file, 'w') as f: - f.writelines(new_contents) - - # Flush the stdout buffer and force write to disk - sys.stdout.flush() - - return True - -def set_static_roots(args): - """ - We need to change the STATIC_ROOT and MEDIA_ROOT variables - """ - [settings_path, SETTINGS] = get_settings(args) - sys.path.append(os.path.dirname(settings_path)) - import settings - - change_settings(settings_path, r'MEDIA_ROOT', "%s/"%(os.path.abspath("%s/media/" %(args.domainname))) ) - change_settings(settings_path, r'STATIC_ROOT', "%s/"%(os.path.abspath("%s/static/" %(args.domainname))) ) - - reload(settings) - - return [settings.STATIC_ROOT, settings.MEDIA_ROOT] diff --git a/anouman/wsgi.py b/anouman/wsgi.py new file mode 100644 index 0000000..52af5d3 --- /dev/null +++ b/anouman/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for anouman 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", "anouman.settings") + +application = get_wsgi_application() diff --git a/build_and_deploy.sh b/build_and_deploy.sh deleted file mode 100755 index 95b2ca1..0000000 --- a/build_and_deploy.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -source buildenv/bin/activate -rm -rf buildenv/lib/python2.7/site-packages/Dnginx-0.1-py2.7.egg-info/ -rm -rf dist - -rm -rf B/anouman-admin.py A/Dnginx-0.1-py2.7.egg-info/ dist - -python setup.py sdist -pip install dist/anouman-0.1.tar.gz - -ls /Users/jfurr/blank/lib/python2.7/site-packages/anouman/templates/ diff --git a/anouman/project/__init__.py b/cloudgroup/__init__.py similarity index 100% rename from anouman/project/__init__.py rename to cloudgroup/__init__.py diff --git a/cloudgroup/admin.py b/cloudgroup/admin.py new file mode 100644 index 0000000..13be29d --- /dev/null +++ b/cloudgroup/admin.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.contrib import admin + +# Register your models here. diff --git a/cloudgroup/apps.py b/cloudgroup/apps.py new file mode 100644 index 0000000..b5c8737 --- /dev/null +++ b/cloudgroup/apps.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class CloudgroupConfig(AppConfig): + name = 'cloudgroup' diff --git a/cloudgroup/migrations/0001_initial.py b/cloudgroup/migrations/0001_initial.py new file mode 100644 index 0000000..6e00107 --- /dev/null +++ b/cloudgroup/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-02-11 11:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='CloudGroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32)), + ], + ), + migrations.CreateModel( + name='Machine', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32)), + ('droplet_id', models.PositiveSmallIntegerField(blank=True, null=True)), + ('ip', models.GenericIPAddressField(blank=True, null=True)), + ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cloudgroup.CloudGroup')), + ], + ), + migrations.CreateModel( + name='WhiteList', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ip', models.GenericIPAddressField()), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cloudgroup.CloudGroup')), + ], + ), + ] diff --git a/anouman/utils/__init__.py b/cloudgroup/migrations/__init__.py similarity index 100% rename from anouman/utils/__init__.py rename to cloudgroup/migrations/__init__.py diff --git a/cloudgroup/models.py b/cloudgroup/models.py new file mode 100644 index 0000000..5cf677e --- /dev/null +++ b/cloudgroup/models.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models + + +class WhiteList(models.Model): + """ + This model holds a list of all IP addresses that are allowed to ssh into any CloudGroup Machine + """ + ip = models.GenericIPAddressField(blank=False, null=False) + group = models.ForeignKey('CloudGroup', on_delete=models.CASCADE) + + +class Machine(models.Model): + """ + This model holds a single machine instance. + """ + name = models.CharField(max_length=32, blank=False, null=False) + droplet_id = models.PositiveSmallIntegerField(blank=True, null=True) + ip = models.GenericIPAddressField(blank=True, null=True) + group = models.ForeignKey('CloudGroup', on_delete=models.CASCADE, blank=True, null=True) + + +class CloudGroup(models.Model): + name = models.CharField(max_length=32, blank=False, null=False) + diff --git a/cloudgroup/tests.py b/cloudgroup/tests.py new file mode 100644 index 0000000..5982e6b --- /dev/null +++ b/cloudgroup/tests.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.test import TestCase + +# Create your tests here. diff --git a/cloudgroup/views.py b/cloudgroup/views.py new file mode 100644 index 0000000..e784a0b --- /dev/null +++ b/cloudgroup/views.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.shortcuts import render + +# Create your views here. diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..620d893 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "anouman.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/packages.txt b/packages.txt deleted file mode 100644 index 7abea1e..0000000 --- a/packages.txt +++ /dev/null @@ -1 +0,0 @@ -Django>=1.5,<=1.6 diff --git a/release_todo b/release_todo deleted file mode 100644 index acca857..0000000 --- a/release_todo +++ /dev/null @@ -1,2 +0,0 @@ -* Make sure up change pip install path for anouman in the anouman/bin/anouman bash script. - diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..95157dc --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +Django==1.11.10 +django-extensions==1.9.9 +python-digitalocean==1.13.2 diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index de44837..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -############################################# -# # -# Simple Test Driver # -# # -# ./run_tests -q (queit) -f (failfast) # -############################################# - -#QUEIT="" -#if [[ "$@" == *-q* ]]; then -# QUEIT=" > /dev/null" -#fi -# -#FAILFAST="" -#if [[ "$@" == *-f* ]]; then -# FAILFAST=" --failfast " -#fi -# -#VERBOSE="" -#if [[ "$@" == *-v* ]]; then -# VERBOSE=" -v " -#fi -# -#echo "/usr/bin/yes | python -m unittest discover $VERBOSE $FAILFAST $QUEIT" -#exec /usr/bin/yes | python -m unittest discover $VERBOSE $FAILFAST $QUEIT - - - -if [[ "$@" == *-q* ]]; -then - if [[ "$@" == *-f* ]]; - then - /usr/bin/yes | python -m unittest discover -v --failfast > /dev/null - else - /usr/bin/yes | python -m unittest discover -v > /dev/null - fi -else - if [[ "$@" == *-f* ]]; - then - /usr/bin/yes | python -m unittest discover -v --failfast - else - /usr/bin/yes | python -m unittest discover -v - fi -fi diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9e53a95..0000000 --- a/setup.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[bdist_rpm] -doc_files = docs extras AUTHORS INSTALL LICENSE -install-script = scripts/rpm-install.sh - -[metadata] -license-file = LICENSE - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 72d9d2b..0000000 --- a/setup.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import sys -from distutils.core import setup -from distutils.sysconfig import get_python_lib - -from setuptools import find_packages - -VERSION="0.0.5.1" - -# Make sure README.rst is in sync with README.md #*rst used by pypi and *md used by github -os.system("pandoc --from=markdown --to=rst --output=README.rst README.md") - -# Warn if we are installing over top of an existing installation. This can -# cause issues where files that were deleted from a more recent Dnginx are -# still present in site-packages. -overlay_warning = False -if "install" in sys.argv: - # We have to try also with an explicit prefix of /usr/local in order to - # catch Debian's custom user site-packages directory. - for lib_path in get_python_lib(), get_python_lib(prefix="/usr/local"): - existing_path = os.path.abspath(os.path.join(lib_path, "anouman")) - if os.path.exists(existing_path): - # We note the need for the warning here, but present it after the - # command is run, so it's more likely to be seen. - overlay_warning = True - break - - -def fullsplit(path, result=None): - """ - Split a pathname into components (the opposite of os.path.join) - in a platform-neutral way. - """ - if result is None: - result = [] - head, tail = os.path.split(path) - if head == '': - return [tail] + result - if head == path: - return result - return fullsplit(head, [tail] + result) - - -EXCLUDE_FROM_PACKAGES = [] - -def is_package(package_name): - for pkg in EXCLUDE_FROM_PACKAGES: - if package_name.startswith(pkg): - return False - return True - - -# Compile the list of packages available, because distutils doesn't have -# an easy way to do this. -packages, package_data = [], {} - -root_dir = os.path.dirname(__file__) -if root_dir != '': - os.chdir(root_dir) -anouman_dir = 'anouman' - -for dirpath, dirnames, filenames in os.walk(anouman_dir): - # Ignore PEP 3147 cache dirs and those whose names start with '.' - dirnames[:] = [d for d in dirnames if not d.startswith('.') and d != '__pycache__'] - parts = fullsplit(dirpath) - package_name = '.'.join(parts) - if '__init__.py' in filenames and is_package(package_name): - packages.append(package_name) - elif filenames: - relative_path = [] - while '.'.join(parts) not in packages: - relative_path.append(parts.pop()) - relative_path.reverse() - path = os.path.join(*relative_path) - package_files = package_data.setdefault('.'.join(parts), []) - package_files.extend([os.path.join(path, f) for f in filenames]) - - -with open('README.rst') as file: - long_description = file.read() - - -setup( - name='anouman', - version=VERSION, - author='John Furr', - author_email='anouman.dev@gmail.com', - url='https://github.com/gnulnx/anouman', - description=('Rapidly deploy your django project behind gunicorn and nginx'), - long_description=long_description, - download_url='https://github.com/gnulnx/anouman/tree/%s'%(VERSION), - license='BSD', - #packages=packages, - include_package_data = True, - packages=find_packages(), - package_data=package_data, - scripts=['anouman/bin/anouman-admin.py', 'anouman/bin/anouman'], - classifiers=[ - 'Environment :: Web Environment', - 'Development Status :: 2 - Pre-Alpha', - 'Intended Audience :: Developers', - 'Programming Language :: Python', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: WSGI', - ], - install_requires=[ - "virtualenvwrapper", - "django", - # Currently only the django template engine is being used - # but there are plans to have an anouman server monitoring - # protion of the website - #"Django >= 1.2", - ], -) - -if overlay_warning: - sys.stderr.write(""" - -===================== -Danger Will Robinson! -===================== - -You have just installed anouman over top of an existing -installation, without removing it first. Because of this, -your install may now include extraneous files from a -previous version that have since been removed from -Dnginx. This is known to cause a variety of problems. You -should manually remove the - -%(existing_path)s - -directory and re-install Dnginx. - -""" % {"existing_path": existing_path}) diff --git a/test.py b/test.py deleted file mode 100644 index d56a276..0000000 --- a/test.py +++ /dev/null @@ -1,281 +0,0 @@ -import os -import unittest -import time -import subprocess -import paramiko -import shutil -from anouman.templates import ( - vagrant, - vagrant_bootstrap, - clean -) - -for line in open("setup.py"): - if "VERSION" in line: - try: - VERSION = line.split("=")[1].strip().replace('"', '') - break - except: - pass - -try: VERSION -except Exception as e: - raise Exception("VERSION NUMBER NOT FOUND") - -VM1="10.0.1.21" - -class TestBuild(unittest.TestCase): - - def setUp(self): - """ - There were a lot of directory changes going on. - It was easier to alway's return to a common root directory - """ - # return to the rool level directory - os.chdir(os.path.dirname(__file__)) - - def test_1_remove_dist(self): - """Make sure the build directory is gone""" - subprocess.call(['rm', '-rf', 'dist']) - self.assertFalse( - os.path.isfile( - 'dist/anouman-%(version)s.tar.gz' % {'version':VERSION} - ) - ) - - def test_2_uninstall_anouman(self): - subprocess.call(['pip', '-q', 'uninstall', 'anouman']) - try: - anouman = subprocess.check_output(['which', 'anouman']) - except subprocess.CalledProcessError: - anouman = False - - self.assertFalse(anouman) - - def test_3_sdist(self): - subprocess.call(['python', 'setup.py', '--quiet', 'sdist']) - self.assertTrue( - os.path.isfile( - 'dist/anouman-%(version)s.tar.gz' % {'version':VERSION} - ) - ) - - - def test_4_install_anouman(self): - subprocess.call(['pip', 'install', 'dist/anouman-%(version)s.tar.gz' % {'version':VERSION}, '--upgrade']) - try: - anouman = subprocess.check_output(['which', 'anouman']) - except subprocess.CalledProcessError: - anouman = False - - self.assertTrue(anouman) - - - def test_5_create_anouman_package(self): - # Pre test cleanup - subprocess.call(['rm', '-rf', 'tmp/*']) - subprocess.call(['rm', '-rf', 'site1.com.tar.gz']) - - #create empty virtualenv - subprocess.call(['virtualenv', 'site1']) - os.system("source site1/bin/activate") - - # build anouman package - results = subprocess.check_output(['anouman', '--django-project', 'test/django/site1', '--domainname', 'site1.com']) - - # Mv package to tmp directory - subprocess.call(['mv', 'site1.com.tar.gz', 'tmp/']) - self.assertTrue(True) - # clean up and remove this virtualenv - - def test_6_check_package_contents(self): - os.chdir('tmp/') - # unpack the package and check basic directory structure. - subprocess.call(['tar', 'xvfz', 'site1.com.tar.gz']) - dir_contents = os.listdir("site1.com") - self.assertEqual( - ['pip_packages.txt', 'src'], - dir_contents - ) - - self.assertTrue( - os.path.isfile("site1.com/src/manage.py") - ) - - self.assertTrue( - os.path.isfile("site1.com/src/site1/settings.py") - ) - - self.assertTrue( - os.path.isfile("site1.com/src/site1/wsgi.py") - ) - - - -class TestVagrant(unittest.TestCase): - - def setUp(self): - """ - There were a lot of directory changes going on. - It was easier to alway's return to a common root directory - """ - # return to the rool level directory - try: - os.chdir(os.path.dirname(__file__)) - except: - os.chdir("/Users/jfurr/anouman/") - - - def connect_to_s1(self, transport=False): - """ - return a connection to server "s1" - This is a vagrant box. that expects to have already - had provisioning from bootstrap.sh done on it. - """ - client = paramiko.SSHClient() - client.load_system_host_keys() - client.connect( - hostname=VM1, - username='anouman', - password='anouman', - timeout=5 - ) - - stdin, stdout, stderr = client.exec_command('hostname') - return client - - def scp(self, remotepath, localpath): - """ - scp a file to remote server s1. - """ - #TODO: Remove the hard coded scp call. In fact why not move this - # out of the test suite and make it a general purpose call. - transport = paramiko.Transport((VM1, 22)) - transport.connect( - username='anouman', - password='anouman' - ) - - sftp = paramiko.SFTPClient.from_transport(transport) - try: - sftp.put(remotepath, localpath) - except Exception as e: - print os.listdir("./") - raise Exception("YOU FAIL: ", e) - sftp.close() - transport.close() - - def exec_s1(self, cmd): - ssh = self.connect_to_s1() - return self.exec_command(ssh, cmd) - - def exec_command(self, ssh, cmd): - stdin, stdout, stderr = ssh.exec_command(cmd) - - out='' - for line in stdout: - out = out + line - - return out - - def test_1_create_new_vagrant_box(self): - print "test_1_create_new_vagrant_box" - try: - shutil.rmtree("test/vm/site3") - print "REMOVED" - except OSError as e: - print "EXCEPTION: ", e - pass - - os.mkdir("test/vm/site3") - os.chdir("test/vm/site3") - - vagrant.save(path="./Vagrantfile", context={ - 'NAME':'site3', - 'PUBLIC':True - }) - - vagrant_bootstrap.save(path="./bootstrap.sh", context={ - 'NGINX':True, - 'MYSQL':True, - }) - - clean.save(path="./clean.sh", context={ - 'DOMAINNAME':'site3.com' - }) - - print "YOU NEED TO ACTUALLY CHECK SOMETHIGN FOR THIS TO BE ATEST" - - def test_2_bring_vagrant_up(self): - base_dir = os.path.dirname(__file__) - os.chdir(os.path.join(base_dir, "test/vm/site1")) - - """ - Frist we try to connect to see if the vm is already up. - If that fails we then call vagrant up and try to connect - again after that finishes. - """ - try: - ssh = self.connect_to_s1() - except Exception as e: - print "\nCONNECTION FAILED. \nTrying to bring vagrant up...." - subprocess.call(['vagrant', 'up']) - print "Now retrying ssh connect" - ssh = self.connect_to_s1() - - stdout = self.exec_command(ssh, 'hostname') - if 'precise64' not in stdout: - self.assertFalse("Incorrect hostname....so no this test fails") - - def test_3_clean_server(self): - out = self.exec_s1("/usr/bin/yes | sh /vagrant/clean.sh") - - # Confirm that the home directory has been cleaned out - out = self.exec_s1("cd /home/anouman; ls") - self.assertEqual(out.strip(), '') - - # Make sure anouman has been uninstalled - out = self.exec_s1("anouman") - self.assertEqual(out, '') - - # TODO There are probably several other checks could do here - - def test_4_scp_anouman_to_s1(self): - # copy anouman to server - self.scp( - "dist/anouman-%(version)s.tar.gz" % {'version':VERSION}, - "/home/anouman/anouman-0.0.4.0.tar.gz" - ) - - out = self.exec_s1("cd /home/anouman; ls") - self.assertEqual( - "anouman-%(version)s.tar.gz" % {'version':VERSION}, - out.strip() - ) - - - def test_5_install_anouman_with_pip(self): - out = self.exec_s1("sudo pip install /home/anouman/anouman-%(version)s.tar.gz --upgrade" % {'version':VERSION}) - - # Check that anouman is installed - out = self.exec_s1("anouman") - self.assertEqual(out.strip(), "anouman") - - def test_6_scp_package_to_s1(self): - - self.scp( - "tmp/site1.com.tar.gz", - "/home/anouman/site1.com.tar.gz" - ) - - out = self.exec_s1("cd /home/anouman; ls") - self.assertEqual( - "anouman-%(version)s.tar.gz\nsite1.com.tar.gz" % {'version':VERSION}, - out.strip() - ) - - def test_7_install_site1(self): - print "cd /home/anouman; /usr/bin/yes | anouman --deploy site1.com.tar.gz" - out = self.exec_s1("cd /home/anouman; /usr/bin/yes | anouman --deploy site1.com.tar.gz") - - print "out: ", out diff --git a/test/django/site1/manage.py b/test/django/site1/manage.py deleted file mode 100644 index 952e57a..0000000 --- a/test/django/site1/manage.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site1.settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff --git a/test/django/site1/site1/__init__.py b/test/django/site1/site1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/django/site1/site1/settings.py b/test/django/site1/site1/settings.py deleted file mode 100644 index 72dfd64..0000000 --- a/test/django/site1/site1/settings.py +++ /dev/null @@ -1,158 +0,0 @@ -# Django settings for site1 project. - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - # ('Your Name', 'your_email@example.com'), -) - -MANAGERS = ADMINS - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': '', # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': '', - 'PASSWORD': '', - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - } -} - -# Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'America/Chicago' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True - -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" -MEDIA_URL = '' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" -STATIC_ROOT = '' - -# URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" -STATIC_URL = '/static/' - -# Additional locations of static files -STATICFILES_DIRS = ( - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) - -# Make this unique, and don't share it with anybody. -SECRET_KEY = '_)@har^yqnqhw(nt!)5&_=)39%_+)6q%ee#0hy8h^^*&z^#&!4' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = 'site1.urls' - -# Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = 'site1.wsgi.application' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', -) - -SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer' - -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} diff --git a/test/django/site1/site1/urls.py b/test/django/site1/site1/urls.py deleted file mode 100644 index 21b4ff0..0000000 --- a/test/django/site1/site1/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.conf.urls import patterns, include, url - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('', - # Examples: - url(r'^$', 'site1.views.home', name='home'), - # url(r'^site1/', include('site1.foo.urls')), - - # Uncomment the admin/doc line below to enable admin documentation: - # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - # url(r'^admin/', include(admin.site.urls)), -) diff --git a/test/django/site1/site1/views.py b/test/django/site1/site1/views.py deleted file mode 100644 index 4fd6507..0000000 --- a/test/django/site1/site1/views.py +++ /dev/null @@ -1,4 +0,0 @@ -from django.http import HttpResponse - -def home(request): - return HttpResponse("Hello From Site1") diff --git a/test/django/site1/site1/wsgi.py b/test/django/site1/site1/wsgi.py deleted file mode 100644 index 40282b3..0000000 --- a/test/django/site1/site1/wsgi.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -WSGI config for site1 project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" -import os - -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "site1.settings" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site1.settings") - -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -from django.core.wsgi import get_wsgi_application -application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/test/django/site2/manage.py b/test/django/site2/manage.py deleted file mode 100644 index 2bcfd5a..0000000 --- a/test/django/site2/manage.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site2.settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff --git a/test/django/site2/site2/__init__.py b/test/django/site2/site2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/django/site2/site2/settings.py b/test/django/site2/site2/settings.py deleted file mode 100644 index d9b8703..0000000 --- a/test/django/site2/site2/settings.py +++ /dev/null @@ -1,158 +0,0 @@ -# Django settings for site2 project. - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - # ('Your Name', 'your_email@example.com'), -) - -MANAGERS = ADMINS - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': '', # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': '', - 'PASSWORD': '', - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - } -} - -# Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'America/Chicago' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True - -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" -MEDIA_URL = '' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" -STATIC_ROOT = '' - -# URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" -STATIC_URL = '/static/' - -# Additional locations of static files -STATICFILES_DIRS = ( - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) - -# Make this unique, and don't share it with anybody. -SECRET_KEY = 'l-4buq75*yn%&k5aps+s(%g@+=$-7ds1$dqleyh7imugm-yse%' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = 'site2.urls' - -# Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = 'site2.wsgi.application' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', -) - -SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer' - -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} diff --git a/test/django/site2/site2/urls.py b/test/django/site2/site2/urls.py deleted file mode 100644 index 9c67a80..0000000 --- a/test/django/site2/site2/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.conf.urls import patterns, include, url - -# Uncomment the next two lines to enable the admin: -# from django.contrib import admin -# admin.autodiscover() - -urlpatterns = patterns('', - # Examples: - url(r'^$', 'site2.views.home', name='home'), - # url(r'^site2/', include('site2.foo.urls')), - - # Uncomment the admin/doc line below to enable admin documentation: - # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - # url(r'^admin/', include(admin.site.urls)), -) diff --git a/test/django/site2/site2/views.py b/test/django/site2/site2/views.py deleted file mode 100644 index c8be81b..0000000 --- a/test/django/site2/site2/views.py +++ /dev/null @@ -1,4 +0,0 @@ -from django.http import HttpResponse - -def home(request): - return HttpResponse("Hello From Site2") diff --git a/test/django/site2/site2/wsgi.py b/test/django/site2/site2/wsgi.py deleted file mode 100644 index 7450849..0000000 --- a/test/django/site2/site2/wsgi.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -WSGI config for site2 project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" -import os - -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "site2.settings" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site2.settings") - -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -from django.core.wsgi import get_wsgi_application -application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/test/vm/site1/.vagrant/machines/default/virtualbox/action_provision b/test/vm/site1/.vagrant/machines/default/virtualbox/action_provision deleted file mode 100644 index 1c58a99..0000000 --- a/test/vm/site1/.vagrant/machines/default/virtualbox/action_provision +++ /dev/null @@ -1 +0,0 @@ -1379886284 \ No newline at end of file diff --git a/test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name b/test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name deleted file mode 100644 index 1c58a99..0000000 --- a/test/vm/site1/.vagrant/machines/default/virtualbox/action_set_name +++ /dev/null @@ -1 +0,0 @@ -1379886284 \ No newline at end of file diff --git a/test/vm/site1/.vagrant/machines/default/virtualbox/id b/test/vm/site1/.vagrant/machines/default/virtualbox/id deleted file mode 100644 index 1d2b141..0000000 --- a/test/vm/site1/.vagrant/machines/default/virtualbox/id +++ /dev/null @@ -1 +0,0 @@ -b9bf713a-af78-4055-aba2-91f4b4abbf06 \ No newline at end of file diff --git a/test/vm/site1/Vagrantfile b/test/vm/site1/Vagrantfile deleted file mode 100644 index de106f9..0000000 --- a/test/vm/site1/Vagrantfile +++ /dev/null @@ -1,33 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = "m1" - - # The url from where the 'config.vm.box' box will be fetched if it - # doesn't already exist on the user's system. - config.vm.box_url = "http://files.vagrantup.com/precise64.box" - - # Run bootstrap.sh provisioning script - config.vm.provision :shell, :path => "bootstrap.sh" - - # Create a private network, which allows host-only access to the machine - # using a specific IP. - config.vm.network :private_network, ip: "192.168.100.100" - - # Create a public network, which will make the machine appear as another - #physical device on your network. - # config.vm.network :public_network - - #config.vm.provider :virtualbox do |vb| - # # Don't boot with headless mode - # vb.gui = true - # - # # Use VBoxManage to customize the VM. For example to change memory: - # vb.customize ["modifyvm", :id, "--memory", "1024"] - #end -end diff --git a/test/vm/site1/bootstrap.sh b/test/vm/site1/bootstrap.sh deleted file mode 100644 index e3615ca..0000000 --- a/test/vm/site1/bootstrap.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -sudo apt-get update # Update apt-get -sudo apt-get install -yf vim #VIM because VI isn't cool -sudo apt-get install -yf git # install git -sudo apt-get install -yf nginx # install nginx -sudo apt-get install -yf mysql-client #only install mysql command line client -sudo apt-get install -yf libmysqlclient-dev # needed for django mysql integration - -### PYTHON STUFF -sudo apt-get install -yf python-setuptools -sudo apt-get install -yf python-virtualenv -sudo apt-get install -yf python-dev -sudo apt-get install -yf build-essential diff --git a/test/vm/site1/clean.sh b/test/vm/site1/clean.sh deleted file mode 100644 index b9c5ae1..0000000 --- a/test/vm/site1/clean.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# This file cleans up a server for a fresh anouman install -# Set the domain name of the project here -DOMAINNAME=site1.com - -# Echo Clean up NGINX sites enabled -# TODO Shouldn't we store these locally in our package directory and then just create the symbolic -# link back to the sites-enabled for nginx? If you are worried about conforming then just create a -# symlink in sites-available to. -sudo rm -rf /etc/nginx/sites-enabled/nginx.$DOMAINNAME.conf /etc/nginx/sites-available/nginx.$DOMAINNAME.conf - -# Remove anouman -/usr/bin/yes | sudo pip uninstall anouman - -# Remove all traces of virtualenv -sudo rm -rf /home/anouman/* -sudo rm -rf /home/anouman/.virtualenvs/ - -# Remove the .bash_profile -# Make sure this test never runs on the clients machine! -rm -rf /home/anouman/.bash_profile - - -# Remove the site upstart command -sudo rm -rf /etc/init/site1.com.conf diff --git a/test/vm/site1/install.sh b/test/vm/site1/install.sh deleted file mode 100644 index 7b18040..0000000 --- a/test/vm/site1/install.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -# Install script for vagrant testing machine -ANOUMAN=/vagrant/anouman-0.0.4.0.tar.gz -sudo pip install $ANOUMAN --upgrade diff --git a/version.py b/version.py deleted file mode 100644 index a47295b..0000000 --- a/version.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python - -VERSION = "0.0.4.0" From 8e050b71c096c8dbd243144adbcfddbdcd9d72d5 Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 07:19:40 -0500 Subject: [PATCH 03/19] set token in settings file --- anouman/management/commands/anouman.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/anouman/management/commands/anouman.py b/anouman/management/commands/anouman.py index e9d3694..a19e753 100644 --- a/anouman/management/commands/anouman.py +++ b/anouman/management/commands/anouman.py @@ -1,4 +1,7 @@ from django.core.management.base import BaseCommand, CommandError +from django.conf import settings +import digitalocean as do + class Command(BaseCommand): help = 'Manage your infrastructure' @@ -16,7 +19,7 @@ def add_arguments(self, parser): def get_keys(self): for tries in range(11): try: - manager = do.Manager(token=TOKEN) + manager = do.Manager(token=settings.DO_TOKEN) return manager.get_all_sshkeys() except do.baseapi.DataReadError: if tries > 10: raise @@ -25,7 +28,8 @@ def get_keys(self): def create_droplet(self, **kwargs): print("CREATING DROPLET") # Create Keys - #keys = self.get_keys() + keys = self.get_keys() + print("keys: ", keys) # Create Droplet """ @@ -45,3 +49,4 @@ def create_droplet(self, **kwargs): def handle(self, *args, **options): print(options) + self.create_droplet() From 22eb9e44f2205e49bada7e04dbae9dc0253086a2 Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 08:50:57 -0500 Subject: [PATCH 04/19] Hold --- anouman/management/commands/anouman.py | 52 --------- anouman/management/commands/create_droplet.py | 107 ++++++++++++++++++ anouman/management/commands/delete_droplet.py | 100 ++++++++++++++++ anouman/management/commands/list_droplets.py | 23 ++++ anouman/settings.py | 3 +- anouman/utils.py | 11 ++ .../migrations/0002_machine_private_ip.py | 20 ++++ cloudgroup/models.py | 1 + requirements.txt | 1 + 9 files changed, 265 insertions(+), 53 deletions(-) delete mode 100644 anouman/management/commands/anouman.py create mode 100644 anouman/management/commands/create_droplet.py create mode 100644 anouman/management/commands/delete_droplet.py create mode 100644 anouman/management/commands/list_droplets.py create mode 100644 anouman/utils.py create mode 100644 cloudgroup/migrations/0002_machine_private_ip.py diff --git a/anouman/management/commands/anouman.py b/anouman/management/commands/anouman.py deleted file mode 100644 index a19e753..0000000 --- a/anouman/management/commands/anouman.py +++ /dev/null @@ -1,52 +0,0 @@ -from django.core.management.base import BaseCommand, CommandError -from django.conf import settings -import digitalocean as do - - -class Command(BaseCommand): - help = 'Manage your infrastructure' - - def add_arguments(self, parser): - parser.add_argument('--create', help="create a new digitial ocean droplet", type=bool) - parser.add_argument('--name', help="The name of the droplet") - parser.add_argument('--region', help="The digitial ocean region") - parser.add_argument('--size_slug', help="The droplet size") - parser.add_argument('--backups', help="Enable backups", type=bool, default=False) - parser.add_argument('--monitoring', help="Enable/Disable monitoring.", type=bool, default=False) - parser.add_argument('--private', help="Enable private networking", type=bool, default=False) - - - def get_keys(self): - for tries in range(11): - try: - manager = do.Manager(token=settings.DO_TOKEN) - return manager.get_all_sshkeys() - except do.baseapi.DataReadError: - if tries > 10: raise - else: pass - - def create_droplet(self, **kwargs): - print("CREATING DROPLET") - # Create Keys - keys = self.get_keys() - print("keys: ", keys) - - # Create Droplet - """ - droplet = do.Droplet( - token=TOKEN, - name=kwargs.get('name', 'qa.teaquinox.com'), - region=kwargs.get('region', 'nyc2'), # New York 2 - image=kwargs.get('image', 'ubuntu-16-04-x64'), # Ubuntu 16.04 x64 - size_slug=kwargs.get('size_slug', '512mb'), # 512MB - ssh_keys=keys, - backups=kwargs.get('backups', False), - monitoring=kwargs.get('monitoring', True), - private_networking=kwargs.get('private_networking', False) - ) - droplet.create() - """ - - def handle(self, *args, **options): - print(options) - self.create_droplet() diff --git a/anouman/management/commands/create_droplet.py b/anouman/management/commands/create_droplet.py new file mode 100644 index 0000000..799e1c8 --- /dev/null +++ b/anouman/management/commands/create_droplet.py @@ -0,0 +1,107 @@ +import sys +import subprocess +from time import time, sleep +import digitalocean as do +from colorama import init +from colorama import Fore, Back, Style +init() + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +from anouman.utils import get_keys +from cloudgroup.models import Machine + + +class Command(BaseCommand): + help = 'Create a digitial ocean droplet' + + def add_arguments(self, parser): + parser.add_argument("--name", help="The name of the droplet") + parser.add_argument("--region", help="The digitial ocean region", default="nyc3") + parser.add_argument("--size_slug", help="The droplet size", default="512mb") + parser.add_argument("--backups", help="Enable backups", type=bool, default=False) + parser.add_argument("--image", help="The digital ocean image type", default="ubuntu-16-04-x64") + parser.add_argument("--monitoring", help="Enable/Disable monitoring.", type=bool, default=False) + parser.add_argument("--private", help="Enable private networking", type=bool, default=False) + + + def create_droplet(self, options, **kwargs): + if not options["name"]: + print(Fore.RED + "--name is a required argument") + sys.exit(1) + # Create Keys + keys = self.get_keys() + if not keys: + print(Fore.RED + "You need to setup ssh keys in your digital ocean account") + sys.exit(1) + + print(Fore.GREEN + "CREATING DROPLET") + + # Create Droplet + droplet = do.Droplet( + token=settings.DO_TOKEN, + name=kwargs.get('name', options["name"]), + region=kwargs.get('region', options["region"]), # New York 2 + image=kwargs.get('image', options["image"]), # Ubuntu 16.04 x64 + size_slug=kwargs.get('size_slug', options["size_slug"]), + ssh_keys=keys, + backups=kwargs.get('backups', options["backups"]), + monitoring=kwargs.get('monitoring', options["monitoring"]), + private_networking=kwargs.get('private_networking', options["private"]) + ) + droplet.create() + + + print(Fore.GREEN + " - New Droplet ID: %s" % droplet.id) + print(Fore.GREEN + " - Waiting on droplet to come online") + # Wait on Droplet to be created...needs to live in it's own method + # You need to constrain this based on time so it doesn't run forever... + MAXTIME = 45 # 45 seconds is the maximum time we wait for machien to come up. + start = time() + while 1: + actions = droplet.get_actions() + try: + for action in actions: + action.load() + if action.status == 'completed': # Once it shows complete, droplet is up and running + break + except do.baseapi.DataReadError as e: + pass + + elapsed = start - time() + if elapsed > MAXTIME: + print(FG.Red + "Droplet Creation Failed") + sys.exit(1) + sleep(1) + + manager = do.Manager(token=settings.DO_TOKEN) + droplet = manager.get_droplet(droplet.id) + + cmd = '''ssh -o "StrictHostKeyChecking no" -A root@%s "echo hello"''' % droplet.ip_address + start = time() + while 1: + try: + subprocess.check_call([cmd], shell=True) + break + except subprocess.CalledProcessError: + time.sleep(1) + + elapsed = start - time() + if elapsed > MAXTIME: + print(FG.Red + " - Unable to login to droplet with ssh keys") + sys.exit(1) + + machine = Machine( + name=options["name"], + droplet_id=droplet.id, + ip=droplet.ip_address, + private_ip=droplet.private_ip_address, + ) + + machine.save() + print(Fore.GREEN + " - Your Droplet is Available at: %s" % machine.ip) + + + def handle(self, *args, **options): + self.create_droplet(options) diff --git a/anouman/management/commands/delete_droplet.py b/anouman/management/commands/delete_droplet.py new file mode 100644 index 0000000..4f368c6 --- /dev/null +++ b/anouman/management/commands/delete_droplet.py @@ -0,0 +1,100 @@ +import sys +import subprocess +from time import time, sleep +import digitalocean as do +from colorama import init +from colorama import Fore, Back, Style +init() + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +from cloudgroup.models import Machine +from anouman.utils import get_keys + +class Command(BaseCommand): + help = 'Create a digitial ocean droplet' + + def add_arguments(self, parser): + parser.add_argument("--dropet-id", help="The droplet id") + + + def create_droplet(self, options, **kwargs): + if not options["name"]: + print(Fore.RED + "--name is a required argument") + sys.exit(1) + # Create Keys + keys = self.get_keys() + if not keys: + print(Fore.RED + "You need to setup ssh keys in your digital ocean account") + sys.exit(1) + + print(Fore.GREEN + "CREATING DROPLET") + + # Create Droplet + droplet = do.Droplet( + token=settings.DO_TOKEN, + name=kwargs.get('name', options["name"]), + region=kwargs.get('region', options["region"]), # New York 2 + image=kwargs.get('image', options["image"]), # Ubuntu 16.04 x64 + size_slug=kwargs.get('size_slug', options["size_slug"]), + ssh_keys=keys, + backups=kwargs.get('backups', options["backups"]), + monitoring=kwargs.get('monitoring', options["monitoring"]), + private_networking=kwargs.get('private_networking', options["private"]) + ) + droplet.create() + + + print(Fore.GREEN + " - New Droplet ID: %s" % droplet.id) + print(Fore.GREEN + " - Waiting on droplet to come online") + # Wait on Droplet to be created...needs to live in it's own method + # You need to constrain this based on time so it doesn't run forever... + MAXTIME = 45 # 45 seconds is the maximum time we wait for machien to come up. + start = time() + while 1: + actions = droplet.get_actions() + try: + for action in actions: + action.load() + if action.status == 'completed': # Once it shows complete, droplet is up and running + break + except do.baseapi.DataReadError as e: + pass + + elapsed = start - time() + if elapsed > MAXTIME: + print(FG.Red + "Droplet Creation Failed") + sys.exit(1) + sleep(1) + + manager = do.Manager(token=settings.DO_TOKEN) + droplet = manager.get_droplet(droplet.id) + + cmd = '''ssh -o "StrictHostKeyChecking no" -A root@%s "echo hello"''' % droplet.ip_address + start = time() + while 1: + try: + subprocess.check_call([cmd], shell=True) + break + except subprocess.CalledProcessError: + time.sleep(1) + + elapsed = start - time() + if elapsed > MAXTIME: + print(FG.Red + " - Unable to login to droplet with ssh keys") + sys.exit(1) + + machine = Machine( + name=options["name"], + droplet_id=droplet.id, + ip=droplet.ip_address, + private_ip=droplet.private_ip_address, + ) + + machine.save() + print(Fore.GREEN + " - Your Droplet is Available at: %s" % machine.ip) + + + def handle(self, *args, **options): + self.create_droplet(options) diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py new file mode 100644 index 0000000..5c6313c --- /dev/null +++ b/anouman/management/commands/list_droplets.py @@ -0,0 +1,23 @@ +import sys +import subprocess +from time import time, sleep +import digitalocean as do +from colorama import init +from colorama import Fore, Back, Style +init() + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +from anouman.utils import get_keys +from cloudgroup.models import Machine + + +class Command(BaseCommand): + help = 'Create a digitial ocean droplet' + + def handle(self, *args, **options): + machines = Machine.objects.all() + + for m in machines: + print(FG.Blue + "%-20s %-20s" % (m.name, m.ip)) diff --git a/anouman/settings.py b/anouman/settings.py index 395441b..b6c9e4b 100644 --- a/anouman/settings.py +++ b/anouman/settings.py @@ -37,7 +37,8 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'anouman', + 'django_extensions', + #'anouman', 'cloudgroup', ] diff --git a/anouman/utils.py b/anouman/utils.py new file mode 100644 index 0000000..f1f0233 --- /dev/null +++ b/anouman/utils.py @@ -0,0 +1,11 @@ +import digitalocean as do +from django.conf import settings + +def get_keys(self): + for tries in range(11): + try: + manager = do.Manager(token=settings.DO_TOKEN) + return manager.get_all_sshkeys() + except do.baseapi.DataReadError: + if tries > 10: raise + else: pass diff --git a/cloudgroup/migrations/0002_machine_private_ip.py b/cloudgroup/migrations/0002_machine_private_ip.py new file mode 100644 index 0000000..1f525e2 --- /dev/null +++ b/cloudgroup/migrations/0002_machine_private_ip.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-02-11 12:46 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cloudgroup', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='machine', + name='private_ip', + field=models.GenericIPAddressField(blank=True, null=True), + ), + ] diff --git a/cloudgroup/models.py b/cloudgroup/models.py index 5cf677e..547dde7 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -19,6 +19,7 @@ class Machine(models.Model): name = models.CharField(max_length=32, blank=False, null=False) droplet_id = models.PositiveSmallIntegerField(blank=True, null=True) ip = models.GenericIPAddressField(blank=True, null=True) + private_ip = models.GenericIPAddressField(blank=True, null=True) group = models.ForeignKey('CloudGroup', on_delete=models.CASCADE, blank=True, null=True) diff --git a/requirements.txt b/requirements.txt index 95157dc..2df7ecf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Django==1.11.10 django-extensions==1.9.9 python-digitalocean==1.13.2 +colorama==0.3.9 From 9b1a2be2b02710ebf91090bd8199403ace64f59d Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 08:52:07 -0500 Subject: [PATCH 05/19] Added __init__.py to anouman --- anouman/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 anouman/__init__.py diff --git a/anouman/__init__.py b/anouman/__init__.py new file mode 100644 index 0000000..e69de29 From 4f89d08442dbf3eb8d67128bb0d2c4dedefacffc Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 09:09:28 -0500 Subject: [PATCH 06/19] List and delete droplets started --- anouman/management/commands/delete_droplet.py | 97 ++++--------------- anouman/management/commands/list_droplets.py | 7 +- anouman/settings.py | 2 +- 3 files changed, 27 insertions(+), 79 deletions(-) diff --git a/anouman/management/commands/delete_droplet.py b/anouman/management/commands/delete_droplet.py index 4f368c6..a734fb0 100644 --- a/anouman/management/commands/delete_droplet.py +++ b/anouman/management/commands/delete_droplet.py @@ -16,85 +16,28 @@ class Command(BaseCommand): help = 'Create a digitial ocean droplet' def add_arguments(self, parser): - parser.add_argument("--dropet-id", help="The droplet id") + parser.add_argument("--droplet-id", help="The droplet id") + parser.add_argument("--clean", + help="Remove machines from local database if there isn't an instance at Digitial Ocean") + def handle(self, *args, **options): + m = do.Manager(token=settings.DO_TOKEN) - def create_droplet(self, options, **kwargs): - if not options["name"]: - print(Fore.RED + "--name is a required argument") - sys.exit(1) - # Create Keys - keys = self.get_keys() - if not keys: - print(Fore.RED + "You need to setup ssh keys in your digital ocean account") - sys.exit(1) - - print(Fore.GREEN + "CREATING DROPLET") - - # Create Droplet - droplet = do.Droplet( - token=settings.DO_TOKEN, - name=kwargs.get('name', options["name"]), - region=kwargs.get('region', options["region"]), # New York 2 - image=kwargs.get('image', options["image"]), # Ubuntu 16.04 x64 - size_slug=kwargs.get('size_slug', options["size_slug"]), - ssh_keys=keys, - backups=kwargs.get('backups', options["backups"]), - monitoring=kwargs.get('monitoring', options["monitoring"]), - private_networking=kwargs.get('private_networking', options["private"]) - ) - droplet.create() - - - print(Fore.GREEN + " - New Droplet ID: %s" % droplet.id) - print(Fore.GREEN + " - Waiting on droplet to come online") - # Wait on Droplet to be created...needs to live in it's own method - # You need to constrain this based on time so it doesn't run forever... - MAXTIME = 45 # 45 seconds is the maximum time we wait for machien to come up. - start = time() - while 1: - actions = droplet.get_actions() - try: - for action in actions: - action.load() - if action.status == 'completed': # Once it shows complete, droplet is up and running - break - except do.baseapi.DataReadError as e: - pass - - elapsed = start - time() - if elapsed > MAXTIME: - print(FG.Red + "Droplet Creation Failed") - sys.exit(1) - sleep(1) - - manager = do.Manager(token=settings.DO_TOKEN) - droplet = manager.get_droplet(droplet.id) - - cmd = '''ssh -o "StrictHostKeyChecking no" -A root@%s "echo hello"''' % droplet.ip_address - start = time() - while 1: - try: - subprocess.check_call([cmd], shell=True) - break - except subprocess.CalledProcessError: - time.sleep(1) - elapsed = start - time() - if elapsed > MAXTIME: - print(FG.Red + " - Unable to login to droplet with ssh keys") - sys.exit(1) - - machine = Machine( - name=options["name"], - droplet_id=droplet.id, - ip=droplet.ip_address, - private_ip=droplet.private_ip_address, - ) + try: + droplet = m.get_droplet(options["droplet_id"]) + droplet.destroy() + print(Fore.GREEN + " - Droplet %s has been destroyed" % options["droplet_id"]) + except do.baseapi.NotFoundError: + print(Fore.RED + " - Droplet %s not found on digitial ocean" % options["droplet_id"]) - machine.save() - print(Fore.GREEN + " - Your Droplet is Available at: %s" % machine.ip) - - def handle(self, *args, **options): - self.create_droplet(options) + # First check that we have a matching Machine in the local database + machine = None + try: + machine = Machine.objects.get(droplet_id=options["droplet_id"]) + machine.delete() + print(Fore.GREEN + " - Machine delete from local database") + except Machine.DoesNotExist: + print(Fore.RED + " - There is no Local Machine with droplet_id=%s" % options["droplet_id"]) + sys.exit(1) diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py index 5c6313c..3916245 100644 --- a/anouman/management/commands/list_droplets.py +++ b/anouman/management/commands/list_droplets.py @@ -19,5 +19,10 @@ class Command(BaseCommand): def handle(self, *args, **options): machines = Machine.objects.all() + print(Fore.YELLOW + "%-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group")) for m in machines: - print(FG.Blue + "%-20s %-20s" % (m.name, m.ip)) + try: + do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) + print(Fore.GREEN + "%-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) + except do.baseapi.NotFoundError: + print(Fore.RED + "%-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) diff --git a/anouman/settings.py b/anouman/settings.py index b6c9e4b..c063944 100644 --- a/anouman/settings.py +++ b/anouman/settings.py @@ -38,7 +38,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'django_extensions', - #'anouman', + 'anouman', 'cloudgroup', ] From 6793638578c9a0928ee5e27ca4be80ea46943f47 Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 10:02:04 -0500 Subject: [PATCH 07/19] list_droplet shows Cloud Group stuff now --- anouman/management/commands/create_droplet.py | 27 ++++++++++--------- anouman/management/commands/list_droplets.py | 17 ++++++++---- cloudgroup/models.py | 5 ++++ requirements.txt | 1 + 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/anouman/management/commands/create_droplet.py b/anouman/management/commands/create_droplet.py index 799e1c8..223ad35 100644 --- a/anouman/management/commands/create_droplet.py +++ b/anouman/management/commands/create_droplet.py @@ -22,16 +22,16 @@ def add_arguments(self, parser): parser.add_argument("--size_slug", help="The droplet size", default="512mb") parser.add_argument("--backups", help="Enable backups", type=bool, default=False) parser.add_argument("--image", help="The digital ocean image type", default="ubuntu-16-04-x64") - parser.add_argument("--monitoring", help="Enable/Disable monitoring.", type=bool, default=False) - parser.add_argument("--private", help="Enable private networking", type=bool, default=False) + parser.add_argument("--monitoring", help="Enable/Disable monitoring.", action="store_true") + parser.add_argument("--private", help="Enable private networking", action="store_true") def create_droplet(self, options, **kwargs): if not options["name"]: print(Fore.RED + "--name is a required argument") sys.exit(1) - # Create Keys - keys = self.get_keys() + + keys = get_keys(settings.DO_TOKEN) if not keys: print(Fore.RED + "You need to setup ssh keys in your digital ocean account") sys.exit(1) @@ -78,27 +78,28 @@ def create_droplet(self, options, **kwargs): manager = do.Manager(token=settings.DO_TOKEN) droplet = manager.get_droplet(droplet.id) - cmd = '''ssh -o "StrictHostKeyChecking no" -A root@%s "echo hello"''' % droplet.ip_address + machine = Machine( + name=options["name"], + droplet_id=droplet.id, + ) + machine.save() + + cmd = '''ssh -o "StrictHostKeyChecking no" -A root@%s "echo ping -> pong"''' % droplet.ip_address start = time() while 1: try: subprocess.check_call([cmd], shell=True) break except subprocess.CalledProcessError: - time.sleep(1) + sleep(1) elapsed = start - time() if elapsed > MAXTIME: print(FG.Red + " - Unable to login to droplet with ssh keys") sys.exit(1) - machine = Machine( - name=options["name"], - droplet_id=droplet.id, - ip=droplet.ip_address, - private_ip=droplet.private_ip_address, - ) - + machine.ip=droplet.ip_address + machine.private_ip=droplet.private_ip_address machine.save() print(Fore.GREEN + " - Your Droplet is Available at: %s" % machine.ip) diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py index 3916245..50ec919 100644 --- a/anouman/management/commands/list_droplets.py +++ b/anouman/management/commands/list_droplets.py @@ -10,19 +10,26 @@ from django.conf import settings from anouman.utils import get_keys -from cloudgroup.models import Machine +from cloudgroup.models import Machine, CloudGroup class Command(BaseCommand): help = 'Create a digitial ocean droplet' def handle(self, *args, **options): - machines = Machine.objects.all() + groups = CloudGroup.objects.all() + print(Fore.MAGENTA + "Cloud Groups") + print(Fore.YELLOW + " Name") + for g in groups: + print(Fore.GREEN + " - %s" % g.name) + - print(Fore.YELLOW + "%-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group")) + machines = Machine.objects.all() + print(Fore.MAGENTA + "Droplets") + print(Fore.YELLOW + " %-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group")) for m in machines: try: do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) - print(Fore.GREEN + "%-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) + print(Fore.GREEN + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) except do.baseapi.NotFoundError: - print(Fore.RED + "%-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) + print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) diff --git a/cloudgroup/models.py b/cloudgroup/models.py index 547dde7..db21b3b 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -24,5 +24,10 @@ class Machine(models.Model): class CloudGroup(models.Model): + """ + Basically a firewall or security group. + """ name = models.CharField(max_length=32, blank=False, null=False) + def __str__(self): + return self.name diff --git a/requirements.txt b/requirements.txt index 2df7ecf..86a51f4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ Django==1.11.10 django-extensions==1.9.9 python-digitalocean==1.13.2 colorama==0.3.9 +ipgetter==0.7 From 69365d1c29f41f286319fa0d51792fb745347f45 Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 11:41:30 -0500 Subject: [PATCH 08/19] Hold --- ansible/iptables.retry | 1 + ansible/iptables.yml | 23 ++++++++++ ansible/iptables/tasks/main.yml | 8 ++++ .../iptables/templates/cloudgroup_iptables.j2 | 33 ++++++++++++++ ansible/iptables_old.retry | 1 + .../migrations/0003_auto_20180211_1508.py | 24 ++++++++++ cloudgroup/models.py | 44 ++++++++++++++++++- create.sh | 3 ++ list.sh | 3 ++ 9 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 ansible/iptables.retry create mode 100644 ansible/iptables.yml create mode 100644 ansible/iptables/tasks/main.yml create mode 100644 ansible/iptables/templates/cloudgroup_iptables.j2 create mode 100644 ansible/iptables_old.retry create mode 100644 cloudgroup/migrations/0003_auto_20180211_1508.py create mode 100755 create.sh create mode 100755 list.sh diff --git a/ansible/iptables.retry b/ansible/iptables.retry new file mode 100644 index 0000000..6ddfd03 --- /dev/null +++ b/ansible/iptables.retry @@ -0,0 +1 @@ +165.227.190.214 diff --git a/ansible/iptables.yml b/ansible/iptables.yml new file mode 100644 index 0000000..518dbef --- /dev/null +++ b/ansible/iptables.yml @@ -0,0 +1,23 @@ +--- +- name: Install iptable firewall rules on cloud group + hosts: all + + pre_tasks: + - name: install python 2 for ansible + raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal) + retries: 10 + delay: 2 + register: result + until: result|succeeded + + - name: report error + fail: + msg: 'Unable to download {{result.url}}: {{result.response|default(result.msg)}}' + when: not result|succeeded + + - name: install python-pip + raw: sudo apt-get install -y python-pip + + roles: + - set_facts + - iptables diff --git a/ansible/iptables/tasks/main.yml b/ansible/iptables/tasks/main.yml new file mode 100644 index 0000000..83828b5 --- /dev/null +++ b/ansible/iptables/tasks/main.yml @@ -0,0 +1,8 @@ +- name: "Copy iptables rules to load balancer" + template: src=cloudgroup_iptables.j2 dest=/etc/iptables_rules owner=root group=root + +- name: "Flush the current iptables" + shell: /sbin/iptables -F + +- name: "Install the new iptables" + shell: /sbin/iptables-restore < /etc/iptables_rules diff --git a/ansible/iptables/templates/cloudgroup_iptables.j2 b/ansible/iptables/templates/cloudgroup_iptables.j2 new file mode 100644 index 0000000..6728244 --- /dev/null +++ b/ansible/iptables/templates/cloudgroup_iptables.j2 @@ -0,0 +1,33 @@ +# Generated by iptables-save v1.6.0 on Tue Jun 27 20:57:42 2017 +*filter +:INPUT ACCEPT [0:0] +-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -i eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT + +# WHITE_LIST +# Special list of ip addresses that can ssh to each machine +{% for ip in WHITE_LIST %} +-A INPUT -s {{ip}} -i eth0 -j ACCEPT +{% endfor %} + +-A INPUT -s 127.0.0.1 -j ACCEPT + +# CLOUD GROUP +# Frontend IP's +{% for ip in FRONT_END_IPS %} +-A INPUT -s {{ip}} -j ACCEPT +{% endfor %} + +# Private IP +{% for ip in PRIVATE_IPS %} +-A INPUT -s {{ip}} -j ACCEPT +{% endfor %} + + +-A INPUT -j DROP +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] +-A OUTPUT -o eth0 -j ACCEPT +-A OUTPUT -o eth1 -j ACCEPT +COMMIT +# Completed on Tue Jun 27 20:57:42 2017 diff --git a/ansible/iptables_old.retry b/ansible/iptables_old.retry new file mode 100644 index 0000000..9242418 --- /dev/null +++ b/ansible/iptables_old.retry @@ -0,0 +1 @@ +104.131.8.110 diff --git a/cloudgroup/migrations/0003_auto_20180211_1508.py b/cloudgroup/migrations/0003_auto_20180211_1508.py new file mode 100644 index 0000000..105a384 --- /dev/null +++ b/cloudgroup/migrations/0003_auto_20180211_1508.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-02-11 15:08 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cloudgroup', '0002_machine_private_ip'), + ] + + operations = [ + migrations.RemoveField( + model_name='whitelist', + name='group', + ), + migrations.AddField( + model_name='whitelist', + name='group', + field=models.ManyToManyField(to='cloudgroup.CloudGroup'), + ), + ] diff --git a/cloudgroup/models.py b/cloudgroup/models.py index db21b3b..8d04c1d 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import ipgetter +from six.moves import input from django.db import models @@ -8,8 +10,8 @@ class WhiteList(models.Model): """ This model holds a list of all IP addresses that are allowed to ssh into any CloudGroup Machine """ - ip = models.GenericIPAddressField(blank=False, null=False) - group = models.ForeignKey('CloudGroup', on_delete=models.CASCADE) + ip = models.GenericIPAddressField(blank=False, null=False, unique=True) + group = models.ManyToManyField('CloudGroup') class Machine(models.Model): @@ -31,3 +33,41 @@ class CloudGroup(models.Model): def __str__(self): return self.name + + def get_context_data(self, **kwargs): + white_list = WhiteList.objects.filter(group=self) + print("white_list: %s" % white_list) + if not white_list.count(): + print("Oh no there isn't a white list...") + myip = ipgetter.myip() + print("can we add your local ip: %s" % myip) + ans = input() + if 'y' == ans.lower()[0]: + wl = WhiteList(ip=myip) + wl.save() + wl.group.add(self) + #WhiteList(name=name, group=self).save() + + white_list = WhiteList.objects.filter(group=self).values_list('ip', flat=True) + print("white_list: %s" % white_list) + + machines = Machine.objects.filter(group=self) + frontend_ips = machines.values_list('ip', flat=True) + private_ip = machines.values_list('private_ip', flat=True) + + context = { + "WHITE_LIST": list(white_list), + "FRONT_END_IPS": list(frontend_ips), + "PRIVATE_IPS": list(private_ip), + } + return context + + def provision(self, hosts_file): + extra_vars = json.dumps(instance.get_context_data()) + print(extra_vars) + playbooks = ( + '''ansible-playbook -s -u root ansible/apt_cleanup.yml -i %s --extra-vars='%s' ''' % (hosts_file, extra_vars), + ) + + print("Made it") + diff --git a/create.sh b/create.sh new file mode 100755 index 0000000..23ff201 --- /dev/null +++ b/create.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +./manage.py create_droplet --name $1 --monitoring --private --settings=anouman.local diff --git a/list.sh b/list.sh new file mode 100755 index 0000000..bdf9879 --- /dev/null +++ b/list.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +./manage.py list_droplets --settings=anouman.local From 9ee771c2fc293dcc1c8e54eeebd2076af5f97d0b Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 11:58:59 -0500 Subject: [PATCH 09/19] working on firewall command --- anouman/management/commands/firewall.py | 24 ++++++++++++++++++++++++ cloudgroup/models.py | 19 +++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 anouman/management/commands/firewall.py diff --git a/anouman/management/commands/firewall.py b/anouman/management/commands/firewall.py new file mode 100644 index 0000000..ba47388 --- /dev/null +++ b/anouman/management/commands/firewall.py @@ -0,0 +1,24 @@ +import sys +import subprocess +from time import time, sleep +import digitalocean as do +from colorama import init +from colorama import Fore, Back, Style +init() + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +from anouman.utils import get_keys +from cloudgroup.models import Machine, CloudGroup + + +class Command(BaseCommand): + help = 'Create a digitial ocean droplet' + def add_arguments(self, parser): + parser.add_argument("--name", help="The name of the droplet") + + def handle(self, *args, **options): + g = CloudGroup.objects.get(name=options["name"]) + g.get_context_data() + g.provision() diff --git a/cloudgroup/models.py b/cloudgroup/models.py index 8d04c1d..891dad4 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import ipgetter from six.moves import input +import json from django.db import models @@ -62,11 +63,21 @@ def get_context_data(self, **kwargs): } return context - def provision(self, hosts_file): - extra_vars = json.dumps(instance.get_context_data()) - print(extra_vars) + def hosts_file(self): + host_name = "%s_hosts" % self.name + + with open(host_name, "w") as f: + f.write("[%s]\n" % self.name) + for ip in Machine.objects.filter(group=self).values_list('ip', flat=True): + f.write("%s\n" % ip) + + return host_name + + def provision(self): + hosts_file = self.hosts_file() + extra_vars = json.dumps(self.get_context_data()) playbooks = ( - '''ansible-playbook -s -u root ansible/apt_cleanup.yml -i %s --extra-vars='%s' ''' % (hosts_file, extra_vars), + '''ansible-playbook -s -u root ansible/iptables.yml -i %s --extra-vars='%s' ''' % (hosts_file, extra_vars), ) print("Made it") From 77fd73e2cc4895b1cc50811c84a4ebcbf37e1c8f Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 18:33:21 -0500 Subject: [PATCH 10/19] Better model arrangement --- anouman/management/commands/list_droplets.py | 21 ++++++----- cloudgroup/admin.py | 30 ++++++++++++++- cloudgroup/migrations/0001_initial.py | 37 +++++++++++++++---- .../migrations/0002_machine_private_ip.py | 20 ---------- .../migrations/0003_auto_20180211_1508.py | 24 ------------ cloudgroup/models.py | 27 ++++++++++++-- requirements.txt | 2 +- 7 files changed, 95 insertions(+), 66 deletions(-) delete mode 100644 cloudgroup/migrations/0002_machine_private_ip.py delete mode 100644 cloudgroup/migrations/0003_auto_20180211_1508.py diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py index 50ec919..5af9cb0 100644 --- a/anouman/management/commands/list_droplets.py +++ b/anouman/management/commands/list_droplets.py @@ -18,18 +18,21 @@ class Command(BaseCommand): def handle(self, *args, **options): groups = CloudGroup.objects.all() - print(Fore.MAGENTA + "Cloud Groups") - print(Fore.YELLOW + " Name") for g in groups: - print(Fore.GREEN + " - %s" % g.name) + print(Fore.MAGENTA + "Cloud Group: " + Fore.CYAN + g.name) + print(Fore.YELLOW + " - %-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group")) + for m in g.machines.all(): + try: + do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) + print(Fore.GREEN + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) + except do.baseapi.NotFoundError: + print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) - machines = Machine.objects.all() - print(Fore.MAGENTA + "Droplets") - print(Fore.YELLOW + " %-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group")) - for m in machines: + print(Fore.MAGENTA + "Rouge Machines") + for m in Machine.objects.filter(cloudgroup__isnull=True): try: do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) - print(Fore.GREEN + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) + print(Fore.GREEN + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) except do.baseapi.NotFoundError: - print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, m.group)) + print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) diff --git a/cloudgroup/admin.py b/cloudgroup/admin.py index 13be29d..9f59fff 100644 --- a/cloudgroup/admin.py +++ b/cloudgroup/admin.py @@ -3,4 +3,32 @@ from django.contrib import admin -# Register your models here. +from cloudgroup.models import SSHKey, IPAddress, Machine, CloudGroup + + +class SSHKeyAdmin(admin.ModelAdmin): + list_display = ('name',) + pass +admin.site.register(SSHKey, SSHKeyAdmin) + + +class SSHKeysInline(admin.TabularInline): + model = SSHKey + +class IPAddressAdmin(admin.ModelAdmin): + list_display = ('ip',) + pass +admin.site.register(IPAddress, IPAddressAdmin) + + +class MachineAdmin(admin.ModelAdmin): + list_display = ('name', 'droplet_id', 'ip', 'private_ip',) + pass +admin.site.register(Machine, MachineAdmin) + + +class CloudGroupAdmin(admin.ModelAdmin): + list_display = ('name',) + pass +admin.site.register(CloudGroup, CloudGroupAdmin) + diff --git a/cloudgroup/migrations/0001_initial.py b/cloudgroup/migrations/0001_initial.py index 6e00107..6b65c0c 100644 --- a/cloudgroup/migrations/0001_initial.py +++ b/cloudgroup/migrations/0001_initial.py @@ -1,9 +1,6 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.10 on 2018-02-11 11:54 -from __future__ import unicode_literals +# Generated by Django 2.0.2 on 2018-02-11 22:54 from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): @@ -21,6 +18,14 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=32)), ], ), + migrations.CreateModel( + name='IPAddress', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=32, null=True)), + ('ip', models.GenericIPAddressField(unique=True)), + ], + ), migrations.CreateModel( name='Machine', fields=[ @@ -28,15 +33,31 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=32)), ('droplet_id', models.PositiveSmallIntegerField(blank=True, null=True)), ('ip', models.GenericIPAddressField(blank=True, null=True)), - ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='cloudgroup.CloudGroup')), + ('private_ip', models.GenericIPAddressField(blank=True, null=True)), ], ), migrations.CreateModel( - name='WhiteList', + name='SSHKey', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('ip', models.GenericIPAddressField()), - ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cloudgroup.CloudGroup')), + ('name', models.CharField(max_length=32)), + ('public', models.TextField()), + ('private', models.TextField()), ], ), + migrations.AddField( + model_name='cloudgroup', + name='machines', + field=models.ManyToManyField(to='cloudgroup.Machine'), + ), + migrations.AddField( + model_name='cloudgroup', + name='sshkeys', + field=models.ManyToManyField(to='cloudgroup.SSHKey'), + ), + migrations.AddField( + model_name='cloudgroup', + name='whitelist', + field=models.ManyToManyField(to='cloudgroup.IPAddress'), + ), ] diff --git a/cloudgroup/migrations/0002_machine_private_ip.py b/cloudgroup/migrations/0002_machine_private_ip.py deleted file mode 100644 index 1f525e2..0000000 --- a/cloudgroup/migrations/0002_machine_private_ip.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.10 on 2018-02-11 12:46 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('cloudgroup', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='machine', - name='private_ip', - field=models.GenericIPAddressField(blank=True, null=True), - ), - ] diff --git a/cloudgroup/migrations/0003_auto_20180211_1508.py b/cloudgroup/migrations/0003_auto_20180211_1508.py deleted file mode 100644 index 105a384..0000000 --- a/cloudgroup/migrations/0003_auto_20180211_1508.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.10 on 2018-02-11 15:08 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('cloudgroup', '0002_machine_private_ip'), - ] - - operations = [ - migrations.RemoveField( - model_name='whitelist', - name='group', - ), - migrations.AddField( - model_name='whitelist', - name='group', - field=models.ManyToManyField(to='cloudgroup.CloudGroup'), - ), - ] diff --git a/cloudgroup/models.py b/cloudgroup/models.py index 891dad4..f319259 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -7,13 +7,29 @@ from django.db import models -class WhiteList(models.Model): +class SSHKey(models.Model): + """ + A model to hold your ssh key information. + These keys are often used during user provision. + CUrrently digitial ocean will provision the servers with the users keys. + """ + name = models.CharField(max_length=32) + public = models.TextField() + private = models.TextField() + + def __str__(self): + return self.name + + +class IPAddress(models.Model): """ This model holds a list of all IP addresses that are allowed to ssh into any CloudGroup Machine """ + name = models.CharField(max_length=32, blank=True, null=True) ip = models.GenericIPAddressField(blank=False, null=False, unique=True) - group = models.ManyToManyField('CloudGroup') + def __str__(self): + return "%s-%s" % (self.name, self.ip) class Machine(models.Model): """ @@ -23,7 +39,9 @@ class Machine(models.Model): droplet_id = models.PositiveSmallIntegerField(blank=True, null=True) ip = models.GenericIPAddressField(blank=True, null=True) private_ip = models.GenericIPAddressField(blank=True, null=True) - group = models.ForeignKey('CloudGroup', on_delete=models.CASCADE, blank=True, null=True) + + def __str__(self): + return self.name class CloudGroup(models.Model): @@ -31,6 +49,9 @@ class CloudGroup(models.Model): Basically a firewall or security group. """ name = models.CharField(max_length=32, blank=False, null=False) + sshkeys = models.ManyToManyField('SSHKey') + whitelist = models.ManyToManyField('IPAddress') + machines = models.ManyToManyField('Machine') def __str__(self): return self.name diff --git a/requirements.txt b/requirements.txt index 86a51f4..fda83f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django==1.11.10 +Django==2.0.2 django-extensions==1.9.9 python-digitalocean==1.13.2 colorama==0.3.9 From bcd689677a2a1b9389e442089359be9a27ef8e4a Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 20:50:47 -0500 Subject: [PATCH 11/19] working on cli --- anouman/management/commands/add.py | 32 +++++++++++++ anouman/management/commands/create_droplet.py | 4 +- anouman/management/commands/delete_droplet.py | 14 +++--- anouman/management/commands/list_droplets.py | 2 +- ansible/iptables.retry | 2 +- ansible/iptables.yml | 33 +++++++------ ansible/iptables/tasks/main.yml | 4 +- cloudgroup/models.py | 46 +++++++++++++++---- create.sh | 7 ++- requirements.txt | 1 + 10 files changed, 109 insertions(+), 36 deletions(-) create mode 100644 anouman/management/commands/add.py diff --git a/anouman/management/commands/add.py b/anouman/management/commands/add.py new file mode 100644 index 0000000..302b86b --- /dev/null +++ b/anouman/management/commands/add.py @@ -0,0 +1,32 @@ +import sys +import subprocess +from time import time, sleep +import digitalocean as do +from colorama import init +from colorama import Fore, Back, Style +init() + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +from anouman.utils import get_keys +from cloudgroup.models import Machine, CloudGroup + + +class Command(BaseCommand): + help = 'Create a digitial ocean droplet' + def add_arguments(self, parser): + parser.add_argument("-n", "--name", help="The name of the droplet", required=True) + parser.add_argument("-d","--droplets", nargs="+", help=" Set flag", required=True) + + def handle(self, *args, **options): + print(options) + g = CloudGroup.objects.get(name=options["name"]) + print(g) + + for machine in Machine.objects.filter(droplet_id__in=options["droplets"]): + g.machines.add(machine) + + #Machine.objects.filter(droplet_id__in=options["droplets"]).update( + #g.get_context_data() + #g.provision() diff --git a/anouman/management/commands/create_droplet.py b/anouman/management/commands/create_droplet.py index 223ad35..c4033e2 100644 --- a/anouman/management/commands/create_droplet.py +++ b/anouman/management/commands/create_droplet.py @@ -5,7 +5,9 @@ from colorama import init from colorama import Fore, Back, Style init() - +import ipgetter +myip = ipgetter.myip() +print(Fore.GREEN + str(myip)) from django.core.management.base import BaseCommand, CommandError from django.conf import settings diff --git a/anouman/management/commands/delete_droplet.py b/anouman/management/commands/delete_droplet.py index a734fb0..e19b58e 100644 --- a/anouman/management/commands/delete_droplet.py +++ b/anouman/management/commands/delete_droplet.py @@ -16,28 +16,30 @@ class Command(BaseCommand): help = 'Create a digitial ocean droplet' def add_arguments(self, parser): - parser.add_argument("--droplet-id", help="The droplet id") + parser.add_argument("-d","--droplets", nargs="+", help=" Set flag", required=True) + #parser.add_argument("--droplet-id", help="The droplet id") parser.add_argument("--clean", help="Remove machines from local database if there isn't an instance at Digitial Ocean") def handle(self, *args, **options): m = do.Manager(token=settings.DO_TOKEN) + # TODO Fix this whole thing try: - droplet = m.get_droplet(options["droplet_id"]) + droplet = m.get_droplet(options["droplets"]) droplet.destroy() - print(Fore.GREEN + " - Droplet %s has been destroyed" % options["droplet_id"]) + print(Fore.GREEN + " - Droplet %s has been destroyed" % options["droplets"]) except do.baseapi.NotFoundError: - print(Fore.RED + " - Droplet %s not found on digitial ocean" % options["droplet_id"]) + print(Fore.RED + " - Droplet %s not found on digitial ocean" % options["droplets"]) # First check that we have a matching Machine in the local database machine = None try: - machine = Machine.objects.get(droplet_id=options["droplet_id"]) + machine = Machine.objects.get(droplet_id=options["droplets"]) machine.delete() print(Fore.GREEN + " - Machine delete from local database") except Machine.DoesNotExist: - print(Fore.RED + " - There is no Local Machine with droplet_id=%s" % options["droplet_id"]) + print(Fore.RED + " - There is no Local Machine with droplets=%s" % options["droplets"]) sys.exit(1) diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py index 5af9cb0..77a01e9 100644 --- a/anouman/management/commands/list_droplets.py +++ b/anouman/management/commands/list_droplets.py @@ -33,6 +33,6 @@ def handle(self, *args, **options): for m in Machine.objects.filter(cloudgroup__isnull=True): try: do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) - print(Fore.GREEN + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) + print(Style.DIM + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) except do.baseapi.NotFoundError: print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) diff --git a/ansible/iptables.retry b/ansible/iptables.retry index 6ddfd03..58e0fa1 100644 --- a/ansible/iptables.retry +++ b/ansible/iptables.retry @@ -1 +1 @@ -165.227.190.214 +159.65.44.214 diff --git a/ansible/iptables.yml b/ansible/iptables.yml index 518dbef..e8c6208 100644 --- a/ansible/iptables.yml +++ b/ansible/iptables.yml @@ -3,21 +3,24 @@ hosts: all pre_tasks: - - name: install python 2 for ansible - raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal) - retries: 10 - delay: 2 - register: result - until: result|succeeded - - - name: report error - fail: - msg: 'Unable to download {{result.url}}: {{result.response|default(result.msg)}}' - when: not result|succeeded - - - name: install python-pip - raw: sudo apt-get install -y python-pip + - name: "Install iptables" + shell: sudo apt-get install -y iptables + #pre_tasks: + # - name: install python 2 for ansible + # raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal) + # retries: 10 + # delay: 2 + # register: result + # until: result|succeeded + # + # - name: report error + # fail: + # msg: 'Unable to download {{result.url}}: {{result.response|default(result.msg)}}' + # when: not result|succeeded + # + # - name: install python-pip + # raw: sudo apt-get install -y python-pip + roles: - - set_facts - iptables diff --git a/ansible/iptables/tasks/main.yml b/ansible/iptables/tasks/main.yml index 83828b5..9bf441c 100644 --- a/ansible/iptables/tasks/main.yml +++ b/ansible/iptables/tasks/main.yml @@ -4,5 +4,5 @@ - name: "Flush the current iptables" shell: /sbin/iptables -F -- name: "Install the new iptables" - shell: /sbin/iptables-restore < /etc/iptables_rules +#- name: "Install the new iptables" +# shell: /sbin/iptables-restore < /etc/iptables_rules diff --git a/cloudgroup/models.py b/cloudgroup/models.py index f319259..99ca634 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -1,8 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals import ipgetter +import time +import subprocess from six.moves import input import json +from colorama import init +from colorama import Fore, Back, Style +init(autoreset=True) from django.db import models @@ -57,31 +62,31 @@ def __str__(self): return self.name def get_context_data(self, **kwargs): - white_list = WhiteList.objects.filter(group=self) + white_list = self.whitelist.all() print("white_list: %s" % white_list) if not white_list.count(): print("Oh no there isn't a white list...") myip = ipgetter.myip() - print("can we add your local ip: %s" % myip) + print("Can I add your local ip: %s" % myip) ans = input() if 'y' == ans.lower()[0]: wl = WhiteList(ip=myip) wl.save() wl.group.add(self) - #WhiteList(name=name, group=self).save() - white_list = WhiteList.objects.filter(group=self).values_list('ip', flat=True) + white_list = self.whitelist.values_list('ip', flat=True) print("white_list: %s" % white_list) - machines = Machine.objects.filter(group=self) + machines = self.machines frontend_ips = machines.values_list('ip', flat=True) - private_ip = machines.values_list('private_ip', flat=True) + private_ip = machines.filter(private_ip__isnull=False).values_list('private_ip', flat=True) context = { "WHITE_LIST": list(white_list), "FRONT_END_IPS": list(frontend_ips), "PRIVATE_IPS": list(private_ip), } + print(Fore.BLUE + str(context)) return context def hosts_file(self): @@ -89,8 +94,8 @@ def hosts_file(self): with open(host_name, "w") as f: f.write("[%s]\n" % self.name) - for ip in Machine.objects.filter(group=self).values_list('ip', flat=True): - f.write("%s\n" % ip) + for ip in self.machines.values_list('ip', flat=True): + f.write("%s ansible_python_interpreter=/usr/bin/python3\n" % ip) return host_name @@ -101,5 +106,30 @@ def provision(self): '''ansible-playbook -s -u root ansible/iptables.yml -i %s --extra-vars='%s' ''' % (hosts_file, extra_vars), ) + for cmd in playbooks: + # Problem here is that you are writing this after the plays have run + # TODO This will be deprecated soon + print("Running: ", cmd) + with open('cmds', 'a') as f: + f.write("%s\n" % cmd) + + try: + logfile = "%s.log" % (self.name) + logfile_handle = open(logfile,"a") + + subprocess.check_call([cmd], stdout=logfile_handle, stderr=logfile_handle, shell=True) + except subprocess.CalledProcessError as e: + print("\n\n*** Failed on first attempts: %s ***" % cmd) + print("\n\n***error: %s ***" % str(e)) + time.sleep(5) + try: + subprocess.check_call([cmd], stdout=logfile_handle, stderr=logfile_handle, shell=True) + except subprocess.CalledProcessError as e: + print("\n\n*** Command failed: ", cmd) + print("\n\n*** error: %s" % str(e)) + with open('failed', 'a') as f: + f.write("%s\n" % cmd) + raise + print("Made it") diff --git a/create.sh b/create.sh index 23ff201..3ce5166 100755 --- a/create.sh +++ b/create.sh @@ -1,3 +1,6 @@ #!/usr/bin/env bash - -./manage.py create_droplet --name $1 --monitoring --private --settings=anouman.local +for var in "$@" +do + echo "Spinning up: $var" + ./manage.py create_droplet --name $var --monitoring --private --settings=anouman.local & +done diff --git a/requirements.txt b/requirements.txt index fda83f5..6b27e52 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ django-extensions==1.9.9 python-digitalocean==1.13.2 colorama==0.3.9 ipgetter==0.7 +ansible==2.4.3.0 From 69449baf663cc1f583bc3efce6865e9f241176ca Mon Sep 17 00:00:00 2001 From: John Furr Date: Sun, 11 Feb 2018 20:58:51 -0500 Subject: [PATCH 12/19] delete_droplet takes list now --- anouman/management/commands/delete_droplet.py | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/anouman/management/commands/delete_droplet.py b/anouman/management/commands/delete_droplet.py index e19b58e..4bca5bc 100644 --- a/anouman/management/commands/delete_droplet.py +++ b/anouman/management/commands/delete_droplet.py @@ -24,22 +24,21 @@ def add_arguments(self, parser): def handle(self, *args, **options): m = do.Manager(token=settings.DO_TOKEN) - # TODO Fix this whole thing - - try: - droplet = m.get_droplet(options["droplets"]) - droplet.destroy() - print(Fore.GREEN + " - Droplet %s has been destroyed" % options["droplets"]) - except do.baseapi.NotFoundError: - print(Fore.RED + " - Droplet %s not found on digitial ocean" % options["droplets"]) - - - # First check that we have a matching Machine in the local database - machine = None - try: - machine = Machine.objects.get(droplet_id=options["droplets"]) - machine.delete() - print(Fore.GREEN + " - Machine delete from local database") - except Machine.DoesNotExist: - print(Fore.RED + " - There is no Local Machine with droplets=%s" % options["droplets"]) - sys.exit(1) + for _id in options["droplets"]: + try: + droplet = m.get_droplet(_id) + droplet.destroy() + print(Fore.GREEN + " - Droplet %s has been destroyed" % _id) + except do.baseapi.NotFoundError: + print(Fore.RED + " - Droplet %s not found on digitial ocean" % _id) + + + # First check that we have a matching Machine in the local database + machine = None + try: + machine = Machine.objects.get(droplet_id=_id) + machine.delete() + print(Fore.GREEN + " - Machine delete from local database") + except Machine.DoesNotExist: + print(Fore.RED + " - There is no Local Machine with droplets=%s" % _id) + sys.exit(1) From 5f88a7043d1a61a522cbc684343743bd7d27c335 Mon Sep 17 00:00:00 2001 From: John Furr Date: Mon, 12 Feb 2018 16:48:29 -0500 Subject: [PATCH 13/19] Apply firewall and show in list --- anouman/management/commands/create_droplet.py | 9 ++++++++- anouman/management/commands/firewall.py | 4 ++-- anouman/management/commands/list_droplets.py | 10 +++++----- ansible/iptables/tasks/main.yml | 4 ++-- .../iptables/templates/cloudgroup_iptables.j2 | 2 +- .../migrations/0002_cloudgroup_firewall.py | 18 ++++++++++++++++++ cloudgroup/models.py | 9 ++++++--- create.sh | 17 +++++++++++++++++ 8 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 cloudgroup/migrations/0002_cloudgroup_firewall.py diff --git a/anouman/management/commands/create_droplet.py b/anouman/management/commands/create_droplet.py index c4033e2..7f213f7 100644 --- a/anouman/management/commands/create_droplet.py +++ b/anouman/management/commands/create_droplet.py @@ -12,7 +12,7 @@ from django.conf import settings from anouman.utils import get_keys -from cloudgroup.models import Machine +from cloudgroup.models import Machine, CloudGroup class Command(BaseCommand): @@ -26,6 +26,7 @@ def add_arguments(self, parser): parser.add_argument("--image", help="The digital ocean image type", default="ubuntu-16-04-x64") parser.add_argument("--monitoring", help="Enable/Disable monitoring.", action="store_true") parser.add_argument("--private", help="Enable private networking", action="store_true") + parser.add_argument("--group", help="Add to Cloud Group. Group created if not found", action="store", default="") def create_droplet(self, options, **kwargs): @@ -85,6 +86,12 @@ def create_droplet(self, options, **kwargs): droplet_id=droplet.id, ) machine.save() + if options["group"]: + group, created = CloudGroup.objects.get_or_create(name=options["group"]) + if created: + print(Fore.GREEN + " - CloudGroup: %s was created" % group.name) + group.machines.add(machine) + print(Fore.GREEN + " - machine added to CloudGroup %s" % group.name) cmd = '''ssh -o "StrictHostKeyChecking no" -A root@%s "echo ping -> pong"''' % droplet.ip_address start = time() diff --git a/anouman/management/commands/firewall.py b/anouman/management/commands/firewall.py index ba47388..f8166ef 100644 --- a/anouman/management/commands/firewall.py +++ b/anouman/management/commands/firewall.py @@ -16,9 +16,9 @@ class Command(BaseCommand): help = 'Create a digitial ocean droplet' def add_arguments(self, parser): - parser.add_argument("--name", help="The name of the droplet") + parser.add_argument("--group", help="The name of the CloudGroup to apply firewall rules to") def handle(self, *args, **options): - g = CloudGroup.objects.get(name=options["name"]) + g = CloudGroup.objects.get(name=options["group"]) g.get_context_data() g.provision() diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py index 77a01e9..b6ad5d6 100644 --- a/anouman/management/commands/list_droplets.py +++ b/anouman/management/commands/list_droplets.py @@ -20,19 +20,19 @@ def handle(self, *args, **options): groups = CloudGroup.objects.all() for g in groups: print(Fore.MAGENTA + "Cloud Group: " + Fore.CYAN + g.name) - print(Fore.YELLOW + " - %-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group")) + print(Fore.YELLOW + " - %-20s %-20s %-20s %-20s %-20s" % ("Name", "IP", "Droplet ID", "Cloud Group", "Firewall")) for m in g.machines.all(): try: do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) - print(Fore.GREEN + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) + print(Fore.GREEN + " - %-20s %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g, g.firewall)) except do.baseapi.NotFoundError: - print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) + print(Fore.RED + " - %-20s %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g, g.firewall)) print(Fore.MAGENTA + "Rouge Machines") for m in Machine.objects.filter(cloudgroup__isnull=True): try: do.Droplet.get_object(settings.DO_TOKEN, m.droplet_id) - print(Style.DIM + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) + print(Style.DIM + " - %-20s %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g, g.firewall)) except do.baseapi.NotFoundError: - print(Fore.RED + " - %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g)) + print(Fore.RED + " - %-20s %-20s %-20s %-20s %-20s" % (m.name, m.ip, m.droplet_id, g, g.firewall)) diff --git a/ansible/iptables/tasks/main.yml b/ansible/iptables/tasks/main.yml index 9bf441c..83828b5 100644 --- a/ansible/iptables/tasks/main.yml +++ b/ansible/iptables/tasks/main.yml @@ -4,5 +4,5 @@ - name: "Flush the current iptables" shell: /sbin/iptables -F -#- name: "Install the new iptables" -# shell: /sbin/iptables-restore < /etc/iptables_rules +- name: "Install the new iptables" + shell: /sbin/iptables-restore < /etc/iptables_rules diff --git a/ansible/iptables/templates/cloudgroup_iptables.j2 b/ansible/iptables/templates/cloudgroup_iptables.j2 index 6728244..5611fb9 100644 --- a/ansible/iptables/templates/cloudgroup_iptables.j2 +++ b/ansible/iptables/templates/cloudgroup_iptables.j2 @@ -4,7 +4,7 @@ -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT -# WHITE_LIST +# WHITE LIST # Special list of ip addresses that can ssh to each machine {% for ip in WHITE_LIST %} -A INPUT -s {{ip}} -i eth0 -j ACCEPT diff --git a/cloudgroup/migrations/0002_cloudgroup_firewall.py b/cloudgroup/migrations/0002_cloudgroup_firewall.py new file mode 100644 index 0000000..fa0b35a --- /dev/null +++ b/cloudgroup/migrations/0002_cloudgroup_firewall.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-02-12 21:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cloudgroup', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='cloudgroup', + name='firewall', + field=models.BooleanField(default=False), + ), + ] diff --git a/cloudgroup/models.py b/cloudgroup/models.py index 99ca634..83d2998 100644 --- a/cloudgroup/models.py +++ b/cloudgroup/models.py @@ -54,6 +54,7 @@ class CloudGroup(models.Model): Basically a firewall or security group. """ name = models.CharField(max_length=32, blank=False, null=False) + firewall = models.BooleanField(default=False) sshkeys = models.ManyToManyField('SSHKey') whitelist = models.ManyToManyField('IPAddress') machines = models.ManyToManyField('Machine') @@ -70,9 +71,9 @@ def get_context_data(self, **kwargs): print("Can I add your local ip: %s" % myip) ans = input() if 'y' == ans.lower()[0]: - wl = WhiteList(ip=myip) + wl, _ = IPAddress.objects.get_or_create(ip=myip) wl.save() - wl.group.add(self) + self.whitelist.add(wl) white_list = self.whitelist.values_list('ip', flat=True) print("white_list: %s" % white_list) @@ -131,5 +132,7 @@ def provision(self): f.write("%s\n" % cmd) raise - print("Made it") + self.firewall = True + self.save() + print(Fore.GREEN + "- Firewall applied") diff --git a/create.sh b/create.sh index 3ce5166..5c1e837 100755 --- a/create.sh +++ b/create.sh @@ -1,4 +1,21 @@ #!/usr/bin/env bash + +# Create multipel droplets simulatneously by calling like: +# +#./create.sh test1 test2 test 3 +# +# NOTE: The jobs are all backgrounded to the system. +# +# You can monitor the job with ./list.sh + +# Help +if [ "$1" == "--help" ] +then + ./manage.py create_droplet --help + exit 1 +fi + +# Create Droplets for var in "$@" do echo "Spinning up: $var" From ad630bed4017c60c3445dafdd5e5240352e9a11b Mon Sep 17 00:00:00 2001 From: John Furr Date: Mon, 12 Feb 2018 17:00:43 -0500 Subject: [PATCH 14/19] Create README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..20d93ef --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# anouman +A django deployment manager + +Anouman is currently a digitial ocean firewall wrapper. From 231ee1873776b323bc7aa1b3242fdaecca5ff8ed Mon Sep 17 00:00:00 2001 From: John Furr Date: Mon, 12 Feb 2018 17:39:24 -0500 Subject: [PATCH 15/19] Playing with a basic setup.py package --- README.rst | 29 +++++++++++++++++++++++++++++ setup.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 README.rst create mode 100644 setup.py diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..451b888 --- /dev/null +++ b/README.rst @@ -0,0 +1,29 @@ +===== +Polls +===== + +Polls is a simple Django app to conduct Web-based polls. For each +question, visitors can choose between a fixed number of answers. + +Detailed documentation is in the "docs" directory. + +Quick start +----------- + +1. Add "polls" to your INSTALLED_APPS setting like this:: + + INSTALLED_APPS = [ + ... + 'polls', + ] + +2. Include the polls URLconf in your project urls.py like this:: + + path('polls/', include('polls.urls')), + +3. Run `python manage.py migrate` to create the polls models. + +4. Start the development server and visit http://127.0.0.1:8000/admin/ + to create a poll (you'll need the Admin app enabled). + +5. Visit http://127.0.0.1:8000/polls/ to participate in the poll. diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..21ed4bb --- /dev/null +++ b/setup.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +import os +from setuptools import find_packages, setup + +with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme: + README = readme.read() + +# allow setup.py to be run from any path +os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) + +setup( + name='anouman', + version='0.1', + packages=find_packages(), + include_package_data=True, + license='BSD License', # example license + description='A django deployment tool', + long_description=README, + #url='https://www.example.com/', + author='John Furr', + author_email='john.furr@gmail.com', + classifiers=[ + 'Environment :: Web Environment', + 'Framework :: Django', + 'Framework :: Django :: X.Y', # replace "X.Y" as appropriate + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', # example license + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Topic :: Internet :: WWW/HTTP', + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + ], +) From 239bdf5091587e04a52baf6eecb392e28afa1152 Mon Sep 17 00:00:00 2001 From: John Furr Date: Mon, 12 Feb 2018 20:18:32 -0500 Subject: [PATCH 16/19] rearragne...still broke --- {cloudgroup => anouman}/admin.py | 2 +- {cloudgroup => anouman}/models.py | 0 anouman/settings.py | 1 - cloudgroup/__init__.py | 0 cloudgroup/apps.py | 8 --- cloudgroup/migrations/0001_initial.py | 63 ------------------- .../migrations/0002_cloudgroup_firewall.py | 18 ------ cloudgroup/migrations/__init__.py | 0 cloudgroup/tests.py | 6 -- cloudgroup/views.py | 6 -- 10 files changed, 1 insertion(+), 103 deletions(-) rename {cloudgroup => anouman}/admin.py (90%) rename {cloudgroup => anouman}/models.py (100%) delete mode 100644 cloudgroup/__init__.py delete mode 100644 cloudgroup/apps.py delete mode 100644 cloudgroup/migrations/0001_initial.py delete mode 100644 cloudgroup/migrations/0002_cloudgroup_firewall.py delete mode 100644 cloudgroup/migrations/__init__.py delete mode 100644 cloudgroup/tests.py delete mode 100644 cloudgroup/views.py diff --git a/cloudgroup/admin.py b/anouman/admin.py similarity index 90% rename from cloudgroup/admin.py rename to anouman/admin.py index 9f59fff..d64b56b 100644 --- a/cloudgroup/admin.py +++ b/anouman/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin -from cloudgroup.models import SSHKey, IPAddress, Machine, CloudGroup +from anouman.models import SSHKey, IPAddress, Machine, CloudGroup class SSHKeyAdmin(admin.ModelAdmin): diff --git a/cloudgroup/models.py b/anouman/models.py similarity index 100% rename from cloudgroup/models.py rename to anouman/models.py diff --git a/anouman/settings.py b/anouman/settings.py index c063944..db80e6a 100644 --- a/anouman/settings.py +++ b/anouman/settings.py @@ -39,7 +39,6 @@ 'django.contrib.staticfiles', 'django_extensions', 'anouman', - 'cloudgroup', ] MIDDLEWARE = [ diff --git a/cloudgroup/__init__.py b/cloudgroup/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/cloudgroup/apps.py b/cloudgroup/apps.py deleted file mode 100644 index b5c8737..0000000 --- a/cloudgroup/apps.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.apps import AppConfig - - -class CloudgroupConfig(AppConfig): - name = 'cloudgroup' diff --git a/cloudgroup/migrations/0001_initial.py b/cloudgroup/migrations/0001_initial.py deleted file mode 100644 index 6b65c0c..0000000 --- a/cloudgroup/migrations/0001_initial.py +++ /dev/null @@ -1,63 +0,0 @@ -# Generated by Django 2.0.2 on 2018-02-11 22:54 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='CloudGroup', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=32)), - ], - ), - migrations.CreateModel( - name='IPAddress', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(blank=True, max_length=32, null=True)), - ('ip', models.GenericIPAddressField(unique=True)), - ], - ), - migrations.CreateModel( - name='Machine', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=32)), - ('droplet_id', models.PositiveSmallIntegerField(blank=True, null=True)), - ('ip', models.GenericIPAddressField(blank=True, null=True)), - ('private_ip', models.GenericIPAddressField(blank=True, null=True)), - ], - ), - migrations.CreateModel( - name='SSHKey', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=32)), - ('public', models.TextField()), - ('private', models.TextField()), - ], - ), - migrations.AddField( - model_name='cloudgroup', - name='machines', - field=models.ManyToManyField(to='cloudgroup.Machine'), - ), - migrations.AddField( - model_name='cloudgroup', - name='sshkeys', - field=models.ManyToManyField(to='cloudgroup.SSHKey'), - ), - migrations.AddField( - model_name='cloudgroup', - name='whitelist', - field=models.ManyToManyField(to='cloudgroup.IPAddress'), - ), - ] diff --git a/cloudgroup/migrations/0002_cloudgroup_firewall.py b/cloudgroup/migrations/0002_cloudgroup_firewall.py deleted file mode 100644 index fa0b35a..0000000 --- a/cloudgroup/migrations/0002_cloudgroup_firewall.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.0.2 on 2018-02-12 21:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('cloudgroup', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='cloudgroup', - name='firewall', - field=models.BooleanField(default=False), - ), - ] diff --git a/cloudgroup/migrations/__init__.py b/cloudgroup/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/cloudgroup/tests.py b/cloudgroup/tests.py deleted file mode 100644 index 5982e6b..0000000 --- a/cloudgroup/tests.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.test import TestCase - -# Create your tests here. diff --git a/cloudgroup/views.py b/cloudgroup/views.py deleted file mode 100644 index e784a0b..0000000 --- a/cloudgroup/views.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.shortcuts import render - -# Create your views here. From 944d44c76f460babf37f8ba6597fca44dcf932d4 Mon Sep 17 00:00:00 2001 From: John Furr Date: Mon, 12 Feb 2018 20:26:21 -0500 Subject: [PATCH 17/19] hold --- anouman/management/commands/add.py | 2 +- anouman/management/commands/create_droplet.py | 2 +- anouman/management/commands/delete_droplet.py | 2 +- anouman/management/commands/firewall.py | 2 +- anouman/management/commands/list_droplets.py | 2 +- setup.py | 2 ++ 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/anouman/management/commands/add.py b/anouman/management/commands/add.py index 302b86b..253cf1a 100644 --- a/anouman/management/commands/add.py +++ b/anouman/management/commands/add.py @@ -10,7 +10,7 @@ from django.conf import settings from anouman.utils import get_keys -from cloudgroup.models import Machine, CloudGroup +from anouman.models import Machine, CloudGroup class Command(BaseCommand): diff --git a/anouman/management/commands/create_droplet.py b/anouman/management/commands/create_droplet.py index 7f213f7..40d4797 100644 --- a/anouman/management/commands/create_droplet.py +++ b/anouman/management/commands/create_droplet.py @@ -12,7 +12,7 @@ from django.conf import settings from anouman.utils import get_keys -from cloudgroup.models import Machine, CloudGroup +from anouman.models import Machine, CloudGroup class Command(BaseCommand): diff --git a/anouman/management/commands/delete_droplet.py b/anouman/management/commands/delete_droplet.py index 4bca5bc..1f07302 100644 --- a/anouman/management/commands/delete_droplet.py +++ b/anouman/management/commands/delete_droplet.py @@ -9,7 +9,7 @@ from django.core.management.base import BaseCommand, CommandError from django.conf import settings -from cloudgroup.models import Machine +from anouman.models import Machine from anouman.utils import get_keys class Command(BaseCommand): diff --git a/anouman/management/commands/firewall.py b/anouman/management/commands/firewall.py index f8166ef..741d4d4 100644 --- a/anouman/management/commands/firewall.py +++ b/anouman/management/commands/firewall.py @@ -10,7 +10,7 @@ from django.conf import settings from anouman.utils import get_keys -from cloudgroup.models import Machine, CloudGroup +from anouman.models import Machine, CloudGroup class Command(BaseCommand): diff --git a/anouman/management/commands/list_droplets.py b/anouman/management/commands/list_droplets.py index b6ad5d6..0535a13 100644 --- a/anouman/management/commands/list_droplets.py +++ b/anouman/management/commands/list_droplets.py @@ -10,7 +10,7 @@ from django.conf import settings from anouman.utils import get_keys -from cloudgroup.models import Machine, CloudGroup +from anouman.models import Machine, CloudGroup class Command(BaseCommand): diff --git a/setup.py b/setup.py index 21ed4bb..489b79f 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,8 @@ # allow setup.py to be run from any path os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) +print (find_packages()) + setup( name='anouman', version='0.1', From 455b71cafe783324ed6acd5caac2c666f774cda2 Mon Sep 17 00:00:00 2001 From: John Furr Date: Mon, 12 Feb 2018 20:45:31 -0500 Subject: [PATCH 18/19] new migrations --- anouman/migrations/0001_initial.py | 64 ++++++++++++++++++++++++++++++ anouman/migrations/__init__.py | 0 2 files changed, 64 insertions(+) create mode 100644 anouman/migrations/0001_initial.py create mode 100644 anouman/migrations/__init__.py diff --git a/anouman/migrations/0001_initial.py b/anouman/migrations/0001_initial.py new file mode 100644 index 0000000..182b81b --- /dev/null +++ b/anouman/migrations/0001_initial.py @@ -0,0 +1,64 @@ +# Generated by Django 2.0.2 on 2018-02-13 01:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='CloudGroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32)), + ('firewall', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='IPAddress', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=32, null=True)), + ('ip', models.GenericIPAddressField(unique=True)), + ], + ), + migrations.CreateModel( + name='Machine', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32)), + ('droplet_id', models.PositiveSmallIntegerField(blank=True, null=True)), + ('ip', models.GenericIPAddressField(blank=True, null=True)), + ('private_ip', models.GenericIPAddressField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name='SSHKey', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32)), + ('public', models.TextField()), + ('private', models.TextField()), + ], + ), + migrations.AddField( + model_name='cloudgroup', + name='machines', + field=models.ManyToManyField(to='anouman.Machine'), + ), + migrations.AddField( + model_name='cloudgroup', + name='sshkeys', + field=models.ManyToManyField(to='anouman.SSHKey'), + ), + migrations.AddField( + model_name='cloudgroup', + name='whitelist', + field=models.ManyToManyField(to='anouman.IPAddress'), + ), + ] diff --git a/anouman/migrations/__init__.py b/anouman/migrations/__init__.py new file mode 100644 index 0000000..e69de29 From cb4b892951e0245cd046ea4faa023e466aba06d0 Mon Sep 17 00:00:00 2001 From: John Furr Date: Tue, 13 Feb 2018 17:21:51 -0500 Subject: [PATCH 19/19] updated README.rst --- README.rst | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/README.rst b/README.rst index 451b888..6600931 100644 --- a/README.rst +++ b/README.rst @@ -1,29 +1,17 @@ ===== -Polls +Anouman ===== -Polls is a simple Django app to conduct Web-based polls. For each -question, visitors can choose between a fixed number of answers. - -Detailed documentation is in the "docs" directory. +Currently Anouman is a cloud firewall wrapper. But soon it will be a django deployment option Quick start ----------- -1. Add "polls" to your INSTALLED_APPS setting like this:: +1. Add "anouman" to your INSTALLED_APPS setting like this:: INSTALLED_APPS = [ ... - 'polls', + 'anouman', ] -2. Include the polls URLconf in your project urls.py like this:: - - path('polls/', include('polls.urls')), - -3. Run `python manage.py migrate` to create the polls models. - -4. Start the development server and visit http://127.0.0.1:8000/admin/ - to create a poll (you'll need the Admin app enabled). - -5. Visit http://127.0.0.1:8000/polls/ to participate in the poll. +2. Run `python manage.py migrate` to create the polls models.