Chris Mahan's Hacking Notebook 2

Home > Hacking > Notebook 2

Rackspacecloud again

On September 22, 2012, I returned to rackspacecloud to set up an automated deployer. I had made one 2 years ago that worked on VPSes, and modified it to work on rackspacecloud. It still worked, mostly. I pushed it around a bit and made it work.

This is the script I use to create a new server.

Note that I read file nodename to get the name of the node, and that I write the node's root IP and password in file ippass (as IP:password).

The Rackspace Deployer

#!/usr/local/bin/python2.6

# easy_install-2.6 apache-libcloud
# and easy_install-2.6 zope.interface
from libcloud.types import Provider 
from libcloud.providers import get_driver 

import time
import sys

# private
RACKSPACE_USER = 'YOURUSERNAME' 
RACKSPACE_KEY = 'YOURAPIKEY' 
 
Driver = get_driver(Provider.RACKSPACE) 
conn = Driver(RACKSPACE_USER, RACKSPACE_KEY) 

# get nodename
nodename = file("nodename", "r").read().strip()

# let's see if the node already exists
nodes = conn.list_nodes()
    
for node in nodes:
    if node.name == nodename:
        print "the node name " + nodename + " is already in use!"
        sys.exit(1)
                
# retrieve available images and sizes 
images = conn.list_images() 
sizes = conn.list_sizes() 
 
for image in images:
    #print image.name
    if image.name == "Debian 6 (Squeeze)":
        targetimage = image 

node = conn.create_node(name=nodename, image=targetimage, size=sizes[0]) 

# rackspacecloud deployer
node_ip = node.public_ip
node_password = node.extra.get('password')

result = node_ip[0] + ":" + node_password

outfile = file("ippass", "w")
outfile.write(result)
outfile.close()
  
# how to get the node status?
node_loaded = False

while not node_loaded:
    time.sleep(10)
    nodes = conn.list_nodes()
    for node in nodes:
        if node.name == nodename:
            nodestate = node.state
            
            nodestate = int(nodestate)
            print "testing to see if " + nodename + " is ready."
            if nodestate == 0:
                node_loaded = True
                print "Yep, it's ready!"   

The change of password

The password is emailed out, so let's change it right away.

Here's the portion of the fab file that cahnges the password. All it really does is logs into the machine with the old credentials, and changes the root password with the chpasswd unix command.

It changes the existing password to the new password that is stored in file newpass.

I run this from the shell file:

#! /bin/sh

fab change_root_password

and now part of the fab file:

def change_root_password():
    ip, password = _get_ip_and_password()
    newpassword = _get_new_password()
    with cd("/"):
        run(' echo "root:' + newpassword + '" | chpasswd')
    _write_ip_and_password(ip, newpassword)


# DO SETUP
print "This ran!"

def _get_ip_and_password():
    ip_pass_file = file("ippass", "r")
    ip_pass = ip_pass_file.readline()
    ip_pass_list = ip_pass.split(":")
    current_ip = ip_pass_list[0]
    current_password = ip_pass_list[1]
    current_password = current_password.strip()
    ip_pass_file.close()
    return current_ip, current_password

def _get_new_password():
    new_pass_file = file("newpass", "r")
    new_pass = new_pass_file.readline()
    new_password = new_pass.strip()
    new_pass_file.close()
    return new_password

Then we update the server.

This is the section of the fab file where we set up the basic info on the server.

def setup_base_debian_6_sytem():
    """Install base system"""
    with settings(warn_only = True):
        with cd("/root"):
            run("apt-get -y update", pty= True)
            run("apt-get -y install debian-keyring debian-archive-keyring", pty = True)
            run("apt-get -y update", pty = True)
            run("apt-get -y install patch", pty = True)
            run("apt-get -y install bzip2", pty = True)
            run("apt-get -y install wget", pty = True)
            run("apt-get -y autoremove", pty = True)

This just updates the debian system to the latest version, and adds patch, bzip2 and wget, which is used by downloaders.

Onward!

The fab file continues with:

fab setup_apache2
fab setup_php5
fab setup_mysql

Where we setup apache2, php5, and mysql (5.1)

Apache2

def setup_apache2():
    """setup apache2"""
    with settings(warn_only = True):
        with cd("/root"):
            run("apt-get -y install apache2", pty = True)

That one's pretty simple. It just installs apache2, with default configuration.

You should be able to browse to your server's IP address using a web browser, and see the "It Works" page.

PHP5

def setup_php5():
    """setup php5"""
    with settings(warn_only = True):
        with cd("/root"):
            run("apt-get -y install php5", pty = True)
            run("apt-get -y install libapache2-mod-php5", pty = True)
            run("apt-get -y install php5-mysql", pty = True)
            put("index.php","/var/www/index.php") 

This installs php5, mod_php, and php5 for mysql.

I also copy a index.php to the web server base directory, so you can go to that page and see the output of phpinfo.

I recommend you remove that file after you're satisfied PHP works as needed.

MySQL

here I install MySQL. This is a simple config, but it will probably change, as I am looking to set up master-slave replication. I'll keep it here so people can see it.

def setup_mysql():
    """ setup mysql """
    with settings(warn_only = True):
        with cd("/root"):
            mysql_password = _get_new_mysql_password()
            run('echo "mysql-server-5.1 mysql-server/root_password password ' + mysql_password + '" | debconf-set-selections')
            run('echo "mysql-server-5.1 mysql-server/root_password_again password ' + mysql_password + '" | debconf-set-selections')
            run("apt-get -y install mysql-server", pty = True)

I got some info there on how to install mysql server with fabric from how to install mysql with fabric from Muhuk.com (Pythonista and Debian user in Singapore). Thanks for sharing Atamert!

As an aside, if you're into Origami, check out Creased.

Munin

Now, setting up munin, since I did not do this before (it's 2012 and I haven't set up munin before? Grig's gonna hunt me down).

for Munin 403 with apache.

Munin configuration error.

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=610825.

Argghh. I give up... Munin too hard. me too tired. Wednesday 9/26/2012 23:22.

Now, it's later, I'm at Peet's coffee with Viggo. Saturday, September 29th.

I changed the setup to point to a different account, and made a test server.

Now, I'm going to set up a master sql server, and a slave, and three front-end web servers.

I'm going to modify the python script and have it create multiple servers... Mmm.

Later that night...

So I went down the rabbit hole and on tangents, realizing I would have to make a python tool that makes the node creator and the fabric functions work together as one. Then, oh man, I thought about what that meant with fabric... and I wasn't sure aI wanted to go and import fabric into a new project instead of using it from the command file with fab like it's supposed to be. So I went looking at paramiko and there was the whole paramiko vs ssh, etc. To his credit, Jeff Forcier seems to have managed to handle this well of late.

As another aside, I was thinking it would be nice to be able to just write books in html, like I do this note, and then I went down another rabbit hole and endded up on google+. Arrrgh! In the end, I'm going to look at xhtml2pdf.

Anyway. Back to this. Paramiko? More information at its github page.

But after reading the section on Fabric on inporting fabric, I can't help but think it's better to just use paramiko.

Yikes, paramiko is hard to find examples for... Back to Fabric!

with: fabric direct api call from stackoverflow, I'm back on track!

Got some help from Paul Bailey of neutron ide.