Skip to content

Instantly share code, notes, and snippets.

@miguelgrinberg
Last active June 10, 2018 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save miguelgrinberg/d9f1fcafc012f3fb3f03 to your computer and use it in GitHub Desktop.
Save miguelgrinberg/d9f1fcafc012f3fb3f03 to your computer and use it in GitHub Desktop.
#!/bin/bash
# note: this script is invoked automatically by rackspace-flasky.py
# save command line arguments
GMAIL_USERNAME=$1
GMAIL_PASSWORD=$2
# install web server dependencies
apt-get update
apt-get -y install python python-virtualenv nginx supervisor git
# create a flasky user
adduser --disabled-password --gecos "" flasky
# clone application from github
cd /home/flasky
git clone https://github.com/miguelgrinberg/flasky.git
cd flasky
# Flasky configuration
cat <<EOF >.env
FLASK_CONFIG=heroku
SECRET_KEY=3947865439567642
MAIL_USERNAME=$GMAIL_USERNAME
MAIL_PASSWORD=$GMAIL_PASSWORD
FLASKY_ADMIN=${GMAIL_USERNAME}@gmail.com
SSL_DISABLE=1
EOF
# create a virtualenv and install dependencies
virtualenv venv
venv/bin/pip install -r requirements/prod.txt
venv/bin/pip install gunicorn
# create database
venv/bin/python manage.py deploy
# make the flasky user the owner of everything
chown -R flasky:flasky ./
# configure supervisor
mkdir /var/log/flasky
cat <<EOF >/etc/supervisor/conf.d/flasky.conf
[program:flasky]
command=/home/flasky/flasky/venv/bin/gunicorn -b 127.0.0.1:8000 -w 4 --chdir /home/flasky/flasky --log-file - manage:app
user=flasky
autostart=true
autorestart=true
stderr_logfile=/var/log/flasky/stderr.log
stdout_logfile=/var/log/flasky/stdout.log
EOF
supervisorctl reread
supervisorctl update
# configure nginx
cat <<EOF >/etc/nginx/sites-available/flasky
server {
listen 80;
server_name _;
access_log /var/log/nginx/flasky.access.log;
error_log /var/log/nginx/flasky.error.log;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_redirect off;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
}
location /static {
alias /home/flasky/flasky/static;
}
location /favicon.ico {
alias /home/flasky/flasky/favicon.ico;
}
}
EOF
rm -f /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/flasky /etc/nginx/sites-enabled/
service nginx restart
#!/usr/bin/env python
import os
import time
import re
import argparse
import errno
from socket import error as socket_error
from getpass import getpass
import paramiko
import pyrax
nova = None
def get_flavor(name):
return nova.flavors.find(name=name)
def get_image(name):
return nova.images.find(name=name)
def create_web_server(flavor=None, image=None, key_name=None):
server = nova.servers.create(name='flasky', flavor=flavor.id,
image=image.id, key_name=key_name)
print 'Building, please wait...'
# wait for server create to be complete
while server.status == 'BUILD':
time.sleep(5)
server = nova.servers.get(server.id) # refresh server
# check for errors
if server.status != 'ACTIVE':
raise RuntimeError('Server did not boot, status=' + server.status)
# the server was assigned IPv4 and IPv6 addresses, locate the IPv4 address
ip_address = None
for network in server.networks['public']:
if re.match('\d+\.\d+\.\d+\.\d+', network):
ip_address = network
break
if ip_address is None:
raise RuntimeError('No IP address assigned!')
print 'Server is running at IP address ' + ip_address
return ip_address
def install_flasky(ip_address, gmail_username, gmail_password):
print 'Installing Flasky...'
# establish a SSH connection
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
retries_left = 3
while True:
try:
ssh.connect(ip_address, username='root')
break
except socket_error as e:
if e.errno != errno.ECONNREFUSED or retries_left <= 1:
raise e
time.sleep(10) # wait 10 seconds and retry
retries_left -= 1
# upload deployment script
ftp = ssh.open_sftp()
ftp.put('install-flasky.sh', 'install-flasky.sh')
ftp.chmod('install-flasky.sh', 0544)
# deploy
stdin, stdout, stderr = ssh.exec_command(
'./install-flasky.sh "{0}" "{1}"'.format(
gmail_username, gmail_password))
status = stdout.channel.recv_exit_status()
open('stdout.log', 'wt').write(stdout.read())
open('stderr.log', 'wt').write(stderr.read())
if status != 0:
raise RuntimeError(
'Deployment script returned status {0}.'.format(status))
def process_args():
parser = argparse.ArgumentParser(
description='Deploy Flasky to a Rackspace cloud server.')
parser.add_argument(
'--flavor', '-f', metavar='FLAVOR', default='512MB Standard Instance',
help='Flavor to use for the instance.'
'Default is 512MB Standard Instance.')
parser.add_argument(
'--image', '-i', metavar='IMAGE',
default='Ubuntu 14.04 LTS (Trusty Tahr)',
help='Image to use for the server. Default is Ubuntu 14.04.')
parser.add_argument(
'key_name', metavar='KEY_NAME',
help='Keypair name to install on the server. '
'Must be uploaded to your cloud account in advance.')
parser.add_argument(
'gmail_username', metavar='GMAIL_USERNAME',
help='The username of the gmail account that the web app '
'will use to send emails.')
return parser.parse_args()
def main():
args = process_args()
gmail_password = getpass('gmail password: ')
# instantiate the nova client
global nova
pyrax.set_setting('identity_type', os.environ['OS_AUTH_SYSTEM'])
pyrax.set_default_region(os.environ['OS_REGION_NAME'])
pyrax.set_credentials(os.environ['OS_USERNAME'], os.environ['OS_PASSWORD'])
nova = pyrax.cloudservers
flavor = get_flavor(args.flavor)
image = get_image(args.image)
ip_address = create_web_server(flavor, image, args.key_name)
install_flasky(ip_address, args.gmail_username, gmail_password)
print 'Flasky is now running at http://{0}.'.format(ip_address)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment