In this example we will use web.py framework to run their Todo-list example in a Vagrant box. This includes installing all dependencies, importing database schema and setting up appropriate configuration.
For this tutorial you will need to install on your machine:
Warning
I’m using PuTTy, but for this tutorial I’ve installed OpenSSH to check everything is running fine. This also wiped out my %PATH% and the only thing left was OpenSSH itself :), so make a backup I’m not sure if this was due my error or because of OpenSSH.
After you are ready with this get our vagrant example from https://github.com/avladev/pypro/examples/vagrant_todo somewhere on your drive.
Project structure is:
/vagrant_todo
/provision // Here lives pypro recipes and settings
/data // Data folder is not required by pypro, we use it to store any data files
db.sql // Database schema for todo-list app
/recipes
config.py // Recipe which acts as global config file for our recipes
dependencies.py // Recipes for dependencies needed by the project
mysql.py // Recipes for installing and running some useful mysql commands
project.py // Recipes for producing /todo/config.py file
utils.py // General useful tools
/settings
config.ini // Settings for our global config
mysql.ini // Settings for mysql mainly for root password
suite.ppr // Suite file with each step
/todo // This is web.py todo-list app with slight change of configuration to be outside of model.py
/templates // HTML views
base.html
index.html
model.py // Model for interacting with mysql db
todo.py // The app itself
Vagrantfile // Vagrant file for running our machine
For this tutorial we will use:
Vagrant is a tool which integrates with VirtualBox to “Create and configure lightweight, reproducible, and portable development environments.” This tutorial will only touch a couple of concepts which you will need to run this example.
Note
If you are not familiar with Vagrant check its documentation at http://docs.vagrantup.com
So Vagrant is very useful when you want to work on your projects in isolated VM environment, its goal is to make our lives easier by providing a couple of useful commands to do that.
Although we will only use vagrant up command because of pre existing Vagrantfile bellow are are most used Vagrant commands.
Basic Vagrant commands | |
---|---|
vagrant init | Creates Vagrantfile file in your current directory. This file is a Vagrant configuration file for your project. |
vagrant add box url | Downloads VirtualBox template virtual disk with pre-installed OS. |
vagrant up | Starts your virtual machine based on the box you specified. |
vagrant halt | Shuts down your VM. |
vagrant destroy | Destroys your virtual disk. Next time you up this project it will start with fresh box copy. |
I assume you already have installed VirtualBox, Vagrant and OpenSSH on your Windows machine. The next step is to open a command prompt and navigate to the directory /vagrant_todo you downloaded.
To create a new VM instance execute:
``vagrant up``
This command will look for Vagrantfile and will download precise32 box and boot your machine based on it.
Note
Your machine is Ubuntu precise32 with predefined IP address 10.10.10.10. This is defined in Vagrantfile you can change it if you want.
Next step is to login trough SSH to your machine, Vagrant uses RSA key for authentication to the machine.:
``vagrant ssh``
OpenSSH will ask you for a passphrase which have to be empty so just press enter. For password use vagrant:
Enter passphrase for key 'C:/Users/<User>/.vagrant.d/insecure_private_key':
vagrant@127.0.0.1's password: vagrant
This will log you in your VM.
Note
If you are using PuTTy note that Vagrant RSA key should be converted with PuTTyGen in order to work with PuTTy. The key is located in C:\Users\<User>\.vagrant.d\insecure_private_key see appendix for more information.
Ubuntu should come with python installed by default, but without pip or easy_install. So we have to install it:
``sudo apt-get install python-pip``
Next step is to install pypro packages:
``sudo pip install pypro``
If everything is successful you should be able to run ppr.py command in the shell. Lets try:
``ppr.py``
Result should be a complain that there is no recipes directory:
[Error] No recipes directory found!
That’s fine.
Now the culmination of our work running our recipes. We need to cd to provision folder which contains our recipes and from this folder to run ppr.py as root because we will install from packages trough apt-get:
``cd /vagrant/provision``
``sudo ppr.py -s suite.ppr -y``
This commands have to be executed without and error (hopefully :)).
So let’s check if your app is working:
``cd /vagrant/todo``
``python todo.py``
You should see output http://0.0.0.0:8080 . Return back to your host machine and open an browser windows and enter http://10.10.10.10:8080 this have to load the todo-list app showing input field and submit button. Play with it if you want.
Next task is to explain all the recipes and suite file so you can learn how to setup projects like this one by yourself.
This file contains our recipes calls with comments in it. Take a look:
# General stuff
---------------
* Check we are with root privileges
utils.CheckRoot
* Update APT
utils.UpdateAPT
# Install dependencies
----------------------
* Install web.py framework
dependencies.InstallWebPy
* Install MySQL server
mysql.Install
* Install MySQLdb support for python
dependencies.InstallMySQLdb
# Setup project
---------------
* Create database schema
mysql.ExecuteSQL file=./data/db.sql database=@{config.db.db_name} username=root password=@{mysql.install.root_password}
* Create database user
mysql.Grant database=@{config.db.db_name} username=@{config.db.username} password=@{config.db.password}
* Create config file
project.CreateConfig source=./data/config.py destination=../todo/config.py
This should be clear enough, so I will not explain more about it.
This recipe just checks that we are running ppr.py as root which is useful because you can forget to run it as root and this will give you error when trying to install packages.
This recipe uses apt-get update command to retrieve fresh list of all packages.
The interesting thing here if you look at the source code is runner.call() method. This method allows you to execute system command. This method returns the command output if you need it for something.
This recipe install web.py framework python package so we can run out todo-list app.
This will install mysql-server. Вe define root_password in mysql.ini settings file, so we can use it in other recipes, we also define an static method root_password() so we can access this from other recipes.
If you look at the source code of Install.root_password() method you will se that it creates new instance of Install() recipe and retrieves its root_password setting. This is possible also in other modules and other recipes too if you want to access some of the settings of other recipes. This should be used with care because it creates dependency between your recipes.
This installs mysql support for python needed for todo-list app to store its todos.
Let see the line in the suite.ppr:
mysql.ExecuteSQL file=./data/db.sql database=@{config.db.db_name} username=root password=@{mysql.install.root_password}
This recipe creates a database with name specified in the config.DB recipe which serves as global configuration. And then imports the ./data/db.sql file into the mysql.
You can also see that we again access mysql.Install root_password so we can login into mysql as root to execute CREATE DATABASE statement and the db.sql file.
Suite line:
mysql.Grant database=@{config.db.db_name} username=@{config.db.username} password=@{config.db.password}
This recipe creates a mysql user for our database used by todo-list app.
Suite line:
project.CreateConfig source=./data/config.py destination=../todo/config.py
This one creates config file ../todo/config.py based on ./data/config.py. Lets take a look at ./data/config.py:
db_name='@{config.db.db_name}'
db_user='@{config.db.username}'
db_password='@{config.db.password}'
db_todo_table='@{config.db.todo_table}'
This is a simple python module with a couple of string variables. The interesting about it is that these @{} notations are replaced in project.CreateConfig run method by pypro.core.Variables.replace(string) method.
import pypro.core
import os
class CreateConfig(pypro.core.Recipe):
def __init__(self, source, destination):
self.source = source
self.destination = destination
def run(self, runner, arguments=None):
# Read the template file
content = ''
with open(self.source, 'r') as f:
content = f.read(os.path.getsize(self.source))
# Replace notations with actual values
content = pypro.core.Variables.replace(content)
# Write the config file
with open(self.destination, 'w') as f:
f.write(content)
This class method is used in pypro itself to parse and find any setting that you want. Basically it searches for @{} notation and finds the recipe, instantiate it and replace the notation with actual value stored in the .ini file.
Install and run PuTTyGen:
Install and run PuTTy: