diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..22a7898 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +proto +*~ +localrc diff --git a/README b/README new file mode 100644 index 0000000..61119e9 --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +Tool to quickly deploy openstack dev environments. + +# Goals + +* To quickly build dev openstack environments in clean natty environments +* To describe working configurations of openstack (which code branches work together? what do config files look like for those branches?) +* To make it easier for developers to dive into openstack so that they can productively contribute without having to understand every part of the system at once +* To make it easy to prototype cross-project features + +Be sure to carefully read these scripts before you run them as they install software and may alter your networking configuration. + +# To start a dev cloud on your local machine (installing on a dedicated vm is safer!): + + ./stack.sh + +If working correctly, you should be able to access openstack endpoints, like: + +* Dashboard: http://myhost/ +* Keystone: http://myhost:5000/v2.0/ + +# To start a dev cloud in an lxc container: + + ./build_lxc.sh + +You will need to configure a bridge and network on your host machine (by default br0) before starting build_lxc.sh. A sample host-only network configuration can be found in lxc_network_hostonlyplusnat.sh. + +# Customizing + +You can tweak environment variables by creating file name 'localrc' should you need to override defaults. It is likely that you will need to do this to tweak your networking configuration should you need to access your cloud from a different host. + +# Todo + +* Add python-novaclient cli support +* syslog +* allow rabbit connection to be specified via environment variables with sensible defaults +* Add volume support +* Add quantum support + +# Future + +* idea: move from screen to tmux? +* idea: create a live-cd / vmware preview image using this? diff --git a/build_lxc.sh b/build_lxc.sh new file mode 100755 index 0000000..643da7e --- /dev/null +++ b/build_lxc.sh @@ -0,0 +1,251 @@ +#!/usr/bin/env bash + +# Sanity check +if [ "$EUID" -ne "0" ]; then + echo "This script must be run with root privileges." + exit 1 +fi + +# Warn users who aren't on natty +if ! grep -q natty /etc/lsb-release; then + echo "WARNING: this script has only been tested on natty" +fi + +# Source params +source ./stackrc + +# Store cwd +CWD=`pwd` + +# Configurable params +BRIDGE=${BRIDGE:-br0} +CONTAINER=${CONTAINER:-STACK} +CONTAINER_IP=${CONTAINER_IP:-192.168.1.50} +CONTAINER_CIDR=${CONTAINER_CIDR:-$CONTAINER_IP/24} +CONTAINER_NETMASK=${CONTAINER_NETMASK:-255.255.255.0} +CONTAINER_GATEWAY=${CONTAINER_GATEWAY:-192.168.1.1} +NAMESERVER=${NAMESERVER:-$CONTAINER_GATEWAY} +COPYENV=${COPYENV:-1} +DEST=${DEST:-/opt/stack} + +# Param string to pass to stack.sh. Like "EC2_DMZ_HOST=192.168.1.1 MYSQL_USER=nova" +STACKSH_PARAMS=${STACKSH_PARAMS:-} + +# Option to use the version of devstack on which we are currently working +USE_CURRENT_DEVSTACK=${USE_CURRENT_DEVSTACK:-1} + + +# Install deps +apt-get install -y lxc debootstrap + +# Install cgroup-bin from source, since the packaging is buggy and possibly incompatible with our setup +if ! which cgdelete | grep -q cgdelete; then + apt-get install -y g++ bison flex libpam0g-dev make + wget http://sourceforge.net/projects/libcg/files/libcgroup/v0.37.1/libcgroup-0.37.1.tar.bz2/download -O /tmp/libcgroup-0.37.1.tar.bz2 + cd /tmp && bunzip2 libcgroup-0.37.1.tar.bz2 && tar xfv libcgroup-0.37.1.tar + cd libcgroup-0.37.1 + ./configure + make install + ldconfig +fi + +# Create lxc configuration +LXC_CONF=/tmp/$CONTAINER.conf +cat > $LXC_CONF <> $ROOTFS/etc/sudoers + +# Copy kernel modules +mkdir -p $ROOTFS/lib/modules/`uname -r`/kernel +cp -p /lib/modules/`uname -r`/modules.dep $ROOTFS/lib/modules/`uname -r`/ +cp -pR /lib/modules/`uname -r`/kernel/net $ROOTFS/lib/modules/`uname -r`/kernel/ + +# Gracefully cp only if source file/dir exists +function cp_it { + if [ -e $1 ] || [ -d $1 ]; then + cp -pRL $1 $2 + fi +} + +# Copy over your ssh keys and env if desired +if [ "$COPYENV" = "1" ]; then + cp_it ~/.ssh $ROOTFS/$DEST/.ssh + cp_it ~/.ssh/id_rsa.pub $ROOTFS/$DEST/.ssh/authorized_keys + cp_it ~/.gitconfig $ROOTFS/$DEST/.gitconfig + cp_it ~/.vimrc $ROOTFS/$DEST/.vimrc + cp_it ~/.bashrc $ROOTFS/$DEST/.bashrc +fi + +# Make our ip address hostnames look nice at the command prompt +echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $ROOTFS/$DEST/.bashrc +echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $ROOTFS/etc/profile + +# Give stack ownership over $DEST so it may do the work needed +chroot $ROOTFS chown -R stack $DEST + +# Configure instance network +INTERFACES=$ROOTFS/etc/network/interfaces +cat > $INTERFACES < $RUN_SH < /$DEST/run.sh.log +echo >> /$DEST/run.sh.log +echo >> /$DEST/run.sh.log +echo "All done! Time to start clicking." >> /$DEST/run.sh.log +EOF + +# Make the run.sh executable +chmod 755 $RUN_SH + +# Make runner launch on boot +RC_LOCAL=$ROOTFS/etc/rc.local +cat > $RC_LOCAL <> $CHROOTCACHE/natty-dev/etc/sudoers +fi + +# clone git repositories onto the system +# ====================================== + +if [ ! -d $CHROOTCACHE/natty-stack ]; then + rsync -azH $CHROOTCACHE/natty-dev/ $CHROOTCACHE/natty-stack/ +fi + +# git clone only if directory doesn't exist already. Since ``DEST`` might not +# be owned by the installation user, we create the directory and change the +# ownership to the proper user. +function git_clone { + + # clone new copy or fetch latest changes + CHECKOUT=$CHROOTCACHE/natty-stack$2 + if [ ! -d $CHECKOUT ]; then + mkdir -p $CHECKOUT + git clone $1 $CHECKOUT + else + pushd $CHECKOUT + git fetch + popd + fi + + # FIXME(ja): checkout specified version (should works for branches and tags) + + pushd $CHECKOUT + # checkout the proper branch/tag + git checkout $3 + # force our local version to be the same as the remote version + git reset --hard origin/$3 + popd + + # give ownership to the stack user + chroot $CHROOTCACHE/natty-stack/ chown -R stack $2 +} + +git_clone $NOVA_REPO $DEST/nova $NOVA_BRANCH +git_clone $GLANCE_REPO $DEST/glance $GLANCE_BRANCH +git_clone $KEYSTONE_REPO $DEST/keystone $KEYSTONE_BRANCH +git_clone $NOVNC_REPO $DEST/novnc $NOVNC_BRANCH +git_clone $DASH_REPO $DEST/dash $DASH_BRANCH $DASH_TAG +git_clone $NOVACLIENT_REPO $DEST/python-novaclient $NOVACLIENT_BRANCH +git_clone $OPENSTACKX_REPO $DEST/openstackx $OPENSTACKX_BRANCH + +chroot $CHROOTCACHE/natty-stack mkdir -p $DEST/files +wget -c http://images.ansolabs.com/tty.tgz -O $CHROOTCACHE/natty-stack$DEST/files/tty.tgz + +# Use this version of devstack? +if [ "$USE_CURRENT_DEVSTACK" = "1" ]; then + rm -rf $CHROOTCACHE/natty-stack/$DEST/devstack + cp -pr $CWD $CHROOTCACHE/natty-stack/$DEST/devstack +fi + +cp -pr $CHROOTCACHE/natty-stack $NFSDIR + +# set hostname +echo $NAME > $NFSDIR/etc/hostname +echo "127.0.0.1 localhost $NAME" > $NFSDIR/etc/hosts + +# injecting root's public ssh key if it exists +if [ -f /root/.ssh/id_rsa.pub ]; then + mkdir $NFSDIR/root/.ssh + chmod 700 $NFSDIR/root/.ssh + cp /root/.ssh/id_rsa.pub $NFSDIR/root/.ssh/authorized_keys +fi diff --git a/build_pxe_boot.sh b/build_pxe_boot.sh new file mode 100755 index 0000000..4feb14d --- /dev/null +++ b/build_pxe_boot.sh @@ -0,0 +1,116 @@ +#!/bin/bash -e +# build_pxe_boot.sh - Create a PXE boot environment +# +# build_pxe_boot.sh [-k kernel-version] destdir +# +# Assumes syslinux is installed +# Assumes devstack files are in `pwd`/pxe +# Only needs to run as root if the destdir permissions require it + +UBUNTU_MIRROR=http://archive.ubuntu.com/ubuntu/dists/natty/main/installer-amd64/current/images/netboot/ubuntu-installer/amd64 + +MEMTEST_VER=4.10 +MEMTEST_BIN=memtest86+-${MEMTEST_VER}.bin +MEMTEST_URL=http://www.memtest.org/download/${MEMTEST_VER}/ + +KVER=`uname -r` +if [ "$1" = "-k" ]; then + KVER=$2 + shift;shift +fi + +DEST_DIR=${1:-/tmp}/tftpboot +PXEDIR=${PXEDIR:-/var/cache/devstack/pxe} +OPWD=`pwd` +PROGDIR=`dirname $0` + +mkdir -p $DEST_DIR/pxelinux.cfg +cd $DEST_DIR +for i in memdisk menu.c32 pxelinux.0; do + cp -p /usr/lib/syslinux/$i $DEST_DIR +done + +DEFAULT=$DEST_DIR/pxelinux.cfg/default +cat >$DEFAULT <>$DEFAULT <>$DEFAULT <>$DEFAULT <>$DEFAULT <>$DEFAULT <> $CHROOTCACHE/natty-dev/etc/sudoers +fi + +# clone git repositories onto the system +# ====================================== + +if [ ! -d $CHROOTCACHE/natty-stack ]; then + rsync -azH $CHROOTCACHE/natty-dev/ $CHROOTCACHE/natty-stack/ +fi + +# git clone only if directory doesn't exist already. Since ``DEST`` might not +# be owned by the installation user, we create the directory and change the +# ownership to the proper user. +function git_clone { + + # clone new copy or fetch latest changes + CHECKOUT=$CHROOTCACHE/natty-stack$2 + if [ ! -d $CHECKOUT ]; then + mkdir -p $CHECKOUT + git clone $1 $CHECKOUT + else + pushd $CHECKOUT + git fetch + popd + fi + + # FIXME(ja): checkout specified version (should works for branches and tags) + + pushd $CHECKOUT + # checkout the proper branch/tag + git checkout $3 + # force our local version to be the same as the remote version + git reset --hard origin/$3 + popd + + # give ownership to the stack user + chroot $CHROOTCACHE/natty-stack/ chown -R stack $2 +} + +git_clone $NOVA_REPO $DEST/nova $NOVA_BRANCH +git_clone $GLANCE_REPO $DEST/glance $GLANCE_BRANCH +git_clone $KEYSTONE_REPO $DEST/keystone $KEYSTONE_BRANCH +git_clone $NOVNC_REPO $DEST/novnc $NOVNC_BRANCH +git_clone $DASH_REPO $DEST/dash $DASH_BRANCH +git_clone $NOVACLIENT_REPO $DEST/python-novaclient $NOVACLIENT_BRANCH +git_clone $OPENSTACKX_REPO $DEST/openstackx $OPENSTACKX_BRANCH + +# Use this version of devstack? +if [ "$USE_CURRENT_DEVSTACK" = "1" ]; then + rm -rf $CHROOTCACHE/natty-stack/$DEST/devstack + cp -pr $CWD $CHROOTCACHE/natty-stack/$DEST/devstack +fi + +# Configure host network for DHCP +mkdir -p $CHROOTCACHE/natty-stack/etc/network +cat > $CHROOTCACHE/natty-stack/etc/network/interfaces < $1 + diff --git a/exercise.sh b/exercise.sh new file mode 100755 index 0000000..d9d4c0a --- /dev/null +++ b/exercise.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +# **exercise.sh** - using the cloud can be fun + +# we will use the ``nova`` cli tool provided by the ``python-novaclient`` +# package +# + + +# This script exits on an error so that errors don't compound and you see +# only the first error that occured. +set -o errexit + +# Print the commands being run so that we can see the command that triggers +# an error. It is also useful for following allowing as the install occurs. +set -o xtrace + + +# Settings +# ======== + +HOST=${HOST:-localhost} + +# Nova original used project_id as the *account* that owned resources (servers, +# ip address, ...) With the addition of Keystone we have standardized on the +# term **tenant** as the entity that owns the resources. **novaclient** still +# uses the old deprecated terms project_id. Note that this field should now be +# set to tenant_name, not tenant_id. +export NOVA_PROJECT_ID=${TENANT:-demo} + +# In addition to the owning entity (tenant), nova stores the entity performing +# the action as the **user**. +export NOVA_USERNAME=${USERNAME:-demo} + +# With Keystone you pass the keystone password instead of an api key. +export NOVA_API_KEY=${PASSWORD:-secrete} + +# With the addition of Keystone, to use an openstack cloud you should +# authenticate against keystone, which returns a **Token** and **Service +# Catalog**. The catalog contains the endpoint for all services the user/tenant +# has access to - including nova, glance, keystone, swift, ... We currently +# recommend using the 2.0 *auth api*. +# +# *NOTE*: Using the 2.0 *auth api* does mean that compute api is 2.0. We will +# use the 1.1 *compute api* +export NOVA_URL=${NOVA_URL:-http://$HOST:5000/v2.0/} + +# Currently novaclient needs you to specify the *compute api* version. This +# needs to match the config of your catalog returned by Keystone. +export NOVA_VERSION=1.1 + +# FIXME - why does this need to be specified? +export NOVA_REGION_NAME=RegionOne + + +# Get a token for clients that don't support service catalog +# ========================================================== +SERVICE_TOKEN=`curl -s -d "{\"auth\":{\"passwordCredentials\": {\"username\": \"$NOVA_PROJECT_ID\", \"password\": \"$NOVA_API_KEY\"}}}" -H "Content-type: application/json" http://$HOST:5000/v2.0/tokens | python -c "import sys; import json; tok = json.loads(sys.stdin.read()); print tok['access']['token']['id'];"` + +# Launching a server +# ================== + +# List servers for tenant: +nova list + +# List of flavors: +nova flavor-list + +# Images +# ------ + +# Nova has a **deprecated** way of listing images. +nova image-list + +# But we recommend using glance directly +glance -A $SERVICE_TOKEN index + +# show details of the active servers:: +# +# nova show 1234 +# +nova list | grep ACTIVE | cut -d \| -f2 | xargs -n1 nova show diff --git a/files/000-default.template b/files/000-default.template new file mode 100644 index 0000000..4e4b5c4 --- /dev/null +++ b/files/000-default.template @@ -0,0 +1,27 @@ + + WSGIScriptAlias / %DASH_DIR%/openstack-dashboard/dashboard/wsgi/django.wsgi + WSGIDaemonProcess dashboard user=%USER% group=%USER% processes=3 threads=10 + SetEnv APACHE_RUN_USER %USER% + SetEnv APACHE_RUN_GROUP %USER% + WSGIProcessGroup dashboard + + DocumentRoot %DASH_DIR%/.blackhole/ + Alias /media %DASH_DIR%/openstack-dashboard/media + + + Options FollowSymLinks + AllowOverride None + + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + + + ErrorLog /var/log/apache2/error.log + LogLevel warn + CustomLog /var/log/apache2/access.log combined + + diff --git a/files/apts/dash b/files/apts/dash new file mode 100644 index 0000000..91b852d --- /dev/null +++ b/files/apts/dash @@ -0,0 +1,4 @@ +apache2 +libapache2-mod-wsgi +python-dateutil +python-anyjson diff --git a/files/apts/general b/files/apts/general new file mode 100644 index 0000000..32379c0 --- /dev/null +++ b/files/apts/general @@ -0,0 +1,14 @@ +pep8 +pylint +python-pip +screen +unzip +wget +psmisc +git-core +lsof # useful when debugging +openssh-server +vim-nox +locate # useful when debugging +python-virtualenv +python-unittest2 diff --git a/files/apts/glance b/files/apts/glance new file mode 100644 index 0000000..1e87d58 --- /dev/null +++ b/files/apts/glance @@ -0,0 +1,8 @@ +python-eventlet +python-routes +python-greenlet +python-argparse +python-sqlalchemy +python-wsgiref +python-pastedeploy +python-xattr diff --git a/files/apts/keystone b/files/apts/keystone new file mode 100644 index 0000000..6e6d3d5 --- /dev/null +++ b/files/apts/keystone @@ -0,0 +1,15 @@ +python-setuptools +python-dev +python-lxml +python-pastescript +python-pastedeploy +python-paste +sqlite3 +python-pysqlite2 +python-sqlalchemy +python-webob +python-greenlet +python-routes +libldap2-dev +libsasl2-dev + diff --git a/files/apts/nova b/files/apts/nova new file mode 100644 index 0000000..eb85e26 --- /dev/null +++ b/files/apts/nova @@ -0,0 +1,35 @@ +dnsmasq-base +kpartx +mysql-server +python-mysqldb +kvm +gawk +iptables +ebtables +sqlite3 +sudo +kvm +libvirt-bin +vlan +curl +rabbitmq-server +socat # used by ajaxterm +python-mox +python-paste +python-migrate +python-gflags +python-greenlet +python-libvirt +python-libxml2 +python-routes +python-netaddr +python-pastedeploy +python-eventlet +python-cheetah +python-carrot +python-tempita +python-sqlalchemy +python-suds +python-lockfile +python-m2crypto +python-boto diff --git a/files/apts/novnc b/files/apts/novnc new file mode 100644 index 0000000..c8722b9 --- /dev/null +++ b/files/apts/novnc @@ -0,0 +1 @@ +python-numpy diff --git a/files/apts/preseed b/files/apts/preseed new file mode 100644 index 0000000..8712d5d --- /dev/null +++ b/files/apts/preseed @@ -0,0 +1,18 @@ +# a collection of packages that speed up installation as they are dependencies +# of packages we can't install during bootstraping (rabbitmq-server, +# mysql-server, libvirt-bin) +# +# NOTE: only add packages to this file that aren't needed directly +mysql-common +mysql-client-5.1 +erlang-base +erlang-ssl +erlang-nox +erlang-inets +erlang-mnesia +libhtml-template-perl +gettext-base +libavahi-client3 +libxml2-utils +libpciaccess0 +libparted0debian1 diff --git a/files/dash_settings.py b/files/dash_settings.py new file mode 100644 index 0000000..74d0350 --- /dev/null +++ b/files/dash_settings.py @@ -0,0 +1,98 @@ +import os + +DEBUG = True +TEMPLATE_DEBUG = DEBUG +PROD = False +USE_SSL = False + +LOCAL_PATH = os.path.dirname(os.path.abspath(__file__)) + +# FIXME: We need to change this to mysql, instead of sqlite. +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(LOCAL_PATH, 'dashboard_openstack.sqlite3'), + }, +} + +CACHE_BACKEND = 'dummy://' + +# Add apps to dash installation. +INSTALLED_APPS = ( + 'dashboard', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django_openstack', + 'django_openstack.templatetags', + 'mailer', +) + + +# Send email to the console by default +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +# Or send them to /dev/null +#EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' + +# django-mailer uses a different settings attribute +MAILER_EMAIL_BACKEND = EMAIL_BACKEND + +# Configure these for your outgoing email host +# EMAIL_HOST = 'smtp.my-company.com' +# EMAIL_PORT = 25 +# EMAIL_HOST_USER = 'djangomail' +# EMAIL_HOST_PASSWORD = 'top-secret!' + +# FIXME: This needs to be changed to allow for multi-node setup. +OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0/" +OPENSTACK_KEYSTONE_ADMIN_URL = "http://localhost:35357/v2.0" +OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member" + +# NOTE(tres): Available services should come from the service +# catalog in Keystone. +SWIFT_ENABLED = False + +# Configure quantum connection details for networking +QUANTUM_ENABLED = False +QUANTUM_URL = '127.0.0.1' +QUANTUM_PORT = '9696' +QUANTUM_TENANT = '1234' +QUANTUM_CLIENT_VERSION='0.1' + +# No monitoring links currently +EXTERNAL_MONITORING = [] + +# Uncomment the following segment to silence most logging +# django.db and boto DEBUG logging is extremely verbose. +#LOGGING = { +# 'version': 1, +# # set to True will disable all logging except that specified, unless +# # nothing is specified except that django.db.backends will still log, +# # even when set to True, so disable explicitly +# 'disable_existing_loggers': False, +# 'handlers': { +# 'null': { +# 'level': 'DEBUG', +# 'class': 'django.utils.log.NullHandler', +# }, +# 'console': { +# 'level': 'DEBUG', +# 'class': 'logging.StreamHandler', +# }, +# }, +# 'loggers': { +# # Comment or Uncomment these to turn on/off logging output +# 'django.db.backends': { +# 'handlers': ['null'], +# 'propagate': False, +# }, +# 'django_openstack': { +# 'handlers': ['null'], +# 'propagate': False, +# }, +# } +#} + +# How much ram on each compute host? +COMPUTE_HOST_RAM_GB = 16 diff --git a/files/glance-api.conf b/files/glance-api.conf new file mode 100644 index 0000000..0358a7a --- /dev/null +++ b/files/glance-api.conf @@ -0,0 +1,178 @@ +[DEFAULT] +# Show more verbose log output (sets INFO log level output) +verbose = True + +# Show debugging output in logs (sets DEBUG log level output) +debug = True + +# Which backend store should Glance use by default is not specified +# in a request to add a new image to Glance? Default: 'file' +# Available choices are 'file', 'swift', and 's3' +default_store = file + +# Address to bind the API server +bind_host = 0.0.0.0 + +# Port the bind the API server to +bind_port = 9292 + +# Address to find the registry server +registry_host = 0.0.0.0 + +# Port the registry server is listening on +registry_port = 9191 + +# Log to this file. Make sure you do not set the same log +# file for both the API and registry servers! +log_file = %DEST%/glance/api.log + +# Send logs to syslog (/dev/log) instead of to file specified by `log_file` +use_syslog = False + +# ============ Notification System Options ===================== + +# Notifications can be sent when images are create, updated or deleted. +# There are three methods of sending notifications, logging (via the +# log_file directive), rabbit (via a rabbitmq queue) or noop (no +# notifications sent, the default) +notifier_strategy = noop + +# Configuration options if sending notifications via rabbitmq (these are +# the defaults) +rabbit_host = localhost +rabbit_port = 5672 +rabbit_use_ssl = false +rabbit_userid = guest +rabbit_password = guest +rabbit_virtual_host = / +rabbit_notification_topic = glance_notifications + +# ============ Filesystem Store Options ======================== + +# Directory that the Filesystem backend store +# writes image data to +filesystem_store_datadir = %DEST%/glance/images/ + +# ============ Swift Store Options ============================= + +# Address where the Swift authentication service lives +swift_store_auth_address = 127.0.0.1:8080/v1.0/ + +# User to authenticate against the Swift authentication service +swift_store_user = jdoe + +# Auth key for the user authenticating against the +# Swift authentication service +swift_store_key = a86850deb2742ec3cb41518e26aa2d89 + +# Container within the account that the account should use +# for storing images in Swift +swift_store_container = glance + +# Do we create the container if it does not exist? +swift_store_create_container_on_put = False + +# What size, in MB, should Glance start chunking image files +# and do a large object manifest in Swift? By default, this is +# the maximum object size in Swift, which is 5GB +swift_store_large_object_size = 5120 + +# When doing a large object manifest, what size, in MB, should +# Glance write chunks to Swift? This amount of data is written +# to a temporary disk buffer during the process of chunking +# the image file, and the default is 200MB +swift_store_large_object_chunk_size = 200 + +# Whether to use ServiceNET to communicate with the Swift storage servers. +# (If you aren't RACKSPACE, leave this False!) +# +# To use ServiceNET for authentication, prefix hostname of +# `swift_store_auth_address` with 'snet-'. +# Ex. https://example.com/v1.0/ -> https://snet-example.com/v1.0/ +swift_enable_snet = False + +# ============ S3 Store Options ============================= + +# Address where the S3 authentication service lives +s3_store_host = 127.0.0.1:8080/v1.0/ + +# User to authenticate against the S3 authentication service +s3_store_access_key = <20-char AWS access key> + +# Auth key for the user authenticating against the +# S3 authentication service +s3_store_secret_key = <40-char AWS secret key> + +# Container within the account that the account should use +# for storing images in S3. Note that S3 has a flat namespace, +# so you need a unique bucket name for your glance images. An +# easy way to do this is append your AWS access key to "glance". +# S3 buckets in AWS *must* be lowercased, so remember to lowercase +# your AWS access key if you use it in your bucket name below! +s3_store_bucket = glance + +# Do we create the bucket if it does not exist? +s3_store_create_bucket_on_put = False + +# ============ Image Cache Options ======================== + +image_cache_enabled = False + +# Directory that the Image Cache writes data to +# Make sure this is also set in glance-pruner.conf +image_cache_datadir = /var/lib/glance/image-cache/ + +# Number of seconds after which we should consider an incomplete image to be +# stalled and eligible for reaping +image_cache_stall_timeout = 86400 + +# ============ Delayed Delete Options ============================= + +# Turn on/off delayed delete +delayed_delete = False + +# Delayed delete time in seconds +scrub_time = 43200 + +# Directory that the scrubber will use to remind itself of what to delete +# Make sure this is also set in glance-scrubber.conf +scrubber_datadir = /var/lib/glance/scrubber + +[pipeline:glance-api] +#pipeline = versionnegotiation context apiv1app +# NOTE: use the following pipeline for keystone +pipeline = versionnegotiation authtoken context apiv1app + +# To enable Image Cache Management API replace pipeline with below: +# pipeline = versionnegotiation context imagecache apiv1app +# NOTE: use the following pipeline for keystone auth (with caching) +# pipeline = versionnegotiation authtoken context imagecache apiv1app + +[pipeline:versions] +pipeline = versionsapp + +[app:versionsapp] +paste.app_factory = glance.api.versions:app_factory + +[app:apiv1app] +paste.app_factory = glance.api.v1:app_factory + +[filter:versionnegotiation] +paste.filter_factory = glance.api.middleware.version_negotiation:filter_factory + +[filter:imagecache] +paste.filter_factory = glance.api.middleware.image_cache:filter_factory + +[filter:context] +paste.filter_factory = glance.common.context:filter_factory + +[filter:authtoken] +paste.filter_factory = keystone.middleware.auth_token:filter_factory +service_protocol = http +service_host = 127.0.0.1 +service_port = 5000 +auth_host = 127.0.0.1 +auth_port = 35357 +auth_protocol = http +auth_uri = http://127.0.0.1:5000/ +admin_token = %SERVICE_TOKEN% diff --git a/files/glance-registry.conf b/files/glance-registry.conf new file mode 100644 index 0000000..c3ca9a7 --- /dev/null +++ b/files/glance-registry.conf @@ -0,0 +1,70 @@ +[DEFAULT] +# Show more verbose log output (sets INFO log level output) +verbose = True + +# Show debugging output in logs (sets DEBUG log level output) +debug = True + +# Address to bind the registry server +bind_host = 0.0.0.0 + +# Port the bind the registry server to +bind_port = 9191 + +# Log to this file. Make sure you do not set the same log +# file for both the API and registry servers! +log_file = %DEST%/glance/registry.log + +# Where to store images +filesystem_store_datadir = %DEST%/glance/images + +# Send logs to syslog (/dev/log) instead of to file specified by `log_file` +use_syslog = False + +# SQLAlchemy connection string for the reference implementation +# registry server. Any valid SQLAlchemy connection string is fine. +# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine +sql_connection = %SQL_CONN% + +# Period in seconds after which SQLAlchemy should reestablish its connection +# to the database. +# +# MySQL uses a default `wait_timeout` of 8 hours, after which it will drop +# idle connections. This can result in 'MySQL Gone Away' exceptions. If you +# notice this, you can lower this value to ensure that SQLAlchemy reconnects +# before MySQL can drop the connection. +sql_idle_timeout = 3600 + +# Limit the api to return `param_limit_max` items in a call to a container. If +# a larger `limit` query param is provided, it will be reduced to this value. +api_limit_max = 1000 + +# If a `limit` query param is not provided in an api request, it will +# default to `limit_param_default` +limit_param_default = 25 + +[pipeline:glance-registry] +#pipeline = context registryapp +# NOTE: use the following pipeline for keystone +pipeline = authtoken keystone_shim context registryapp + +[app:registryapp] +paste.app_factory = glance.registry.server:app_factory + +[filter:context] +context_class = glance.registry.context.RequestContext +paste.filter_factory = glance.common.context:filter_factory + +[filter:authtoken] +paste.filter_factory = keystone.middleware.auth_token:filter_factory +service_protocol = http +service_host = 127.0.0.1 +service_port = 5000 +auth_host = 127.0.0.1 +auth_port = 35357 +auth_protocol = http +auth_uri = http://127.0.0.1:5000/ +admin_token = %SERVICE_TOKEN% + +[filter:keystone_shim] +paste.filter_factory = keystone.middleware.glance_auth_token:filter_factory diff --git a/files/keystone.conf b/files/keystone.conf new file mode 100644 index 0000000..687273b --- /dev/null +++ b/files/keystone.conf @@ -0,0 +1,86 @@ +[DEFAULT] +# Show more verbose log output (sets INFO log level output) +verbose = False + +# Show debugging output in logs (sets DEBUG log level output) +debug = False + +# Which backend store should Keystone use by default. +# Default: 'sqlite' +# Available choices are 'sqlite' [future will include LDAP, PAM, etc] +default_store = sqlite + +# Log to this file. Make sure you do not set the same log +# file for both the API and registry servers! +log_file = %DEST%/keystone/keystone.log + +# List of backends to be configured +backends = keystone.backends.sqlalchemy +#For LDAP support, add: ,keystone.backends.ldap + +# Dictionary Maps every service to a header.Missing services would get header +# X_(SERVICE_NAME) Key => Service Name, Value => Header Name +service-header-mappings = { + 'nova' : 'X-Server-Management-Url', + 'swift' : 'X-Storage-Url', + 'cdn' : 'X-CDN-Management-Url'} + +# Address to bind the API server +# TODO Properties defined within app not available via pipeline. +service_host = 0.0.0.0 + +# Port the bind the API server to +service_port = 5000 + +# Address to bind the Admin API server +admin_host = 0.0.0.0 + +# Port the bind the Admin API server to +admin_port = 35357 + +#Role that allows to perform admin operations. +keystone-admin-role = KeystoneAdmin + +#Role that allows to perform service admin operations. +keystone-service-admin-role = KeystoneServiceAdmin + +[keystone.backends.sqlalchemy] +# SQLAlchemy connection string for the reference implementation registry +# server. Any valid SQLAlchemy connection string is fine. +# See: http://bit.ly/ideIpI +#sql_connection = sqlite:///keystone.db +sql_connection = %SQL_CONN% +backend_entities = ['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant', + 'User', 'Credentials', 'EndpointTemplates', 'Token', + 'Service'] + +# Period in seconds after which SQLAlchemy should reestablish its connection +# to the database. +sql_idle_timeout = 30 + +[pipeline:admin] +pipeline = + urlrewritefilter + admin_api + +[pipeline:keystone-legacy-auth] +pipeline = + urlrewritefilter + legacy_auth + RAX-KEY-extension + service_api + +[app:service_api] +paste.app_factory = keystone.server:service_app_factory + +[app:admin_api] +paste.app_factory = keystone.server:admin_app_factory + +[filter:urlrewritefilter] +paste.filter_factory = keystone.middleware.url:filter_factory + +[filter:legacy_auth] +paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory + +[filter:RAX-KEY-extension] +paste.filter_factory = keystone.contrib.extensions.service.raxkey.frontend:filter_factory diff --git a/files/keystone_data.sh b/files/keystone_data.sh new file mode 100755 index 0000000..f48eaf9 --- /dev/null +++ b/files/keystone_data.sh @@ -0,0 +1,43 @@ +#!/bin/bash +BIN_DIR=${BIN_DIR:-.} +# Tenants +$BIN_DIR/keystone-manage $* tenant add admin +$BIN_DIR/keystone-manage $* tenant add demo +$BIN_DIR/keystone-manage $* tenant add invisible_to_admin + +# Users +$BIN_DIR/keystone-manage $* user add admin %ADMIN_PASSWORD% +$BIN_DIR/keystone-manage $* user add demo %ADMIN_PASSWORD% + +# Roles +$BIN_DIR/keystone-manage $* role add Admin +$BIN_DIR/keystone-manage $* role add Member +$BIN_DIR/keystone-manage $* role add KeystoneAdmin +$BIN_DIR/keystone-manage $* role add KeystoneServiceAdmin +$BIN_DIR/keystone-manage $* role grant Admin admin admin +$BIN_DIR/keystone-manage $* role grant Member demo demo +$BIN_DIR/keystone-manage $* role grant Member demo invisible_to_admin +$BIN_DIR/keystone-manage $* role grant Admin admin demo +$BIN_DIR/keystone-manage $* role grant Admin admin +$BIN_DIR/keystone-manage $* role grant KeystoneAdmin admin +$BIN_DIR/keystone-manage $* role grant KeystoneServiceAdmin admin + +# Services +$BIN_DIR/keystone-manage $* service add nova compute "Nova Compute Service" +$BIN_DIR/keystone-manage $* service add glance image "Glance Image Service" +$BIN_DIR/keystone-manage $* service add keystone identity "Keystone Identity Service" + +#endpointTemplates +$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne nova http://%HOST_IP%:8774/v1.1/%tenant_id% http://%HOST_IP%:8774/v1.1/%tenant_id% http://%HOST_IP%:8774/v1.1/%tenant_id% 1 1 +$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne glance http://%HOST_IP%:9292/v1.1/%tenant_id% http://%HOST_IP%:9292/v1.1/%tenant_id% http://%HOST_IP%:9292/v1.1/%tenant_id% 1 1 +$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne keystone http://%HOST_IP%:5000/v2.0 http://%HOST_IP%:35357/v2.0 http://%HOST_IP%:5000/v2.0 1 1 +# $BIN_DIR/keystone-manage $* endpointTemplates add RegionOne swift http://%HOST_IP%:8080/v1/AUTH_%tenant_id% http://%HOST_IP%:8080/ http://%HOST_IP%:8080/v1/AUTH_%tenant_id% 1 1 + +# Tokens +$BIN_DIR/keystone-manage $* token add %SERVICE_TOKEN% admin admin 2015-02-05T00:00 + +# EC2 related creds - note we are setting the token to user_password +# but keystone doesn't parse them - it is just a blob from keystone's +# point of view +$BIN_DIR/keystone-manage $* credentials add admin EC2 'admin_%ADMIN_PASSWORD%' admin admin || echo "no support for adding credentials" +$BIN_DIR/keystone-manage $* credentials add demo EC2 'demo_%ADMIN_PASSWORD%' demo demo || echo "no support for adding credentials" diff --git a/files/pips/dash b/files/pips/dash new file mode 100644 index 0000000..4d6343e --- /dev/null +++ b/files/pips/dash @@ -0,0 +1,21 @@ +nose==1.0.0 +Django==1.3 +django-nose==0.1.2 +django-mailer +django-registration==0.7 +kombu +python-cloudfiles +python-dateutil +routes +webob +sqlalchemy +paste +PasteDeploy +sqlalchemy-migrate +eventlet +xattr +pep8 +pylint + +-e git+https://github.com/jacobian/openstack.compute.git#egg=openstack + diff --git a/files/pips/keystone b/files/pips/keystone new file mode 100644 index 0000000..09636e4 --- /dev/null +++ b/files/pips/keystone @@ -0,0 +1 @@ +PassLib diff --git a/files/screenrc b/files/screenrc new file mode 100644 index 0000000..1ca47da --- /dev/null +++ b/files/screenrc @@ -0,0 +1,9 @@ +hardstatus on +hardstatus alwayslastline +hardstatus string "%{.bW}%-w%{.rW}%n %t%{-}%+w %=%{..G}%H %{..Y}%d/%m %c" + +defscrollback 1024 + +vbell off +startup_message off + diff --git a/files/sources.list b/files/sources.list new file mode 100644 index 0000000..96fab5f --- /dev/null +++ b/files/sources.list @@ -0,0 +1,9 @@ +deb http://us.archive.ubuntu.com/ubuntu/ natty main restricted +deb http://us.archive.ubuntu.com/ubuntu/ natty-updates main restricted +deb http://us.archive.ubuntu.com/ubuntu/ natty universe +deb http://us.archive.ubuntu.com/ubuntu/ natty-updates universe +deb http://us.archive.ubuntu.com/ubuntu/ natty multiverse +deb http://us.archive.ubuntu.com/ubuntu/ natty-updates multiverse +deb http://security.ubuntu.com/ubuntu natty-security main restricted +deb http://security.ubuntu.com/ubuntu natty-security universe +deb http://security.ubuntu.com/ubuntu natty-security multiverse diff --git a/files/sudo/nova b/files/sudo/nova new file mode 100644 index 0000000..3843416 --- /dev/null +++ b/files/sudo/nova @@ -0,0 +1 @@ +socat diff --git a/lxc_network_hostonlyplusnat.sh b/lxc_network_hostonlyplusnat.sh new file mode 100755 index 0000000..4e29ed7 --- /dev/null +++ b/lxc_network_hostonlyplusnat.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# Print some usage info +function usage { + echo "Usage: $0 [OPTION] [host_ip]" + echo "Set up temporary networking for LXC" + echo "" + echo " -n, --dry-run Just print the commands that would execute." + echo " -h, --help Print this usage message." + echo "" + exit +} + +# Allow passing the ip address on the command line. +function process_option { + case "$1" in + -h|--help) usage;; + -n|--dry-run) dry_run=1;; + *) host_ip="$1" + esac +} + +# Set up some defaults +host_ip= +dry_run=0 +bridge=br0 +DRIER= + +# Process the args +for arg in "$@"; do + process_option $arg +done + +if [ $dry_run ]; then + DRIER=echo +fi + +if [ "$UID" -ne "0" ]; then + echo "This script must be run with root privileges." + exit 1 +fi + +# Check for bridge-utils. +BRCTL=`which brctl` +if [ ! -x "$BRCTL" ]; then + echo "This script requires you to install bridge-utils." + echo "Try: sudo apt-get install bridge-utils." + exit 1 +fi + +# Scare off the nubs. +echo "=====================================================" +echo +echo "WARNING" +echo +echo "This script will modify your current network setup," +echo "this can be a scary thing and it is recommended that" +echo "you have something equivalent to physical access to" +echo "this machine before continuing in case your network" +echo "gets all funky." +echo +echo "If you don't want to continue, hit CTRL-C now." + +if [ -z "$host_ip" ]; +then + echo "Otherwise, please type in your host's ip address and" + echo "hit enter." + echo + echo "=====================================================" + read host_ip +else + echo "Otherwise hit enter." + echo + echo "=====================================================" + read accept +fi + + +# Add a bridge interface, this will choke if there is already +# a bridge named $bridge +$DRIER $BRCTL addbr $bridge +$DRIER ip addr add 192.168.1.1/24 dev $bridge +if [ $dry_run ]; then + echo "echo 1 > /proc/sys/net/ipv4/ip_forward" +else + echo 1 > /proc/sys/net/ipv4/ip_forward +fi +$DRIER ifconfig $bridge up + +# Set up the NAT for the instances +$DRIER iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source $host_ip +$DRIER iptables -I FORWARD -s 192.168.1.0/24 -j ACCEPT + diff --git a/make_image.sh b/make_image.sh new file mode 100755 index 0000000..0d5074b --- /dev/null +++ b/make_image.sh @@ -0,0 +1,178 @@ +#!/bin/bash +# make_image.sh - Create Ubuntu images in various formats +# +# Supported formats: qcow (kvm), vmdk (vmserver), vdi (vbox), vhd (vpc), raw +# +# Requires sudo to root + +ROOTSIZE=${ROOTSIZE:-8192} +SWAPSIZE=${SWAPSIZE:-1024} +MIN_PKGS=${MIN_PKGS:-"apt-utils gpgv openssh-server"} + +usage() { + echo "Usage: $0 - Create Ubuntu images" + echo "" + echo "$0 [-m] [-r rootsize] [-s swapsize] release format" + echo "$0 -C [-m] release chrootdir" + echo "$0 -I [-r rootsize] [-s swapsize] chrootdir format" + echo "" + echo "-C - Create the initial chroot dir" + echo "-I - Create the final image from a chroot" + echo "-m - minimal installation" + echo "-r size - root fs size in MB" + echo "-s size - swap fs size in MB" + echo "release - Ubuntu release: jaunty - oneric" + echo "format - image format: qcow2, vmdk, vdi, vhd, xen, raw, fs" + exit 1 +} + +while getopts CIhmr:s: c; do + case $c in + C) CHROOTONLY=1 + ;; + I) IMAGEONLY=1 + ;; + h) usage + ;; + m) MINIMAL=1 + ;; + r) ROOTSIZE=$OPTARG + ;; + s) SWAPSIZE=$OPTARG + ;; + esac +done +shift `expr $OPTIND - 1` + +if [ ! "$#" -eq "2" -o -n "$CHROOTONLY" -a -n "$IMAGEONLY" ]; then + usage +fi + +# Default args +RELEASE=$1 +FORMAT=$2 +CHROOTDIR="" + +if [ -n "$CHROOTONLY" ]; then + RELEASE=$1 + CHROOTDIR=$2 + FORMAT="pass" +fi + +if [ -n "$IMAGEONLY" ]; then + CHROOTDIR=$1 + FORMAT=$2 + RELEASE="pass" +fi + +case $FORMAT in + kvm|qcow2) FORMAT=qcow2 + QFORMAT=qcow2 + HYPER=kvm + ;; + vmserver|vmdk) + FORMAT=vmdk + QFORMAT=vmdk + HYPER=vmserver + ;; + vbox|vdi) FORMAT=vdi + QFORMAT=vdi + HYPER=kvm + ;; + vhd|vpc) FORMAT=vhd + QFORMAT=vpc + HYPER=kvm + ;; + xen) FORMAT=raw + QFORMAT=raw + HYPER=xen + ;; + raw) FORMAT=raw + QFORMAT=raw + HYPER=kvm + ;; + pass) ;; + *) echo "Unknown format: $FORMAT" + usage +esac + +case $RELEASE in + natty) ;; + maverick) ;; + lucid) ;; + karmic) ;; + jaunty) ;; + pass) ;; + *) echo "Unknown release: $RELEASE" + usage + ;; +esac + +# Install stuff if necessary +if [ -z `which vmbuilder` ]; then + sudo apt-get install ubuntu-vm-builder +fi + +if [ -n "$CHROOTONLY" ]; then + # Build a chroot directory + HYPER=kvm + if [ "$MINIMAL" = 1 ]; then + ARGS="--variant=minbase" + for i in $MIN_PKGS; do + ARGS="$ARGS --addpkg=$i" + done + fi + sudo vmbuilder $HYPER ubuntu $ARGS \ + --suite $RELEASE \ + --only-chroot \ + --chroot-dir=$CHROOTDIR \ + --overwrite \ + --addpkg=$MIN_PKGS \ + + sudo cp -p files/sources.list $CHROOTDIR/etc/apt/sources.list + sudo chroot $CHROOTDIR apt-get update + + exit 0 +fi + +# Build the image +TMPDIR=tmp +TMPDISK=`mktemp imgXXXXXXXX` +SIZE=$[$ROOTSIZE+$SWAPSIZE+1] +dd if=/dev/null of=$TMPDISK bs=1M seek=$SIZE count=1 + +if [ -n "$IMAGEONLY" ]; then + # Build image from chroot + sudo vmbuilder $HYPER ubuntu $ARGS \ + --existing-chroot=$CHROOTDIR \ + --overwrite \ + --rootsize=$ROOTSIZE \ + --swapsize=$SWAPSIZE \ + --tmpfs - \ + --raw=$TMPDISK \ + +else + # Do the whole shebang in one pass + ARGS="--variant=minbase" + for i in $MIN_PKGS; do + ARGS="$ARGS --addpkg=$i" + done + sudo vmbuilder $HYPER ubuntu $ARGS \ + --suite $RELEASE \ + --overwrite \ + --rootsize=$ROOTSIZE \ + --swapsize=$SWAPSIZE \ + --tmpfs - \ + --raw=$TMPDISK \ + +fi + +if [ "$FORMAT" = "raw" ]; then + # Get image + mv $TMPDISK $RELEASE.$FORMAT +else + # Convert image + qemu-img convert -O $QFORMAT $TMPDISK $RELEASE.$FORMAT + rm $TMPDISK +fi +rm -rf ubuntu-$HYPER diff --git a/stack.sh b/stack.sh new file mode 100755 index 0000000..f6bf534 --- /dev/null +++ b/stack.sh @@ -0,0 +1,672 @@ +#!/usr/bin/env bash + +# **stack.sh** is an opinionated openstack developer installation. + +# This script installs and configures *nova*, *glance*, *dashboard* and *keystone* + +# This script allows you to specify configuration options of what git +# repositories to use, enabled services, network configuration and various +# passwords. If you are crafty you can run the script on multiple nodes using +# shared settings for common resources (mysql, rabbitmq) and build a multi-node +# developer install. + +# To keep this script simple we assume you are running on an **Ubuntu 11.04 +# Natty** machine. It should work in a VM or physical server. Additionally we +# put the list of *apt* and *pip* dependencies and other configuration files in +# this repo. So start by grabbing this script and the dependencies. + +# Learn more and get the most recent version at http://devstack.org + +# Sanity Check +# ============ + +# Record the start time. This allows us to print how long this script takes to run. +START_TIME=`python -c "import time; print time.time()"` + +# Warn users who aren't on natty, but allow them to override check and attempt +# installation with ``FORCE=yes ./stack`` +if ! grep -q natty /etc/lsb-release; then + echo "WARNING: this script has only been tested on natty" + if [[ "$FORCE" != "yes" ]]; then + echo "If you wish to run this script anyway run with FORCE=yes" + exit 1 + fi +fi + +# stack.sh keeps the list of **apt** and **pip** dependencies in external +# files, along with config templates and other useful files. You can find these +# in the ``files`` directory (next to this script). We will reference this +# directory using the ``FILES`` variable in this script. +FILES=`pwd`/files +if [ ! -d $FILES ]; then + echo "ERROR: missing devstack/files - did you grab more than just stack.sh?" + exit 1 +fi + +# OpenStack is designed to be run as a regular user (Dashboard will fail to run +# as root, since apache refused to startup serve content from root user). If +# stack.sh is run as root, it automatically creates a stack user with +# sudo privileges and runs as that user. + +if [[ $EUID -eq 0 ]]; then + echo "You are running this script as root." + + # since this script runs as a normal user, we need to give that user + # ability to run sudo + apt-get update + apt-get install -qqy sudo + + if ! getent passwd | grep -q stack; then + echo "Creating a user called stack" + useradd -U -G sudo -s /bin/bash -m stack + fi + echo "Giving stack user passwordless sudo priviledges" + echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + + echo "Copying files to stack user" + cp -r -f `pwd` /home/stack/ + THIS_DIR=$(basename $(dirname $(readlink -f $0))) + chown -R stack /home/stack/$THIS_DIR + echo "Running the script as stack in 3 seconds..." + sleep 3 + if [[ "$SHELL_AFTER_RUN" != "no" ]]; then + exec su -c "cd /home/stack/$THIS_DIR/; bash stack.sh; bash" stack + else + exec su -c "cd /home/stack/$THIS_DIR/; bash stack.sh" stack + fi + exit 0 +fi + +# So that errors don't compound we exit on any errors so you see only the +# first error that occured. +set -o errexit + +# Print the commands being run so that we can see the command that triggers +# an error. It is also useful for following allowing as the install occurs. +set -o xtrace + +# Settings +# ======== + +# This script is customizable through setting environment variables. If you +# want to override a setting you can either:: +# +# export MYSQL_PASS=anothersecret +# ./stack.sh +# +# You can also pass options on a single line ``MYSQL_PASS=simple ./stack.sh`` +# +# Additionally, you can put any local variables into a ``localrc`` file, like:: +# +# MYSQL_PASS=anothersecret +# MYSQL_USER=hellaroot +# +# We try to have sensible defaults, so you should be able to run ``./stack.sh`` +# in most cases. +# +# We our settings from ``stackrc``. This file is distributed with devstack and +# contains locations for what repositories to use. If you want to use other +# repositories and branches, you can add your own settings with another file +# called ``localrc`` +# +# If ``localrc`` exists, then ``stackrc`` will load those settings. This is +# useful for changing a branch or repostiory to test other versions. Also you +# can store your other settings like **MYSQL_PASS** or **ADMIN_PASSWORD** instead +# of letting devstack generate random ones for you. +source ./stackrc + +# Destination path for installation ``DEST`` +DEST=${DEST:-/opt/stack} +sudo mkdir -p $DEST +sudo chown `whoami` $DEST + +# Set the destination directories for openstack projects +NOVA_DIR=$DEST/nova +DASH_DIR=$DEST/dash +GLANCE_DIR=$DEST/glance +KEYSTONE_DIR=$DEST/keystone +NOVACLIENT_DIR=$DEST/python-novaclient +OPENSTACKX_DIR=$DEST/openstackx +NOVNC_DIR=$DEST/noVNC + +# Specify which services to launch. These generally correspond to screen tabs +ENABLED_SERVICES=${ENABLED_SERVICES:-g-api,g-reg,key,n-api,n-cpu,n-net,n-sch,n-vnc,dash,mysql,rabbit} + +# Nova hypervisor configuration. We default to **kvm** but will drop back to +# **qemu** if we are unable to load the kvm module. Stack.sh can also install +# an **LXC** based system. +LIBVIRT_TYPE=${LIBVIRT_TYPE:-kvm} + +# nova supports pluggable schedulers. ``SimpleScheduler`` should work in most +# cases unless you are working on multi-zone mode. +SCHEDULER=${SCHEDULER:-nova.scheduler.simple.SimpleScheduler} + +# Use the first IP unless an explicit is set by ``HOST_IP`` environment variable +if [ ! -n "$HOST_IP" ]; then + HOST_IP=`LC_ALL=C /sbin/ifconfig | grep -m 1 'inet addr:'| cut -d: -f2 | awk '{print $1}'` +fi + +# Nova Network Configuration +# -------------------------- + +# FIXME: more documentation about why these are important flags. Also +# we should make sure we use the same variable names as the flag names. + +PUBLIC_INTERFACE=${PUBLIC_INTERFACE:-eth0} +FIXED_RANGE=${FIXED_RANGE:-10.0.0.0/24} +FIXED_NETWORK_SIZE=${FIXED_NETWORK_SIZE:-256} +FLOATING_RANGE=${FLOATING_RANGE:-172.24.4.1/28} +NET_MAN=${NET_MAN:-FlatDHCPManager} +EC2_DMZ_HOST=${EC2_DMZ_HOST:-$HOST_IP} +FLAT_NETWORK_BRIDGE=${FLAT_NETWORK_BRIDGE:-br100} +VLAN_INTERFACE=${VLAN_INTERFACE:-$PUBLIC_INTERFACE} + +# Multi-host is a mode where each compute node runs its own network node. This +# allows network operations and routing for a VM to occur on the server that is +# running the VM - removing a SPOF and bandwidth bottleneck. +MULTI_HOST=${MULTI_HOST:-0} + +# If you are using FlatDHCP on multiple hosts, set the ``FLAT_INTERFACE`` +# variable but make sure that the interface doesn't already have an +# ip or you risk breaking things. +# +# **DHCP Warning**: If your flat interface device uses DHCP, there will be a +# hiccup while the network is moved from the flat interface to the flat network +# bridge. This will happen when you launch your first instance. Upon launch +# you will lose all connectivity to the node, and the vm launch will probably +# fail. +# +# If you are running on a single node and don't need to access the VMs from +# devices other than that node, you can set the flat interface to the same +# value as ``FLAT_NETWORK_BRIDGE``. This will stop the network hiccup from +# occuring. +FLAT_INTERFACE=${FLAT_INTERFACE:-eth0} + +## FIXME(ja): should/can we check that FLAT_INTERFACE is sane? + + +# MySQL & RabbitMQ +# ---------------- + +# We configure Nova, Dashboard, Glance and Keystone to use MySQL as their +# database server. While they share a single server, each has their own +# database and tables. + +# By default this script will install and configure MySQL. If you want to +# use an existing server, you can pass in the user/password/host parameters. +# You will need to send the same ``MYSQL_PASS`` to every host if you are doing +# a multi-node devstack installation. +MYSQL_USER=${MYSQL_USER:-root} +MYSQL_PASS=${MYSQL_PASS:-`openssl rand -hex 12`} +MYSQL_HOST=${MYSQL_HOST:-localhost} + +# don't specify /db in this string, so we can use it for multiple services +BASE_SQL_CONN=${BASE_SQL_CONN:-mysql://$MYSQL_USER:$MYSQL_PASS@$MYSQL_HOST} + +# Rabbit connection info +RABBIT_HOST=${RABBIT_HOST:-localhost} +RABBIT_PASSWORD=${RABBIT_PASSWORD:-`openssl rand -hex 12`} + +# Glance connection info. Note the port must be specified. +GLANCE_HOSTPORT=${GLANCE_HOSTPORT:-$HOST_IP:9292} + +# Keystone +# -------- + +# Service Token - Openstack components need to have an admin token +# to validate user tokens. +SERVICE_TOKEN=${SERVICE_TOKEN:-`openssl rand -hex 12`} +# Dash currently truncates usernames and passwords at 20 characters +# so use 10 bytes +ADMIN_PASSWORD=${ADMIN_PASSWORD:-`openssl rand -hex 10`} + + +# Install Packages +# ================ +# +# Openstack uses a fair number of other projects. + + +# install apt requirements +sudo apt-get install -qqy `cat $FILES/apts/* | cut -d\# -f1 | grep -Ev "mysql-server|rabbitmq-server"` + +# install python requirements +sudo PIP_DOWNLOAD_CACHE=/var/cache/pip pip install `cat $FILES/pips/*` + +# git clone only if directory doesn't exist already. Since ``DEST`` might not +# be owned by the installation user, we create the directory and change the +# ownership to the proper user. +function git_clone { + if [ ! -d $2 ]; then + sudo mkdir $2 + sudo chown `whoami` $2 + git clone $1 $2 + cd $2 + # This checkout syntax works for both branches and tags + git checkout $3 + fi +} + +# compute service +git_clone $NOVA_REPO $NOVA_DIR $NOVA_BRANCH +# image catalog service +git_clone $GLANCE_REPO $GLANCE_DIR $GLANCE_BRANCH +# unified auth system (manages accounts/tokens) +git_clone $KEYSTONE_REPO $KEYSTONE_DIR $KEYSTONE_BRANCH +# a websockets/html5 or flash powered VNC console for vm instances +git_clone $NOVNC_REPO $NOVNC_DIR $NOVNC_BRANCH +# django powered web control panel for openstack +git_clone $DASH_REPO $DASH_DIR $DASH_BRANCH $DASH_TAG +# python client library to nova that dashboard (and others) use +git_clone $NOVACLIENT_REPO $NOVACLIENT_DIR $NOVACLIENT_BRANCH +# openstackx is a collection of extensions to openstack.compute & nova +# that is *deprecated*. The code is being moved into python-novaclient & nova. +git_clone $OPENSTACKX_REPO $OPENSTACKX_DIR $OPENSTACKX_BRANCH + +# Initialization +# ============== + + +# setup our checkouts so they are installed into python path +# allowing ``import nova`` or ``import glance.client`` +cd $NOVA_DIR; sudo python setup.py develop +cd $NOVACLIENT_DIR; sudo python setup.py develop +cd $KEYSTONE_DIR; sudo python setup.py develop +cd $GLANCE_DIR; sudo python setup.py develop +cd $OPENSTACKX_DIR; sudo python setup.py develop +cd $DASH_DIR/django-openstack; sudo python setup.py develop +cd $DASH_DIR/openstack-dashboard; sudo python setup.py develop + +# Add a useful screenrc. This isn't required to run openstack but is we do +# it since we are going to run the services in screen for simple +cp $FILES/screenrc ~/.screenrc + +## TODO: update current user to allow sudo for all commands in files/sudo/* + +# Rabbit +# --------- + +if [[ "$ENABLED_SERVICES" =~ "rabbit" ]]; then + # Install and start rabbitmq-server + sudo apt-get install -y -q rabbitmq-server + # change the rabbit password since the default is "guest" + sudo rabbitmqctl change_password guest $RABBIT_PASSWORD +fi + +# Mysql +# --------- + +if [[ "$ENABLED_SERVICES" =~ "mysql" ]]; then + + # Seed configuration with mysql password so that apt-get install doesn't + # prompt us for a password upon install. + cat <> $NOVA_DIR/bin/nova.conf +} + +# (re)create nova.conf +rm -f $NOVA_DIR/bin/nova.conf +add_nova_flag "--verbose" +add_nova_flag "--nodaemon" +add_nova_flag "--scheduler_driver=$SCHEDULER" +add_nova_flag "--dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf" +add_nova_flag "--network_manager=nova.network.manager.$NET_MAN" +add_nova_flag "--my_ip=$HOST_IP" +add_nova_flag "--public_interface=$PUBLIC_INTERFACE" +add_nova_flag "--vlan_interface=$VLAN_INTERFACE" +add_nova_flag "--sql_connection=$BASE_SQL_CONN/nova" +add_nova_flag "--libvirt_type=$LIBVIRT_TYPE" +add_nova_flag "--osapi_extensions_path=$OPENSTACKX_DIR/extensions" +add_nova_flag "--vncproxy_url=http://$HOST_IP:6080" +add_nova_flag "--vncproxy_wwwroot=$NOVNC_DIR/" +add_nova_flag "--api_paste_config=$KEYSTONE_DIR/examples/paste/nova-api-paste.ini" +add_nova_flag "--image_service=nova.image.glance.GlanceImageService" +add_nova_flag "--ec2_dmz_host=$EC2_DMZ_HOST" +add_nova_flag "--rabbit_host=$RABBIT_HOST" +add_nova_flag "--rabbit_password=$RABBIT_PASSWORD" +add_nova_flag "--glance_api_servers=$GLANCE_HOSTPORT" +add_nova_flag "--flat_network_bridge=$FLAT_NETWORK_BRIDGE" +if [ -n "$FLAT_INTERFACE" ]; then + add_nova_flag "--flat_interface=$FLAT_INTERFACE" +fi +if [ -n "$MULTI_HOST" ]; then + add_nova_flag "--multi_host=$MULTI_HOST" +fi + +# Nova Database +# ~~~~~~~~~~~~~ + +# All nova components talk to a central database. We will need to do this step +# only once for an entire cluster. + +if [[ "$ENABLED_SERVICES" =~ "mysql" ]]; then + # (re)create nova database + mysql -u$MYSQL_USER -p$MYSQL_PASS -e 'DROP DATABASE IF EXISTS nova;' + mysql -u$MYSQL_USER -p$MYSQL_PASS -e 'CREATE DATABASE nova;' + + # (re)create nova database + $NOVA_DIR/bin/nova-manage db sync + + # create a small network + $NOVA_DIR/bin/nova-manage network create private $FIXED_RANGE 1 $FIXED_NETWORK_SIZE + + # create some floating ips + $NOVA_DIR/bin/nova-manage floating create $FLOATING_RANGE +fi + + +# Keystone +# -------- + +if [[ "$ENABLED_SERVICES" =~ "key" ]]; then + # (re)create keystone database + mysql -u$MYSQL_USER -p$MYSQL_PASS -e 'DROP DATABASE IF EXISTS keystone;' + mysql -u$MYSQL_USER -p$MYSQL_PASS -e 'CREATE DATABASE keystone;' + + # FIXME (anthony) keystone should use keystone.conf.example + KEYSTONE_CONF=$KEYSTONE_DIR/etc/keystone.conf + cp $FILES/keystone.conf $KEYSTONE_CONF + sudo sed -e "s,%SQL_CONN%,$BASE_SQL_CONN/keystone,g" -i $KEYSTONE_CONF + sudo sed -e "s,%DEST%,$DEST,g" -i $KEYSTONE_CONF + + # keystone_data.sh creates our admin user and our ``SERVICE_TOKEN``. + KEYSTONE_DATA=$KEYSTONE_DIR/bin/keystone_data.sh + cp $FILES/keystone_data.sh $KEYSTONE_DATA + sudo sed -e "s,%HOST_IP%,$HOST_IP,g" -i $KEYSTONE_DATA + sudo sed -e "s,%SERVICE_TOKEN%,$SERVICE_TOKEN,g" -i $KEYSTONE_DATA + sudo sed -e "s,%ADMIN_PASSWORD%,$ADMIN_PASSWORD,g" -i $KEYSTONE_DATA + # initialize keystone with default users/endpoints + BIN_DIR=$KEYSTONE_DIR/bin bash $KEYSTONE_DATA +fi + + +# Launch Services +# =============== + +# nova api crashes if we start it with a regular screen command, +# so send the start command by forcing text into the window. +# Only run the services specified in ``ENABLED_SERVICES`` + +# our screen helper to launch a service in a hidden named screen +function screen_it { + NL=`echo -ne '\015'` + if [[ "$ENABLED_SERVICES" =~ "$1" ]]; then + screen -S nova -X screen -t $1 + screen -S nova -p $1 -X stuff "$2$NL" + fi +} + +# create a new named screen to run processes in +screen -d -m -S nova -t nova +sleep 1 + +# launch the glance registery service +if [[ "$ENABLED_SERVICES" =~ "g-reg" ]]; then + screen_it g-reg "cd $GLANCE_DIR; bin/glance-registry --config-file=etc/glance-registry.conf" +fi + +# launch the glance api and wait for it to answer before continuing +if [[ "$ENABLED_SERVICES" =~ "g-api" ]]; then + screen_it g-api "cd $GLANCE_DIR; bin/glance-api --config-file=etc/glance-api.conf" + while ! wget -q -O- http://$GLANCE_HOSTPORT; do + echo "Waiting for g-api ($GLANCE_HOSTPORT) to start..." + sleep 1 + done +fi + +# launch the keystone and wait for it to answer before continuing +if [[ "$ENABLED_SERVICES" =~ "key" ]]; then + screen_it key "cd $KEYSTONE_DIR && $KEYSTONE_DIR/bin/keystone --config-file $KEYSTONE_CONF -d" + while ! wget -q -O- http://127.0.0.1:5000; do + echo "Waiting for keystone to start..." + sleep 1 + done +fi + +# launch the nova-api and wait for it to answer before continuing +if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then + screen_it n-api "cd $NOVA_DIR && $NOVA_DIR/bin/nova-api" + while ! wget -q -O- http://127.0.0.1:8774; do + echo "Waiting for nova-api to start..." + sleep 1 + done +fi +# Launching nova-compute should be as simple as running ``nova-compute`` but +# have to do a little more than that in our script. Since we add the group +# ``libvirtd`` to our user in this script, when nova-compute is run it is +# within the context of our original shell (so our groups won't be updated). +# We can send the command nova-compute to the ``newgrp`` command to execute +# in a specific context. +screen_it n-cpu "cd $NOVA_DIR && echo $NOVA_DIR/bin/nova-compute | newgrp libvirtd" +screen_it n-net "cd $NOVA_DIR && $NOVA_DIR/bin/nova-network" +screen_it n-sch "cd $NOVA_DIR && $NOVA_DIR/bin/nova-scheduler" +screen_it n-vnc "cd $NOVNC_DIR && ./utils/nova-wsproxy.py 6080 --web . --flagfile=../nova/bin/nova.conf" +screen_it dash "cd $DASH_DIR && sudo /etc/init.d/apache2 restart; sudo tail -f /var/log/apache2/error.log" + +# Install Images +# ============== + +# Upload a couple images to glance. **TTY** is a simple small image that use the +# lets you login to it with username/password of user/password. TTY is useful +# for basic functionality. We all include an Ubuntu cloud build of **Natty**. +# Natty uses cloud-init, supporting login via keypair and sending scripts as +# userdata. +# +# Read more about cloud-init at https://help.ubuntu.com/community/CloudInit + +if [[ "$ENABLED_SERVICES" =~ "g-reg" ]]; then + # create a directory for the downloadedthe images tarballs. + mkdir -p $FILES/images + + # Debug Image (TTY) + # ----------------- + + # Downloads the image (ami/aki/ari style), then extracts it. Upon extraction + # we upload to glance with the glance cli tool. TTY is a stripped down + # version of ubuntu. + if [ ! -f $FILES/tty.tgz ]; then + wget -c http://images.ansolabs.com/tty.tgz -O $FILES/tty.tgz + fi + + # extract ami-tty/image, aki-tty/image & ari-tty/image + tar -zxf $FILES/tty.tgz -C $FILES/images + + # Use glance client to add the kernel, ramdisk and finally the root + # filesystem. We parse the results of the uploads to get glance IDs of the + # ramdisk and kernel and use them for the root filesystem. + RVAL=`glance add -A $SERVICE_TOKEN name="tty-kernel" is_public=true container_format=aki disk_format=aki < $FILES/images/aki-tty/image` + KERNEL_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "` + RVAL=`glance add -A $SERVICE_TOKEN name="tty-ramdisk" is_public=true container_format=ari disk_format=ari < $FILES/images/ari-tty/image` + RAMDISK_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "` + glance add -A $SERVICE_TOKEN name="tty" is_public=true container_format=ami disk_format=ami kernel_id=$KERNEL_ID ramdisk_id=$RAMDISK_ID < $FILES/images/ami-tty/image + + # Ubuntu 11.04 aka Natty + # ---------------------- + + # Downloaded from ubuntu enterprise cloud images. This + # image doesn't use the ramdisk functionality + if [ ! -f $FILES/natty.tgz ]; then + wget -c http://uec-images.ubuntu.com/natty/current/natty-server-cloudimg-amd64.tar.gz -O $FILES/natty.tgz + fi + + tar -zxf $FILES/natty.tgz -C $FILES/images + + RVAL=`glance add -A $SERVICE_TOKEN name="uec-natty-kernel" is_public=true container_format=aki disk_format=aki < $FILES/images/natty-server-cloudimg-amd64-vmlinuz-virtual` + KERNEL_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "` + glance add -A $SERVICE_TOKEN name="uec-natty" is_public=true container_format=ami disk_format=ami kernel_id=$KERNEL_ID < $FILES/images/natty-server-cloudimg-amd64.img + +fi + +# Using the cloud +# =============== + +# If you installed the dashboard on this server, then you should be able +# to access the site using your browser. +if [[ "$ENABLED_SERVICES" =~ "dash" ]]; then + echo "dashboard is now available at http://$HOST_IP/" +fi + +# If keystone is present, you can point nova cli to this server +if [[ "$ENABLED_SERVICES" =~ "key" ]]; then + echo "keystone is serving at http://$HOST_IP:5000/v2.0/" + echo "examples on using novaclient command line is in exercise.sh" + echo "the default users are: admin and demo" + echo "the password: $ADMIN_PASSWORD" +fi + +# Fin +# === + +# End our timer and give a timing summary +END_TIME=`python -c "import time; print time.time()"` +ELAPSED=`python -c "print $END_TIME - $START_TIME"` +echo "stack.sh completed in $ELAPSED seconds." diff --git a/stackrc b/stackrc new file mode 100644 index 0000000..15d73ce --- /dev/null +++ b/stackrc @@ -0,0 +1,33 @@ +# compute service +NOVA_REPO=https://github.com/cloudbuilders/nova.git +NOVA_BRANCH=diablo + +# image catalog service +GLANCE_REPO=https://github.com/cloudbuilders/glance.git +GLANCE_BRANCH=diablo + +# unified auth system (manages accounts/tokens) +KEYSTONE_REPO=https://github.com/cloudbuilders/keystone.git +KEYSTONE_BRANCH=diablo + +# a websockets/html5 or flash powered VNC console for vm instances +NOVNC_REPO=https://github.com/cloudbuilders/noVNC.git +NOVNC_BRANCH=master + +# django powered web control panel for openstack +DASH_REPO=https://github.com/cloudbuilders/openstack-dashboard.git +DASH_BRANCH=master + +# python client library to nova that dashboard (and others) use +NOVACLIENT_REPO=https://github.com/cloudbuilders/python-novaclient.git +NOVACLIENT_BRANCH=master + +# openstackx is a collection of extensions to openstack.compute & nova +# that is *deprecated*. The code is being moved into python-novaclient & nova. +OPENSTACKX_REPO=https://github.com/cloudbuilders/openstackx.git +OPENSTACKX_BRANCH=diablo + +# allow local overrides of env variables +if [ -f ./localrc ]; then + source ./localrc +fi diff --git a/tools/install_openvpn.sh b/tools/install_openvpn.sh new file mode 100644 index 0000000..a3a2346 --- /dev/null +++ b/tools/install_openvpn.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# install_openvpn.sh - Install OpenVPN and generate required certificates +# +# install_openvpn.sh --client name +# install_openvpn.sh --server [name] +# +# name is used on the CN of the generated cert, and the filename of +# the configuration, certificate and key files. +# +# --server mode configures the host with a running OpenVPN server instance +# --client mode creates a tarball of a client configuration for this server + +# VPN Config +VPN_SERVER=${VPN_SERVER:-`ifconfig eth0 | awk "/inet addr:/ { print \$2 }" | cut -d: -f2`} # 50.56.12.212 +VPN_PROTO=${VPN_PROTO:-tcp} +VPN_PORT=${VPN_PORT:-6081} +VPN_DEV=${VPN_DEV:-tun} +VPN_CLIENT_NET=${VPN_CLIENT_NET:-172.16.28.0} +VPN_CLIENT_MASK=${VPN_CLIENT_MASK:-255.255.255.0} +VPN_LOCAL_NET=${VPN_LOCAL_NET:-10.0.0.0} +VPN_LOCAL_MASK=${VPN_LOCAL_MASK:-255.255.0.0} + +VPN_DIR=/etc/openvpn +CA_DIR=/etc/openvpn/easy-rsa + +usage() { + echo "$0 - OpenVPN install and certificate generation" + echo "" + echo "$0 --client name" + echo "$0 --server [name]" + echo "" + echo " --server mode configures the host with a running OpenVPN server instance" + echo " --client mode creates a tarball of a client configuration for this server" + exit 1 +} + +if [ -z $1 ]; then + usage +fi + +# Install OpenVPN +if [ ! -x `which openvpn` ]; then + apt-get install -y openvpn bridge-utils +fi +if [ ! -d $CA_DIR ]; then + cp -pR /usr/share/doc/openvpn/examples/easy-rsa/2.0/ $CA_DIR +fi + +OPWD=`pwd` +cd $CA_DIR +source ./vars + +# Override the defaults +export KEY_COUNTRY="US" +export KEY_PROVINCE="TX" +export KEY_CITY="SanAntonio" +export KEY_ORG="Cloudbuilders" +export KEY_EMAIL="rcb@lists.rackspace.com" + +if [ ! -r $CA_DIR/keys/dh1024.pem ]; then + # Initialize a new CA + $CA_DIR/clean-all + $CA_DIR/build-dh + $CA_DIR/pkitool --initca + openvpn --genkey --secret $CA_DIR/keys/ta.key ## Build a TLS key +fi + +do_server() { + NAME=$1 + # Generate server certificate + $CA_DIR/pkitool --server $NAME + + (cd $CA_DIR/keys; + cp $NAME.crt $NAME.key ca.crt dh1024.pem ta.key $VPN_DIR + ) + cat >$VPN_DIR/$NAME.conf <$TMP_DIR/$HOST.conf <$VPN_DIR/hostname + fi + do_server $NAME + ;; + --clean) $CA_DIR/clean-all + ;; + *) usage +esac diff --git a/upload_image.sh b/upload_image.sh new file mode 100755 index 0000000..da73f16 --- /dev/null +++ b/upload_image.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# upload_image.sh - Upload Ubuntu images (create if necessary) in various formats +# Supported formats: qcow (kvm), vmdk (vmserver), vdi (vbox), vhd (vpc) +# Requires sudo to root + +usage() { + echo "$0 - Upload images to OpenStack" + echo "" + echo "$0 [-h host] [-p port] release format" + exit 1 +} + +HOST=${HOST:-localhost} +PORT=${PORT:-9292} +DEST=${DEST:-/opt/stack} + +while getopts h:p: c; do + case $c in + h) HOST=$OPTARG + ;; + p) PORT=$OPTARG + ;; + esac +done +shift `expr $OPTIND - 1` + +RELEASE=$1 +FORMAT=$2 + +case $FORMAT in + kvm|qcow2) FORMAT=qcow2 + TARGET=kvm + ;; + vmserver|vmdk) + FORMAT=vmdk + TARGET=vmserver + ;; + vbox|vdi) TARGET=kvm + FORMAT=vdi + ;; + vhd|vpc) TARGET=kvm + FORMAT=vhd + ;; + *) echo "Unknown format: $FORMAT" + usage +esac + +case $RELEASE in + natty) ;; + maverick) ;; + lucid) ;; + karmic) ;; + jaunty) ;; + *) if [ ! -r $RELEASE.$FORMAT ]; then + echo "Unknown release: $RELEASE" + usage + fi + ;; +esac + +GLANCE=`which glance` +if [ -z "$GLANCE" ]; then + if [ -x "$DEST/glance/bin/glance" ]; then + # Look for stack.sh's install + GLANCE="$DEST/glance/bin/glance" + else + # Install Glance client in $DEST + echo "Glance not found, must install client" + OWD=`pwd` + cd $DEST + sudo apt-get install python-pip python-eventlet python-routes python-greenlet python-argparse python-sqlalchemy python-wsgiref python-pastedeploy python-xattr + sudo pip install kombu + sudo git clone https://github.com/cloudbuilders/glance.git + cd glance + sudo python setup.py develop + cd $OWD + GLANCE=`which glance` + fi +fi + +# Create image if it doesn't exist +if [ ! -r $RELEASE.$FORMAT ]; then + DIR=`dirname $0` + echo "$RELEASE.$FORMAT not found, creating..." + $DIR/make_image.sh $RELEASE $FORMAT +fi + +# Upload the image +echo "Uploading image $RELEASE.$FORMAT to $HOST" +$GLANCE add name=$RELEASE.$FORMAT is_public=true disk_format=$FORMAT --host $HOST --port $PORT <$RELEASE.$FORMAT