From c910b470e61a35230bc7ddaced13c3d51fac32fd Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 24 Jun 2010 04:11:53 +0100 Subject: re-added cloudpipe Conflicts: bin/nova-manage nova/auth/users.py nova/compute/network.py --- CA/geninter.sh | 6 +- bin/nova-manage | 41 ++++++++++++ debian/changelog | 127 +++++++++++++++++++++++++++++++++++- debian/nova-common.install | 1 + nova/auth/users.py | 25 ++++++- nova/cloudpipe/__init__.py | 26 ++++++++ nova/cloudpipe/api.py | 70 ++++++++++++++++++++ nova/cloudpipe/bootscript.sh | 58 ++++++++++++++++ nova/cloudpipe/client.ovpn.template | 41 ++++++++++++ nova/cloudpipe/pipelib.py | 83 +++++++++++++++++++++++ nova/compute/network.py | 10 +++ nova/endpoint/api.py | 3 + nova/flags.py | 2 + 13 files changed, 487 insertions(+), 6 deletions(-) create mode 100644 nova/cloudpipe/__init__.py create mode 100644 nova/cloudpipe/api.py create mode 100755 nova/cloudpipe/bootscript.sh create mode 100644 nova/cloudpipe/client.ovpn.template create mode 100644 nova/cloudpipe/pipelib.py diff --git a/CA/geninter.sh b/CA/geninter.sh index ad3332ad9..2aa64a842 100755 --- a/CA/geninter.sh +++ b/CA/geninter.sh @@ -16,7 +16,7 @@ # ARG is the id of the user - +export SUBJ=/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=customer-intCA-$3 mkdir INTER/$1 cd INTER/$1 cp ../../openssl.cnf.tmpl openssl.cnf @@ -25,6 +25,6 @@ mkdir certs crl newcerts private echo "10" > serial touch index.txt openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes -openssl req -new -sha1 -key private/cakey.pem -out ../../reqs/inter$1.csr -batch -subj "/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=customer-intCA-$1" +openssl req -new -sha2 -key private/cakey.pem -out ../../reqs/inter$1.csr -batch -subj "$SUBJ" cd ../../ -openssl ca -extensions v3_ca -days 365 -out INTER/$1/cacert.pem -in reqs/inter$1.csr -config openssl.cnf -batch \ No newline at end of file +openssl ca -extensions v3_ca -days 365 -out INTER/$1/cacert.pem -in reqs/inter$1.csr -config openssl.cnf -batch diff --git a/bin/nova-manage b/bin/nova-manage index 765eb1f53..76de41308 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -25,11 +25,51 @@ from nova import flags from nova import utils from nova.auth import users from nova.compute import model +from nova.cloudpipe import pipelib from nova.endpoint import cloud import time FLAGS = flags.FLAGS +class VpnCommands(object): + def __init__(self): + self.manager = users.UserManager.instance() + self.instdir = model.InstanceDirectory() + self.pipe = pipelib.CloudPipe(cloud.CloudController()) + + def list(self): + print "%-12s\t" % 'user', + print "%-12s\t" % 'ip:port', + print "%s" % 'state' + for user in self.manager.get_users(): + print "%-12s\t" % user.name, + print "%s:%s\t" % (user.vpn_ip, user.vpn_port), + + vpn = self.__vpn_for(user.name) + if vpn: + print vpn['instance_id'], + print vpn['state'] + else: + print None + + def __vpn_for(self, username): + for instance in self.instdir.all: + if (instance.state.has_key('image_id') + and instance['image_id'] == FLAGS.vpn_image_id + and not instance['state'] in ['shutting_down', 'shutdown'] + and instance['owner_id'] == username): + return instance + + def spawn(self): + for u in reversed(self.manager.get_users()): + if not self.__vpn_for(u.id): + print 'spawning %s' % u.id + self.pipe.launch_vpn_instance(u.id) + time.sleep(10) + + def run(self, username): + self.pipe.launch_vpn_instance(username) + class UserCommands(object): def __init__(self): @@ -109,6 +149,7 @@ def usage(script_name): categories = [ ('user', UserCommands), ('project', ProjectCommands), + ('vpn', VpnCommands), ] diff --git a/debian/changelog b/debian/changelog index 2b226e048..ee326f3a8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,129 @@ -nova (0.3.0-1) UNRELEASED; urgency=low +nova (0.2.1-1) UNRELEASED; urgency=low + + * Support ephemeral (local) space for instances + * instance related fixes + * fix network & cloudpipe bugs + + -- Vishvananda Ishaya Mon, 25 May 2010 12:14:00 -0700 + +nova (0.2.0-20) UNRELEASED; urgency=low + + * template files are in proper folder + + -- Vishvananda Ishaya Mon, 25 May 2010 12:14:00 -0700 + +nova (0.2.0-19) UNRELEASED; urgency=low + + * removed mox dependency and added templates to install + + -- Vishvananda Ishaya Mon, 25 May 2010 11:53:00 -0700 + +nova (0.2.0-18) UNRELEASED; urgency=low + + * api server properly sends instance status code + + -- Vishvananda Ishaya Mon, 24 May 2010 17:18:00 -0700 + +nova (0.2.0-17) UNRELEASED; urgency=low + + * redis-backed datastore + + -- Vishvananda Ishaya Mon, 24 May 2010 16:28:00 -0700 + +nova (0.2.0-16) UNRELEASED; urgency=low + + * make sure twistd.pid is really overriden + + -- Manish Singh Sun, 23 May 2010 22:18:47 -0700 + +nova (0.2.0-15) UNRELEASED; urgency=low + + * rpc shouldn't require tornado unless you are using attach_to_tornado + + -- Jesse Andrews Sun, 23 May 2010 21:59:00 -0700 + +nova (0.2.0-14) UNRELEASED; urgency=low + + * quicky init scripts for the other services, based on nova-objectstore + + -- Manish Singh Sun, 23 May 2010 21:49:43 -0700 + +nova (0.2.0-13) UNRELEASED; urgency=low + + * init script for nova-objectstore + + -- Manish Singh Sun, 23 May 2010 21:33:25 -0700 + +nova (0.2.0-12) UNRELEASED; urgency=low + + * kvm, kpartx required for nova-compute + + -- Jesse Andrews Sun, 23 May 2010 21:32:00 -0700 + +nova (0.2.0-11) UNRELEASED; urgency=low + + * Need to include the python modules in nova-common.install as well. + + -- Manish Singh Sun, 23 May 2010 20:04:27 -0700 + +nova (0.2.0-10) UNRELEASED; urgency=low + + * add more requirements to bin packages + + -- Jesse Andrews Sun, 23 May 2010 19:54:00 -0700 + +nova (0.2.0-9) UNRELEASED; urgency=low + + * nova bin packages should depend on the same version of nova-common they + were built from. + + -- Manish Singh Sun, 23 May 2010 18:46:34 -0700 + +nova (0.2.0-8) UNRELEASED; urgency=low + + * Require libvirt 0.8.1 or newer for nova-compute + + -- Jesse Andrews Sun, 23 May 2010 18:33:00 -0700 + +nova (0.2.0-7) UNRELEASED; urgency=low + + * Split bins into separate packages + + -- Manish Singh Sun, 23 May 2010 18:46:34 -0700 + +nova (0.2.0-6) UNRELEASED; urgency=low + + * Add python-m2crypto to deps + + -- Jesse Andrews Sun, 23 May 2010 18:33:00 -0700 + +nova (0.2.0-5) UNRELEASED; urgency=low + + * Add python-gflags to deps + + -- Manish Singh Sun, 23 May 2010 18:28:50 -0700 + +nova (0.2.0-4) UNRELEASED; urgency=low + + * install scripts + + -- Manish Singh Sun, 23 May 2010 18:16:27 -0700 + +nova (0.2.0-3) UNRELEASED; urgency=low + + * debian build goop + + -- Manish Singh Sun, 23 May 2010 18:06:37 -0700 + +nova (0.2.0-2) UNRELEASED; urgency=low + + * improved requirements + + -- Jesse Andrews Sun, 23 May 2010 17:42:00 -0700 + +nova (0.2.0-1) UNRELEASED; urgency=low * initial release - -- Jesse Andrews Thur, 27 May 2010 12:28:00 -0700 + -- Jesse Andrews Fri, 21 May 2010 12:28:00 -0700 diff --git a/debian/nova-common.install b/debian/nova-common.install index c9358ac41..ab7455314 100644 --- a/debian/nova-common.install +++ b/debian/nova-common.install @@ -1,4 +1,5 @@ bin/nova-manage usr/bin nova/auth/novarc.template usr/lib/pymodules/python2.6/nova/auth +nova/cloudpipe/client.ovpn.template usr/lib/pymodules/python2.6/nova/cloudpipe nova/compute/libvirt.xml.template usr/lib/pymodules/python2.6/nova/compute usr/lib/python*/*-packages/nova/* diff --git a/nova/auth/users.py b/nova/auth/users.py index c60922feb..2bfc3cec3 100644 --- a/nova/auth/users.py +++ b/nova/auth/users.py @@ -23,6 +23,7 @@ import logging import os import shutil import string +from string import Template import tempfile import uuid import zipfile @@ -56,12 +57,16 @@ flags.DEFINE_string('project_ldap_subtree', 'ou=Groups,dc=example,dc=com', 'OU f flags.DEFINE_string('credentials_template', utils.abspath('auth/novarc.template'), 'Template for creating users rc file') +flags.DEFINE_string('vpn_client_template', + utils.abspath('cloudpipe/client.ovpn.template'), + 'Template for creating users vpn file') flags.DEFINE_string('credential_key_file', 'pk.pem', 'Filename of private key in credentials zip') flags.DEFINE_string('credential_cert_file', 'cert.pem', 'Filename of certificate in credentials zip') flags.DEFINE_string('credential_rc_file', 'novarc', 'Filename of rc in credentials zip') +flags.DEFINE_string('vpn_ip', '127.0.0.1', 'Public IP for the cloudpipe VPN servers') class AuthBase(object): @classmethod @@ -83,6 +88,23 @@ class User(AuthBase): self.secret = secret self.admin = admin + @property + def vpn_port(self): + port_map = self.keeper['vpn_ports'] + if not port_map: port_map = {} + if not port_map.has_key(self.id): + ports = port_map.values() + if len(ports) > 0: + port_map[self.id] = max(ports) + 1 + else: + port_map[self.id] = 8000 + self.keeper['vpn_ports'] = port_map + return self.keeper['vpn_ports'][self.id] + + @property + def vpn_ip(self): + return FLAGS.vpn_ip + def is_admin(self): """allows user to see objects from all projects""" return self.admin @@ -353,7 +375,8 @@ class UserManager(object): return crypto.sign_csr(csr, uid) def __cert_subject(self, uid): - return "/C=US/ST=California/L=The_Mission/O=AnsoLabs/OU=Nova/CN=%s-%s" % (uid, str(datetime.datetime.utcnow().isoformat())) + # FIXME(ja) - this should be pulled from a global configuration + return "/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=%s-%s" % (uid, str(datetime.datetime.utcnow().isoformat())) class LDAPWrapper(object): diff --git a/nova/cloudpipe/__init__.py b/nova/cloudpipe/__init__.py new file mode 100644 index 000000000..e8ac53976 --- /dev/null +++ b/nova/cloudpipe/__init__.py @@ -0,0 +1,26 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright [2010] [Anso Labs, LLC] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +:mod:`nova.cloudpipe` -- VPN Server Management +===================================================== + +.. automodule:: nova.cloudpipe + :platform: Unix + :synopsis: An OpenVPN server for every nova user. +.. moduleauthor:: Devin Carlen +.. moduleauthor:: Vishvananda Ishaya +.. moduleauthor:: Joshua McKenty +""" diff --git a/nova/cloudpipe/api.py b/nova/cloudpipe/api.py new file mode 100644 index 000000000..5395e9724 --- /dev/null +++ b/nova/cloudpipe/api.py @@ -0,0 +1,70 @@ +#!/usr/bin/python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright [2010] [Anso Labs, LLC] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Tornado REST API Request Handlers for CloudPipe +""" + +import logging +import urllib + +from nova import vendor +import tornado.web + +from nova import crypto +from nova.auth import users + +_log = logging.getLogger("api") +_log.setLevel(logging.DEBUG) + + +class CloudPipeRequestHandler(tornado.web.RequestHandler): + def get(self, path): + path = self.request.path + _log.debug( "Cloudpipe path is %s" % path) + self.manager = users.UserManager.instance() + if path.endswith("/getca/"): + self.send_root_ca() + elif path.endswith("/getcert/"): + _log.debug( "Getting zip for %s" % (path[9:])) + try: + self.send_signed_zip(self.path[9:]) + except Exception, err: + _log.debug('ERROR: %s\n' % str(err)) + raise tornado.web.HTTPError(404) + self.finish() + + def get_username_from_ip(self, ip): + cc = self.application.controllers['Cloud'] + instance = cc.get_instance_by_ip(ip) + return instance['owner_id'] + + def send_root_ca(self): + _log.debug( "Getting root ca") + username = self.get_username_from_ip(self.request.remote_ip) + self.set_header("Content-Type", "text/plain") + self.write(crypto.fetch_ca(username)) + + def send_signed_zip(self, username): + self.set_header("Content-Type", "application/zip") + self.write(self.manager.get_signed_zip(username)) + + def post(self, *args, **kwargs): + self.manager = users.UserManager.instance() + username = self.get_username_from_ip(self.request.remote_ip) + cert = self.get_argument('cert', '') + self.write(self.manager.sign_cert(urllib.unquote(cert), username)) + self.finish() diff --git a/nova/cloudpipe/bootscript.sh b/nova/cloudpipe/bootscript.sh new file mode 100755 index 000000000..bb710617e --- /dev/null +++ b/nova/cloudpipe/bootscript.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright [2010] [Anso Labs, LLC] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This gets zipped and run on the cloudpipe-managed OpenVPN server + +export SUPERVISOR="http://10.255.255.1:8773/cloudpipe" +export VPN_IP=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{print $1}'` +export BROADCAST=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f3 | awk '{print $1}'` +export DHCP_MASK=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f4 | awk '{print $1}'` +export GATEWAY=`netstat -r | grep default | cut -d' ' -f10` +export SUBJ=/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=customer-vpn-$VPN_IP + +DHCP_LOWER=`echo $BROADCAST | awk -F. '{print $1"."$2"."$3"." $4 - 10 }'` +DHCP_UPPER=`echo $BROADCAST | awk -F. '{print $1"."$2"."$3"." $4 - 1 }'` + +# generate a server DH +openssl dhparam -out /etc/openvpn/dh1024.pem 1024 + +# generate a server priv key +openssl genrsa -out /etc/openvpn/server.key 2048 + +# generate a server CSR +openssl req -new -key /etc/openvpn/server.key -out /etc/openvpn/server.csr -batch -subj "$SUBJ" + +# URLEncode the CSR +CSRTEXT=`cat /etc/openvpn/server.csr` +CSRTEXT=$(python -c "import urllib; print urllib.quote('''$CSRTEXT''')") + +# SIGN the csr and save as server.crt +# CURL fetch to the supervisor, POSTing the CSR text, saving the result as the CRT file +curl $SUPERVISOR -d "cert=$CSRTEXT" > /etc/openvpn/server.crt +curl $SUPERVISOR/getca/ > /etc/openvpn/ca.crt + +# Customize the server.conf.template +cd /etc/openvpn + +sed -e s/VPN_IP/$VPN_IP/g server.conf.template > server.conf +sed -i -e s/DHCP_SUBNET/$DHCP_MASK/g server.conf +sed -i -e s/DHCP_LOWER/$DHCP_LOWER/g server.conf +sed -i -e s/DHCP_UPPER/$DHCP_UPPER/g server.conf +sed -i -e s/max-clients\ 1/max-clients\ 10/g server.conf + +echo "\npush \"route 10.255.255.1 255.255.255.255 $GATEWAY\"\n" >> server.conf +echo "\npush \"route 10.255.255.253 255.255.255.255 $GATEWAY\"\n" >> server.conf + +/etc/init.d/openvpn start diff --git a/nova/cloudpipe/client.ovpn.template b/nova/cloudpipe/client.ovpn.template new file mode 100644 index 000000000..d6cf8e19c --- /dev/null +++ b/nova/cloudpipe/client.ovpn.template @@ -0,0 +1,41 @@ +# Copyright [2010] [Anso Labs, LLC] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# NOVA user connection +# Edit the following lines to point to your cert files: +cert $certfile +key $keyfile + +ca cacert.pem + +client +dev tap +proto udp + +remote $ip $port +resolv-retry infinite +nobind + +# Downgrade privileges after initialization (non-Windows only) +user nobody +group nogroup +comp-lzo + +# Set log file verbosity. +verb 2 + +keepalive 10 120 +ping-timer-rem +persist-tun +persist-key diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py new file mode 100644 index 000000000..f69486f3e --- /dev/null +++ b/nova/cloudpipe/pipelib.py @@ -0,0 +1,83 @@ +# Copyright [2010] [Anso Labs, LLC] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +CloudPipe - Build a user-data payload zip file, and launch +an instance with it. + +""" + +import logging +import os +import tempfile +from zipfile import ZipFile, ZIP_DEFLATED + +from nova import flags +from nova.auth import users +from nova import utils +from nova.endpoint import api + +FLAGS = flags.FLAGS + +flags.DEFINE_string('boot_script_template', + utils.abspath('cloudpipe/bootscript.sh'), + 'Template for script to run on cloudpipe instance boot') + +class CloudPipe(object): + def __init__(self, cloud_controller): + self.controller = cloud_controller + self.manager = users.UserManager.instance() + + def launch_vpn_instance(self, username): + logging.debug( "Launching VPN for %s" % (username)) + user = self.manager.get_user(username) + # Make a payload.zip + tmpfolder = tempfile.mkdtemp() + filename = "payload.zip" + zippath = os.path.join(tmpfolder, filename) + z = ZipFile(zippath, "w", ZIP_DEFLATED) + + z.write(FLAGS.boot_script_template,'autorun.sh') + z.close() + + self.setup_keypair(username) + zippy = open(zippath, "r") + context = api.APIRequestContext(handler=None, user=user) + + reservation = self.controller.run_instances(context, + user_data=zippy.read().encode("base64"), + max_count=1, + min_count=1, + image_id=FLAGS.vpn_image_id, + key_name="vpn-key", + security_groups=["vpn-secgroup"]) + zippy.close() + + def setup_keypair(self, username): + try: + private_key, fingerprint = self.manager.generate_key_pair(username, "vpn-key") + os.mkdir("%s/%s" % (FLAGS.keys_path, username)) + private_key.save(os.path.abspath("%s/%s" % (FLAGS.keys_path, username))) + except: + pass + + # def setup_secgroups(self, username): + # conn = self.euca.connection_for(username) + # try: + # secgroup = conn.create_security_group("vpn-secgroup", "vpn-secgroup") + # secgroup.authorize(ip_protocol = "udp", from_port = "1194", to_port = "1194", cidr_ip = "0.0.0.0/0") + # secgroup.authorize(ip_protocol = "tcp", from_port = "80", to_port = "80", cidr_ip = "0.0.0.0/0") + # secgroup.authorize(ip_protocol = "tcp", from_port = "22", to_port = "22", cidr_ip = "0.0.0.0/0") + # except: + # pass diff --git a/nova/compute/network.py b/nova/compute/network.py index 618e7bffb..3001b1375 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -51,6 +51,11 @@ flags.DEFINE_string('private_range', '10.0.0.0/8', 'Private IP address block') logging.getLogger().setLevel(logging.DEBUG) +# CLEANUP: +# TODO(ja): Save the IPs at the top of each subnet for cloudpipe vpn clients +# TODO(ja): use singleton for usermanager instead of self.manager in vlanpool et al +# TODO(ja): does vlanpool "keeper" need to know the min/max - shouldn't FLAGS always win? +# TODO(joshua): Save the IPs at the top of each subnet for cloudpipe vpn clients class BaseNetwork(datastore.RedisModel): bridge_gets_ip = False @@ -97,6 +102,11 @@ class BaseNetwork(datastore.RedisModel): def bridge_name(self): return "br%s" % (self["vlan"]) + def range(self): + # the .2 address is always CloudPipe + for idx in range(3, len(self.network)-2): + yield self.network[idx] + @property def user(self): return users.UserManager.instance().get_user(self['user_id']) diff --git a/nova/endpoint/api.py b/nova/endpoint/api.py index e70694210..977daff27 100755 --- a/nova/endpoint/api.py +++ b/nova/endpoint/api.py @@ -37,6 +37,7 @@ from nova import flags from nova import utils from nova.endpoint import cloud from nova.auth import users +import nova.cloudpipe.api FLAGS = flags.FLAGS flags.DEFINE_integer('cc_port', 8773, 'cloud controller port') @@ -322,6 +323,8 @@ class APIServerApplication(tornado.web.Application): def __init__(self, user_manager, controllers): tornado.web.Application.__init__(self, [ (r'/', RootRequestHandler), + (r'/cloudpipe/(.*)', nova.cloudpipe.api.CloudPipeRequestHandler), + (r'/cloudpipe', nova.cloudpipe.api.CloudPipeRequestHandler), (r'/services/([A-Za-z0-9]+)/', APIRequestHandler), (r'/latest/([-A-Za-z0-9/]*)', MetadataRequestHandler), (r'/2009-04-04/([-A-Za-z0-9/]*)', MetadataRequestHandler), diff --git a/nova/flags.py b/nova/flags.py index 7818e1b14..84a670e6b 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -68,6 +68,8 @@ DEFINE_string('default_instance_type', 'm1.small', 'default instance type to use, testing only') +DEFINE_string('vpn_image_id', 'ami-CLOUDPIPE', 'AMI for cloudpipe vpn server') + # UNUSED DEFINE_string('node_availability_zone', 'nova', -- cgit